This is an archive of the discontinued LLVM Phabricator instance.

Extend the statepoint intrinsic to allow statepoints to be marked as transitions from GC-aware code to code that is not GC-aware.
ClosedPublic

Authored by pgavlin on May 5 2015, 9:20 AM.

Details

Summary

This changes the shape of the statepoint intrinsic from:

@llvm.experimental.gc.statepoint(anyptr target, i32 # call args, i32 unused, ...call args, i32 # deopt args, ...deopt args, ...gc args)

to:

@llvm.experimental.gc.statepoint(anyptr target, i32 # call args, i32 flags, ...call args, i32 # transition args, ...transition args, i32 # deopt args, ...deopt args, ...gc args)

This extension offers the backend the opportunity to insert (somewhat) arbitrary code to manage the transition from GC-aware code to code that is not GC-aware and back.

In order to support the injection of transition code, this extension wraps the STATEPOINT ISD node generated by the usual lowering lowering with two additional nodes: GC_TRANSITION_START and GC_TRANSITION_END. The transition arguments that were passed passed to the intrinsic (if any) are lowered and provided as operands to these nodes and may be used by the backend during code generation.

Eventually, the lowering of the GC_TRANSITION_{START,END} nodes should be informed by the GC strategy in use for the function containing the intrinsic call; for now, these nodes are instead replaced with no-ops.

Diff Detail

Repository
rL LLVM

Event Timeline

pgavlin updated this revision to Diff 24953.May 5 2015, 9:20 AM
pgavlin retitled this revision from to Extend the statepoint intrinsic to allow statepoints to be marked as transitions from GC-aware code to code that is not GC-aware..
pgavlin updated this object.
pgavlin edited the test plan for this revision. (Show Details)
pgavlin added a subscriber: Unknown Object (MLST).
reames edited edge metadata.May 5 2015, 5:28 PM

General approach seems reasonable. The documentation needs major improvement though before this is ready to go in. If we hadn't talked about this offline, I would have been very confused about what this patch was trying to accomplish.

docs/Statepoints.rst
253 ↗(On Diff #24953)

Which bit of the flags is used for this? From the current documentation, it's not clear how to use these.

264 ↗(On Diff #24953)

What does "normally" mean?

268 ↗(On Diff #24953)

oeprands -> operands

271 ↗(On Diff #24953)

Meta point: you never really define transition sequence or transition. Add section to the documentation with the background (preferably with an example) and reference it appropriately.

As part of this, justify why the gc attributes isn't enough. Your function pointer case is fine, just mention it since the reader might be wondering.

485 ↗(On Diff #24953)

If you feel like it, you can delete the deopt args from this example. If not, I'll do it at some point.

include/llvm/IR/Statepoint.h
27 ↗(On Diff #24953)

Consider using a class enum here. Possibly:
enum class StatepointFlags {
....
}

76 ↗(On Diff #24953)

I'd prefer to see a getFlags function added and this become, getFlags() & statepoint::GCTransition.

120 ↗(On Diff #24953)

Isn't this just return call_args_end()

It looks like you're defining the length argument to be part of the gc_transition_args range? At first, I thought you were breaking with the convention, but then I noticed you copied this from vm_state_begin and friends. That really doesn't seem like the right approach. Having the length being consider part of the arg bundle just doesn't seem right.

I'm okay with this landing as is for the moment, but I'll likely fix all of these in the not too distant future.

lib/CodeGen/SelectionDAG/StatepointLowering.cpp
600 ↗(On Diff #24953)

You're changes here collide with a review Sanjoy has up for review. Please talk with him to separate the shared naming/refactoring pieces. Otherwise, whoever commits second will have a nasty merge conflict to fix.

620 ↗(On Diff #24953)

What's the format here? Are what are the source values used for? This should probably be documented somewhere as well. At least in comment form, probably as actual documentation.

675 ↗(On Diff #24953)

Doesn't this need to be Chain since you just added a new node?

692 ↗(On Diff #24953)

You've got name colision with the Ops at the outer scope. Given the structure of the code, it most likely makes sense to either sink the statepoint operands into a scoped block of their own, or use another name here.

lib/IR/Verifier.cpp
1534 ↗(On Diff #24953)

By converting to a 32 bit value, I believe you have silent truncation here. This should probably be a uint64_t.

1535 ↗(On Diff #24953)

A more extensible way to express this would to add a MaskAllSet to the enum, then write this as:
Flags & ~MaskAllSet == 0

1538 ↗(On Diff #24953)

Adding a check that says "if the callee has a gc attribute that is not the same as the caller, the transition bit should be set" would seem reasonable. Is there a reason not to do this? Or the inverse check for when the flag is set?

Actually, such a check probably *doesn't* belong in the Verifier. You could have unreachable code that gets exposed during optimization and the resulting IR would fail that check, but still be semantically valid IR. It should be a lint rule and probably an instcombine rule to replace a mismatch with undef. :) A follow up patch or filed bug is fine.

lib/Target/X86/X86ISelLowering.cpp
17418 ↗(On Diff #24953)

A bit of context would be good here. Readers of the code need to know why these are here.

17423 ↗(On Diff #24953)

Just use getGluedNode?

17427 ↗(On Diff #24953)

This looks slightly suspicious to me. I wouldn't necessarily expect a noop node to take a control and glue. Are you sure the rest of the backend will expect this?

reames requested changes to this revision.May 5 2015, 5:30 PM
reames edited edge metadata.
This revision now requires changes to proceed.May 5 2015, 5:30 PM
sanjoy added inline comments.May 5 2015, 5:44 PM
lib/CodeGen/SelectionDAG/StatepointLowering.cpp
600 ↗(On Diff #24953)

The latest version of my change (http://reviews.llvm.org/D9480) should not conflict with this one.

Thanks for the feedback! I'll post a new version of the code with the requested changes later today.

docs/Statepoints.rst
253 ↗(On Diff #24953)

The first bit. Should I add a table for the flags bits here, or out-of-line?

264 ↗(On Diff #24953)

I intended this to mean that transition arguments are not lowered in the same fashion as deopt args or GC args (e.g. no spilling is done). Instead, they are lowered however ISel would usually lower them.

268 ↗(On Diff #24953)

Yup. Thanks.

271 ↗(On Diff #24953)

Good point. I'll add the suggested background.

485 ↗(On Diff #24953)

I will leave the deopt args for now.

include/llvm/IR/Statepoint.h
27 ↗(On Diff #24953)

Will do.

76 ↗(On Diff #24953)

Will do.

120 ↗(On Diff #24953)

I thought that this pattern was a bit weird myself. The value I saw here was the assertion, but it's probably acceptable to write the assertion as

assert((call_args_end() - StatepointCS.args_begin()) <= (int)StatepointCS.arg_size());

However, I'd rather be consistent for now and fix all of these in a followup change.

lib/CodeGen/SelectionDAG/StatepointLowering.cpp
600 ↗(On Diff #24953)

I don't mind dealing with any merge pain. It does look like Sanjoy is correct, however, and things should be pretty clean.

620 ↗(On Diff #24953)

The SrcValues are used so that later lowering can form MachinePointerInfos. As suggested, I'll document the format. Should I just add a section to the existing statepoint docs?

675 ↗(On Diff #24953)

Yes, good catch.

692 ↗(On Diff #24953)

The name hiding is deliberate, and IMHO more reliable: we shouldn't be accessing the operands to the STATEPOINT node itself here.

lib/IR/Verifier.cpp
1534 ↗(On Diff #24953)

Yes, you're correct. This pattern is common throughout statepoint validation--should I fix the other instances now, or file a bug and follow up with another patch?

1535 ↗(On Diff #24953)

I agree. I had originally intended to do just that, but could not think of a terribly robust way of defining MaskAllSet.

1538 ↗(On Diff #24953)

I'll file a bug for this one :)

lib/Target/X86/X86ISelLowering.cpp
17418 ↗(On Diff #24953)

Will add.

17423 ↗(On Diff #24953)

Using getGluedNode would change the code to something like:

SDNode *GluedNode = Op->getGluedNode();
if (GluedNode)

Ops.push_back(SDValue(GluedNode, GluedNode->getNumValues() - 1);

I don't feel terribly strongly one way or the other: either way we're following a convention (glue is the terminal {operand,value}). FWIW, the code that is already present is a pretty common pattern.

17427 ↗(On Diff #24953)

I tested this by running all of the statepoint lowering tests with the GC transition flag set to '1'. There were no failures (or even asm diffs, as the NOOP instructions are removed by dead machine instruction elimination), which seems like a reasonable indication that the backend can tolerate this.

pgavlin updated this revision to Diff 25090.May 6 2015, 2:48 PM
pgavlin edited edge metadata.

Expand the documentation for GC transitions and address CR feedback.

reames added a comment.May 6 2015, 4:18 PM

Responding to questions in comments, not yet actually reviewing most recent code.

docs/Statepoints.rst
253 ↗(On Diff #24953)

No strong preference. Do what you think creates more readable docs.

include/llvm/IR/Statepoint.h
120 ↗(On Diff #24953)

Sounds reasonable. Any chance I can convince you to do the cleanup? If not, I'll try to get to it myself.

lib/CodeGen/SelectionDAG/StatepointLowering.cpp
620 ↗(On Diff #24953)

Yep.

692 ↗(On Diff #24953)

I generally dislike any code where you can disable a declaration and silently get wrong behaviour.

Please change this. I will not sign off on this with the name collision. I don't really care how you resolve the collision, but I do care you resolve it.

lib/IR/Verifier.cpp
1534 ↗(On Diff #24953)

File a bug, fix later. I can't ask you to fix all of my bugs in one go. :)

1535 ↗(On Diff #24953)

In the enum declaration:
MaskAllSet = GCTransition | NextFlag | NextFlag,

lib/Target/X86/X86ISelLowering.cpp
17423 ↗(On Diff #24953)

Eh, I don't really care here. I'll defer to your preference.

17427 ↗(On Diff #24953)

Agreed.

reames added a comment.May 6 2015, 4:33 PM

This is looking really close to ready to land. Not quite there yet, but probably only one more round of updates.

I did notice that there are no tests specifically for the lowering of statepoints with transition arguments. You should be able to write tests using statepoint-example, even if they're not the most useful tests in the world. At minimum, we can make sure the backend doesn't crash when presented with such a statepoint. The challenge in testing this really makes me think we should have the CLR GC strategy be included as a builtin GC.

docs/Statepoints.rst
249 ↗(On Diff #25090)

This paragraph gets confusing. I think you'd be better off introducing a hypothetical GC, describe briefly how you might add support for such a GC, and then show the resulting code. Just make it clear that such a GC is hypothetical. :)

You might also mention where this is actually used. (i.e. the CLR GC support.)

I'd be tempted to have you guys actually add your strategy so that we can have the actual support conditional on the gc name and just use that for our example.

315 ↗(On Diff #25090)

LSB? MSB? What order of the bits are you using?

320 ↗(On Diff #25090)

Currently unused, but required to be unset to allow possible future extensions.

lib/CodeGen/SelectionDAG/StatepointLowering.cpp
672 ↗(On Diff #25090)

This shift should be define in StackMaps.h for the StatepointOperands class with a more clear name.

The other option is to just split this operand into 2. I have no idea why I masked them to start with, that's just unnecessary complexity. Might be better to do this as a separate change though.

708 ↗(On Diff #25090)

You could shorten this comment if desired by just referencing the format already defined for GC_TRANSITION_START.

pgavlin updated this revision to Diff 25115.May 6 2015, 6:02 PM
pgavlin edited edge metadata.

Expand documentation and address further CR feedback.

pgavlin added inline comments.May 6 2015, 6:05 PM
docs/Statepoints.rst
249 ↗(On Diff #25090)

Noted. I'll see if we can get a GC strategy for CoreCLR added in the very near future.

include/llvm/IR/Statepoint.h
120 ↗(On Diff #24953)

Sure, I'm happy to do the cleanup.

lib/CodeGen/SelectionDAG/StatepointLowering.cpp
692 ↗(On Diff #24953)

That's reasonable enough.

672 ↗(On Diff #25090)

I like the sound of the latter option. Do you mind if I do this in a separate change?

708 ↗(On Diff #25090)

Done.

reames added a comment.May 6 2015, 6:07 PM

Still missing the requested test case, but otherwise LGTM. Once that's in place, let me know, and I'll commit. (Assuming you haven't gotten commit access yet.)

reames added inline comments.May 6 2015, 6:09 PM
lib/CodeGen/SelectionDAG/StatepointLowering.cpp
672 ↗(On Diff #25090)

I'd prefer that actually. Given the future change, this portion is fine for submission.

reames requested changes to this revision.May 6 2015, 6:09 PM
reames edited edge metadata.
This revision now requires changes to proceed.May 6 2015, 6:09 PM
pgavlin updated this revision to Diff 25121.May 6 2015, 8:40 PM
pgavlin edited edge metadata.

Added a test for GC transition lowering.

I do have commit access now, so I can commit this once you've signed off.

reames accepted this revision.May 7 2015, 1:53 PM
reames edited edge metadata.

LGTM w/the comment and test fixes mentioned.

test/CodeGen/X86/statepoint-gctransition-call-lowering.ll
2 ↗(On Diff #25121)

Stale comment.

16 ↗(On Diff #25121)

Please add at least one test which includes transition arguments which get lowered, but dropped due to the noops. I want to exercise the newly added code.

This revision is now accepted and ready to land.May 7 2015, 1:53 PM
This revision was automatically updated to reflect the committed changes.