This is an archive of the discontinued LLVM Phabricator instance.

[RS4GC] Introduce intrinsics to get base ptr and offset
ClosedPublic

Authored by yrouban on Apr 13 2021, 10:10 PM.

Details

Summary

There can be a need for some optimizations to get (base, offset) for any GC pointer. The base can be calculated by generating needed instructions as it is done by the RewriteStatepointsForGC::findBasePointer() function. The offset can be calculated in the same way. Though to not expose the base calculation and to make the offset calculation as simple as ptrtoint(derived_ptr) - ptrtoint(base_ptr), which is illegal outside RS4GC, this patch introduces 2 intrinsics:

  • declare i8 addrspace(1)* @llvm.experimental.gc.get.pointer.base(i8 addrspace(1)* readnone nocapture %derived_ptr) nounwind readnone willreturn
  • declare i64 @llvm.experimental.gc.get.pointer.offset(i8 addrspace(1)* readnone nocapture %derived_ptr) nounwind readnone willreturn

These intrinsics are inlined by RS4GC along with generation of statepoint sequences.

With these new intrinsics the GC parseable lowering for atomic memcpy intrinsics (D88861) could be implemented as a separate pass.

Diff Detail

Event Timeline

yrouban created this revision.Apr 13 2021, 10:10 PM
yrouban requested review of this revision.Apr 13 2021, 10:10 PM
Herald added a project: Restricted Project. · View Herald TranscriptApr 13 2021, 10:10 PM
Herald added a subscriber: jdoerfert. · View Herald Transcript

Finally had time to touch base and understand the background to this.

I think this is an entirely reasonable direction. I have minor comments on the patch, but no major concerns.

A couple of requested changes:

  1. Please add verifier support to check that the return and argument type of gc.pointer.base are the same.
  2. Please drop the gc-leaf intrinsic piece. That can and should be it's own patch. If you look at callsGCLeafFunction, you'll see we currently assume most intrinsics are GCLeaf, so this should be redundant.
llvm/docs/Statepoints.rst
443

Name out of sync with following text.

Also, the documentation for these should be in LangRef. If you want some extra discussion here, that's fine, but put the definition in LangRef.

464

is an pointer which is based on some object with an unknown offset from the base of said object.

469

Please add this sentence to the beginning of your current paragraph.

This intrinsic is used in the abstract machine model for GC to represent the base pointer for an arbitrary derived pointer.

498

Same change as above.

503

Add same sentence as above.

llvm/lib/Transforms/Scalar/RewriteStatepointsForGC.cpp
599

I don't think this piece of the change should be required. Can you explain why this is needed?

2475

This doesn't really have anything to do with the task of inserting parse points. I see why you're structuring it this way - to avoid recomputing the base pointer - but I'd prefer to keep the api clean. Please do this before the call to insertParsePoints with a separate call to findBasePointers. This should be correct, if slightly less optimal. We can then build on that in a following patch.

reames requested changes to this revision.May 18 2021, 3:54 PM
This revision now requires changes to proceed.May 18 2021, 3:54 PM

Drive by, just interested in potential use outside gc. But don't want to get into this now.

llvm/lib/Transforms/Scalar/RewriteStatepointsForGC.cpp
2856
yrouban marked 5 inline comments as done.May 24 2021, 2:12 AM

I'm still working on the next version.

llvm/lib/Transforms/Scalar/RewriteStatepointsForGC.cpp
599

This case is tested in the new intrinsics.ll:

Here is a simplified version:

define void @test_chained(i8 addrspace(1)* %obj1, i8 addrspace(1)* %obj2, i32 %len, i1 %c) gc "statepoint-example" {
entry:
  %obj1.12 = getelementptr inbounds i8, i8 addrspace(1)* %obj1, i64 12
  %obj2.16 = getelementptr inbounds i8, i8 addrspace(1)* %obj2, i64 16
  %obj.x = select i1 %c, i8 addrspace(1)* %obj1.12, i8 addrspace(1)* %obj2.16

  %obj.x.base = call i8 addrspace(1)* @llvm.experimental.gc.get.pointer.base.p1i8.p1i8(i8 addrspace(1)* %obj.x)
  %obj.x.base_of_base = call i8 addrspace(1)* @llvm.experimental.gc.get.pointer.base.p1i8.p1i8(i8 addrspace(1)* %obj.x.base)

  ret void
}

After the first %obj.x.base = get.pointer.base(%obj.x) is inlined by inlineGetBaseAndOffset() we get all %obj.x.base uses RAUWed with the result %obj.x.base1 which is marked with !is_base_value:

%obj1.12 = getelementptr inbounds i8, i8 addrspace(1)* %obj1, i64 12
%obj2.16 = getelementptr inbounds i8, i8 addrspace(1)* %obj2, i64 16
%obj.x.base1 = select i1 %c, i8 addrspace(1)* %obj1, i8 addrspace(1)* %obj2, !is_base_value !0
%obj.x = select i1 %c, i8 addrspace(1)* %obj1.12, i8 addrspace(1)* %obj2.16
%obj.x.base_of_base = call i8 addrspace(1)* @llvm.experimental.gc.get.pointer.base.p1i8.p1i8(i8 addrspace(1)* %obj.x.base1)

Then inlineGetBaseAndOffset() calls findBasePointer(%obj.x.base1), which ends up in instantiating BaseDefiningValueResult(%obj.x.base1, IsKnownBase).

reames added inline comments.May 24 2021, 3:21 PM
llvm/lib/Transforms/Scalar/RewriteStatepointsForGC.cpp
599

I think you might be thinking about an older implementation of RS4GC, we recently improved the find base pointer algorithm to detect obj.x.base as a base pointer without the hint, and the metadata check should no longer be needed. If not, I'd like to see the reduced test case which still requires it because it's probably a lurking inference bug.

Can I ask you to run that test?

To be clear, I don't really care about this. It doesn't do any major harm to have the redundant check.

yrouban planned changes to this revision.May 24 2021, 7:53 PM
yrouban added inline comments.
llvm/lib/Transforms/Scalar/RewriteStatepointsForGC.cpp
599

Can I ask you to run that test?

Yes, I ran the simplified test with the fresh workspace right before sending the comment. I will make this a separate small test case.

yrouban updated this revision to Diff 347897.May 26 2021, 3:43 AM
yrouban edited the summary of this revision. (Show Details)

Philip, thank you for comments. I believe I addressed them all.

reames accepted this revision.May 26 2021, 8:22 AM

LGTM w/minor comment.

As a follow up, it would be interesting to explore lowering these early during optimization when feasible. e.g. base_of(gep alloca, 15) -> alloca

llvm/lib/Transforms/Scalar/RewriteStatepointsForGC.cpp
2402

minor: use a switch here.

This revision is now accepted and ready to land.May 26 2021, 8:22 AM
yrouban edited the summary of this revision. (Show Details)May 26 2021, 7:00 PM
yrouban marked 2 inline comments as done.
This revision was landed with ongoing or failed builds.May 26 2021, 7:15 PM
This revision was automatically updated to reflect the committed changes.