xref: /llvm-project/llvm/test/Transforms/InstCombine/assume-align.ll (revision 7629e01479bb1ec8b7279ec7515b3bba7e6c9e31)
1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --check-globals smart
2; RUN: opt -S -passes=instcombine,simplifycfg < %s 2>&1 | FileCheck %s
3
4declare void @llvm.assume(i1 noundef)
5
6define void @f1(ptr %a) {
7; CHECK-LABEL: @f1(
8; CHECK-NEXT:  entry:
9; CHECK-NEXT:    [[PTR:%.*]] = getelementptr inbounds nuw i8, ptr [[A:%.*]], i64 4
10; CHECK-NEXT:    [[TMP0:%.*]] = ptrtoint ptr [[PTR]] to i64
11; CHECK-NEXT:    [[TMP1:%.*]] = and i64 [[TMP0]], 3
12; CHECK-NEXT:    [[TMP2:%.*]] = icmp eq i64 [[TMP1]], 0
13; CHECK-NEXT:    br i1 [[TMP2]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
14; CHECK:       if.then:
15; CHECK-NEXT:    call void @llvm.assume(i1 true) [ "align"(ptr [[PTR]], i64 4) ]
16; CHECK-NEXT:    store i32 4, ptr [[PTR]], align 4
17; CHECK-NEXT:    br label [[IF_END]]
18; CHECK:       if.end:
19; CHECK-NEXT:    ret void
20;
21entry:
22  %ptr = getelementptr inbounds i8, ptr %a, i64 4
23  %0 = ptrtoint ptr %ptr to i64
24  %1 = and i64 %0, 3
25  %2 = icmp eq i64 %1, 0
26  br i1 %2, label %if.then, label %if.end
27
28if.then:                                          ; preds = %entry
29  call void @llvm.assume(i1 true) [ "align"(ptr %ptr, i64 4) ]
30  %3 = ptrtoint ptr %ptr to i64
31  %4 = and i64 %3, 3
32  %5 = icmp eq i64 %4, 0
33  br i1 %5, label %if.then1, label %if.else1
34
35if.then1:                                         ; preds = %if.then
36  store i32 4, ptr %ptr, align 4
37  br label %if.end
38
39if.else1:                                         ; preds = %if.then
40  store i8 1, ptr %ptr, align 1
41  br label %if.end
42
43if.end:                                           ; preds = %if.then1, %if.else1, %entry
44  ret void
45}
46
47; TODO: We could fold away the branch "br i1 %3, ..." by either using a GEP or make getKnowledgeValidInContext aware the alignment bundle offset, and the improvement of value tracking of GEP.
48
49define void @f2(ptr %a) {
50; CHECK-LABEL: @f2(
51; CHECK-NEXT:  entry:
52; CHECK-NEXT:    call void @llvm.assume(i1 true) [ "align"(ptr [[A:%.*]], i64 32, i32 24) ]
53; CHECK-NEXT:    [[TMP0:%.*]] = getelementptr inbounds nuw i8, ptr [[A]], i64 8
54; CHECK-NEXT:    [[TMP1:%.*]] = ptrtoint ptr [[TMP0]] to i64
55; CHECK-NEXT:    [[TMP2:%.*]] = and i64 [[TMP1]], 8
56; CHECK-NEXT:    [[TMP3:%.*]] = icmp eq i64 [[TMP2]], 0
57; CHECK-NEXT:    br i1 [[TMP3]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
58; CHECK:       if.then:
59; CHECK-NEXT:    store i64 16, ptr [[TMP0]], align 4
60; CHECK-NEXT:    br label [[IF_END:%.*]]
61; CHECK:       if.else:
62; CHECK-NEXT:    store i8 1, ptr [[TMP0]], align 1
63; CHECK-NEXT:    br label [[IF_END]]
64; CHECK:       if.end:
65; CHECK-NEXT:    ret void
66;
67entry:
68  call void @llvm.assume(i1 true) [ "align"(ptr %a, i64 32, i32 24) ]
69  %0 = getelementptr inbounds i8, ptr %a, i64 8
70  %1 = ptrtoint ptr %0 to i64
71  %2 = and i64 %1, 15
72  %3 = icmp eq i64 %2, 0
73  br i1 %3, label %if.then, label %if.else
74
75if.then:                                          ; preds = %entry
76  store i64 16, ptr %0, align 4
77  br label %if.end
78
79if.else:                                          ; preds = %entry
80  store i8 1, ptr %0, align 1
81  br label %if.end
82
83if.end:                                           ; preds = %if.else, %if.then
84  ret void
85}
86
87define void @f3(i64 %a, ptr %b) {
88; CHECK-LABEL: @f3(
89; CHECK-NEXT:    [[C:%.*]] = ptrtoint ptr [[B:%.*]] to i64
90; CHECK-NEXT:    call void @llvm.assume(i1 true) [ "align"(ptr [[B]], i64 4294967296) ]
91; CHECK-NEXT:    [[D:%.*]] = add i64 [[A:%.*]], [[C]]
92; CHECK-NEXT:    call void @g(i64 [[D]])
93; CHECK-NEXT:    ret void
94;
95  %c = ptrtoint ptr %b to i64
96  call void @llvm.assume(i1 true) [ "align"(ptr %b, i64 4294967296) ]
97  %d = add i64 %a, %c
98  call void @g(i64 %d)
99  ret void
100}
101
102declare void @g(i64)
103
104define i8 @assume_align_zero(ptr %p) {
105; CHECK-LABEL: @assume_align_zero(
106; CHECK-NEXT:    call void @llvm.assume(i1 true) [ "align"(ptr [[P:%.*]], i64 0) ]
107; CHECK-NEXT:    [[V:%.*]] = load i8, ptr [[P]], align 1
108; CHECK-NEXT:    ret i8 [[V]]
109;
110  call void @llvm.assume(i1 true) [ "align"(ptr %p, i64 0) ]
111  %v = load i8, ptr %p
112  ret i8 %v
113}
114
115define i8 @assume_align_non_pow2(ptr %p) {
116; CHECK-LABEL: @assume_align_non_pow2(
117; CHECK-NEXT:    call void @llvm.assume(i1 true) [ "align"(ptr [[P:%.*]], i64 123) ]
118; CHECK-NEXT:    [[V:%.*]] = load i8, ptr [[P]], align 1
119; CHECK-NEXT:    ret i8 [[V]]
120;
121  call void @llvm.assume(i1 true) [ "align"(ptr %p, i64 123) ]
122  %v = load i8, ptr %p
123  ret i8 %v
124}
125
126; TODO: Can fold alignment assumption into !align metadata on load.
127define ptr @fold_assume_align_pow2_of_loaded_pointer_into_align_metadata(ptr %p) {
128; CHECK-LABEL: @fold_assume_align_pow2_of_loaded_pointer_into_align_metadata(
129; CHECK-NEXT:    [[P2:%.*]] = load ptr, ptr [[P:%.*]], align 8
130; CHECK-NEXT:    call void @llvm.assume(i1 true) [ "align"(ptr [[P2]], i64 8) ]
131; CHECK-NEXT:    ret ptr [[P2]]
132;
133  %p2 = load ptr, ptr %p
134  call void @llvm.assume(i1 true) [ "align"(ptr %p2, i64 8) ]
135  ret ptr %p2
136}
137
138define ptr @dont_fold_assume_align_pow2_of_loaded_pointer_into_align_metadata_due_to_call(ptr %p) {
139; CHECK-LABEL: @dont_fold_assume_align_pow2_of_loaded_pointer_into_align_metadata_due_to_call(
140; CHECK-NEXT:    [[P2:%.*]] = load ptr, ptr [[P:%.*]], align 8
141; CHECK-NEXT:    call void @g(i64 0)
142; CHECK-NEXT:    call void @llvm.assume(i1 true) [ "align"(ptr [[P2]], i64 8) ]
143; CHECK-NEXT:    ret ptr [[P2]]
144;
145  %p2 = load ptr, ptr %p
146  call void @g(i64 0)
147  call void @llvm.assume(i1 true) [ "align"(ptr %p2, i64 8) ]
148  ret ptr %p2
149}
150
151; !align must have a power-of-2 alignment.
152define ptr @dont_fold_assume_align_non_pow2_of_loaded_pointer_into_align_metadata(ptr %p) {
153; CHECK-LABEL: @dont_fold_assume_align_non_pow2_of_loaded_pointer_into_align_metadata(
154; CHECK-NEXT:    [[P2:%.*]] = load ptr, ptr [[P:%.*]], align 8
155; CHECK-NEXT:    call void @llvm.assume(i1 true) [ "align"(ptr [[P2]], i64 13) ]
156; CHECK-NEXT:    ret ptr [[P2]]
157;
158  %p2 = load ptr, ptr %p
159  call void @llvm.assume(i1 true) [ "align"(ptr %p2, i64 13) ]
160  ret ptr %p2
161}
162
163; !align must have a power-of-2 alignment.
164define ptr @dont_fold_assume_align_zero_of_loaded_pointer_into_align_metadata(ptr %p) {
165; CHECK-LABEL: @dont_fold_assume_align_zero_of_loaded_pointer_into_align_metadata(
166; CHECK-NEXT:    [[P2:%.*]] = load ptr, ptr [[P:%.*]], align 8
167; CHECK-NEXT:    call void @llvm.assume(i1 true) [ "align"(ptr [[P2]], i64 0) ]
168; CHECK-NEXT:    ret ptr [[P2]]
169;
170  %p2 = load ptr, ptr %p
171  call void @llvm.assume(i1 true) [ "align"(ptr %p2, i64 0) ]
172  ret ptr %p2
173}
174
175define ptr @redundant_assume_align_1(ptr %p) {
176; CHECK-LABEL: @redundant_assume_align_1(
177; CHECK-NEXT:    [[P2:%.*]] = load ptr, ptr [[P:%.*]], align 8
178; CHECK-NEXT:    call void @llvm.assume(i1 true) [ "align"(ptr [[P2]], i32 1) ]
179; CHECK-NEXT:    call void @foo(ptr [[P2]])
180; CHECK-NEXT:    ret ptr [[P2]]
181;
182  %p2 = load ptr, ptr %p
183  call void @llvm.assume(i1 true) [ "align"(ptr %p2, i32 1) ]
184  call void @foo(ptr %p2)
185  ret ptr %p2
186}
187
188
189define ptr @redundant_assume_align_8_via_align_metadata(ptr %p) {
190; CHECK-LABEL: @redundant_assume_align_8_via_align_metadata(
191; CHECK-NEXT:    [[P2:%.*]] = load ptr, ptr [[P:%.*]], align 8, !align [[META0:![0-9]+]]
192; CHECK-NEXT:    call void @llvm.assume(i1 true) [ "align"(ptr [[P2]], i32 8) ]
193; CHECK-NEXT:    call void @foo(ptr [[P2]])
194; CHECK-NEXT:    ret ptr [[P2]]
195;
196  %p2 = load ptr, ptr %p, !align !{i64 8}
197  call void @llvm.assume(i1 true) [ "align"(ptr %p2, i32 8) ]
198  call void @foo(ptr %p2)
199  ret ptr %p2
200}
201
202define ptr @assume_align_16_via_align_metadata(ptr %p) {
203; CHECK-LABEL: @assume_align_16_via_align_metadata(
204; CHECK-NEXT:    [[P2:%.*]] = load ptr, ptr [[P:%.*]], align 8, !align [[META0]]
205; CHECK-NEXT:    call void @llvm.assume(i1 true) [ "align"(ptr [[P2]], i32 16) ]
206; CHECK-NEXT:    call void @foo(ptr [[P2]])
207; CHECK-NEXT:    ret ptr [[P2]]
208;
209  %p2 = load ptr, ptr %p, !align !{i64 8}
210  call void @llvm.assume(i1 true) [ "align"(ptr %p2, i32 16) ]
211  call void @foo(ptr %p2)
212  ret ptr %p2
213}
214
215define ptr @redundant_assume_align_8_via_align_attribute(ptr align 8 %p) {
216; CHECK-LABEL: @redundant_assume_align_8_via_align_attribute(
217; CHECK-NEXT:    call void @llvm.assume(i1 true) [ "align"(ptr [[P:%.*]], i32 8) ]
218; CHECK-NEXT:    call void @foo(ptr [[P]])
219; CHECK-NEXT:    ret ptr [[P]]
220;
221  call void @llvm.assume(i1 true) [ "align"(ptr %p, i32 8) ]
222  call void @foo(ptr %p)
223  ret ptr %p
224}
225
226define ptr @assume_align_16_via_align_attribute(ptr align 8 %p) {
227; CHECK-LABEL: @assume_align_16_via_align_attribute(
228; CHECK-NEXT:    call void @llvm.assume(i1 true) [ "align"(ptr [[P:%.*]], i32 16) ]
229; CHECK-NEXT:    call void @foo(ptr [[P]])
230; CHECK-NEXT:    ret ptr [[P]]
231;
232  call void @llvm.assume(i1 true) [ "align"(ptr %p, i32 16) ]
233  call void @foo(ptr %p)
234  ret ptr %p
235}
236
237define ptr @redundant_assume_align_8_via_asume(ptr %p) {
238; CHECK-LABEL: @redundant_assume_align_8_via_asume(
239; CHECK-NEXT:    call void @llvm.assume(i1 true) [ "align"(ptr [[P:%.*]], i32 16) ]
240; CHECK-NEXT:    call void @foo(ptr [[P]])
241; CHECK-NEXT:    call void @llvm.assume(i1 true) [ "align"(ptr [[P]], i32 8) ]
242; CHECK-NEXT:    call void @foo(ptr [[P]])
243; CHECK-NEXT:    ret ptr [[P]]
244;
245  call void @llvm.assume(i1 true) [ "align"(ptr %p, i32 16) ]
246  call void @foo(ptr %p)
247  call void @llvm.assume(i1 true) [ "align"(ptr %p, i32 8) ]
248  call void @foo(ptr %p)
249  ret ptr %p
250}
251
252declare void @foo(ptr)
253;.
254; CHECK: [[META0]] = !{i64 8}
255;.
256