1 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2 ; RUN: opt < %s -data-layout="e-p:32:32:32-p1:16:16:16-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-n8:16:32" -passes=gvn,dce -enable-split-backedge-in-load-pre -S | FileCheck %s --check-prefixes=CHECK,LE
3 ; RUN: opt < %s -data-layout="E-p:32:32:32-p1:16:16:16-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:64:64-n32" -passes=gvn,dce -enable-split-backedge-in-load-pre -S | FileCheck %s --check-prefixes=CHECK,BE
6 define i32 @test0(i32 %V, ptr %P) {
8 ; CHECK-NEXT: store i32 [[V:%.*]], ptr [[P:%.*]], align 4
9 ; CHECK-NEXT: ret i32 [[V]]
18 ;;===----------------------------------------------------------------------===;;
20 ;;===----------------------------------------------------------------------===;;
23 define i8 @crash0({i32, i32} %A, ptr %P) {
24 ; CHECK-LABEL: @crash0(
25 ; CHECK-NEXT: store { i32, i32 } [[A:%.*]], ptr [[P:%.*]], align 4
26 ; CHECK-NEXT: [[Y:%.*]] = load i8, ptr [[P]], align 1
27 ; CHECK-NEXT: ret i8 [[Y]]
29 store {i32, i32} %A, ptr %P
34 ;; No PR filed, crashed in CaptureTracker.
35 declare void @helper()
36 define void @crash1() {
37 ; CHECK-LABEL: @crash1(
38 ; CHECK-NEXT: tail call void @llvm.memcpy.p0.p0.i64(ptr undef, ptr undef, i64 undef, i1 false) #[[ATTR3:[0-9]+]]
39 ; CHECK-NEXT: ret void
41 tail call void @llvm.memcpy.p0.p0.i64(ptr undef, ptr undef, i64 undef, i1 false) nounwind
42 %ttmp = load i8, ptr @helper
43 %x = icmp eq i8 %ttmp, 15
48 ;;===----------------------------------------------------------------------===;;
49 ;; Store -> Load and Load -> Load forwarding where src and dst are different
50 ;; types, but where the base pointer is a must alias.
51 ;;===----------------------------------------------------------------------===;;
53 ;; i32 -> f32 forwarding.
54 define float @coerce_mustalias1(i32 %V, ptr %P) {
55 ; CHECK-LABEL: @coerce_mustalias1(
56 ; CHECK-NEXT: store i32 [[V:%.*]], ptr [[P:%.*]], align 4
57 ; CHECK-NEXT: [[TMP1:%.*]] = bitcast i32 [[V]] to float
58 ; CHECK-NEXT: ret float [[TMP1]]
63 %A = load float, ptr %P
67 ;; ptr -> float forwarding.
68 define float @coerce_mustalias2(ptr %V, ptr %P) {
69 ; CHECK-LABEL: @coerce_mustalias2(
70 ; CHECK-NEXT: store ptr [[V:%.*]], ptr [[P:%.*]], align 4
71 ; CHECK-NEXT: [[TMP1:%.*]] = ptrtoint ptr [[V]] to i32
72 ; CHECK-NEXT: [[TMP2:%.*]] = bitcast i32 [[TMP1]] to float
73 ; CHECK-NEXT: ret float [[TMP2]]
78 %A = load float, ptr %P
82 ;; float -> ptr forwarding.
83 define ptr @coerce_mustalias3(float %V, ptr %P) {
84 ; CHECK-LABEL: @coerce_mustalias3(
85 ; CHECK-NEXT: store float [[V:%.*]], ptr [[P:%.*]], align 4
86 ; CHECK-NEXT: [[TMP1:%.*]] = bitcast float [[V]] to i32
87 ; CHECK-NEXT: [[TMP2:%.*]] = inttoptr i32 [[TMP1]] to ptr
88 ; CHECK-NEXT: ret ptr [[TMP2]]
90 store float %V, ptr %P
97 ;; i32 -> f32 load forwarding.
98 define float @coerce_mustalias4(ptr %P, i1 %cond) {
99 ; CHECK-LABEL: @coerce_mustalias4(
100 ; CHECK-NEXT: [[A:%.*]] = load i32, ptr [[P:%.*]], align 4
101 ; CHECK-NEXT: [[TMP1:%.*]] = bitcast i32 [[A]] to float
102 ; CHECK-NEXT: br i1 [[COND:%.*]], label [[T:%.*]], label [[F:%.*]]
104 ; CHECK-NEXT: ret float [[TMP1]]
106 ; CHECK-NEXT: ret float [[TMP1]]
108 %A = load i32, ptr %P
110 %B = load float, ptr %P
111 br i1 %cond, label %T, label %F
116 %X = bitcast i32 %A to float
121 ;; i32 -> i8 forwarding
122 define i8 @coerce_mustalias5(i32 %V, ptr %P) {
123 ; LE-LABEL: @coerce_mustalias5(
124 ; LE-NEXT: store i32 [[V:%.*]], ptr [[P:%.*]], align 4
125 ; LE-NEXT: [[TMP1:%.*]] = trunc i32 [[V]] to i8
126 ; LE-NEXT: ret i8 [[TMP1]]
128 ; BE-LABEL: @coerce_mustalias5(
129 ; BE-NEXT: store i32 [[V:%.*]], ptr [[P:%.*]], align 4
130 ; BE-NEXT: [[TMP1:%.*]] = lshr i32 [[V]], 24
131 ; BE-NEXT: [[TMP2:%.*]] = trunc i32 [[TMP1]] to i8
132 ; BE-NEXT: ret i8 [[TMP2]]
141 ;; i64 -> float forwarding
142 define float @coerce_mustalias6(i64 %V, ptr %P) {
143 ; LE-LABEL: @coerce_mustalias6(
144 ; LE-NEXT: store i64 [[V:%.*]], ptr [[P:%.*]], align 4
145 ; LE-NEXT: [[TMP1:%.*]] = trunc i64 [[V]] to i32
146 ; LE-NEXT: [[TMP2:%.*]] = bitcast i32 [[TMP1]] to float
147 ; LE-NEXT: ret float [[TMP2]]
149 ; BE-LABEL: @coerce_mustalias6(
150 ; BE-NEXT: store i64 [[V:%.*]], ptr [[P:%.*]], align 4
151 ; BE-NEXT: [[TMP1:%.*]] = lshr i64 [[V]], 32
152 ; BE-NEXT: [[TMP2:%.*]] = trunc i64 [[TMP1]] to i32
153 ; BE-NEXT: [[TMP3:%.*]] = bitcast i32 [[TMP2]] to float
154 ; BE-NEXT: ret float [[TMP3]]
159 %A = load float, ptr %P
163 ;; i64 -> ptr (32-bit) forwarding
164 define ptr @coerce_mustalias7(i64 %V, ptr %P) {
165 ; LE-LABEL: @coerce_mustalias7(
166 ; LE-NEXT: store i64 [[V:%.*]], ptr [[P:%.*]], align 4
167 ; LE-NEXT: [[TMP1:%.*]] = trunc i64 [[V]] to i32
168 ; LE-NEXT: [[TMP2:%.*]] = inttoptr i32 [[TMP1]] to ptr
169 ; LE-NEXT: ret ptr [[TMP2]]
171 ; BE-LABEL: @coerce_mustalias7(
172 ; BE-NEXT: store i64 [[V:%.*]], ptr [[P:%.*]], align 4
173 ; BE-NEXT: [[TMP1:%.*]] = lshr i64 [[V]], 32
174 ; BE-NEXT: [[TMP2:%.*]] = trunc i64 [[TMP1]] to i32
175 ; BE-NEXT: [[TMP3:%.*]] = inttoptr i32 [[TMP2]] to ptr
176 ; BE-NEXT: ret ptr [[TMP3]]
181 %A = load ptr, ptr %P
185 ; memset -> i16 forwarding.
186 define signext i16 @memset_to_i16_local(ptr %A) nounwind ssp {
187 ; CHECK-LABEL: @memset_to_i16_local(
189 ; CHECK-NEXT: tail call void @llvm.memset.p0.i64(ptr [[A:%.*]], i8 1, i64 200, i1 false)
190 ; CHECK-NEXT: ret i16 257
193 tail call void @llvm.memset.p0.i64(ptr %A, i8 1, i64 200, i1 false)
194 %arrayidx = getelementptr inbounds i16, ptr %A, i64 42
195 %ttmp2 = load i16, ptr %arrayidx
199 ; memset -> float forwarding.
200 define float @memset_to_float_local(ptr %A, i8 %Val) nounwind ssp {
201 ; CHECK-LABEL: @memset_to_float_local(
203 ; CHECK-NEXT: tail call void @llvm.memset.p0.i64(ptr [[A:%.*]], i8 [[VAL:%.*]], i64 400, i1 false)
204 ; CHECK-NEXT: [[TMP0:%.*]] = zext i8 [[VAL]] to i32
205 ; CHECK-NEXT: [[TMP1:%.*]] = shl i32 [[TMP0]], 8
206 ; CHECK-NEXT: [[TMP2:%.*]] = or i32 [[TMP0]], [[TMP1]]
207 ; CHECK-NEXT: [[TMP3:%.*]] = shl i32 [[TMP2]], 16
208 ; CHECK-NEXT: [[TMP4:%.*]] = or i32 [[TMP2]], [[TMP3]]
209 ; CHECK-NEXT: [[TMP5:%.*]] = bitcast i32 [[TMP4]] to float
210 ; CHECK-NEXT: ret float [[TMP5]]
213 tail call void @llvm.memset.p0.i64(ptr %A, i8 %Val, i64 400, i1 false)
214 %arrayidx = getelementptr inbounds float, ptr %A, i64 42 ; <ptr> [#uses=1]
215 %ttmp2 = load float, ptr %arrayidx ; <float> [#uses=1]
219 ;; non-local memset -> i16 load forwarding.
220 define i16 @memset_to_i16_nonlocal0(ptr %P, i1 %cond) {
221 ; CHECK-LABEL: @memset_to_i16_nonlocal0(
222 ; CHECK-NEXT: br i1 [[COND:%.*]], label [[T:%.*]], label [[F:%.*]]
224 ; CHECK-NEXT: tail call void @llvm.memset.p0.i64(ptr [[P:%.*]], i8 1, i64 400, i1 false)
225 ; CHECK-NEXT: br label [[CONT:%.*]]
227 ; CHECK-NEXT: tail call void @llvm.memset.p0.i64(ptr [[P]], i8 2, i64 400, i1 false)
228 ; CHECK-NEXT: br label [[CONT]]
230 ; CHECK-NEXT: [[A:%.*]] = phi i16 [ 514, [[F]] ], [ 257, [[T]] ]
231 ; CHECK-NEXT: ret i16 [[A]]
233 br i1 %cond, label %T, label %F
235 tail call void @llvm.memset.p0.i64(ptr %P, i8 1, i64 400, i1 false)
239 tail call void @llvm.memset.p0.i64(ptr %P, i8 2, i64 400, i1 false)
243 %P2 = getelementptr i16, ptr %P, i32 4
244 %A = load i16, ptr %P2
249 @GCst = constant {i32, float, i32 } { i32 42, float 14., i32 97 }
250 @GCst_as1 = addrspace(1) constant {i32, float, i32 } { i32 42, float 14., i32 97 }
252 ; memset -> float forwarding.
253 define float @memcpy_to_float_local(ptr %A) nounwind ssp {
254 ; CHECK-LABEL: @memcpy_to_float_local(
256 ; CHECK-NEXT: tail call void @llvm.memcpy.p0.p0.i64(ptr [[A:%.*]], ptr @GCst, i64 12, i1 false)
257 ; CHECK-NEXT: ret float 1.400000e+01
260 tail call void @llvm.memcpy.p0.p0.i64(ptr %A, ptr @GCst, i64 12, i1 false)
261 %arrayidx = getelementptr inbounds float, ptr %A, i64 1 ; <ptr> [#uses=1]
262 %ttmp2 = load float, ptr %arrayidx ; <float> [#uses=1]
266 ; memcpy from address space 1
267 define float @memcpy_to_float_local_as1(ptr %A) nounwind ssp {
268 ; CHECK-LABEL: @memcpy_to_float_local_as1(
270 ; CHECK-NEXT: tail call void @llvm.memcpy.p0.p1.i64(ptr [[A:%.*]], ptr addrspace(1) @GCst_as1, i64 12, i1 false)
271 ; CHECK-NEXT: ret float 1.400000e+01
274 tail call void @llvm.memcpy.p0.p1.i64(ptr %A, ptr addrspace(1) @GCst_as1, i64 12, i1 false)
275 %arrayidx = getelementptr inbounds float, ptr %A, i64 1 ; <ptr> [#uses=1]
276 %ttmp2 = load float, ptr %arrayidx ; <float> [#uses=1]
280 ;; non-local i32/float -> i8 load forwarding.
281 define i8 @coerce_mustalias_nonlocal0(ptr %P, i1 %cond) {
282 ; LE-LABEL: @coerce_mustalias_nonlocal0(
283 ; LE-NEXT: br i1 [[COND:%.*]], label [[T:%.*]], label [[F:%.*]]
285 ; LE-NEXT: store i32 42, ptr [[P:%.*]], align 4
286 ; LE-NEXT: br label [[CONT:%.*]]
288 ; LE-NEXT: store float 1.000000e+00, ptr [[P]], align 4
289 ; LE-NEXT: br label [[CONT]]
291 ; LE-NEXT: [[A:%.*]] = phi i8 [ 0, [[F]] ], [ 42, [[T]] ]
292 ; LE-NEXT: ret i8 [[A]]
294 ; BE-LABEL: @coerce_mustalias_nonlocal0(
295 ; BE-NEXT: br i1 [[COND:%.*]], label [[T:%.*]], label [[F:%.*]]
297 ; BE-NEXT: store i32 42, ptr [[P:%.*]], align 4
298 ; BE-NEXT: br label [[CONT:%.*]]
300 ; BE-NEXT: store float 1.000000e+00, ptr [[P]], align 4
301 ; BE-NEXT: br label [[CONT]]
303 ; BE-NEXT: [[A:%.*]] = phi i8 [ 63, [[F]] ], [ 0, [[T]] ]
304 ; BE-NEXT: ret i8 [[A]]
306 br i1 %cond, label %T, label %F
312 store float 1.0, ptr %P
322 ;; non-local i32/float -> i8 load forwarding. This also tests that the "P3"
323 ;; bitcast equivalence can be properly phi translated.
324 define i8 @coerce_mustalias_nonlocal1(ptr %P, i1 %cond) {
325 ; LE-LABEL: @coerce_mustalias_nonlocal1(
326 ; LE-NEXT: br i1 [[COND:%.*]], label [[T:%.*]], label [[F:%.*]]
328 ; LE-NEXT: store i32 42, ptr [[P:%.*]], align 4
329 ; LE-NEXT: br label [[CONT:%.*]]
331 ; LE-NEXT: store float 1.000000e+00, ptr [[P]], align 4
332 ; LE-NEXT: br label [[CONT]]
334 ; LE-NEXT: [[A:%.*]] = phi i8 [ 0, [[F]] ], [ 42, [[T]] ]
335 ; LE-NEXT: ret i8 [[A]]
337 ; BE-LABEL: @coerce_mustalias_nonlocal1(
338 ; BE-NEXT: br i1 [[COND:%.*]], label [[T:%.*]], label [[F:%.*]]
340 ; BE-NEXT: store i32 42, ptr [[P:%.*]], align 4
341 ; BE-NEXT: br label [[CONT:%.*]]
343 ; BE-NEXT: store float 1.000000e+00, ptr [[P]], align 4
344 ; BE-NEXT: br label [[CONT]]
346 ; BE-NEXT: [[A:%.*]] = phi i8 [ 63, [[F]] ], [ 0, [[T]] ]
347 ; BE-NEXT: ret i8 [[A]]
349 br i1 %cond, label %T, label %F
355 store float 1.0, ptr %P
365 ;; non-local i32 -> i8 partial redundancy load forwarding.
366 define i8 @coerce_mustalias_pre0(ptr %P, i1 %cond) {
367 ; LE-LABEL: @coerce_mustalias_pre0(
368 ; LE-NEXT: br i1 [[COND:%.*]], label [[T:%.*]], label [[F:%.*]]
370 ; LE-NEXT: store i32 42, ptr [[P:%.*]], align 4
371 ; LE-NEXT: br label [[CONT:%.*]]
373 ; LE-NEXT: [[A_PRE:%.*]] = load i8, ptr [[P]], align 1
374 ; LE-NEXT: br label [[CONT]]
376 ; LE-NEXT: [[A:%.*]] = phi i8 [ [[A_PRE]], [[F]] ], [ 42, [[T]] ]
377 ; LE-NEXT: ret i8 [[A]]
379 ; BE-LABEL: @coerce_mustalias_pre0(
380 ; BE-NEXT: br i1 [[COND:%.*]], label [[T:%.*]], label [[F:%.*]]
382 ; BE-NEXT: store i32 42, ptr [[P:%.*]], align 4
383 ; BE-NEXT: br label [[CONT:%.*]]
385 ; BE-NEXT: [[A_PRE:%.*]] = load i8, ptr [[P]], align 1
386 ; BE-NEXT: br label [[CONT]]
388 ; BE-NEXT: [[A:%.*]] = phi i8 [ [[A_PRE]], [[F]] ], [ 0, [[T]] ]
389 ; BE-NEXT: ret i8 [[A]]
391 br i1 %cond, label %T, label %F
405 ;;===----------------------------------------------------------------------===;;
406 ;; Store -> Load and Load -> Load forwarding where src and dst are different
407 ;; types, and the reload is an offset from the store pointer.
408 ;;===----------------------------------------------------------------------===;;
410 ;; i32 -> i8 forwarding.
412 define i8 @coerce_offset0(i32 %V, ptr %P) {
413 ; LE-LABEL: @coerce_offset0(
414 ; LE-NEXT: store i32 [[V:%.*]], ptr [[P:%.*]], align 4
415 ; LE-NEXT: [[TMP1:%.*]] = lshr i32 [[V]], 16
416 ; LE-NEXT: [[TMP2:%.*]] = trunc i32 [[TMP1]] to i8
417 ; LE-NEXT: ret i8 [[TMP2]]
419 ; BE-LABEL: @coerce_offset0(
420 ; BE-NEXT: store i32 [[V:%.*]], ptr [[P:%.*]], align 4
421 ; BE-NEXT: [[TMP1:%.*]] = lshr i32 [[V]], 8
422 ; BE-NEXT: [[TMP2:%.*]] = trunc i32 [[TMP1]] to i8
423 ; BE-NEXT: ret i8 [[TMP2]]
427 %P3 = getelementptr i8, ptr %P, i32 2
429 %A = load i8, ptr %P3
433 ;; non-local i32/float -> i8 load forwarding.
434 define i8 @coerce_offset_nonlocal0(ptr %P, i1 %cond) {
435 ; LE-LABEL: @coerce_offset_nonlocal0(
436 ; LE-NEXT: br i1 [[COND:%.*]], label [[T:%.*]], label [[F:%.*]]
438 ; LE-NEXT: store i32 57005, ptr [[P:%.*]], align 4
439 ; LE-NEXT: br label [[CONT:%.*]]
441 ; LE-NEXT: store float 1.000000e+00, ptr [[P]], align 4
442 ; LE-NEXT: br label [[CONT]]
444 ; LE-NEXT: [[A:%.*]] = phi i8 [ -128, [[F]] ], [ 0, [[T]] ]
445 ; LE-NEXT: ret i8 [[A]]
447 ; BE-LABEL: @coerce_offset_nonlocal0(
448 ; BE-NEXT: br i1 [[COND:%.*]], label [[T:%.*]], label [[F:%.*]]
450 ; BE-NEXT: store i32 57005, ptr [[P:%.*]], align 4
451 ; BE-NEXT: br label [[CONT:%.*]]
453 ; BE-NEXT: store float 1.000000e+00, ptr [[P]], align 4
454 ; BE-NEXT: br label [[CONT]]
456 ; BE-NEXT: [[A:%.*]] = phi i8 [ 0, [[F]] ], [ -34, [[T]] ]
457 ; BE-NEXT: ret i8 [[A]]
459 %P4 = getelementptr i8, ptr %P, i32 2
460 br i1 %cond, label %T, label %F
462 store i32 57005, ptr %P
466 store float 1.0, ptr %P
470 %A = load i8, ptr %P4
476 ;; non-local i32 -> i8 partial redundancy load forwarding.
477 define i8 @coerce_offset_pre0(ptr %P, i1 %cond) {
478 ; CHECK-LABEL: @coerce_offset_pre0(
479 ; CHECK-NEXT: [[P4:%.*]] = getelementptr i8, ptr [[P:%.*]], i32 2
480 ; CHECK-NEXT: br i1 [[COND:%.*]], label [[T:%.*]], label [[F:%.*]]
482 ; CHECK-NEXT: store i32 42, ptr [[P]], align 4
483 ; CHECK-NEXT: br label [[CONT:%.*]]
485 ; CHECK-NEXT: [[A_PRE:%.*]] = load i8, ptr [[P4]], align 1
486 ; CHECK-NEXT: br label [[CONT]]
488 ; CHECK-NEXT: [[A:%.*]] = phi i8 [ [[A_PRE]], [[F]] ], [ 0, [[T]] ]
489 ; CHECK-NEXT: ret i8 [[A]]
491 %P4 = getelementptr i8, ptr %P, i32 2
492 br i1 %cond, label %T, label %F
501 %A = load i8, ptr %P4
506 define i32 @chained_load(ptr %p, i32 %x, i32 %y) {
507 ; CHECK-LABEL: @chained_load(
508 ; CHECK-NEXT: block1:
509 ; CHECK-NEXT: [[A:%.*]] = alloca ptr, align 4
510 ; CHECK-NEXT: [[Z:%.*]] = load ptr, ptr [[P:%.*]], align 4
511 ; CHECK-NEXT: store ptr [[Z]], ptr [[A]], align 4
512 ; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[X:%.*]], [[Y:%.*]]
513 ; CHECK-NEXT: br i1 [[CMP]], label [[BLOCK2:%.*]], label [[BLOCK3:%.*]]
515 ; CHECK-NEXT: br label [[BLOCK4:%.*]]
517 ; CHECK-NEXT: br label [[BLOCK4]]
519 ; CHECK-NEXT: [[D:%.*]] = load i32, ptr [[Z]], align 4
520 ; CHECK-NEXT: ret i32 [[D]]
525 %z = load ptr, ptr %p
527 %cmp = icmp eq i32 %x, %y
528 br i1 %cmp, label %block2, label %block3
531 %a = load ptr, ptr %p
535 %b = load ptr, ptr %p
539 %c = load ptr, ptr %p
540 %d = load i32, ptr %c
546 declare i1 @cond() readonly
547 declare i1 @cond2() readonly
549 define i32 @phi_trans2() {
550 ; CHECK-LABEL: @phi_trans2(
552 ; CHECK-NEXT: [[P:%.*]] = alloca i32, i32 400, align 4
553 ; CHECK-NEXT: br label [[F1:%.*]]
555 ; CHECK-NEXT: [[A:%.*]] = phi i32 [ 1, [[ENTRY:%.*]] ], [ 2, [[F:%.*]] ]
556 ; CHECK-NEXT: [[COND2:%.*]] = call i1 @cond()
557 ; CHECK-NEXT: br i1 [[COND2]], label [[T1:%.*]], label [[TY:%.*]]
559 ; CHECK-NEXT: [[P2:%.*]] = getelementptr i32, ptr [[P]], i32 [[A]]
560 ; CHECK-NEXT: [[X:%.*]] = load i32, ptr [[P2]], align 4
561 ; CHECK-NEXT: [[COND:%.*]] = call i1 @cond2()
562 ; CHECK-NEXT: br i1 [[COND]], label [[TX:%.*]], label [[F]]
564 ; CHECK-NEXT: [[P3:%.*]] = getelementptr i32, ptr [[P]], i32 2
565 ; CHECK-NEXT: store i32 17, ptr [[P3]], align 4
566 ; CHECK-NEXT: store i32 42, ptr [[P2]], align 4
567 ; CHECK-NEXT: br label [[F1]]
569 ; CHECK-NEXT: ret i32 [[X]]
571 ; CHECK-NEXT: ret i32 0
574 %P = alloca i32, i32 400
578 %A = phi i32 [1, %entry], [2, %F]
579 %cond2 = call i1 @cond()
580 br i1 %cond2, label %T1, label %TY
583 %P2 = getelementptr i32, ptr %P, i32 %A
584 %x = load i32, ptr %P2
585 %cond = call i1 @cond2()
586 br i1 %cond, label %TX, label %F
589 %P3 = getelementptr i32, ptr %P, i32 2
590 store i32 17, ptr %P3
592 store i32 42, ptr %P2 ; Provides "P[A]".
596 ; This load should not be compiled to 'ret i32 42'. An overly clever
597 ; implementation of GVN would see that we're returning 17 if the loop
598 ; executes once or 42 if it executes more than that, but we'd have to do
599 ; loop restructuring to expose this, and GVN shouldn't do this sort of CFG
607 define i32 @phi_trans3(ptr %p, i32 %x, i32 %y, i32 %z) {
608 ; CHECK-LABEL: @phi_trans3(
609 ; CHECK-NEXT: block1:
610 ; CHECK-NEXT: [[CMPXY:%.*]] = icmp eq i32 [[X:%.*]], [[Y:%.*]]
611 ; CHECK-NEXT: br i1 [[CMPXY]], label [[BLOCK2:%.*]], label [[BLOCK3:%.*]]
613 ; CHECK-NEXT: store i32 87, ptr [[P:%.*]], align 4
614 ; CHECK-NEXT: br label [[BLOCK4:%.*]]
616 ; CHECK-NEXT: [[P2:%.*]] = getelementptr i32, ptr [[P]], i32 43
617 ; CHECK-NEXT: store i32 97, ptr [[P2]], align 4
618 ; CHECK-NEXT: br label [[BLOCK4]]
620 ; CHECK-NEXT: [[D:%.*]] = phi i32 [ 87, [[BLOCK2]] ], [ 97, [[BLOCK3]] ]
621 ; CHECK-NEXT: br i1 [[CMPXY]], label [[BLOCK5:%.*]], label [[EXIT:%.*]]
623 ; CHECK-NEXT: br i1 true, label [[BLOCK6:%.*]], label [[BLOCK5_EXIT_CRIT_EDGE:%.*]]
624 ; CHECK: block5.exit_crit_edge:
625 ; CHECK-NEXT: br label [[EXIT]]
627 ; CHECK-NEXT: br i1 true, label [[BLOCK7:%.*]], label [[BLOCK6_EXIT_CRIT_EDGE:%.*]]
628 ; CHECK: block6.exit_crit_edge:
629 ; CHECK-NEXT: br label [[EXIT]]
631 ; CHECK-NEXT: ret i32 [[D]]
633 ; CHECK-NEXT: ret i32 -1
636 %cmpxy = icmp eq i32 %x, %y
637 br i1 %cmpxy, label %block2, label %block3
644 %p2 = getelementptr i32, ptr %p, i32 43
645 store i32 97, ptr %p2
649 %A = phi i32 [-1, %block2], [42, %block3]
650 br i1 %cmpxy, label %block5, label %exit
655 br i1 %cmpxy, label %block6, label %exit
658 %C = getelementptr i32, ptr %p, i32 %B
659 br i1 %cmpxy, label %block7, label %exit
662 %D = load i32, ptr %C
670 define i8 @phi_trans4(ptr %p) {
671 ; CHECK-LABEL: @phi_trans4(
673 ; CHECK-NEXT: [[X3:%.*]] = getelementptr i8, ptr [[P:%.*]], i32 192
674 ; CHECK-NEXT: store i8 -64, ptr [[X3]], align 1
675 ; CHECK-NEXT: [[X:%.*]] = getelementptr i8, ptr [[P]], i32 4
676 ; CHECK-NEXT: [[Y:%.*]] = load i8, ptr [[X]], align 1
677 ; CHECK-NEXT: br label [[LOOP:%.*]]
679 ; CHECK-NEXT: [[Y2:%.*]] = phi i8 [ [[Y]], [[ENTRY:%.*]] ], [ 0, [[LOOP]] ]
680 ; CHECK-NEXT: [[COND:%.*]] = call i1 @cond2()
681 ; CHECK-NEXT: store i32 0, ptr [[X3]], align 4
682 ; CHECK-NEXT: br i1 [[COND]], label [[LOOP]], label [[OUT:%.*]]
684 ; CHECK-NEXT: [[R:%.*]] = add i8 [[Y]], [[Y2]]
685 ; CHECK-NEXT: ret i8 [[R]]
688 %X3 = getelementptr i8, ptr %p, i32 192
689 store i8 192, ptr %X3
691 %X = getelementptr i8, ptr %p, i32 4
696 %i = phi i32 [4, %entry], [192, %loop]
697 %X2 = getelementptr i8, ptr %p, i32 %i
698 %Y2 = load i8, ptr %X2
701 %cond = call i1 @cond2()
704 br i1 %cond, label %loop, label %out
711 define i8 @phi_trans5(ptr %p) {
712 ; CHECK-LABEL: @phi_trans5(
714 ; CHECK-NEXT: [[X4:%.*]] = getelementptr i8, ptr [[P:%.*]], i32 2
715 ; CHECK-NEXT: store i8 19, ptr [[X4]], align 1
716 ; CHECK-NEXT: [[X:%.*]] = getelementptr i8, ptr [[P]], i32 4
717 ; CHECK-NEXT: [[Y:%.*]] = load i8, ptr [[X]], align 1
718 ; CHECK-NEXT: br label [[LOOP:%.*]]
720 ; CHECK-NEXT: [[Y2:%.*]] = phi i8 [ [[Y]], [[ENTRY:%.*]] ], [ [[Y2_PRE:%.*]], [[CONT:%.*]] ]
721 ; CHECK-NEXT: [[I:%.*]] = phi i32 [ 4, [[ENTRY]] ], [ 3, [[CONT]] ]
722 ; CHECK-NEXT: [[X2:%.*]] = getelementptr i8, ptr [[P]], i32 [[I]]
723 ; CHECK-NEXT: [[COND:%.*]] = call i1 @cond2()
724 ; CHECK-NEXT: br i1 [[COND]], label [[CONT]], label [[OUT:%.*]]
726 ; CHECK-NEXT: [[Z:%.*]] = getelementptr i8, ptr [[X2]], i32 -1
727 ; CHECK-NEXT: store i32 50462976, ptr [[Z]], align 4
728 ; CHECK-NEXT: [[X2_PHI_TRANS_INSERT:%.*]] = getelementptr i8, ptr [[P]], i32 3
729 ; CHECK-NEXT: [[Y2_PRE]] = load i8, ptr [[X2_PHI_TRANS_INSERT]], align 1
730 ; CHECK-NEXT: br label [[LOOP]]
732 ; CHECK-NEXT: [[R:%.*]] = add i8 [[Y]], [[Y2]]
733 ; CHECK-NEXT: ret i8 [[R]]
737 %X4 = getelementptr i8, ptr %p, i32 2
740 %X = getelementptr i8, ptr %p, i32 4
745 %i = phi i32 [4, %entry], [3, %cont]
746 %X2 = getelementptr i8, ptr %p, i32 %i
747 %Y2 = load i8, ptr %X2 ; Ensure this load is not being incorrectly replaced.
748 %cond = call i1 @cond2()
749 br i1 %cond, label %cont, label %out
752 %Z = getelementptr i8, ptr %X2, i32 -1
753 store i32 50462976, ptr %Z ;; (1 << 8) | (2 << 16) | (3 << 24)
763 declare void @use_i32(i32) readonly
765 ; indirectbr currently prevents MergeBlockIntoPredecessor from merging latch
766 ; into header. Make sure we translate the address for %l1 correctly where
767 ; parts of the address computations are in different basic blocks.
768 define i32 @phi_trans6(ptr noalias nocapture readonly %x, i1 %cond) {
769 ; CHECK-LABEL: @phi_trans6(
771 ; CHECK-NEXT: [[L0:%.*]] = load i32, ptr [[X:%.*]], align 4
772 ; CHECK-NEXT: call void @use_i32(i32 [[L0]])
773 ; CHECK-NEXT: br label [[HEADER:%.*]]
775 ; CHECK-NEXT: [[L1:%.*]] = phi i32 [ [[L0]], [[ENTRY:%.*]] ], [ [[L1_PRE:%.*]], [[LATCH_HEADER_CRIT_EDGE:%.*]] ]
776 ; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY]] ], [ [[IV_NEXT:%.*]], [[LATCH_HEADER_CRIT_EDGE]] ]
777 ; CHECK-NEXT: indirectbr ptr blockaddress(@phi_trans6, [[LATCH:%.*]]), [label %latch]
779 ; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1
780 ; CHECK-NEXT: br i1 [[COND:%.*]], label [[EXIT:%.*]], label [[LATCH_HEADER_CRIT_EDGE]]
781 ; CHECK: latch.header_crit_edge:
782 ; CHECK-NEXT: [[GEP_1_PHI_TRANS_INSERT_PHI_TRANS_INSERT:%.*]] = getelementptr i32, ptr [[X]], i32 [[IV_NEXT]]
783 ; CHECK-NEXT: [[L1_PRE]] = load i32, ptr [[GEP_1_PHI_TRANS_INSERT_PHI_TRANS_INSERT]], align 4
784 ; CHECK-NEXT: br label [[HEADER]]
786 ; CHECK-NEXT: ret i32 [[L1]]
789 %l0 = load i32, ptr %x
790 call void @use_i32(i32 %l0)
794 %iv = phi i32 [0, %entry], [ %iv.next, %latch]
795 indirectbr ptr blockaddress(@phi_trans6, %latch), [label %latch]
798 %gep.1 = getelementptr i32, ptr %x, i32 %iv
799 %l1 = load i32, ptr %gep.1
800 %iv.next = add i32 %iv, 1
801 br i1 %cond, label %exit, label %header
807 ; FIXME: Currently we fail to translate the PHI in this case.
808 define i32 @phi_trans7(ptr noalias nocapture readonly %x, i1 %cond) {
809 ; CHECK-LABEL: @phi_trans7(
811 ; CHECK-NEXT: [[L0:%.*]] = load i32, ptr [[X:%.*]], align 4
812 ; CHECK-NEXT: call void @use_i32(i32 [[L0]])
813 ; CHECK-NEXT: br label [[HEADER:%.*]]
815 ; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 2, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LATCH_HEADER_CRIT_EDGE:%.*]] ]
816 ; CHECK-NEXT: [[OFFSET:%.*]] = add i32 [[IV]], -2
817 ; CHECK-NEXT: indirectbr ptr blockaddress(@phi_trans7, [[LATCH:%.*]]), [label %latch]
819 ; CHECK-NEXT: [[GEP_1:%.*]] = getelementptr i32, ptr [[X]], i32 [[OFFSET]]
820 ; CHECK-NEXT: [[L1:%.*]] = load i32, ptr [[GEP_1]], align 4
821 ; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1
822 ; CHECK-NEXT: br i1 [[COND:%.*]], label [[EXIT:%.*]], label [[LATCH_HEADER_CRIT_EDGE]]
823 ; CHECK: latch.header_crit_edge:
824 ; CHECK-NEXT: br label [[HEADER]]
826 ; CHECK-NEXT: ret i32 [[L1]]
829 %l0 = load i32, ptr %x
830 call void @use_i32(i32 %l0)
834 %iv = phi i32 [2, %entry], [ %iv.next, %latch]
835 %offset = add i32 %iv, -2
836 indirectbr ptr blockaddress(@phi_trans7, %latch), [label %latch]
839 %gep.1 = getelementptr i32, ptr %x, i32 %offset
840 %l1 = load i32, ptr %gep.1
841 %iv.next = add i32 %iv, 1
842 br i1 %cond, label %exit, label %header
848 ; FIXME: Currently we fail to translate the PHI in this case.
849 define i32 @phi_trans8(ptr noalias nocapture readonly %x, i1 %cond) {
850 ; CHECK-LABEL: @phi_trans8(
852 ; CHECK-NEXT: [[L0:%.*]] = load i32, ptr [[X:%.*]], align 4
853 ; CHECK-NEXT: call void @use_i32(i32 [[L0]])
854 ; CHECK-NEXT: br label [[HEADER:%.*]]
856 ; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 2, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LATCH_HEADER_CRIT_EDGE:%.*]] ]
857 ; CHECK-NEXT: indirectbr ptr blockaddress(@phi_trans8, [[LATCH:%.*]]), [label %latch]
859 ; CHECK-NEXT: [[OFFSET:%.*]] = add i32 [[IV]], -2
860 ; CHECK-NEXT: [[GEP_1:%.*]] = getelementptr i32, ptr [[X]], i32 [[OFFSET]]
861 ; CHECK-NEXT: [[L1:%.*]] = load i32, ptr [[GEP_1]], align 4
862 ; CHECK-NEXT: [[IV_NEXT]] = add i32 [[IV]], 1
863 ; CHECK-NEXT: br i1 [[COND:%.*]], label [[EXIT:%.*]], label [[LATCH_HEADER_CRIT_EDGE]]
864 ; CHECK: latch.header_crit_edge:
865 ; CHECK-NEXT: br label [[HEADER]]
867 ; CHECK-NEXT: ret i32 [[L1]]
870 %l0 = load i32, ptr %x
871 call void @use_i32(i32 %l0)
875 %iv = phi i32 [2, %entry], [ %iv.next, %latch]
876 indirectbr ptr blockaddress(@phi_trans8, %latch), [label %latch]
879 %offset = add i32 %iv, -2
880 %gep.1 = getelementptr i32, ptr %x, i32 %offset
881 %l1 = load i32, ptr %gep.1
882 %iv.next = add i32 %iv, 1
883 br i1 %cond, label %exit, label %header
892 define i32 @memset_to_load() nounwind readnone {
893 ; CHECK-LABEL: @memset_to_load(
895 ; CHECK-NEXT: [[X:%.*]] = alloca [256 x i32], align 4
896 ; CHECK-NEXT: call void @llvm.memset.p0.i64(ptr align 4 [[X]], i8 0, i64 1024, i1 false)
897 ; CHECK-NEXT: ret i32 0
900 %x = alloca [256 x i32], align 4 ; <ptr> [#uses=2]
901 call void @llvm.memset.p0.i64(ptr align 4 %x, i8 0, i64 1024, i1 false)
902 %arraydecay = getelementptr inbounds [256 x i32], ptr %x, i32 0, i32 0 ; <ptr>
903 %ttmp1 = load i32, ptr %arraydecay ; <i32> [#uses=1]
908 ;;===----------------------------------------------------------------------===;;
909 ;; Load -> Load forwarding in partial alias case.
910 ;;===----------------------------------------------------------------------===;;
912 define i32 @load_load_partial_alias(ptr %P) nounwind ssp {
913 ; LE-LABEL: @load_load_partial_alias(
915 ; LE-NEXT: [[TTMP2:%.*]] = load i32, ptr [[P:%.*]], align 4
916 ; LE-NEXT: [[TMP0:%.*]] = lshr i32 [[TTMP2]], 8
917 ; LE-NEXT: [[TMP1:%.*]] = trunc i32 [[TMP0]] to i8
918 ; LE-NEXT: [[CONV:%.*]] = zext i8 [[TMP1]] to i32
919 ; LE-NEXT: [[ADD:%.*]] = add nsw i32 [[TTMP2]], [[CONV]]
920 ; LE-NEXT: ret i32 [[ADD]]
922 ; BE-LABEL: @load_load_partial_alias(
924 ; BE-NEXT: [[TTMP2:%.*]] = load i32, ptr [[P:%.*]], align 4
925 ; BE-NEXT: [[TMP0:%.*]] = lshr i32 [[TTMP2]], 16
926 ; BE-NEXT: [[TMP1:%.*]] = trunc i32 [[TMP0]] to i8
927 ; BE-NEXT: [[CONV:%.*]] = zext i8 [[TMP1]] to i32
928 ; BE-NEXT: [[ADD:%.*]] = add nsw i32 [[TTMP2]], [[CONV]]
929 ; BE-NEXT: ret i32 [[ADD]]
932 %ttmp2 = load i32, ptr %P
933 %add.ptr = getelementptr inbounds i8, ptr %P, i64 1
934 %ttmp5 = load i8, ptr %add.ptr
935 %conv = zext i8 %ttmp5 to i32
936 %add = add nsw i32 %ttmp2, %conv
941 ; Cross block partial alias case.
942 define i32 @load_load_partial_alias_cross_block(ptr %P) nounwind ssp {
943 ; LE-LABEL: @load_load_partial_alias_cross_block(
945 ; LE-NEXT: [[X1:%.*]] = load i32, ptr [[P:%.*]], align 4
946 ; LE-NEXT: [[CMP:%.*]] = icmp eq i32 [[X1]], 127
947 ; LE-NEXT: [[TMP0:%.*]] = lshr i32 [[X1]], 8
948 ; LE-NEXT: [[TMP1:%.*]] = trunc i32 [[TMP0]] to i8
949 ; LE-NEXT: br i1 [[CMP]], label [[LAND_LHS_TRUE:%.*]], label [[IF_END:%.*]]
951 ; LE-NEXT: [[CONV6:%.*]] = zext i8 [[TMP1]] to i32
952 ; LE-NEXT: ret i32 [[CONV6]]
954 ; LE-NEXT: ret i32 52
956 ; BE-LABEL: @load_load_partial_alias_cross_block(
958 ; BE-NEXT: [[X1:%.*]] = load i32, ptr [[P:%.*]], align 4
959 ; BE-NEXT: [[CMP:%.*]] = icmp eq i32 [[X1]], 127
960 ; BE-NEXT: [[TMP0:%.*]] = lshr i32 [[X1]], 16
961 ; BE-NEXT: [[TMP1:%.*]] = trunc i32 [[TMP0]] to i8
962 ; BE-NEXT: br i1 [[CMP]], label [[LAND_LHS_TRUE:%.*]], label [[IF_END:%.*]]
964 ; BE-NEXT: [[CONV6:%.*]] = zext i8 [[TMP1]] to i32
965 ; BE-NEXT: ret i32 [[CONV6]]
967 ; BE-NEXT: ret i32 52
970 %x1 = load i32, ptr %P, align 4
971 %cmp = icmp eq i32 %x1, 127
972 br i1 %cmp, label %land.lhs.true, label %if.end
974 land.lhs.true: ; preds = %entry
975 %arrayidx4 = getelementptr inbounds i8, ptr %P, i64 1
976 %ttmp5 = load i8, ptr %arrayidx4, align 1
977 %conv6 = zext i8 %ttmp5 to i32
984 define i32 @load_load_partial_alias_cross_block_phi_trans(ptr %P) nounwind {
985 ; LE-LABEL: @load_load_partial_alias_cross_block_phi_trans(
987 ; LE-NEXT: [[X1:%.*]] = load i32, ptr [[P:%.*]], align 4
988 ; LE-NEXT: [[CMP:%.*]] = icmp eq i32 [[X1]], 127
989 ; LE-NEXT: [[TMP0:%.*]] = lshr i32 [[X1]], 16
990 ; LE-NEXT: [[TMP1:%.*]] = trunc i32 [[TMP0]] to i8
991 ; LE-NEXT: [[TMP2:%.*]] = lshr i32 [[X1]], 8
992 ; LE-NEXT: [[TMP3:%.*]] = trunc i32 [[TMP2]] to i8
993 ; LE-NEXT: br i1 [[CMP]], label [[IF:%.*]], label [[ELSE:%.*]]
995 ; LE-NEXT: br label [[JOIN:%.*]]
997 ; LE-NEXT: br label [[JOIN]]
999 ; LE-NEXT: [[TTMP5:%.*]] = phi i8 [ [[TMP3]], [[IF]] ], [ [[TMP1]], [[ELSE]] ]
1000 ; LE-NEXT: [[CONV6:%.*]] = zext i8 [[TTMP5]] to i32
1001 ; LE-NEXT: ret i32 [[CONV6]]
1003 ; LE-NEXT: ret i32 52
1005 ; BE-LABEL: @load_load_partial_alias_cross_block_phi_trans(
1007 ; BE-NEXT: [[X1:%.*]] = load i32, ptr [[P:%.*]], align 4
1008 ; BE-NEXT: [[CMP:%.*]] = icmp eq i32 [[X1]], 127
1009 ; BE-NEXT: [[TMP0:%.*]] = lshr i32 [[X1]], 8
1010 ; BE-NEXT: [[TMP1:%.*]] = trunc i32 [[TMP0]] to i8
1011 ; BE-NEXT: [[TMP2:%.*]] = lshr i32 [[X1]], 16
1012 ; BE-NEXT: [[TMP3:%.*]] = trunc i32 [[TMP2]] to i8
1013 ; BE-NEXT: br i1 [[CMP]], label [[IF:%.*]], label [[ELSE:%.*]]
1015 ; BE-NEXT: br label [[JOIN:%.*]]
1017 ; BE-NEXT: br label [[JOIN]]
1019 ; BE-NEXT: [[TTMP5:%.*]] = phi i8 [ [[TMP3]], [[IF]] ], [ [[TMP1]], [[ELSE]] ]
1020 ; BE-NEXT: [[CONV6:%.*]] = zext i8 [[TTMP5]] to i32
1021 ; BE-NEXT: ret i32 [[CONV6]]
1023 ; BE-NEXT: ret i32 52
1026 %x1 = load i32, ptr %P, align 4
1027 %cmp = icmp eq i32 %x1, 127
1028 br i1 %cmp, label %if, label %else
1031 %arrayidx.if = getelementptr inbounds i8, ptr %P, i64 1
1035 %arrayidx.else = getelementptr inbounds i8, ptr %P, i64 2
1039 %idx = phi i64 [ 1, %if ], [ 2, %else ]
1040 %arrayidx4 = getelementptr inbounds i8, ptr %P, i64 %idx
1041 %ttmp5 = load i8, ptr %arrayidx4, align 1
1042 %conv6 = zext i8 %ttmp5 to i32
1049 define void @load_load_partial_alias_loop(ptr %P) {
1050 ; LE-LABEL: @load_load_partial_alias_loop(
1052 ; LE-NEXT: [[P_1:%.*]] = getelementptr i8, ptr [[P:%.*]], i64 1
1053 ; LE-NEXT: [[V_1:%.*]] = load i8, ptr [[P_1]], align 1
1054 ; LE-NEXT: call void @use.i8(i8 [[V_1]])
1055 ; LE-NEXT: [[V_1_32:%.*]] = load i32, ptr [[P_1]], align 4
1056 ; LE-NEXT: call void @use.i32(i32 [[V_1_32]])
1057 ; LE-NEXT: [[TMP0:%.*]] = trunc i32 [[V_1_32]] to i8
1058 ; LE-NEXT: br label [[LOOP:%.*]]
1060 ; LE-NEXT: [[V_I:%.*]] = phi i8 [ [[TMP0]], [[ENTRY:%.*]] ], [ [[V_I_PRE:%.*]], [[LOOP_LOOP_CRIT_EDGE:%.*]] ]
1061 ; LE-NEXT: [[I:%.*]] = phi i64 [ 1, [[ENTRY]] ], [ [[I_INC:%.*]], [[LOOP_LOOP_CRIT_EDGE]] ]
1062 ; LE-NEXT: [[P_I:%.*]] = getelementptr i8, ptr [[P]], i64 [[I]]
1063 ; LE-NEXT: call void @use.i8(i8 [[V_I]])
1064 ; LE-NEXT: [[V_I_32:%.*]] = load i32, ptr [[P_I]], align 4
1065 ; LE-NEXT: call void @use.i32(i32 [[V_I_32]])
1066 ; LE-NEXT: [[I_INC]] = add i64 [[I]], 1
1067 ; LE-NEXT: [[CMP:%.*]] = icmp ne i64 [[I_INC]], 64
1068 ; LE-NEXT: br i1 [[CMP]], label [[LOOP_LOOP_CRIT_EDGE]], label [[EXIT:%.*]]
1069 ; LE: loop.loop_crit_edge:
1070 ; LE-NEXT: [[P_I_PHI_TRANS_INSERT:%.*]] = getelementptr i8, ptr [[P]], i64 [[I_INC]]
1071 ; LE-NEXT: [[V_I_PRE]] = load i8, ptr [[P_I_PHI_TRANS_INSERT]], align 1
1072 ; LE-NEXT: br label [[LOOP]]
1076 ; BE-LABEL: @load_load_partial_alias_loop(
1078 ; BE-NEXT: [[P_1:%.*]] = getelementptr i8, ptr [[P:%.*]], i64 1
1079 ; BE-NEXT: [[V_1:%.*]] = load i8, ptr [[P_1]], align 1
1080 ; BE-NEXT: call void @use.i8(i8 [[V_1]])
1081 ; BE-NEXT: [[V_1_32:%.*]] = load i32, ptr [[P_1]], align 4
1082 ; BE-NEXT: call void @use.i32(i32 [[V_1_32]])
1083 ; BE-NEXT: [[TMP0:%.*]] = lshr i32 [[V_1_32]], 24
1084 ; BE-NEXT: [[TMP1:%.*]] = trunc i32 [[TMP0]] to i8
1085 ; BE-NEXT: br label [[LOOP:%.*]]
1087 ; BE-NEXT: [[V_I:%.*]] = phi i8 [ [[TMP1]], [[ENTRY:%.*]] ], [ [[V_I_PRE:%.*]], [[LOOP_LOOP_CRIT_EDGE:%.*]] ]
1088 ; BE-NEXT: [[I:%.*]] = phi i64 [ 1, [[ENTRY]] ], [ [[I_INC:%.*]], [[LOOP_LOOP_CRIT_EDGE]] ]
1089 ; BE-NEXT: [[P_I:%.*]] = getelementptr i8, ptr [[P]], i64 [[I]]
1090 ; BE-NEXT: call void @use.i8(i8 [[V_I]])
1091 ; BE-NEXT: [[V_I_32:%.*]] = load i32, ptr [[P_I]], align 4
1092 ; BE-NEXT: call void @use.i32(i32 [[V_I_32]])
1093 ; BE-NEXT: [[I_INC]] = add i64 [[I]], 1
1094 ; BE-NEXT: [[CMP:%.*]] = icmp ne i64 [[I_INC]], 64
1095 ; BE-NEXT: br i1 [[CMP]], label [[LOOP_LOOP_CRIT_EDGE]], label [[EXIT:%.*]]
1096 ; BE: loop.loop_crit_edge:
1097 ; BE-NEXT: [[P_I_PHI_TRANS_INSERT:%.*]] = getelementptr i8, ptr [[P]], i64 [[I_INC]]
1098 ; BE-NEXT: [[V_I_PRE]] = load i8, ptr [[P_I_PHI_TRANS_INSERT]], align 1
1099 ; BE-NEXT: br label [[LOOP]]
1104 %P.1 = getelementptr i8, ptr %P, i64 1
1105 %v.1 = load i8, ptr %P.1
1106 call void @use.i8(i8 %v.1)
1107 %v.1.32 = load i32, ptr %P.1
1108 call void @use.i32(i32 %v.1.32)
1112 %i = phi i64 [ 1, %entry ], [ %i.inc, %loop ]
1113 %P.i = getelementptr i8, ptr %P, i64 %i
1114 %v.i = load i8, ptr %P.i
1115 call void @use.i8(i8 %v.i)
1116 %v.i.32 = load i32, ptr %P.i
1117 call void @use.i32(i32 %v.i.32)
1118 %i.inc = add i64 %i, 1
1119 %cmp = icmp ne i64 %i.inc, 64
1120 br i1 %cmp, label %loop, label %exit
1126 declare void @use.i8(i8) readnone
1127 declare void @use.i32(i32) readnone
1129 @global = external local_unnamed_addr global i8, align 4
1131 define void @load_load_partial_alias_atomic(ptr %arg) {
1132 ; LE-LABEL: @load_load_partial_alias_atomic(
1134 ; LE-NEXT: [[TMP2_1:%.*]] = getelementptr inbounds i8, ptr [[ARG:%.*]], i64 1
1135 ; LE-NEXT: [[TMP2_3:%.*]] = load i64, ptr [[TMP2_1]], align 4
1136 ; LE-NEXT: [[TMP3_1:%.*]] = getelementptr inbounds i8, ptr [[ARG]], i64 2
1137 ; LE-NEXT: [[TMP0:%.*]] = lshr i64 [[TMP2_3]], 8
1138 ; LE-NEXT: [[TMP1:%.*]] = trunc i64 [[TMP0]] to i8
1139 ; LE-NEXT: br label [[BB5:%.*]]
1141 ; LE-NEXT: [[TMP4_1:%.*]] = phi i8 [ [[TMP4_1_PRE:%.*]], [[BB5]] ], [ [[TMP1]], [[BB:%.*]] ]
1142 ; LE-NEXT: [[TMP6_1:%.*]] = load atomic i8, ptr @global acquire, align 4
1143 ; LE-NEXT: [[TMP7_1:%.*]] = add i8 [[TMP6_1]], [[TMP4_1]]
1144 ; LE-NEXT: store i8 [[TMP7_1]], ptr [[ARG]], align 1
1145 ; LE-NEXT: [[TMP4_1_PRE]] = load i8, ptr [[TMP3_1]], align 4
1146 ; LE-NEXT: br label [[BB5]]
1148 ; BE-LABEL: @load_load_partial_alias_atomic(
1150 ; BE-NEXT: [[TMP2_1:%.*]] = getelementptr inbounds i8, ptr [[ARG:%.*]], i64 1
1151 ; BE-NEXT: [[TMP2_3:%.*]] = load i64, ptr [[TMP2_1]], align 4
1152 ; BE-NEXT: [[TMP3_1:%.*]] = getelementptr inbounds i8, ptr [[ARG]], i64 2
1153 ; BE-NEXT: [[TMP0:%.*]] = lshr i64 [[TMP2_3]], 48
1154 ; BE-NEXT: [[TMP1:%.*]] = trunc i64 [[TMP0]] to i8
1155 ; BE-NEXT: br label [[BB5:%.*]]
1157 ; BE-NEXT: [[TMP4_1:%.*]] = phi i8 [ [[TMP4_1_PRE:%.*]], [[BB5]] ], [ [[TMP1]], [[BB:%.*]] ]
1158 ; BE-NEXT: [[TMP6_1:%.*]] = load atomic i8, ptr @global acquire, align 4
1159 ; BE-NEXT: [[TMP7_1:%.*]] = add i8 [[TMP6_1]], [[TMP4_1]]
1160 ; BE-NEXT: store i8 [[TMP7_1]], ptr [[ARG]], align 1
1161 ; BE-NEXT: [[TMP4_1_PRE]] = load i8, ptr [[TMP3_1]], align 4
1162 ; BE-NEXT: br label [[BB5]]
1165 %tmp2.1 = getelementptr inbounds i8, ptr %arg, i64 1
1166 %tmp2.3 = load i64, ptr %tmp2.1, align 4
1167 %tmp2.4 = icmp ugt i64 %tmp2.3, 1
1169 %tmp3.1 = getelementptr inbounds i8, ptr %arg, i64 2
1172 bb5: ; preds = %bb14, %bb
1173 %tmp4.1 = load i8, ptr %tmp3.1, align 4
1174 %tmp6.1 = load atomic i8, ptr @global acquire, align 4
1175 %tmp7.1 = add i8 %tmp6.1, %tmp4.1
1176 store i8 %tmp7.1, ptr %arg
1181 ;;===----------------------------------------------------------------------===;;
1183 ;; We explicitly choose NOT to widen. And are testing to make sure we don't.
1184 ;;===----------------------------------------------------------------------===;;
1186 %widening1 = type { i32, i8, i8, i8, i8 }
1188 @f = global %widening1 zeroinitializer, align 4
1190 define i32 @test_widening1(ptr %P) nounwind ssp noredzone {
1191 ; CHECK-LABEL: @test_widening1(
1192 ; CHECK-NEXT: entry:
1193 ; CHECK-NEXT: [[TTMP:%.*]] = load i8, ptr getelementptr inbounds ([[WIDENING1:%.*]], ptr @f, i64 0, i32 1), align 4
1194 ; CHECK-NEXT: [[CONV:%.*]] = zext i8 [[TTMP]] to i32
1195 ; CHECK-NEXT: [[TTMP1:%.*]] = load i8, ptr getelementptr inbounds ([[WIDENING1]], ptr @f, i64 0, i32 2), align 1
1196 ; CHECK-NEXT: [[CONV2:%.*]] = zext i8 [[TTMP1]] to i32
1197 ; CHECK-NEXT: [[ADD:%.*]] = add nsw i32 [[CONV]], [[CONV2]]
1198 ; CHECK-NEXT: ret i32 [[ADD]]
1201 %ttmp = load i8, ptr getelementptr inbounds (%widening1, ptr @f, i64 0, i32 1), align 4
1202 %conv = zext i8 %ttmp to i32
1203 %ttmp1 = load i8, ptr getelementptr inbounds (%widening1, ptr @f, i64 0, i32 2), align 1
1204 %conv2 = zext i8 %ttmp1 to i32
1205 %add = add nsw i32 %conv, %conv2
1209 define i32 @test_widening2() nounwind ssp noredzone {
1210 ; CHECK-LABEL: @test_widening2(
1211 ; CHECK-NEXT: entry:
1212 ; CHECK-NEXT: [[TTMP:%.*]] = load i8, ptr getelementptr inbounds ([[WIDENING1:%.*]], ptr @f, i64 0, i32 1), align 4
1213 ; CHECK-NEXT: [[CONV:%.*]] = zext i8 [[TTMP]] to i32
1214 ; CHECK-NEXT: [[TTMP1:%.*]] = load i8, ptr getelementptr inbounds ([[WIDENING1]], ptr @f, i64 0, i32 2), align 1
1215 ; CHECK-NEXT: [[CONV2:%.*]] = zext i8 [[TTMP1]] to i32
1216 ; CHECK-NEXT: [[ADD:%.*]] = add nsw i32 [[CONV]], [[CONV2]]
1217 ; CHECK-NEXT: [[TTMP2:%.*]] = load i8, ptr getelementptr inbounds ([[WIDENING1]], ptr @f, i64 0, i32 3), align 2
1218 ; CHECK-NEXT: [[CONV3:%.*]] = zext i8 [[TTMP2]] to i32
1219 ; CHECK-NEXT: [[ADD2:%.*]] = add nsw i32 [[ADD]], [[CONV3]]
1220 ; CHECK-NEXT: [[TTMP3:%.*]] = load i8, ptr getelementptr inbounds ([[WIDENING1]], ptr @f, i64 0, i32 4), align 1
1221 ; CHECK-NEXT: [[CONV4:%.*]] = zext i8 [[TTMP3]] to i32
1222 ; CHECK-NEXT: [[ADD3:%.*]] = add nsw i32 [[ADD2]], [[CONV4]]
1223 ; CHECK-NEXT: ret i32 [[ADD3]]
1226 %ttmp = load i8, ptr getelementptr inbounds (%widening1, ptr @f, i64 0, i32 1), align 4
1227 %conv = zext i8 %ttmp to i32
1228 %ttmp1 = load i8, ptr getelementptr inbounds (%widening1, ptr @f, i64 0, i32 2), align 1
1229 %conv2 = zext i8 %ttmp1 to i32
1230 %add = add nsw i32 %conv, %conv2
1232 %ttmp2 = load i8, ptr getelementptr inbounds (%widening1, ptr @f, i64 0, i32 3), align 2
1233 %conv3 = zext i8 %ttmp2 to i32
1234 %add2 = add nsw i32 %add, %conv3
1236 %ttmp3 = load i8, ptr getelementptr inbounds (%widening1, ptr @f, i64 0, i32 4), align 1
1237 %conv4 = zext i8 %ttmp3 to i32
1238 %add3 = add nsw i32 %add2, %conv4
1244 declare void @llvm.memset.p0.i64(ptr nocapture, i8, i64, i1) nounwind
1246 declare void @llvm.memcpy.p0.p0.i64(ptr nocapture, ptr nocapture, i64, i1) nounwind
1247 declare void @llvm.memcpy.p0.p1.i64(ptr nocapture, ptr addrspace(1) nocapture, i64, i1) nounwind
1250 ;;===----------------------------------------------------------------------===;;
1251 ;; Load -> Store dependency which isn't interfered with by a call that happens
1252 ;; before the pointer was captured.
1253 ;;===----------------------------------------------------------------------===;;
1255 %class.X = type { [8 x i8] }
1257 @_ZTV1X = weak_odr constant [5 x ptr] zeroinitializer
1258 @_ZTV1Y = weak_odr constant [5 x ptr] zeroinitializer
1261 declare void @use3(ptr, ptr)
1264 define void @test_escape1() nounwind {
1265 ; CHECK-LABEL: @test_escape1(
1266 ; CHECK-NEXT: [[X:%.*]] = alloca ptr, align 8
1267 ; CHECK-NEXT: store ptr getelementptr inbounds ([5 x ptr], ptr @_ZTV1X, i64 0, i64 2), ptr [[X]], align 8
1268 ; CHECK-NEXT: call void @use() #[[ATTR3]]
1269 ; CHECK-NEXT: call void @use3(ptr [[X]], ptr getelementptr inbounds ([5 x ptr], ptr @_ZTV1X, i64 0, i64 2)) #[[ATTR3]]
1270 ; CHECK-NEXT: ret void
1272 %x = alloca ptr, align 8
1273 store ptr getelementptr inbounds ([5 x ptr], ptr @_ZTV1X, i64 0, i64 2), ptr %x, align 8
1274 call void @use() nounwind
1275 %DEAD = load ptr, ptr %x, align 8
1276 call void @use3(ptr %x, ptr %DEAD) nounwind