Skip to content

Commit 5b0f4f2

Browse files
authored
[BasicAA] Treat returns_twice functions as clobbering unescaped objects (#117902)
Effectively this models all the accesses that occur between the first and second return as happening at the point of the call. Fixes #116668.
1 parent 1d6ab18 commit 5b0f4f2

File tree

2 files changed

+71
-3
lines changed

2 files changed

+71
-3
lines changed

llvm/lib/Analysis/BasicAliasAnalysis.cpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -947,8 +947,14 @@ ModRefInfo BasicAAResult::getModRefInfo(const CallBase *Call,
947947
//
948948
// Make sure the object has not escaped here, and then check that none of the
949949
// call arguments alias the object below.
950+
//
951+
// We model calls that can return twice (setjmp) as clobbering non-escaping
952+
// objects, to model any accesses that may occur prior to the second return.
953+
// As an exception, ignore allocas, as setjmp is not required to preserve
954+
// non-volatile stores for them.
950955
if (!isa<Constant>(Object) && Call != Object &&
951-
AAQI.CA->isNotCapturedBefore(Object, Call, /*OrAt*/ false)) {
956+
AAQI.CA->isNotCapturedBefore(Object, Call, /*OrAt*/ false) &&
957+
(isa<AllocaInst>(Object) || !Call->hasFnAttr(Attribute::ReturnsTwice))) {
952958

953959
// Optimistically assume that call doesn't touch Object and check this
954960
// assumption in the following loop.

llvm/test/Transforms/GVN/setjmp.ll

Lines changed: 64 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ declare i32 @setjmp() returns_twice
55
declare void @longjmp()
66
declare ptr @malloc(i64)
77

8-
; FIXME: This is a miscompile.
98
define i32 @test() {
109
; CHECK-LABEL: define i32 @test() {
1110
; CHECK-NEXT: [[MALLOC:%.*]] = call noalias ptr @malloc(i64 4)
@@ -18,7 +17,8 @@ define i32 @test() {
1817
; CHECK-NEXT: call void @longjmp()
1918
; CHECK-NEXT: unreachable
2019
; CHECK: [[IF_END]]:
21-
; CHECK-NEXT: ret i32 10
20+
; CHECK-NEXT: [[RES:%.*]] = load i32, ptr [[MALLOC]], align 4
21+
; CHECK-NEXT: ret i32 [[RES]]
2222
;
2323
%malloc = call noalias ptr @malloc(i64 4)
2424
store i32 10, ptr %malloc, align 4
@@ -35,3 +35,65 @@ if.end:
3535
%res = load i32, ptr %malloc
3636
ret i32 %res
3737
}
38+
39+
; We are still allowed to optimize non-volatile accesses to allocas.
40+
define i32 @test_alloca() {
41+
; CHECK-LABEL: define i32 @test_alloca() {
42+
; CHECK-NEXT: [[ALLOC:%.*]] = alloca i43, align 8
43+
; CHECK-NEXT: store i32 10, ptr [[ALLOC]], align 4
44+
; CHECK-NEXT: [[SJ:%.*]] = call i32 @setjmp()
45+
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[SJ]], 0
46+
; CHECK-NEXT: br i1 [[CMP]], label %[[IF_THEN:.*]], label %[[IF_END:.*]]
47+
; CHECK: [[IF_THEN]]:
48+
; CHECK-NEXT: store i32 20, ptr [[ALLOC]], align 4
49+
; CHECK-NEXT: call void @longjmp()
50+
; CHECK-NEXT: unreachable
51+
; CHECK: [[IF_END]]:
52+
; CHECK-NEXT: ret i32 10
53+
;
54+
%alloc = alloca i43
55+
store i32 10, ptr %alloc, align 4
56+
%sj = call i32 @setjmp()
57+
%cmp = icmp eq i32 %sj, 0
58+
br i1 %cmp, label %if.then, label %if.end
59+
60+
if.then:
61+
store i32 20, ptr %alloc
62+
call void @longjmp()
63+
unreachable
64+
65+
if.end:
66+
%res = load i32, ptr %alloc
67+
ret i32 %res
68+
}
69+
70+
define i32 @test_alloca_volatile() {
71+
; CHECK-LABEL: define i32 @test_alloca_volatile() {
72+
; CHECK-NEXT: [[ALLOC:%.*]] = alloca i43, align 8
73+
; CHECK-NEXT: store volatile i32 10, ptr [[ALLOC]], align 4
74+
; CHECK-NEXT: [[SJ:%.*]] = call i32 @setjmp()
75+
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[SJ]], 0
76+
; CHECK-NEXT: br i1 [[CMP]], label %[[IF_THEN:.*]], label %[[IF_END:.*]]
77+
; CHECK: [[IF_THEN]]:
78+
; CHECK-NEXT: store volatile i32 20, ptr [[ALLOC]], align 4
79+
; CHECK-NEXT: call void @longjmp()
80+
; CHECK-NEXT: unreachable
81+
; CHECK: [[IF_END]]:
82+
; CHECK-NEXT: [[RES:%.*]] = load volatile i32, ptr [[ALLOC]], align 4
83+
; CHECK-NEXT: ret i32 [[RES]]
84+
;
85+
%alloc = alloca i43
86+
store volatile i32 10, ptr %alloc, align 4
87+
%sj = call i32 @setjmp()
88+
%cmp = icmp eq i32 %sj, 0
89+
br i1 %cmp, label %if.then, label %if.end
90+
91+
if.then:
92+
store volatile i32 20, ptr %alloc
93+
call void @longjmp()
94+
unreachable
95+
96+
if.end:
97+
%res = load volatile i32, ptr %alloc
98+
ret i32 %res
99+
}

0 commit comments

Comments
 (0)