Skip to content

Commit 7c827dc

Browse files
committed
[RS4GC] Copy argument attributes from call to statepoint
The current implementation completely ignores argument attributes on calls, discarding them completely when creating a statepoint from a call instruction. This is problematic in some scenarios as the argument attributes affect the ABI of the call, leading to undefined behavior if called with the wrong ABI attributes. Note that this cannot be solved either by just having the function declaration annotated with the right parameter attributes as the call might be indirect, therefore requiring them to be present on the arguments. This PR simply copies all parameter attributes over from the original call to the created statepoint. declare i32 @personality_function() declare i32 @personality_function() Note that some argument attributes become invalid after the lowering as they imply memory effects that no longer hold with the statepoints. These do not need to be explicitly handled in this PR as they are removed by the `stripNonValidDataFromBody`.
1 parent b15b846 commit 7c827dc

File tree

2 files changed

+79
-12
lines changed

2 files changed

+79
-12
lines changed

llvm/lib/Transforms/Scalar/RewriteStatepointsForGC.cpp

Lines changed: 37 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1423,7 +1423,7 @@ static constexpr Attribute::AttrKind FnAttrsToStrip[] =
14231423

14241424
// Create new attribute set containing only attributes which can be transferred
14251425
// from original call to the safepoint.
1426-
static AttributeList legalizeCallAttributes(LLVMContext &Ctx,
1426+
static AttributeList legalizeCallAttributes(LLVMContext &Ctx, unsigned NumArgs,
14271427
AttributeList OrigAL,
14281428
AttributeList StatepointAL) {
14291429
if (OrigAL.isEmpty())
@@ -1439,7 +1439,15 @@ static AttributeList legalizeCallAttributes(LLVMContext &Ctx,
14391439
FnAttrs.removeAttribute(A);
14401440
}
14411441

1442-
// Just skip parameter and return attributes for now
1442+
// Attach the argument attributes from the original call at the corresponding
1443+
// arguments in the statepoint. Note that any argument attributes that are
1444+
// invalid after lowering are stripped in stripNonValidDataFromBody.
1445+
for (unsigned I : llvm::seq(NumArgs))
1446+
StatepointAL = StatepointAL.addParamAttributes(
1447+
Ctx, GCStatepointInst::CallArgsBeginPos + I,
1448+
AttrBuilder(Ctx, OrigAL.getParamAttrs(I)));
1449+
1450+
// Return attributes are later attached to the gc.result intrinsic.
14431451
return StatepointAL.addFnAttributes(Ctx, FnAttrs);
14441452
}
14451453

@@ -1630,6 +1638,7 @@ makeStatepointExplicitImpl(CallBase *Call, /* to replace */
16301638
// with a return value, we lower then as never returning calls to
16311639
// __llvm_deoptimize that are followed by unreachable to get better codegen.
16321640
bool IsDeoptimize = false;
1641+
bool IsMemIntrinsic = false;
16331642

16341643
StatepointDirectives SD =
16351644
parseStatepointDirectivesFromAttrs(Call->getAttributes());
@@ -1670,6 +1679,8 @@ makeStatepointExplicitImpl(CallBase *Call, /* to replace */
16701679
IsDeoptimize = true;
16711680
} else if (IID == Intrinsic::memcpy_element_unordered_atomic ||
16721681
IID == Intrinsic::memmove_element_unordered_atomic) {
1682+
IsMemIntrinsic = true;
1683+
16731684
// Unordered atomic memcpy and memmove intrinsics which are not explicitly
16741685
// marked as "gc-leaf-function" should be lowered in a GC parseable way.
16751686
// Specifically, these calls should be lowered to the
@@ -1785,12 +1796,19 @@ makeStatepointExplicitImpl(CallBase *Call, /* to replace */
17851796
SPCall->setTailCallKind(CI->getTailCallKind());
17861797
SPCall->setCallingConv(CI->getCallingConv());
17871798

1788-
// Currently we will fail on parameter attributes and on certain
1789-
// function attributes. In case if we can handle this set of attributes -
1790-
// set up function attrs directly on statepoint and return attrs later for
1799+
// Set up function attrs directly on statepoint and return attrs later for
17911800
// gc_result intrinsic.
1792-
SPCall->setAttributes(legalizeCallAttributes(
1793-
CI->getContext(), CI->getAttributes(), SPCall->getAttributes()));
1801+
AttributeList AttributeList = CI->getAttributes();
1802+
// The memory intrinsics do not have a 1:1 correspondence of the original
1803+
// call arguments to the produced statepoint. Remove the parameter
1804+
// attributes to avoid putting them on incorrect arguments.
1805+
if (IsMemIntrinsic)
1806+
AttributeList =
1807+
AttributeList::get(CI->getContext(), AttributeList.getFnAttrs(),
1808+
AttributeList.getRetAttrs(), {});
1809+
SPCall->setAttributes(legalizeCallAttributes(CI->getContext(),
1810+
CI->arg_size(), AttributeList,
1811+
SPCall->getAttributes()));
17941812

17951813
Token = cast<GCStatepointInst>(SPCall);
17961814

@@ -1812,12 +1830,19 @@ makeStatepointExplicitImpl(CallBase *Call, /* to replace */
18121830

18131831
SPInvoke->setCallingConv(II->getCallingConv());
18141832

1815-
// Currently we will fail on parameter attributes and on certain
1816-
// function attributes. In case if we can handle this set of attributes -
1817-
// set up function attrs directly on statepoint and return attrs later for
1833+
// Set up function attrs directly on statepoint and return attrs later for
18181834
// gc_result intrinsic.
1819-
SPInvoke->setAttributes(legalizeCallAttributes(
1820-
II->getContext(), II->getAttributes(), SPInvoke->getAttributes()));
1835+
AttributeList AttributeList = II->getAttributes();
1836+
// The memory intrinsics do not have a 1:1 correspondence of the original
1837+
// call arguments to the produced statepoint. Remove the parameter
1838+
// attributes to avoid putting them on incorrect arguments.
1839+
if (IsMemIntrinsic)
1840+
AttributeList =
1841+
AttributeList::get(II->getContext(), AttributeList.getFnAttrs(),
1842+
AttributeList.getRetAttrs(), {});
1843+
SPInvoke->setAttributes(
1844+
legalizeCallAttributes(II->getContext(), II->arg_size(),
1845+
II->getAttributes(), SPInvoke->getAttributes()));
18211846

18221847
Token = cast<GCStatepointInst>(SPInvoke);
18231848

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 3
2+
; RUN: opt < %s -passes=rewrite-statepoints-for-gc -S | FileCheck %s
3+
4+
declare i8 @callee(ptr, i8, float, ptr)
5+
6+
define i8 @test(ptr %arg) gc "statepoint-example" {
7+
; CHECK-LABEL: define i8 @test(
8+
; CHECK-SAME: ptr [[ARG:%.*]]) gc "statepoint-example" {
9+
; CHECK-NEXT: [[STATEPOINT_TOKEN:%.*]] = call token (i64, i32, ptr, i32, i32, ...) @llvm.experimental.gc.statepoint.p0(i64 2882400000, i32 0, ptr elementtype(i8 (ptr, i8, float, ptr)) @callee, i32 4, i32 0, ptr nocapture sret({ i64, i64 }) align 8 null, i8 signext 8, float inreg 1.000000e+00, ptr [[ARG]], i32 0, i32 0)
10+
; CHECK-NEXT: [[R1:%.*]] = call zeroext i8 @llvm.experimental.gc.result.i8(token [[STATEPOINT_TOKEN]])
11+
; CHECK-NEXT: ret i8 [[R1]]
12+
;
13+
%r = call zeroext i8 @callee(ptr sret({i64, i64}) noalias align 8 nocapture null, i8 signext 8, float inreg 1.0, ptr writeonly %arg)
14+
ret i8 %r
15+
}
16+
17+
declare i32 @personality_function()
18+
19+
define i8 @test_invoke(ptr %arg) gc "statepoint-example" personality ptr @personality_function {
20+
; CHECK-LABEL: define i8 @test_invoke(
21+
; CHECK-SAME: ptr [[ARG:%.*]]) gc "statepoint-example" personality ptr @personality_function {
22+
; CHECK-NEXT: [[STATEPOINT_TOKEN:%.*]] = invoke token (i64, i32, ptr, i32, i32, ...) @llvm.experimental.gc.statepoint.p0(i64 2882400000, i32 0, ptr elementtype(i8 (ptr, i8, float, ptr)) @callee, i32 4, i32 0, ptr nocapture sret({ i64, i64 }) align 8 null, i8 signext 8, float inreg 1.000000e+00, ptr [[ARG]], i32 0, i32 0)
23+
; CHECK-NEXT: to label [[NORMAL_RETURN:%.*]] unwind label [[EXCEPTIONAL_RETURN:%.*]]
24+
; CHECK: normal_return:
25+
; CHECK-NEXT: [[R1:%.*]] = call zeroext i8 @llvm.experimental.gc.result.i8(token [[STATEPOINT_TOKEN]])
26+
; CHECK-NEXT: ret i8 [[R1]]
27+
; CHECK: exceptional_return:
28+
; CHECK-NEXT: [[LANDING_PAD4:%.*]] = landingpad token
29+
; CHECK-NEXT: cleanup
30+
; CHECK-NEXT: ret i8 0
31+
;
32+
%r = invoke zeroext i8 @callee(ptr sret({i64, i64}) noalias align 8 nocapture null, i8 signext 8, float inreg 1.0, ptr writeonly %arg)
33+
to label %normal_return unwind label %exceptional_return
34+
35+
normal_return:
36+
ret i8 %r
37+
38+
exceptional_return:
39+
%landing_pad4 = landingpad token
40+
cleanup
41+
ret i8 0
42+
}

0 commit comments

Comments
 (0)