Skip to content

Conversation

@blaumeise20
Copy link
Contributor

This PR adds a method CompilerDirectives.mergeExplodeKey which can be used to explicitly mark variables to be used as the merge key in MERGE_EXPLODE loop explosion.

Currently, the entire frame state is used for merging. Taking Espresso as an example, if you would jump to the same bci but assign a different value to another variable, it will result in two separate code paths. This can lead to unexpected graph size explosion and bugs. With the method introduced in this PR, you can mark a single variable to be used as the key. Truffle will merge on this key only, but verify that other variables stay the same. If merging should occur but there is a mismatch, the compilation will bail out.

Future steps include allowing multiple variables to be marked simultaneously (which has to be extended into irreducible loop handling), and creating an option for explicit PHI nodes, so local variables can be used as counters without the need for objects.

@oracle-contributor-agreement oracle-contributor-agreement bot added the OCA Verified All contributors have signed the Oracle Contributor Agreement. label Nov 18, 2025
@blaumeise20
Copy link
Contributor Author

@gilles-duboscq

Copy link
Member

@gilles-duboscq gilles-duboscq left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please also check the 2 failed gates

import jdk.graal.compiler.nodes.spi.CanonicalizerTool;

@NodeInfo(nameTemplate = "LoopExplosionKey", cycles = CYCLES_0, size = SIZE_0)
public final class LoopExplosionKeyNode extends FloatingNode implements Canonicalizable {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What happens if the directive is used in a non-merge-explode method and this node remains in the graph?
I think this should either be a very explicit compilation failure or performance warning. If it's only a warning then we need to remove such nodes.

@chumer what do you think? Should using CompilationDirective.mergeExplodeKey outside of the context of a @ExplodeLoop(kind = LoopExplosionKind.MERGE_EXPLODE) method be a compilation error or a performance warning?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would go with a compilation error. We can do a similar thing as in VerifyFrameDoesNotEscapePhase.
Register the phase in TruffleTier.

* @param i the variable that should be used as the merge key.
* @return the unchanged value
*
* @since 25.1
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add an entry about this in the truffle changelog.md. Including a migration recommendation that if you use ExplodeLoop MERGE that you should also use this new API.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What issue ID should I specify?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can use GR-71613 ("Allow explicitly selecting the value used for merging in MERGE_EXPLODE")

* lose the node when encoding the graph. At the time of decoding,
* `canDelayIntrinsification` will be false, so the actual node is created.
*/
return false;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That is a good thought, but I don't think it is necessary here to delay the intrinisification.
We delay it for isPartialEvaluationConstant because the interpretation will be different if the argument is a constant and it is only really a PE constant during decoding. For this intrinsic it does not make a difference as we unconditionally wrap the value into LoopExplosionKeyNode. So I think it would actually be better always do this during parsing already, as a method once parsed is decoded many times, so we avoid the overhead of applying the intrinsic here. Probably a minor effect on compile speed, but small things add up and its also simpler this way.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I couldn't manage to keep the node alive until decoding. It would always vanish, even though I explicitly made canonicalize return this. This was the only solution I found that worked. Do you have any idea why the node could have been deleted?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Out of my expertise. Maybe @davleopo knows?

import jdk.graal.compiler.nodes.spi.CanonicalizerTool;

@NodeInfo(nameTemplate = "LoopExplosionKey", cycles = CYCLES_0, size = SIZE_0)
public final class LoopExplosionKeyNode extends FloatingNode implements Canonicalizable {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would go with a compilation error. We can do a similar thing as in VerifyFrameDoesNotEscapePhase.
Register the phase in TruffleTier.

while (methodScope.currentLoopScope != null) {
/* Process nodes of loop. */
while (!methodScope.currentLoopScope.nodesToProcess.isEmpty()) {
// TODO(blaumeise20): use MethodScope instead of LoopScope here and set currentLoopScope directly
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TODOs must never link to user names but either link Jira or Github issues.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I saw quite a few TODOs with a username or even no assignment at all, so I thought it would be fine... What should I put here instead?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well it's still unclear to me as part of which change you want to do this and why.
FYI there is:

  • GR-71753 Allow multiple explicit keys in MERGE_EXPLODE
  • GR-71752 Allow marking variables explicitly for phi node creation in MERGE_EXPLODE

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! The way this is currently handled isn't particularly beautiful and I was thinking of actually setting the currentLoopScope inside processNextNode. I already got a few changes (not done yet) that I would add as part of the next step. Should I specify GR-71752 then?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I saw quite a few TODOs with a username

It is only a strongly enforced rule for the Truffle team, not necessarily for the compiler team. I think it is good practice regardless.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should I specify GR-71752 then

That should be fine

keyNode.replaceAndDelete(keyNode.value);
}
}
if (mergeKey != null && mergeKey.size() > 1) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add a comment that if mergeKey is null we do what we previously did and that is there for compatibility reasons if the merge key is not yet used.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll add it in the method below where the actual values are read from the frame state, this here is just the check for multiple marked variables.

@chumer chumer requested a review from davleopo December 1, 2025 15:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

OCA Verified All contributors have signed the Oracle Contributor Agreement.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants