1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
|
; RUN: opt -aa-pipeline=basic-aa -passes=aa-eval -print-all-alias-modref-info %s 2>&1 | FileCheck %s
; %col.ptr.1 and %col.ptr.2 do not alias, if we know that %skip >= 0, because
; the distance between %col.ptr.1 and %col.ptr.2 is %skip + 6 and we load 6
; elements.
define void @test1(ptr %ptr, i32 %skip) {
; CHECK-LABEL: Function: test1: 2 pointers, 1 call sites
; CHECK-NEXT: NoAlias: <6 x double>* %col.ptr.2, <6 x double>* %ptr
;
%gt = icmp sgt i32 %skip, -1
call void @llvm.assume(i1 %gt)
%stride = add nsw nuw i32 %skip, 6
%lv.1 = load <6 x double>, ptr %ptr, align 8
%col.ptr.2 = getelementptr double, ptr %ptr, i32 %stride
%lv.2 = load <6 x double>, ptr %col.ptr.2, align 8
%res.1 = fadd <6 x double> %lv.1, %lv.1
%res.2 = fadd <6 x double> %lv.2, %lv.2
store <6 x double> %res.1, ptr %ptr, align 8
store <6 x double> %res.2, ptr %col.ptr.2, align 8
ret void
}
; Same as @test1, but now we do not have an assume guaranteeing %skip >= 0.
define void @test2(ptr %ptr, i32 %skip) {
; CHECK-LABEL: Function: test2: 2 pointers, 0 call sites
; CHECK-NEXT: MayAlias: <6 x double>* %col.ptr.2, <6 x double>* %ptr
;
%stride = add nsw nuw i32 %skip, 6
%lv.1 = load <6 x double>, ptr %ptr, align 8
%col.ptr.2 = getelementptr double, ptr %ptr, i32 %stride
%lv.2 = load <6 x double>, ptr %col.ptr.2, align 8
%res.1 = fadd <6 x double> %lv.1, %lv.1
%res.2 = fadd <6 x double> %lv.2, %lv.2
store <6 x double> %res.1, ptr %ptr, align 8
store <6 x double> %res.2, ptr %col.ptr.2, align 8
ret void
}
; Same as @test1, this time the assume just guarantees %skip > -3, which is
; enough to derive NoAlias for %ptr and %col.ptr.2 (distance is more than 3
; doubles, and we load 1 double), but not %col.ptr.1 and %col.ptr.2 (distance
; is more than 3 doubles, and we load 6 doubles).
define void @test3(ptr %ptr, i32 %skip) {
; CHECK-LABEL: Function: test3: 2 pointers, 1 call sites
; CHECK-NEXT: MayAlias: <6 x double>* %col.ptr.2, <6 x double>* %ptr
;
%gt = icmp sgt i32 %skip, -3
call void @llvm.assume(i1 %gt)
%stride = add nsw nuw i32 %skip, 6
%lv.1 = load <6 x double>, ptr %ptr, align 8
%col.ptr.2 = getelementptr double, ptr %ptr, i32 %stride
%lv.2 = load <6 x double>, ptr %col.ptr.2, align 8
%res.1 = fadd <6 x double> %lv.1, %lv.1
%res.2 = fadd <6 x double> %lv.2, %lv.2
store <6 x double> %res.1, ptr %ptr, align 8
store <6 x double> %res.2, ptr %col.ptr.2, align 8
ret void
}
; Same as @test1, but the assume uses the sge predicate for %skip >= 0.
define void @test4(ptr %ptr, i32 %skip) {
; CHECK-LABEL: Function: test4: 2 pointers, 1 call sites
; CHECK-NEXT: NoAlias: <6 x double>* %col.ptr.2, <6 x double>* %ptr
;
%gt = icmp sge i32 %skip, 0
call void @llvm.assume(i1 %gt)
%stride = add nsw nuw i32 %skip, 6
%lv.1 = load <6 x double>, ptr %ptr, align 8
%col.ptr.2 = getelementptr double, ptr %ptr, i32 %stride
%lv.2 = load <6 x double>, ptr %col.ptr.2, align 8
%res.1 = fadd <6 x double> %lv.1, %lv.1
%res.2 = fadd <6 x double> %lv.2, %lv.2
store <6 x double> %res.1, ptr %ptr, align 8
store <6 x double> %res.2, ptr %col.ptr.2, align 8
ret void
}
define void @symmetry(ptr %ptr, i32 %a, i32 %b, i32 %c) {
; CHECK-LABEL: Function: symmetry
; CHECK: NoAlias: i8* %gep1, i8* %gep2
;
%b.cmp = icmp slt i32 %b, 0
call void @llvm.assume(i1 %b.cmp)
%gep1 = getelementptr [0 x i8], ptr %ptr, i32 %a, i32 %b
load i8, ptr %gep1
call void @barrier()
%c.cmp = icmp sgt i32 %c, -1
call void @llvm.assume(i1 %c.cmp)
%c.off = add nuw nsw i32 %c, 1
%gep2 = getelementptr [0 x i8], ptr %ptr, i32 %a, i32 %c.off
load i8, ptr %gep2
ret void
}
; %ptr.neg and %ptr.shl may alias, as the shl renders the previously
; non-negative value potentially negative.
define void @shl_of_non_negative(ptr %ptr, i64 %a) {
; CHECK-LABEL: Function: shl_of_non_negative
; CHECK: NoAlias: i8* %ptr.a, i8* %ptr.neg
; CHECK: MayAlias: i8* %ptr.neg, i8* %ptr.shl
;
%a.cmp = icmp sge i64 %a, 0
call void @llvm.assume(i1 %a.cmp)
%ptr.neg = getelementptr i8, ptr %ptr, i64 -2
%ptr.a = getelementptr i8, ptr %ptr, i64 %a
%shl = shl i64 %a, 1
%ptr.shl = getelementptr i8, ptr %ptr, i64 %shl
load i8, ptr %ptr.a
load i8, ptr %ptr.neg
load i8, ptr %ptr.shl
ret void
}
; Unlike the previous case, %ptr.neg and %ptr.shl can't alias, because
; shl nsw of non-negative is non-negative.
define void @shl_nsw_of_non_negative(ptr %ptr, i64 %a) {
; CHECK-LABEL: Function: shl_nsw_of_non_negative
; CHECK: NoAlias: i8* %ptr.a, i8* %ptr.neg
; CHECK: NoAlias: i8* %ptr.neg, i8* %ptr.shl
;
%a.cmp = icmp sge i64 %a, 0
call void @llvm.assume(i1 %a.cmp)
%ptr.neg = getelementptr i8, ptr %ptr, i64 -2
%ptr.a = getelementptr i8, ptr %ptr, i64 %a
%shl = shl nsw i64 %a, 1
%ptr.shl = getelementptr i8, ptr %ptr, i64 %shl
load i8, ptr %ptr.a
load i8, ptr %ptr.neg
load i8, ptr %ptr.shl
ret void
}
define void @test5(ptr %ptr, i32 %stride) {
; CHECK-LABEL: Function: test5: 2 pointers, 1 call sites
; CHECK-NEXT: MayAlias: <6 x double>* %col.ptr.2, <6 x double>* %ptr
;
%gt = icmp sge i32 %stride, 5
call void @llvm.assume(i1 %gt)
%lv.1 = load <6 x double>, ptr %ptr, align 8
%col.ptr.2= getelementptr double, ptr %ptr, i32 %stride
%lv.2 = load <6 x double>, ptr %col.ptr.2, align 8
%res.1 = fadd <6 x double> %lv.1, %lv.1
%res.2 = fadd <6 x double> %lv.2, %lv.2
store <6 x double> %res.1, ptr %ptr, align 8
store <6 x double> %res.2, ptr %col.ptr.2, align 8
ret void
}
define void @test6(ptr %ptr, i32 %stride) {
; CHECK-LABEL: Function: test6: 2 pointers, 1 call sites
; CHECK-NEXT: NoAlias: <6 x double>* %col.ptr.2, <6 x double>* %ptr
;
%gt = icmp sge i32 %stride, 6
call void @llvm.assume(i1 %gt)
%lv.1 = load <6 x double>, ptr %ptr, align 8
%col.ptr.2= getelementptr double, ptr %ptr, i32 %stride
%lv.2 = load <6 x double>, ptr %col.ptr.2, align 8
%res.1 = fadd <6 x double> %lv.1, %lv.1
%res.2 = fadd <6 x double> %lv.2, %lv.2
store <6 x double> %res.1, ptr %ptr, align 8
store <6 x double> %res.2, ptr %col.ptr.2, align 8
ret void
}
define void @test7(ptr %ptr, i32 %stride) {
; CHECK-LABEL: Function: test7: 2 pointers, 1 call sites
; CHECK-NEXT: MayAlias: <6 x double>* %col.ptr.2, <6 x double>* %ptr
;
%gt = icmp sge i32 %stride, 0
call void @llvm.assume(i1 %gt)
%lv.1 = load <6 x double>, ptr %ptr, align 8
%col.ptr.2= getelementptr double, ptr %ptr, i32 %stride
%lv.2 = load <6 x double>, ptr %col.ptr.2, align 8
%res.1 = fadd <6 x double> %lv.1, %lv.1
%res.2 = fadd <6 x double> %lv.2, %lv.2
store <6 x double> %res.1, ptr %ptr, align 8
store <6 x double> %res.2, ptr %col.ptr.2, align 8
ret void
}
declare void @llvm.assume(i1 %cond)
declare void @barrier()
|