This is an archive of the discontinued LLVM Phabricator instance.

Support of the gc.relocates for invoke statepoints
ClosedPublic

Authored by igor-laevsky on Feb 20 2015, 1:44 PM.

Details

Summary

This change builds up on http://reviews.llvm.org/D7760

It implements support for the gc.relocates tied to the invoke statepoint. It adds new 'FuncInfo::InvokeStatepointValueSlots' field to store exported gc values and uses it during visitGCRelocate.

Diff Detail

Repository
rL LLVM

Event Timeline

igor-laevsky retitled this revision from to Support of the gc.relocates for invoke statepoints.
igor-laevsky updated this object.
igor-laevsky edited the test plan for this revision. (Show Details)
igor-laevsky added a reviewer: reames.
igor-laevsky set the repository for this revision to rL LLVM.
igor-laevsky added a subscriber: Unknown Object (MLST).
reames edited edge metadata.Mar 4 2015, 11:25 PM

Is there a missing part to this patch? The current code doesn't seem complete/correct.

include/llvm/CodeGen/FunctionLoweringInfo.h
82 ↗(On Diff #21229)

I don't think we're actually guaranteed that the same stack slot is used across all statepoints. Are we? If not, this needs to be keyed by a pair of derived pointer and statepoint instruction.

Consider:
V = ...
if (X) statepoint; else statepoint;

lib/CodeGen/SelectionDAG/StatepointLowering.cpp
533 ↗(On Diff #21229)

It's not all the spilled values here, just the relocated ones. Can you fix the comment?

535 ↗(On Diff #21229)

Given we already have the derived pointers above, can't this be rewritten as a loop over Ptrs?

Actually, I would have expected to see this as part of the previous loop. If lowerIncomingStatepointValue returned the lowered value, this code could be expressed neatly within the previously loop.

542 ↗(On Diff #21229)

See my comment above about coliding stack slots. If this isn't possible, please add an assertion.

681 ↗(On Diff #21229)

It seems like it would be easier to just not run the debug loop above for invokes. Am I missing something?

722 ↗(On Diff #21229)

CamelCase - er wait, you're just moving this. Remind me to rename this as soon as your patch lands. You don't need to and shouldn't change the name here.

746 ↗(On Diff #21229)

Er, I don't think there should be such a case. Do you have an example or should this be an assert?

755 ↗(On Diff #21229)

This really doesn't look like right. The allocation logic used inside spilling is assuming it can reuse slots. It looks like you've essentially created an alternate mechanism for recording locations in invokes, but not updated the stack slot reuse/allocation code paths. Am I missing something here?

igor-laevsky edited edge metadata.

Add more test cases.
Remove 'clearValidationInfo'
Updated comments.

igor-laevsky added inline comments.Apr 30 2015, 8:25 AM
include/llvm/CodeGen/FunctionLoweringInfo.h
82 ↗(On Diff #21229)

You are right, we are not guaranteed that same stack slot is allocated for the same value in different statepoints. But we are guaranteed that when we start processing new safepoint with same value we already finished processing all gc relocates of the previous one and can safely discard previously saved location.

See comment on line 557 in StatepointLowering.cpp for more info. Test case "test_same_val" checks this case.

lib/CodeGen/SelectionDAG/StatepointLowering.cpp
535 ↗(On Diff #21229)

In Ptr's array we only have values with unique SDValues. But we need to store locations of the all possible relocated values. Notice that this loop is over StatepointSite.getRelocates().

746 ↗(On Diff #21229)

There is such cases for constants, allocas and undefs. See "test_null_undef" and "test_alloca_and_const" tests.

755 ↗(On Diff #21229)

At the beginning of each statepoint we know that all previous relocates were visited (otherwise statepoint intervals will intersect and it does not have any sense). It means that we are not going to need locations for this relocates and can reuse all allocated slots.

To be clear, by "previous relocates" I mean relocates that dominate current safepoint. For example relocates on exceptional path could have been left unvisited. This is not problematic because we are still reusing slots only at the point dominated by only visited relocates. I.e when we start reusing slots on exceptional path all exceptional relocates should be visited.

reames requested changes to this revision.May 5 2015, 3:55 PM
reames edited edge metadata.

Please make the changes suggested in previous rounds of discussion. I do not plan to respond further until at least the minor items are addressed. If you *disagree* with a proposed change, we can discuss, but anything which can be addressed without discussion should be done before replying. Reviewing a concrete piece of code is much easier than keeping track of proposed revisions.

include/llvm/CodeGen/FunctionLoweringInfo.h
82 ↗(On Diff #21229)

I'm having trouble understanding your comment in context of the comment in the code. Are you saying we remove entries from this map after visiting a particular safepoint? That doesn't seem to agree with the comment in code.

lib/CodeGen/SelectionDAG/StatepointLowering.cpp
535 ↗(On Diff #21229)

Er, yes. But by definition, the unique SDValues *are* all the values that need to be relocated. That was my point.

746 ↗(On Diff #21229)

Please clarify the comment to include the first half of your response.

Also, the fact this is the *exact* same case as the previous but for the invoke handling seems questionable. I might suggest:
if (isCall) {

above code;

} else {

new code with comment

}

755 ↗(On Diff #21229)

I'm still confused here. Really, really basic question: What is the invariant this code is trying to uphold? Is the same Value always spilled to the same slot? Please summarize this in a block comment in the revised code and point me to it.

This revision now requires changes to proceed.May 5 2015, 3:55 PM
sanjoy added a subscriber: sanjoy.May 6 2015, 11:49 AM

Some minor comments inline. I can't say I've fully understood this; I'll do a second, review tomorrow.

include/llvm/CodeGen/FunctionLoweringInfo.h
82 ↗(On Diff #24709)

Why not use a DenseMap<const Value *, Optional<int>>?

lib/CodeGen/SelectionDAG/StatepointLowering.cpp
554 ↗(On Diff #24709)

LLVM conventions say variable names should be CamelCase starting with an uppercase letter.

574 ↗(On Diff #24709)

So this case is for values like allocas and constants, right? If so, an assert will make things clearer.

579 ↗(On Diff #24709)

So is it correct to say that we need this because gc_relocate only "indirectly" uses V, in a manner invisible to LLVM? For instance, if our representation of a gc_relocate was

TOK = safepoint
i8* V.relocated = gc_relocate(TOK, i8* V.original)

then we would not need this since V.original would get exported at its def if needed?

igor-laevsky added a reviewer: sanjoy.

I think a lot of confusion were due to the two mechanisms for recording spilled values locations - one inside StatepointLowering, and one for cross basic block values in FunctionLoweringInfo.

I updated diff so that only one such mechanism is left. Now we record all value locations in "StatepointRelocatedValues" map in FuncitonLoweringInfo.

Also I included statepoint instruction as a key to this map to make it obvious that there could not be any collisions when we allocate different stack sots for the same values in different statepoints. This is not required for correctness, but makes reasoning about correctness a lot easier.

As a side effect "RelocLocations" map is no longer possible to maintain with reasonable effort, so I removed it completely. Anyway it added a lot of complexity while serving only purpose to not emit spill loads for values with non-unique sdvalues. (I.e preventing several spill loads from the same slots) After running some experiments I see that machineCSE is capable to handle such cases for us.

Also after this change it is clear that all structures inside StatepointLowering are used only during call to the "LowerStatepoint" (they are cleared at the beginning of this function). So it will be possible to remove StatepointLowering from SelectionDAG and create it only inside "LowerStatepoint".

igor-laevsky added inline comments.May 7 2015, 8:54 AM
include/llvm/CodeGen/FunctionLoweringInfo.h
82 ↗(On Diff #21229)

This should not be the problem anymore as I added statepoint as a key to the map.

lib/CodeGen/SelectionDAG/StatepointLowering.cpp
579 ↗(On Diff #24709)

That's right, but only for values we are not spilling on the stack, like allocas. For spilled values even if we will export them we still need to know stack slot we spilled them to.

(I am not considering that we can not have gc_relocate using original value as it would mean use of unrelocated value after statepoint)

535 ↗(On Diff #21229)

That is correct. We need to record in a StackMap and spill only unique SDValues. However we might visit two different gc_relocates relocating values with same SDValues. In order to handle this we are recording locations for all possible values. Simply for values with same SDValues we will have same locations.

746 ↗(On Diff #21229)

Should not be the problem in updated code.

755 ↗(On Diff #21229)

Basic invariant here is that statepoint ranges are not intersecting. Or in other words - on entry to each statepoint all previous gc_relocates are already visited.

This is not a new invariant, current code asserts it in startNewStatepoint by checking "PendingGCRelocateCalls.empty()". Unfortunately I have not found easy way of asserting it for invoke statepoints, but IR verification should prevent such cases anyway.

Very gentle ping. I believe code is easier to understand now. If it is still hard to read - please tell me about it, I will try something else.

sanjoy requested changes to this revision.May 15 2015, 4:53 PM
sanjoy edited edge metadata.

I think this is mostly ready to go in. Let's do one more iteration if you don't mind.

Btw, some of the GCRelocateOperands accessors you use have been renamed; but those will show up as compiler errors.

include/llvm/CodeGen/FunctionLoweringInfo.h
79 ↗(On Diff #25190)

What is "location" here? Is it the frame index?

83 ↗(On Diff #25190)

I'd find this easier to understand if you had DenseMap<Instruction *, DenseMap<Value *, int>> instead. IOW, currently your map is of the type (Statept, Value) -> Index, but I think making it of the type Statept -> Value -> Index would be clearer (even though it is equivalent) as it would emphasize that per safepoint we have a mapping of Values to frame indices.

85 ↗(On Diff #25190)

I'm not sure if the typedef is adding much here.

lib/CodeGen/SelectionDAG/StatepointLowering.cpp
540 ↗(On Diff #25190)

Minor: should be embedded.

542 ↗(On Diff #25190)

Use RelocatedOpers or RO as the variable name.

545 ↗(On Diff #25190)

LLVM style would be SDV here.

553 ↗(On Diff #25190)

I think LLVM style is } else {. You might want to just run this patch through clang-format before check-in.

557 ↗(On Diff #25190)

I'd change the language slightly: "Actually we do not need to record them in this map at all." assuming that is what you meant.

730 ↗(On Diff #25190)

Use RelocateOpers or RO.

This revision now requires changes to proceed.May 15 2015, 4:53 PM
igor-laevsky edited edge metadata.
sanjoy accepted this revision.May 18 2015, 2:32 PM
sanjoy edited edge metadata.

LGTM.

This revision was automatically updated to reflect the committed changes.