1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2; RUN: opt < %s -passes=instsimplify -S | FileCheck %s
3target datalayout = "p:32:32-p1:64:64"
4
5; This is a collection of tests checking whether we can prove pointers
6; derived from two allocas as inequal *via offset checks*.  Note that
7; instcombine has alternate approaches (one cmp rule, and compare
8; bases of common offset) that also handles these, but with different
9; logic.
10
11; %a follows %b, derived equal
12define i1 @adjacent_alloca() {
13; CHECK-LABEL: @adjacent_alloca(
14; CHECK-NEXT:    [[A:%.*]] = alloca i8, i32 4, align 1
15; CHECK-NEXT:    [[B:%.*]] = alloca i8, i32 4, align 1
16; CHECK-NEXT:    [[B_OFF:%.*]] = getelementptr i8, ptr [[B]], i64 4
17; CHECK-NEXT:    [[RES:%.*]] = icmp ne ptr [[A]], [[B_OFF]]
18; CHECK-NEXT:    ret i1 [[RES]]
19;
20  %a = alloca i8, i32 4
21  %b = alloca i8, i32 4
22  %b.off = getelementptr i8, ptr %b, i64 4
23  %res = icmp ne ptr %a, %b.off
24  ret i1 %res
25}
26
27; %b follows %a, derived equal
28define i1 @adjacent_alloca2() {
29; CHECK-LABEL: @adjacent_alloca2(
30; CHECK-NEXT:    [[A:%.*]] = alloca i8, i32 4, align 1
31; CHECK-NEXT:    [[B:%.*]] = alloca i8, i32 4, align 1
32; CHECK-NEXT:    [[A_OFF:%.*]] = getelementptr i8, ptr [[A]], i64 4
33; CHECK-NEXT:    [[RES:%.*]] = icmp ne ptr [[A_OFF]], [[B]]
34; CHECK-NEXT:    ret i1 [[RES]]
35;
36  %a = alloca i8, i32 4
37  %b = alloca i8, i32 4
38  %a.off = getelementptr i8, ptr %a, i64 4
39  %res = icmp ne ptr %a.off, %b
40  ret i1 %res
41}
42
43; FIXME: Can't be equal
44define i1 @positive_non_equal_end() {
45; CHECK-LABEL: @positive_non_equal_end(
46; CHECK-NEXT:    [[A:%.*]] = alloca i8, i32 4, align 1
47; CHECK-NEXT:    [[B:%.*]] = alloca i8, i32 4, align 1
48; CHECK-NEXT:    [[A_OFF:%.*]] = getelementptr i8, ptr [[A]], i64 4
49; CHECK-NEXT:    [[B_OFF:%.*]] = getelementptr i8, ptr [[B]], i64 4
50; CHECK-NEXT:    [[RES:%.*]] = icmp ne ptr [[A_OFF]], [[B_OFF]]
51; CHECK-NEXT:    ret i1 [[RES]]
52;
53  %a = alloca i8, i32 4
54  %b = alloca i8, i32 4
55  %a.off = getelementptr i8, ptr %a, i64 4
56  %b.off = getelementptr i8, ptr %b, i64 4
57  %res = icmp ne ptr %a.off, %b.off
58  ret i1 %res
59}
60
61; %b follows %a, derived equal
62define i1 @positive_equal_past_end() {
63; CHECK-LABEL: @positive_equal_past_end(
64; CHECK-NEXT:    [[A:%.*]] = alloca i8, i32 4, align 1
65; CHECK-NEXT:    [[B:%.*]] = alloca i8, i32 4, align 1
66; CHECK-NEXT:    [[A_OFF:%.*]] = getelementptr i8, ptr [[A]], i64 8
67; CHECK-NEXT:    [[B_OFF:%.*]] = getelementptr i8, ptr [[B]], i64 12
68; CHECK-NEXT:    [[RES:%.*]] = icmp ne ptr [[A_OFF]], [[B_OFF]]
69; CHECK-NEXT:    ret i1 [[RES]]
70;
71  %a = alloca i8, i32 4
72  %b = alloca i8, i32 4
73  %a.off = getelementptr i8, ptr %a, i64 8
74  %b.off = getelementptr i8, ptr %b, i64 12
75  %res = icmp ne ptr %a.off, %b.off
76  ret i1 %res
77}
78
79define i1 @positive_non_equal() {
80; CHECK-LABEL: @positive_non_equal(
81; CHECK-NEXT:    ret i1 true
82;
83  %a = alloca i8, i32 4
84  %b = alloca i8, i32 4
85  %a.off = getelementptr i8, ptr %a, i64 3
86  %b.off = getelementptr i8, ptr %b, i64 3
87  %res = icmp ne ptr %a.off, %b.off
88  ret i1 %res
89}
90
91; %a follows %b, derived equal
92define i1 @one_neg_equal1() {
93; CHECK-LABEL: @one_neg_equal1(
94; CHECK-NEXT:    [[A:%.*]] = alloca i8, i32 4, align 1
95; CHECK-NEXT:    [[B:%.*]] = alloca i8, i32 4, align 1
96; CHECK-NEXT:    [[A_OFF:%.*]] = getelementptr i8, ptr [[A]], i64 -1
97; CHECK-NEXT:    [[B_OFF:%.*]] = getelementptr i8, ptr [[B]], i64 3
98; CHECK-NEXT:    [[RES:%.*]] = icmp ne ptr [[A_OFF]], [[B_OFF]]
99; CHECK-NEXT:    ret i1 [[RES]]
100;
101  %a = alloca i8, i32 4
102  %b = alloca i8, i32 4
103  %a.off = getelementptr i8, ptr %a, i64 -1
104  %b.off = getelementptr i8, ptr %b, i64 3
105  %res = icmp ne ptr %a.off, %b.off
106  ret i1 %res
107}
108
109; %b follows %a, derived equal
110define i1 @one_neg_equal2() {
111; CHECK-LABEL: @one_neg_equal2(
112; CHECK-NEXT:    [[A:%.*]] = alloca i8, i32 4, align 1
113; CHECK-NEXT:    [[B:%.*]] = alloca i8, i32 4, align 1
114; CHECK-NEXT:    [[A_OFF:%.*]] = getelementptr i8, ptr [[A]], i64 3
115; CHECK-NEXT:    [[B_OFF:%.*]] = getelementptr i8, ptr [[B]], i64 -1
116; CHECK-NEXT:    [[RES:%.*]] = icmp ne ptr [[A_OFF]], [[B_OFF]]
117; CHECK-NEXT:    ret i1 [[RES]]
118;
119  %a = alloca i8, i32 4
120  %b = alloca i8, i32 4
121  %a.off = getelementptr i8, ptr %a, i64 3
122  %b.off = getelementptr i8, ptr %b, i64 -1
123  %res = icmp ne ptr %a.off, %b.off
124  ret i1 %res
125}
126
127; %b follows %a, derived equal
128define i1 @both_neg_equal() {
129; CHECK-LABEL: @both_neg_equal(
130; CHECK-NEXT:    [[A:%.*]] = alloca i8, i32 4, align 1
131; CHECK-NEXT:    [[B:%.*]] = alloca i8, i32 4, align 1
132; CHECK-NEXT:    [[A_OFF:%.*]] = getelementptr i8, ptr [[A]], i64 -4
133; CHECK-NEXT:    [[B_OFF:%.*]] = getelementptr i8, ptr [[B]], i64 -8
134; CHECK-NEXT:    [[RES:%.*]] = icmp ne ptr [[A_OFF]], [[B_OFF]]
135; CHECK-NEXT:    ret i1 [[RES]]
136;
137  %a = alloca i8, i32 4
138  %b = alloca i8, i32 4
139  %a.off = getelementptr i8, ptr %a, i64 -4
140  %b.off = getelementptr i8, ptr %b, i64 -8
141  %res = icmp ne ptr %a.off, %b.off
142  ret i1 %res
143}
144
145; FIXME: Can't be equal
146define i1 @mixed_offsets1() {
147; CHECK-LABEL: @mixed_offsets1(
148; CHECK-NEXT:    [[A:%.*]] = alloca i8, i32 4, align 1
149; CHECK-NEXT:    [[B:%.*]] = alloca i8, i32 4, align 1
150; CHECK-NEXT:    [[A_OFF:%.*]] = getelementptr i8, ptr [[A]], i64 -1
151; CHECK-NEXT:    [[B_OFF:%.*]] = getelementptr i8, ptr [[B]], i64 2
152; CHECK-NEXT:    [[RES:%.*]] = icmp ne ptr [[A_OFF]], [[B_OFF]]
153; CHECK-NEXT:    ret i1 [[RES]]
154;
155  %a = alloca i8, i32 4
156  %b = alloca i8, i32 4
157  %a.off = getelementptr i8, ptr %a, i64 -1
158  %b.off = getelementptr i8, ptr %b, i64 2
159  %res = icmp ne ptr %a.off, %b.off
160  ret i1 %res
161}
162
163; FIXME: Can't be equal
164define i1 @mixed_offsets2() {
165; CHECK-LABEL: @mixed_offsets2(
166; CHECK-NEXT:    [[A:%.*]] = alloca i8, i32 4, align 1
167; CHECK-NEXT:    [[B:%.*]] = alloca i8, i32 4, align 1
168; CHECK-NEXT:    [[A_OFF:%.*]] = getelementptr i8, ptr [[A]], i64 1
169; CHECK-NEXT:    [[B_OFF:%.*]] = getelementptr i8, ptr [[B]], i64 -2
170; CHECK-NEXT:    [[RES:%.*]] = icmp ne ptr [[A_OFF]], [[B_OFF]]
171; CHECK-NEXT:    ret i1 [[RES]]
172;
173  %a = alloca i8, i32 4
174  %b = alloca i8, i32 4
175  %a.off = getelementptr i8, ptr %a, i64 1
176  %b.off = getelementptr i8, ptr %b, i64 -2
177  %res = icmp ne ptr %a.off, %b.off
178  ret i1 %res
179}
180
181; FIXME: Can't be equal
182define i1 @negative_in_other() {
183; CHECK-LABEL: @negative_in_other(
184; CHECK-NEXT:    [[A:%.*]] = alloca i8, i32 4, align 1
185; CHECK-NEXT:    [[B:%.*]] = alloca i8, i32 4, align 1
186; CHECK-NEXT:    [[A_OFF:%.*]] = getelementptr i8, ptr [[A]], i64 -3
187; CHECK-NEXT:    [[B_OFF:%.*]] = getelementptr i8, ptr [[B]], i64 -2
188; CHECK-NEXT:    [[RES:%.*]] = icmp ne ptr [[A_OFF]], [[B_OFF]]
189; CHECK-NEXT:    ret i1 [[RES]]
190;
191  %a = alloca i8, i32 4
192  %b = alloca i8, i32 4
193  %a.off = getelementptr i8, ptr %a, i64 -3
194  %b.off = getelementptr i8, ptr %b, i64 -2
195  %res = icmp ne ptr %a.off, %b.off
196  ret i1 %res
197}
198
199
200attributes #0 = { null_pointer_is_valid }
201