1 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --check-globals
2 ; RUN: opt < %s -passes=simplifycfg -simplifycfg-require-and-preserve-domtree=1 -hoist-common-insts=true -S | FileCheck %s
4 define void @hoist_range(i1 %c, ptr %p) {
5 ; CHECK-LABEL: @hoist_range(
7 ; CHECK-NEXT: [[T:%.*]] = load i8, ptr [[P:%.*]], align 1, !range [[RNG0:![0-9]+]]
11 br i1 %c, label %then, label %else
13 %t = load i8, ptr %p, !range !0
16 %e = load i8, ptr %p, !range !1
22 define void @hoist_range_switch(i64 %i, ptr %p) {
23 ; CHECK-LABEL: @hoist_range_switch(
24 ; CHECK-NEXT: switch i64 [[I:%.*]], label [[BB0:%.*]] [
25 ; CHECK-NEXT: i64 1, label [[BB1:%.*]]
26 ; CHECK-NEXT: i64 2, label [[BB2:%.*]]
29 ; CHECK-NEXT: [[T:%.*]] = load i8, ptr [[P:%.*]], align 1, !range [[RNG1:![0-9]+]]
30 ; CHECK-NEXT: br label [[OUT:%.*]]
32 ; CHECK-NEXT: [[E:%.*]] = load i8, ptr [[P]], align 1, !range [[RNG2:![0-9]+]]
33 ; CHECK-NEXT: br label [[OUT]]
35 ; CHECK-NEXT: [[F:%.*]] = load i8, ptr [[P]], align 1, !range [[RNG3:![0-9]+]]
36 ; CHECK-NEXT: br label [[OUT]]
38 ; CHECK-NEXT: ret void
40 switch i64 %i, label %bb0 [
45 %t = load i8, ptr %p, !range !0
48 %e = load i8, ptr %p, !range !1
51 %f = load i8, ptr %p, !range !3
57 define void @hoist_both_noundef(i1 %c, ptr %p) {
58 ; CHECK-LABEL: @hoist_both_noundef(
60 ; CHECK-NEXT: [[T:%.*]] = load i8, ptr [[P:%.*]], align 1, !noundef !4
61 ; CHECK-NEXT: ret void
64 br i1 %c, label %then, label %else
67 %t = load i8, ptr %p, !noundef !2
71 %e = load i8, ptr %p, !noundef !2
79 define void @hoist_both_noundef_switch(i64 %i, ptr %p) {
80 ; CHECK-LABEL: @hoist_both_noundef_switch(
81 ; CHECK-NEXT: switch i64 [[I:%.*]], label [[BB0:%.*]] [
82 ; CHECK-NEXT: i64 1, label [[BB1:%.*]]
83 ; CHECK-NEXT: i64 2, label [[BB2:%.*]]
86 ; CHECK-NEXT: [[T:%.*]] = load i8, ptr [[P:%.*]], align 1, !noundef !4
87 ; CHECK-NEXT: br label [[OUT:%.*]]
89 ; CHECK-NEXT: [[E:%.*]] = load i8, ptr [[P]], align 1, !noundef !4
90 ; CHECK-NEXT: br label [[OUT]]
92 ; CHECK-NEXT: [[F:%.*]] = load i8, ptr [[P]], align 1, !noundef !4
93 ; CHECK-NEXT: br label [[OUT]]
95 ; CHECK-NEXT: ret void
97 switch i64 %i, label %bb0 [
102 %t = load i8, ptr %p, !noundef !2
105 %e = load i8, ptr %p, !noundef !2
108 %f = load i8, ptr %p, !noundef !2
114 define void @hoist_one_noundef(i1 %c, ptr %p) {
115 ; CHECK-LABEL: @hoist_one_noundef(
117 ; CHECK-NEXT: [[T:%.*]] = load i8, ptr [[P:%.*]], align 1
118 ; CHECK-NEXT: ret void
121 br i1 %c, label %then, label %else
124 %t = load i8, ptr %p, !noundef !2
135 define void @hoist_one_noundef_switch(i64 %i, ptr %p) {
136 ; CHECK-LABEL: @hoist_one_noundef_switch(
137 ; CHECK-NEXT: switch i64 [[I:%.*]], label [[BB0:%.*]] [
138 ; CHECK-NEXT: i64 1, label [[BB1:%.*]]
139 ; CHECK-NEXT: i64 2, label [[BB2:%.*]]
142 ; CHECK-NEXT: [[T:%.*]] = load i8, ptr [[P:%.*]], align 1, !noundef !4
143 ; CHECK-NEXT: br label [[OUT:%.*]]
145 ; CHECK-NEXT: [[E:%.*]] = load i8, ptr [[P]], align 1
146 ; CHECK-NEXT: br label [[OUT]]
148 ; CHECK-NEXT: [[F:%.*]] = load i8, ptr [[P]], align 1, !noundef !4
149 ; CHECK-NEXT: br label [[OUT]]
151 ; CHECK-NEXT: ret void
153 switch i64 %i, label %bb0 [
158 %t = load i8, ptr %p, !noundef !2
164 %f = load i8, ptr %p, !noundef !2
170 define void @hoist_dereferenceable(i1 %c, ptr %p) {
171 ; CHECK-LABEL: @hoist_dereferenceable(
173 ; CHECK-NEXT: [[T:%.*]] = load ptr, ptr [[P:%.*]], align 8, !dereferenceable !5
174 ; CHECK-NEXT: ret void
177 br i1 %c, label %then, label %else
179 %t = load ptr, ptr %p, !dereferenceable !{i64 10}
182 %e = load ptr, ptr %p, !dereferenceable !{i64 20}
188 define void @hoist_dereferenceable_switch(i64 %i, ptr %p) {
189 ; CHECK-LABEL: @hoist_dereferenceable_switch(
190 ; CHECK-NEXT: switch i64 [[I:%.*]], label [[BB0:%.*]] [
191 ; CHECK-NEXT: i64 1, label [[BB1:%.*]]
192 ; CHECK-NEXT: i64 2, label [[BB2:%.*]]
195 ; CHECK-NEXT: [[T:%.*]] = load ptr, ptr [[P:%.*]], align 8, !dereferenceable !5
196 ; CHECK-NEXT: br label [[OUT:%.*]]
198 ; CHECK-NEXT: [[E:%.*]] = load ptr, ptr [[P]], align 8, !dereferenceable !6
199 ; CHECK-NEXT: br label [[OUT]]
201 ; CHECK-NEXT: [[F:%.*]] = load ptr, ptr [[P]], align 8, !dereferenceable !7
202 ; CHECK-NEXT: br label [[OUT]]
204 ; CHECK-NEXT: ret void
206 switch i64 %i, label %bb0 [
211 %t = load ptr, ptr %p, !dereferenceable !{i64 10}
214 %e = load ptr, ptr %p, !dereferenceable !{i64 20}
217 %f = load ptr, ptr %p, !dereferenceable !{i64 30}
223 define void @hoist_dereferenceable_or_null(i1 %c, ptr %p) {
224 ; CHECK-LABEL: @hoist_dereferenceable_or_null(
226 ; CHECK-NEXT: [[T:%.*]] = load ptr, ptr [[P:%.*]], align 8, !dereferenceable_or_null !5
227 ; CHECK-NEXT: ret void
230 br i1 %c, label %then, label %else
232 %t = load ptr, ptr %p, !dereferenceable_or_null !{i64 20}
235 %e = load ptr, ptr %p, !dereferenceable_or_null !{i64 10}
241 define void @hoist_dereferenceable_or_null_switch(i64 %i, ptr %p) {
242 ; CHECK-LABEL: @hoist_dereferenceable_or_null_switch(
243 ; CHECK-NEXT: switch i64 [[I:%.*]], label [[BB0:%.*]] [
244 ; CHECK-NEXT: i64 1, label [[BB1:%.*]]
245 ; CHECK-NEXT: i64 2, label [[BB2:%.*]]
248 ; CHECK-NEXT: [[T:%.*]] = load ptr, ptr [[P:%.*]], align 8, !dereferenceable_or_null !6
249 ; CHECK-NEXT: br label [[OUT:%.*]]
251 ; CHECK-NEXT: [[E:%.*]] = load ptr, ptr [[P]], align 8, !dereferenceable_or_null !5
252 ; CHECK-NEXT: br label [[OUT]]
254 ; CHECK-NEXT: [[F:%.*]] = load ptr, ptr [[P]], align 8, !dereferenceable_or_null !7
255 ; CHECK-NEXT: br label [[OUT]]
257 ; CHECK-NEXT: ret void
259 switch i64 %i, label %bb0 [
264 %t = load ptr, ptr %p, !dereferenceable_or_null !{i64 20}
267 %e = load ptr, ptr %p, !dereferenceable_or_null !{i64 10}
270 %f = load ptr, ptr %p, !dereferenceable_or_null !{i64 30}
276 ; !range violation only returns poison, and is thus safe to speculate.
277 define i32 @speculate_range(i1 %c, ptr dereferenceable(8) align 8 %p) {
278 ; CHECK-LABEL: @speculate_range(
280 ; CHECK-NEXT: [[V:%.*]] = load i32, ptr [[P:%.*]], align 4, !range [[RNG8:![0-9]+]]
281 ; CHECK-NEXT: [[SPEC_SELECT:%.*]] = select i1 [[C:%.*]], i32 [[V]], i32 0
282 ; CHECK-NEXT: ret i32 [[SPEC_SELECT]]
285 br i1 %c, label %if, label %join
288 %v = load i32, ptr %p, !range !{i32 0, i32 10}
292 %phi = phi i32 [ %v, %if ], [ 0, %entry ]
296 ; !nonnull is safe to speculate, but !noundef is not, as the latter causes
297 ; immediate undefined behavior.
298 define ptr @speculate_nonnull(i1 %c, ptr dereferenceable(8) align 8 %p) {
299 ; CHECK-LABEL: @speculate_nonnull(
301 ; CHECK-NEXT: [[V:%.*]] = load ptr, ptr [[P:%.*]], align 8, !nonnull !4
302 ; CHECK-NEXT: [[SPEC_SELECT:%.*]] = select i1 [[C:%.*]], ptr [[V]], ptr null
303 ; CHECK-NEXT: ret ptr [[SPEC_SELECT]]
306 br i1 %c, label %if, label %join
309 %v = load ptr, ptr %p, !nonnull !{}, !noundef !{}
313 %phi = phi ptr [ %v, %if ], [ null, %entry ]
317 ; !align is safe to speculate, but !dereferenceable is not, as the latter causes
318 ; immediate undefined behavior.
319 define ptr @speculate_align(i1 %c, ptr dereferenceable(8) align 8 %p) {
320 ; CHECK-LABEL: @speculate_align(
322 ; CHECK-NEXT: [[V:%.*]] = load ptr, ptr [[P:%.*]], align 8, !align !9
323 ; CHECK-NEXT: [[SPEC_SELECT:%.*]] = select i1 [[C:%.*]], ptr [[V]], ptr null
324 ; CHECK-NEXT: ret ptr [[SPEC_SELECT]]
327 br i1 %c, label %if, label %join
330 %v = load ptr, ptr %p, !align !{i64 4}, !dereferenceable !{i64 4}
334 %phi = phi ptr [ %v, %if ], [ null, %entry ]
338 define void @hoist_fpmath(i1 %c, double %x) {
339 ; CHECK-LABEL: @hoist_fpmath(
341 ; CHECK-NEXT: [[T:%.*]] = fadd double [[X:%.*]], 1.000000e+00, !fpmath !10
342 ; CHECK-NEXT: ret void
345 br i1 %c, label %then, label %else
347 %t = fadd double %x, 1.0, !fpmath !{ float 2.5 }
350 %e = fadd double %x, 1.0, !fpmath !{ float 5.0 }
356 define void @hoist_fpmath_switch(i64 %i, double %x) {
357 ; CHECK-LABEL: @hoist_fpmath_switch(
358 ; CHECK-NEXT: switch i64 [[I:%.*]], label [[BB0:%.*]] [
359 ; CHECK-NEXT: i64 1, label [[BB1:%.*]]
360 ; CHECK-NEXT: i64 2, label [[BB2:%.*]]
363 ; CHECK-NEXT: [[T:%.*]] = fadd double [[X:%.*]], 1.000000e+00, !fpmath !10
364 ; CHECK-NEXT: br label [[OUT:%.*]]
366 ; CHECK-NEXT: [[E:%.*]] = fadd double [[X]], 1.000000e+00, !fpmath !11
367 ; CHECK-NEXT: br label [[OUT]]
369 ; CHECK-NEXT: [[F:%.*]] = fadd double [[X]], 1.000000e+00, !fpmath !12
370 ; CHECK-NEXT: br label [[OUT]]
372 ; CHECK-NEXT: ret void
374 switch i64 %i, label %bb0 [
379 %t = fadd double %x, 1.0, !fpmath !{ float 2.5 }
382 %e = fadd double %x, 1.0, !fpmath !{ float 5.0 }
385 %f = fadd double %x, 1.0, !fpmath !{ float 7.5 }
396 ; CHECK: [[RNG0]] = !{i8 0, i8 1, i8 3, i8 5}
397 ; CHECK: [[RNG1]] = !{i8 0, i8 1}
398 ; CHECK: [[RNG2]] = !{i8 3, i8 5}
399 ; CHECK: [[RNG3]] = !{i8 7, i8 9}
400 ; CHECK: [[META4:![0-9]+]] = !{}
401 ; CHECK: [[META5:![0-9]+]] = !{i64 10}
402 ; CHECK: [[META6:![0-9]+]] = !{i64 20}
403 ; CHECK: [[META7:![0-9]+]] = !{i64 30}
404 ; CHECK: [[RNG8]] = !{i32 0, i32 10}
405 ; CHECK: [[META9:![0-9]+]] = !{i64 4}
406 ; CHECK: [[META10:![0-9]+]] = !{float 2.500000e+00}
407 ; CHECK: [[META11:![0-9]+]] = !{float 5.000000e+00}
408 ; CHECK: [[META12:![0-9]+]] = !{float 7.500000e+00}