Skip to content

Commit 1d2b76a

Browse files
committed
[AssumeBundles] adapte GVN to assume bundles
Summary: prevent GVN from removing assume bundles make GVN preserve information from removed instructions Reviewers: jdoerfert Reviewed By: jdoerfert Subscribers: hiraditya, llvm-commits Tags: #llvm Differential Revision: https://reviews.llvm.org/D77405
1 parent f2b5e60 commit 1d2b76a

File tree

2 files changed

+182
-77
lines changed

2 files changed

+182
-77
lines changed

llvm/lib/Transforms/Scalar/GVN.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#include "llvm/ADT/SmallPtrSet.h"
2727
#include "llvm/ADT/SmallVector.h"
2828
#include "llvm/ADT/Statistic.h"
29+
#include "llvm/Analysis/AssumeBundleQueries.h"
2930
#include "llvm/Analysis/AliasAnalysis.h"
3031
#include "llvm/Analysis/AssumptionCache.h"
3132
#include "llvm/Analysis/CFG.h"
@@ -72,6 +73,7 @@
7273
#include "llvm/Support/Debug.h"
7374
#include "llvm/Support/raw_ostream.h"
7475
#include "llvm/Transforms/Utils.h"
76+
#include "llvm/Transforms/Utils/AssumeBundleBuilder.h"
7577
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
7678
#include "llvm/Transforms/Utils/Local.h"
7779
#include "llvm/Transforms/Utils/SSAUpdater.h"
@@ -1489,7 +1491,8 @@ bool GVN::processAssumeIntrinsic(IntrinsicInst *IntrinsicI) {
14891491
Constant::getNullValue(Int8Ty->getPointerTo()),
14901492
IntrinsicI);
14911493
}
1492-
markInstructionForDeletion(IntrinsicI);
1494+
if (isAssumeWithEmptyBundle(*IntrinsicI))
1495+
markInstructionForDeletion(IntrinsicI);
14931496
return false;
14941497
} else if (isa<Constant>(V)) {
14951498
// If it's not false, and constant, it must evaluate to true. This means our
@@ -2231,6 +2234,7 @@ bool GVN::processBlock(BasicBlock *BB) {
22312234
for (auto *I : InstrsToErase) {
22322235
assert(I->getParent() == BB && "Removing instruction from wrong block?");
22332236
LLVM_DEBUG(dbgs() << "GVN removed: " << *I << '\n');
2237+
salvageKnowledge(I, AC);
22342238
salvageDebugInfo(*I);
22352239
if (MD) MD->removeInstruction(I);
22362240
LLVM_DEBUG(verifyRemoved(I));
Lines changed: 177 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -1,127 +1,228 @@
1-
; This testcase tests for various features the basicaa test should be able to
1+
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2+
; This testcase tests for various features the basicaa test should be able to
23
; determine, as noted in the comments.
34

4-
; RUN: opt < %s -basicaa -gvn -instcombine -dce -S | FileCheck %s
5+
; RUN: opt < %s -basicaa -gvn -instcombine -dce -S | FileCheck %s --check-prefixes=CHECK,NO_ASSUME
6+
; RUN: opt < %s -basicaa -gvn -instcombine -dce --enable-knowledge-retention -S | FileCheck %s --check-prefixes=CHECK,USE_ASSUME
57
target datalayout = "E-p:64:64:64-a0:0:8-f32:32:32-f64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-v64:64:64-v128:128:128"
68

79
@Global = external global { i32 }
810

911
declare void @external(i32*)
12+
declare void @llvm.assume(i1)
1013

11-
; Array test: Test that operations on one local array do not invalidate
14+
; Array test: Test that operations on one local array do not invalidate
1215
; operations on another array. Important for scientific codes.
1316
;
1417
define i32 @different_array_test(i64 %A, i64 %B) {
15-
%Array1 = alloca i32, i32 100
16-
%Array2 = alloca i32, i32 200
17-
18-
call void @external(i32* %Array1)
19-
call void @external(i32* %Array2)
20-
21-
%pointer = getelementptr i32, i32* %Array1, i64 %A
22-
%val = load i32, i32* %pointer
23-
24-
%pointer2 = getelementptr i32, i32* %Array2, i64 %B
25-
store i32 7, i32* %pointer2
26-
27-
%REMOVE = load i32, i32* %pointer ; redundant with above load
28-
%retval = sub i32 %REMOVE, %val
29-
ret i32 %retval
30-
; CHECK: @different_array_test
31-
; CHECK: ret i32 0
18+
; NO_ASSUME-LABEL: @different_array_test(
19+
; NO_ASSUME-NEXT: [[ARRAY11:%.*]] = alloca [100 x i32], align 4
20+
; NO_ASSUME-NEXT: [[ARRAY22:%.*]] = alloca [200 x i32], align 4
21+
; NO_ASSUME-NEXT: [[ARRAY22_SUB:%.*]] = getelementptr inbounds [200 x i32], [200 x i32]* [[ARRAY22]], i64 0, i64 0
22+
; NO_ASSUME-NEXT: [[ARRAY11_SUB:%.*]] = getelementptr inbounds [100 x i32], [100 x i32]* [[ARRAY11]], i64 0, i64 0
23+
; NO_ASSUME-NEXT: call void @llvm.assume(i1 true) [ "align"(i32* [[ARRAY11_SUB]], i32 4) ]
24+
; NO_ASSUME-NEXT: call void @external(i32* nonnull [[ARRAY11_SUB]])
25+
; NO_ASSUME-NEXT: call void @external(i32* nonnull [[ARRAY22_SUB]])
26+
; NO_ASSUME-NEXT: [[POINTER2:%.*]] = getelementptr [200 x i32], [200 x i32]* [[ARRAY22]], i64 0, i64 [[B:%.*]]
27+
; NO_ASSUME-NEXT: store i32 7, i32* [[POINTER2]], align 4
28+
; NO_ASSUME-NEXT: ret i32 0
29+
;
30+
; USE_ASSUME-LABEL: @different_array_test(
31+
; USE_ASSUME-NEXT: [[ARRAY11:%.*]] = alloca [100 x i32], align 4
32+
; USE_ASSUME-NEXT: [[ARRAY22:%.*]] = alloca [200 x i32], align 4
33+
; USE_ASSUME-NEXT: [[ARRAY22_SUB:%.*]] = getelementptr inbounds [200 x i32], [200 x i32]* [[ARRAY22]], i64 0, i64 0
34+
; USE_ASSUME-NEXT: [[ARRAY11_SUB:%.*]] = getelementptr inbounds [100 x i32], [100 x i32]* [[ARRAY11]], i64 0, i64 0
35+
; USE_ASSUME-NEXT: call void @llvm.assume(i1 true) [ "align"(i32* [[ARRAY11_SUB]], i32 4) ]
36+
; USE_ASSUME-NEXT: call void @external(i32* nonnull [[ARRAY11_SUB]])
37+
; USE_ASSUME-NEXT: call void @external(i32* nonnull [[ARRAY22_SUB]])
38+
; USE_ASSUME-NEXT: [[POINTER:%.*]] = getelementptr [100 x i32], [100 x i32]* [[ARRAY11]], i64 0, i64 [[A:%.*]]
39+
; USE_ASSUME-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(i32* [[POINTER]], i64 4), "nonnull"(i32* [[POINTER]]) ]
40+
; USE_ASSUME-NEXT: [[POINTER2:%.*]] = getelementptr [200 x i32], [200 x i32]* [[ARRAY22]], i64 0, i64 [[B:%.*]]
41+
; USE_ASSUME-NEXT: store i32 7, i32* [[POINTER2]], align 4
42+
; USE_ASSUME-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(i32* [[POINTER]], i64 4), "nonnull"(i32* [[POINTER]]) ]
43+
; USE_ASSUME-NEXT: ret i32 0
44+
;
45+
%Array1 = alloca i32, i32 100
46+
%Array2 = alloca i32, i32 200
47+
call void @llvm.assume(i1 true) ["align"(i32* %Array1, i32 4)]
48+
49+
call void @external(i32* %Array1)
50+
call void @external(i32* %Array2)
51+
52+
%pointer = getelementptr i32, i32* %Array1, i64 %A
53+
%val = load i32, i32* %pointer
54+
55+
%pointer2 = getelementptr i32, i32* %Array2, i64 %B
56+
store i32 7, i32* %pointer2
57+
58+
%REMOVE = load i32, i32* %pointer ; redundant with above load
59+
%retval = sub i32 %REMOVE, %val
60+
ret i32 %retval
3261
}
3362

34-
; Constant index test: Constant indexes into the same array should not
63+
; Constant index test: Constant indexes into the same array should not
3564
; interfere with each other. Again, important for scientific codes.
3665
;
3766
define i32 @constant_array_index_test() {
38-
%Array = alloca i32, i32 100
39-
call void @external(i32* %Array)
40-
41-
%P1 = getelementptr i32, i32* %Array, i64 7
42-
%P2 = getelementptr i32, i32* %Array, i64 6
43-
44-
%A = load i32, i32* %P1
45-
store i32 1, i32* %P2 ; Should not invalidate load
46-
%BREMOVE = load i32, i32* %P1
47-
%Val = sub i32 %A, %BREMOVE
48-
ret i32 %Val
49-
; CHECK: @constant_array_index_test
50-
; CHECK: ret i32 0
67+
; NO_ASSUME-LABEL: @constant_array_index_test(
68+
; NO_ASSUME-NEXT: [[ARRAY1:%.*]] = alloca [100 x i32], align 4
69+
; NO_ASSUME-NEXT: [[ARRAY1_SUB:%.*]] = getelementptr inbounds [100 x i32], [100 x i32]* [[ARRAY1]], i64 0, i64 0
70+
; NO_ASSUME-NEXT: call void @external(i32* nonnull [[ARRAY1_SUB]])
71+
; NO_ASSUME-NEXT: [[P2:%.*]] = getelementptr inbounds [100 x i32], [100 x i32]* [[ARRAY1]], i64 0, i64 6
72+
; NO_ASSUME-NEXT: store i32 1, i32* [[P2]], align 4
73+
; NO_ASSUME-NEXT: ret i32 0
74+
;
75+
; USE_ASSUME-LABEL: @constant_array_index_test(
76+
; USE_ASSUME-NEXT: [[ARRAY1:%.*]] = alloca [100 x i32], align 4
77+
; USE_ASSUME-NEXT: [[ARRAY1_SUB:%.*]] = getelementptr inbounds [100 x i32], [100 x i32]* [[ARRAY1]], i64 0, i64 0
78+
; USE_ASSUME-NEXT: call void @external(i32* nonnull [[ARRAY1_SUB]])
79+
; USE_ASSUME-NEXT: [[P1:%.*]] = getelementptr inbounds [100 x i32], [100 x i32]* [[ARRAY1]], i64 0, i64 7
80+
; USE_ASSUME-NEXT: [[P2:%.*]] = getelementptr inbounds [100 x i32], [100 x i32]* [[ARRAY1]], i64 0, i64 6
81+
; USE_ASSUME-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(i32* [[P1]], i64 4), "nonnull"(i32* [[P1]]) ]
82+
; USE_ASSUME-NEXT: store i32 1, i32* [[P2]], align 4
83+
; USE_ASSUME-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(i32* [[P1]], i64 4), "nonnull"(i32* [[P1]]) ]
84+
; USE_ASSUME-NEXT: ret i32 0
85+
;
86+
%Array = alloca i32, i32 100
87+
call void @external(i32* %Array)
88+
89+
%P1 = getelementptr i32, i32* %Array, i64 7
90+
%P2 = getelementptr i32, i32* %Array, i64 6
91+
92+
%A = load i32, i32* %P1
93+
store i32 1, i32* %P2 ; Should not invalidate load
94+
%BREMOVE = load i32, i32* %P1
95+
%Val = sub i32 %A, %BREMOVE
96+
ret i32 %Val
5197
}
5298

53-
; Test that if two pointers are spaced out by a constant getelementptr, that
99+
; Test that if two pointers are spaced out by a constant getelementptr, that
54100
; they cannot alias.
55101
define i32 @gep_distance_test(i32* %A) {
56-
%REMOVEu = load i32, i32* %A
57-
%B = getelementptr i32, i32* %A, i64 2 ; Cannot alias A
58-
store i32 7, i32* %B
59-
%REMOVEv = load i32, i32* %A
60-
%r = sub i32 %REMOVEu, %REMOVEv
61-
ret i32 %r
62-
; CHECK: @gep_distance_test
63-
; CHECK: ret i32 0
102+
; NO_ASSUME-LABEL: @gep_distance_test(
103+
; NO_ASSUME-NEXT: [[B:%.*]] = getelementptr i32, i32* [[A:%.*]], i64 2
104+
; NO_ASSUME-NEXT: store i32 7, i32* [[B]], align 4
105+
; NO_ASSUME-NEXT: ret i32 0
106+
;
107+
; USE_ASSUME-LABEL: @gep_distance_test(
108+
; USE_ASSUME-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(i32* [[A:%.*]], i64 4), "nonnull"(i32* [[A]]) ]
109+
; USE_ASSUME-NEXT: [[B:%.*]] = getelementptr i32, i32* [[A]], i64 2
110+
; USE_ASSUME-NEXT: store i32 7, i32* [[B]], align 4
111+
; USE_ASSUME-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(i32* [[A]], i64 4), "nonnull"(i32* [[A]]) ]
112+
; USE_ASSUME-NEXT: ret i32 0
113+
;
114+
%REMOVEu = load i32, i32* %A
115+
%B = getelementptr i32, i32* %A, i64 2 ; Cannot alias A
116+
store i32 7, i32* %B
117+
%REMOVEv = load i32, i32* %A
118+
%r = sub i32 %REMOVEu, %REMOVEv
119+
ret i32 %r
64120
}
65121

66122
; Test that if two pointers are spaced out by a constant offset, that they
67123
; cannot alias, even if there is a variable offset between them...
68124
define i32 @gep_distance_test2({i32,i32}* %A, i64 %distance) {
69-
%A1 = getelementptr {i32,i32}, {i32,i32}* %A, i64 0, i32 0
70-
%REMOVEu = load i32, i32* %A1
71-
%B = getelementptr {i32,i32}, {i32,i32}* %A, i64 %distance, i32 1
72-
store i32 7, i32* %B ; B cannot alias A, it's at least 4 bytes away
73-
%REMOVEv = load i32, i32* %A1
74-
%r = sub i32 %REMOVEu, %REMOVEv
75-
ret i32 %r
76-
; CHECK: @gep_distance_test2
77-
; CHECK: ret i32 0
125+
; NO_ASSUME-LABEL: @gep_distance_test2(
126+
; NO_ASSUME-NEXT: [[B:%.*]] = getelementptr { i32, i32 }, { i32, i32 }* [[A:%.*]], i64 [[DISTANCE:%.*]], i32 1
127+
; NO_ASSUME-NEXT: store i32 7, i32* [[B]], align 4
128+
; NO_ASSUME-NEXT: ret i32 0
129+
;
130+
; USE_ASSUME-LABEL: @gep_distance_test2(
131+
; USE_ASSUME-NEXT: [[A1:%.*]] = getelementptr { i32, i32 }, { i32, i32 }* [[A:%.*]], i64 0, i32 0
132+
; USE_ASSUME-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(i32* [[A1]], i64 4), "nonnull"(i32* [[A1]]) ]
133+
; USE_ASSUME-NEXT: [[B:%.*]] = getelementptr { i32, i32 }, { i32, i32 }* [[A]], i64 [[DISTANCE:%.*]], i32 1
134+
; USE_ASSUME-NEXT: store i32 7, i32* [[B]], align 4
135+
; USE_ASSUME-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(i32* [[A1]], i64 4), "nonnull"(i32* [[A1]]) ]
136+
; USE_ASSUME-NEXT: ret i32 0
137+
;
138+
%A1 = getelementptr {i32,i32}, {i32,i32}* %A, i64 0, i32 0
139+
%REMOVEu = load i32, i32* %A1
140+
%B = getelementptr {i32,i32}, {i32,i32}* %A, i64 %distance, i32 1
141+
store i32 7, i32* %B ; B cannot alias A, it's at least 4 bytes away
142+
%REMOVEv = load i32, i32* %A1
143+
%r = sub i32 %REMOVEu, %REMOVEv
144+
ret i32 %r
78145
}
79146

80-
; Test that we can do funny pointer things and that distance calc will still
147+
; Test that we can do funny pointer things and that distance calc will still
81148
; work.
82149
define i32 @gep_distance_test3(i32 * %A) {
83-
%X = load i32, i32* %A
84-
%B = bitcast i32* %A to i8*
85-
%C = getelementptr i8, i8* %B, i64 4
86-
store i8 42, i8* %C
87-
%Y = load i32, i32* %A
88-
%R = sub i32 %X, %Y
89-
ret i32 %R
90-
; CHECK: @gep_distance_test3
91-
; CHECK: ret i32 0
150+
; NO_ASSUME-LABEL: @gep_distance_test3(
151+
; NO_ASSUME-NEXT: [[C1:%.*]] = getelementptr i32, i32* [[A:%.*]], i64 1
152+
; NO_ASSUME-NEXT: [[C:%.*]] = bitcast i32* [[C1]] to i8*
153+
; NO_ASSUME-NEXT: store i8 42, i8* [[C]], align 1
154+
; NO_ASSUME-NEXT: ret i32 0
155+
;
156+
; USE_ASSUME-LABEL: @gep_distance_test3(
157+
; USE_ASSUME-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(i32* [[A:%.*]], i64 4), "nonnull"(i32* [[A]]) ]
158+
; USE_ASSUME-NEXT: [[C1:%.*]] = getelementptr i32, i32* [[A]], i64 1
159+
; USE_ASSUME-NEXT: [[C:%.*]] = bitcast i32* [[C1]] to i8*
160+
; USE_ASSUME-NEXT: store i8 42, i8* [[C]], align 1
161+
; USE_ASSUME-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(i32* [[A]], i64 4), "nonnull"(i32* [[A]]) ]
162+
; USE_ASSUME-NEXT: ret i32 0
163+
;
164+
%X = load i32, i32* %A
165+
%B = bitcast i32* %A to i8*
166+
%C = getelementptr i8, i8* %B, i64 4
167+
store i8 42, i8* %C
168+
%Y = load i32, i32* %A
169+
%R = sub i32 %X, %Y
170+
ret i32 %R
92171
}
93172

94173
; Test that we can disambiguate globals reached through constantexpr geps
95174
define i32 @constexpr_test() {
96-
%X = alloca i32
97-
call void @external(i32* %X)
98-
99-
%Y = load i32, i32* %X
100-
store i32 5, i32* getelementptr ({ i32 }, { i32 }* @Global, i64 0, i32 0)
101-
%REMOVE = load i32, i32* %X
102-
%retval = sub i32 %Y, %REMOVE
103-
ret i32 %retval
104-
; CHECK: @constexpr_test
105-
; CHECK: ret i32 0
175+
; NO_ASSUME-LABEL: @constexpr_test(
176+
; NO_ASSUME-NEXT: [[X:%.*]] = alloca i32, align 4
177+
; NO_ASSUME-NEXT: call void @external(i32* nonnull [[X]])
178+
; NO_ASSUME-NEXT: store i32 5, i32* getelementptr inbounds ({ i32 }, { i32 }* @Global, i64 0, i32 0), align 4
179+
; NO_ASSUME-NEXT: ret i32 0
180+
;
181+
; USE_ASSUME-LABEL: @constexpr_test(
182+
; USE_ASSUME-NEXT: [[X:%.*]] = alloca i32, align 4
183+
; USE_ASSUME-NEXT: call void @external(i32* nonnull [[X]])
184+
; USE_ASSUME-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(i32* [[X]], i64 4), "nonnull"(i32* [[X]]) ]
185+
; USE_ASSUME-NEXT: store i32 5, i32* getelementptr inbounds ({ i32 }, { i32 }* @Global, i64 0, i32 0), align 4
186+
; USE_ASSUME-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(i32* [[X]], i64 4), "nonnull"(i32* [[X]]) ]
187+
; USE_ASSUME-NEXT: ret i32 0
188+
;
189+
%X = alloca i32
190+
call void @external(i32* %X)
191+
192+
%Y = load i32, i32* %X
193+
store i32 5, i32* getelementptr ({ i32 }, { i32 }* @Global, i64 0, i32 0)
194+
%REMOVE = load i32, i32* %X
195+
%retval = sub i32 %Y, %REMOVE
196+
ret i32 %retval
106197
}
107198

108199

109200

110201
; PR7589
111202
; These two index expressions are different, this cannot be CSE'd.
112203
define i16 @zext_sext_confusion(i16* %row2col, i5 %j) nounwind{
204+
; CHECK-LABEL: @zext_sext_confusion(
205+
; CHECK-NEXT: entry:
206+
; CHECK-NEXT: [[SUM5_CAST:%.*]] = zext i5 [[J:%.*]] to i64
207+
; CHECK-NEXT: [[P1:%.*]] = getelementptr i16, i16* [[ROW2COL:%.*]], i64 [[SUM5_CAST]]
208+
; CHECK-NEXT: [[ROW2COL_LOAD_1_2:%.*]] = load i16, i16* [[P1]], align 1
209+
; CHECK-NEXT: [[SUM13_CAST31:%.*]] = sext i5 [[J]] to i6
210+
; CHECK-NEXT: [[SUM13_CAST:%.*]] = zext i6 [[SUM13_CAST31]] to i64
211+
; CHECK-NEXT: [[P2:%.*]] = getelementptr i16, i16* [[ROW2COL]], i64 [[SUM13_CAST]]
212+
; CHECK-NEXT: [[ROW2COL_LOAD_1_6:%.*]] = load i16, i16* [[P2]], align 1
213+
; CHECK-NEXT: [[DOTRET:%.*]] = sub i16 [[ROW2COL_LOAD_1_6]], [[ROW2COL_LOAD_1_2]]
214+
; CHECK-NEXT: ret i16 [[DOTRET]]
215+
;
113216
entry:
114217
%sum5.cast = zext i5 %j to i64 ; <i64> [#uses=1]
115218
%P1 = getelementptr i16, i16* %row2col, i64 %sum5.cast
116219
%row2col.load.1.2 = load i16, i16* %P1, align 1 ; <i16> [#uses=1]
117-
220+
118221
%sum13.cast31 = sext i5 %j to i6 ; <i6> [#uses=1]
119222
%sum13.cast = zext i6 %sum13.cast31 to i64 ; <i64> [#uses=1]
120223
%P2 = getelementptr i16, i16* %row2col, i64 %sum13.cast
121224
%row2col.load.1.6 = load i16, i16* %P2, align 1 ; <i16> [#uses=1]
122-
225+
123226
%.ret = sub i16 %row2col.load.1.6, %row2col.load.1.2 ; <i16> [#uses=1]
124227
ret i16 %.ret
125-
; CHECK: @zext_sext_confusion
126-
; CHECK: ret i16 %.ret
127228
}

0 commit comments

Comments
 (0)