Skip to content

Commit 8d94d3c

Browse files
committed
[Attributor][FIX] Disallow function signature rewrite for casted calls
We will now ensure ensure the return type of called function is the type of all call sites we are going to rewrite. This avoids a problem partially fixed by D79680. The part that was not covered is a use of this "weird" casted call site (see `@func3` in `misc_crash.ll`). misc_crash.ll checks are auto-generated now.
1 parent c115a78 commit 8d94d3c

File tree

2 files changed

+53
-7
lines changed

2 files changed

+53
-7
lines changed

llvm/lib/Transforms/IPO/Attributor.cpp

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1341,6 +1341,13 @@ bool Attributor::isValidFunctionSignatureRewrite(
13411341
Argument &Arg, ArrayRef<Type *> ReplacementTypes) {
13421342

13431343
auto CallSiteCanBeChanged = [](AbstractCallSite ACS) {
1344+
// Forbid the call site to cast the function return type. If we need to
1345+
// rewrite these functions we need to re-create a cast for the new call site
1346+
// (if the old had uses).
1347+
if (!ACS.getCalledFunction() ||
1348+
ACS.getInstruction()->getType() !=
1349+
ACS.getCalledFunction()->getReturnType())
1350+
return false;
13441351
// Forbid must-tail calls for now.
13451352
return !ACS.isCallbackCall() && !ACS.getInstruction()->isMustTailCall();
13461353
};
@@ -1594,10 +1601,11 @@ ChangeStatus Attributor::rewriteFunctionSignatures(
15941601
for (auto &CallSitePair : CallSitePairs) {
15951602
CallBase &OldCB = *CallSitePair.first;
15961603
CallBase &NewCB = *CallSitePair.second;
1604+
assert(OldCB.getType() == NewCB.getType() &&
1605+
"Cannot handle call sites with different types!");
15971606
ModifiedFns.insert(OldCB.getFunction());
15981607
CGUpdater.replaceCallSite(OldCB, NewCB);
1599-
if (!OldCB.use_empty())
1600-
OldCB.replaceAllUsesWith(&NewCB);
1608+
OldCB.replaceAllUsesWith(&NewCB);
16011609
OldCB.eraseFromParent();
16021610
}
16031611

Lines changed: 43 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,77 @@
1+
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature
12
; RUN: opt -attributor -S %s | FileCheck %s
23
; RUN: opt -passes=attributor -S %s | FileCheck %s
34

45
@var1 = internal global [1 x i32] undef
56
@var2 = internal global i32 0
67

7-
; CHECK-LABEL: define i32 addrspace(1)* @foo(i32 addrspace(4)* nofree readnone %arg)
88
define i32 addrspace(1)* @foo(i32 addrspace(4)* %arg) {
9+
; CHECK-LABEL: define {{[^@]+}}@foo
10+
; CHECK-SAME: (i32 addrspace(4)* nofree readnone [[ARG:%.*]]) #0
11+
; CHECK-NEXT: entry:
12+
; CHECK-NEXT: [[TMP0:%.*]] = addrspacecast i32 addrspace(4)* [[ARG]] to i32 addrspace(1)*
13+
; CHECK-NEXT: ret i32 addrspace(1)* [[TMP0]]
14+
;
915
entry:
1016
%0 = addrspacecast i32 addrspace(4)* %arg to i32 addrspace(1)*
1117
ret i32 addrspace(1)* %0
1218
}
1319

1420
define i32* @func1() {
21+
; CHECK-LABEL: define {{[^@]+}}@func1() #0
22+
; CHECK-NEXT: [[PTR:%.*]] = call i32* @func1a() #0
23+
; CHECK-NEXT: ret i32* [[PTR]]
24+
;
1525
%ptr = call i32* @func1a([1 x i32]* @var1)
1626
ret i32* %ptr
1727
}
1828

29+
; UTC_ARGS: --disable
1930
; CHECK-LABEL: define internal nonnull align 4 dereferenceable(4) i32* @func1a()
2031
; CHECK-NEXT: ret i32* getelementptr inbounds ([1 x i32], [1 x i32]* @var1, i32 0, i32 0)
2132
define internal i32* @func1a([1 x i32]* %arg) {
2233
%ptr = getelementptr inbounds [1 x i32], [1 x i32]* %arg, i64 0, i64 0
2334
ret i32* %ptr
2435
}
36+
; UTC_ARGS: --enable
2537

2638
define internal void @func2a(i32* %0) {
39+
; CHECK-LABEL: define {{[^@]+}}@func2a
40+
; CHECK-SAME: (i32* nocapture nofree nonnull writeonly align 4 dereferenceable(4) [[TMP0:%.*]]) #1
41+
; CHECK-NEXT: store i32 0, i32* @var2, align 4
42+
; CHECK-NEXT: ret void
43+
;
2744
store i32 0, i32* %0
2845
ret void
2946
}
3047

31-
; CHECK-LABEL: define i32 @func2()
32-
; CHECK-NEXT: tail call void @func2a()
33-
; CHECK-NEXT: %1 = load i32, i32* @var2, align 4
34-
; CHECK-NEXT: ret i32 %1
3548
define i32 @func2() {
49+
; CHECK-LABEL: define {{[^@]+}}@func2()
50+
; CHECK-NEXT: [[TMP1:%.*]] = tail call i32 (i32*, ...) bitcast (void (i32*)* @func2a to i32 (i32*, ...)*)(i32* nonnull align 4 dereferenceable(4) @var2)
51+
; CHECK-NEXT: [[TMP2:%.*]] = load i32, i32* @var2, align 4
52+
; CHECK-NEXT: ret i32 [[TMP2]]
53+
;
3654
%1 = tail call i32 (i32*, ...) bitcast (void (i32*)* @func2a to i32 (i32*, ...)*)(i32* @var2)
3755
%2 = load i32, i32* @var2
3856
ret i32 %2
3957
}
58+
59+
define i32 @func3(i1 %false) {
60+
; CHECK-LABEL: define {{[^@]+}}@func3
61+
; CHECK-SAME: (i1 [[FALSE:%.*]])
62+
; CHECK-NEXT: [[TMP1:%.*]] = tail call i32 (i32*, ...) bitcast (void (i32*)* @func2a to i32 (i32*, ...)*)(i32* nonnull align 4 dereferenceable(4) @var2)
63+
; CHECK-NEXT: br i1 [[FALSE]], label [[USE_BB:%.*]], label [[RET_BB:%.*]]
64+
; CHECK: use_bb:
65+
; CHECK-NEXT: ret i32 [[TMP1]]
66+
; CHECK: ret_bb:
67+
; CHECK-NEXT: [[TMP2:%.*]] = load i32, i32* @var2, align 4
68+
; CHECK-NEXT: ret i32 [[TMP2]]
69+
;
70+
%1 = tail call i32 (i32*, ...) bitcast (void (i32*)* @func2a to i32 (i32*, ...)*)(i32* @var2)
71+
br i1 %false, label %use_bb, label %ret_bb
72+
use_bb:
73+
ret i32 %1
74+
ret_bb:
75+
%2 = load i32, i32* @var2
76+
ret i32 %2
77+
}

0 commit comments

Comments
 (0)