Nikita Popov 4ab87ffd1e
[SCCP] Enable PredicateInfo for non-interprocedural SCCP (#153003)
SCCP can use PredicateInfo to constrain ranges based on assume and
branch conditions. Currently, this is only enabled during IPSCCP.

This enables it for SCCP as well, which runs after functions have
already been simplified, while IPSCCP runs pre-inline. To a large
degree, CVP already handles range-based optimizations, but SCCP is more
reliable for the cases it can handle. In particular, SCCP works reliably
inside loops, which is something that CVP struggles with due to LVI
cycles.

I have made various optimizations to make PredicateInfo more efficient,
but unfortunately this still has significant compile-time cost (around
0.1-0.2%).
2025-08-19 10:59:38 +02:00

660 lines
22 KiB
LLVM

; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt %s -passes=sccp -S | FileCheck --check-prefixes=CHECK,SCCP %s
; RUN: opt %s -passes=ipsccp -S | FileCheck --check-prefixes=CHECK,IPSCCP %s
; Test different widening scenarios.
declare void @use(i1)
declare i1 @cond()
define void @test_2_incoming_constants(i32 %x) {
; CHECK-LABEL: @test_2_incoming_constants(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[C_1:%.*]] = call i1 @cond()
; CHECK-NEXT: br i1 [[C_1]], label [[BB1:%.*]], label [[EXIT:%.*]]
; CHECK: bb1:
; CHECK-NEXT: br label [[EXIT]]
; CHECK: exit:
; CHECK-NEXT: [[P:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ 1, [[BB1]] ]
; CHECK-NEXT: [[A:%.*]] = add nuw nsw i32 [[P]], 1
; CHECK-NEXT: call void @use(i1 true)
; CHECK-NEXT: call void @use(i1 false)
; CHECK-NEXT: ret void
;
entry:
%c.1 = call i1 @cond()
br i1 %c.1, label %bb1, label %exit
bb1:
br label %exit
exit:
%p = phi i32 [0, %entry], [1, %bb1]
%a = add i32 %p, 1
%t.1 = icmp ult i32 %a, 20
call void @use(i1 %t.1)
%f.1 = icmp ugt i32 %a, 10
call void @use(i1 %f.1)
ret void
}
define void @test_3_incoming_constants(i32 %x) {
; CHECK-LABEL: @test_3_incoming_constants(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[C_1:%.*]] = call i1 @cond()
; CHECK-NEXT: br i1 [[C_1]], label [[BB1:%.*]], label [[EXIT:%.*]]
; CHECK: bb1:
; CHECK-NEXT: [[C_2:%.*]] = call i1 @cond()
; CHECK-NEXT: br i1 [[C_2]], label [[BB2:%.*]], label [[EXIT]]
; CHECK: bb2:
; CHECK-NEXT: br label [[EXIT]]
; CHECK: exit:
; CHECK-NEXT: [[P:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ 1, [[BB1]] ], [ 2, [[BB2]] ]
; CHECK-NEXT: [[A:%.*]] = add nuw nsw i32 [[P]], 1
; CHECK-NEXT: call void @use(i1 true)
; CHECK-NEXT: call void @use(i1 false)
; CHECK-NEXT: ret void
;
entry:
%c.1 = call i1 @cond()
br i1 %c.1, label %bb1, label %exit
bb1:
%c.2 = call i1 @cond()
br i1 %c.2, label %bb2, label %exit
bb2:
br label %exit
exit:
%p = phi i32 [0, %entry], [1, %bb1], [2, %bb2]
%a = add i32 %p, 1
%t.1 = icmp ult i32 %a, 20
call void @use(i1 %t.1)
%f.1 = icmp ugt i32 %a, 10
call void @use(i1 %f.1)
ret void
}
define void @test_5_incoming_constants(i32 %x) {
; CHECK-LABEL: @test_5_incoming_constants(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[C_1:%.*]] = call i1 @cond()
; CHECK-NEXT: br i1 [[C_1]], label [[BB1:%.*]], label [[EXIT:%.*]]
; CHECK: bb1:
; CHECK-NEXT: [[C_2:%.*]] = call i1 @cond()
; CHECK-NEXT: br i1 [[C_2]], label [[BB2:%.*]], label [[EXIT]]
; CHECK: bb2:
; CHECK-NEXT: [[C_3:%.*]] = call i1 @cond()
; CHECK-NEXT: br i1 [[C_3]], label [[BB3:%.*]], label [[EXIT]]
; CHECK: bb3:
; CHECK-NEXT: [[C_4:%.*]] = call i1 @cond()
; CHECK-NEXT: br i1 [[C_4]], label [[BB4:%.*]], label [[EXIT]]
; CHECK: bb4:
; CHECK-NEXT: br label [[EXIT]]
; CHECK: exit:
; CHECK-NEXT: [[P:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ 1, [[BB1]] ], [ 2, [[BB2]] ], [ 3, [[BB3]] ], [ 4, [[BB4]] ]
; CHECK-NEXT: [[A:%.*]] = add nuw nsw i32 [[P]], 1
; CHECK-NEXT: call void @use(i1 true)
; CHECK-NEXT: call void @use(i1 false)
; CHECK-NEXT: ret void
;
entry:
%c.1 = call i1 @cond()
br i1 %c.1, label %bb1, label %exit
bb1:
%c.2 = call i1 @cond()
br i1 %c.2, label %bb2, label %exit
bb2:
%c.3 = call i1 @cond()
br i1 %c.3, label %bb3, label %exit
bb3:
%c.4 = call i1 @cond()
br i1 %c.4, label %bb4, label %exit
bb4:
br label %exit
exit:
%p = phi i32 [0, %entry], [1, %bb1], [2, %bb2], [3, %bb3], [4, %bb4]
%a = add i32 %p, 1
%t.1 = icmp ult i32 %a, 20
call void @use(i1 %t.1)
%f.1 = icmp ugt i32 %a, 10
call void @use(i1 %f.1)
ret void
}
; For the rotated_loop_* test cases %p and %a are extended on each iteration.
define void @rotated_loop_2(i32 %x) {
; CHECK-LABEL: @rotated_loop_2(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[C_1:%.*]] = call i1 @cond()
; CHECK-NEXT: br i1 [[C_1]], label [[EXIT:%.*]], label [[BB1:%.*]]
; CHECK: bb1:
; CHECK-NEXT: [[C_2:%.*]] = call i1 @cond()
; CHECK-NEXT: br i1 [[C_2]], label [[EXIT]], label [[BB2:%.*]]
; CHECK: bb2:
; CHECK-NEXT: [[C_3:%.*]] = call i1 @cond()
; CHECK-NEXT: br i1 [[C_3]], label [[BB3:%.*]], label [[EXIT]]
; CHECK: bb3:
; CHECK-NEXT: br label [[EXIT]]
; CHECK: exit:
; CHECK-NEXT: [[P:%.*]] = phi i32 [ 1, [[ENTRY:%.*]] ], [ 3, [[BB1]] ], [ 2, [[BB2]] ], [ 5, [[BB3]] ]
; CHECK-NEXT: [[A:%.*]] = add nuw nsw i32 [[P]], 1
; CHECK-NEXT: call void @use(i1 true)
; CHECK-NEXT: call void @use(i1 false)
; CHECK-NEXT: br label [[EXIT_1:%.*]]
; CHECK: exit.1:
; CHECK-NEXT: ret void
;
entry:
%c.1 = call i1 @cond()
br i1 %c.1, label %exit, label %bb1
bb1:
%c.2 = call i1 @cond()
br i1 %c.2, label %exit, label %bb2
bb2:
%c.3 = call i1 @cond()
br i1 %c.3, label %bb3, label %exit
bb3:
br label %exit
exit:
%p = phi i32 [1, %entry], [3, %bb1], [2, %bb2], [5, %bb3], [%a, %exit]
%a = add i32 %p, 1
%t.1 = icmp ult i32 %a, 20
call void @use(i1 %t.1)
%f.1 = icmp ugt i32 %a, 10
call void @use(i1 %f.1)
%c.4 = icmp ult i32 %a, 2
br i1 %c.4, label %exit, label %exit.1
exit.1:
ret void
}
define void @rotated_loop_3(i32 %x) {
; CHECK-LABEL: @rotated_loop_3(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[C_1:%.*]] = call i1 @cond()
; CHECK-NEXT: br i1 [[C_1]], label [[EXIT:%.*]], label [[BB1:%.*]]
; CHECK: bb1:
; CHECK-NEXT: [[C_2:%.*]] = call i1 @cond()
; CHECK-NEXT: br i1 [[C_2]], label [[EXIT]], label [[BB2:%.*]]
; CHECK: bb2:
; CHECK-NEXT: [[C_3:%.*]] = call i1 @cond()
; CHECK-NEXT: br i1 [[C_3]], label [[BB3:%.*]], label [[EXIT]]
; CHECK: bb3:
; CHECK-NEXT: br label [[EXIT]]
; CHECK: exit:
; CHECK-NEXT: [[P:%.*]] = phi i32 [ 1, [[ENTRY:%.*]] ], [ 3, [[BB1]] ], [ 2, [[BB2]] ], [ 5, [[BB3]] ], [ [[A:%.*]], [[EXIT]] ]
; CHECK-NEXT: [[A]] = add i32 [[P]], 1
; CHECK-NEXT: [[T_1:%.*]] = icmp ult i32 [[A]], 20
; CHECK-NEXT: call void @use(i1 [[T_1]])
; CHECK-NEXT: [[F_1:%.*]] = icmp ugt i32 [[A]], 10
; CHECK-NEXT: call void @use(i1 [[F_1]])
; CHECK-NEXT: [[C_4:%.*]] = icmp ult i32 [[A]], 3
; CHECK-NEXT: br i1 [[C_4]], label [[EXIT]], label [[EXIT_1:%.*]]
; CHECK: exit.1:
; CHECK-NEXT: ret void
;
entry:
%c.1 = call i1 @cond()
br i1 %c.1, label %exit, label %bb1
bb1:
%c.2 = call i1 @cond()
br i1 %c.2, label %exit, label %bb2
bb2:
%c.3 = call i1 @cond()
br i1 %c.3, label %bb3, label %exit
bb3:
br label %exit
exit:
%p = phi i32 [1, %entry], [3, %bb1], [2, %bb2], [5, %bb3], [%a, %exit]
%a = add i32 %p, 1
%t.1 = icmp ult i32 %a, 20
call void @use(i1 %t.1)
%f.1 = icmp ugt i32 %a, 10
call void @use(i1 %f.1)
%c.4 = icmp ult i32 %a, 3
br i1 %c.4, label %exit, label %exit.1
exit.1:
ret void
}
; For the loop_with_header_* tests, %iv and %a change on each iteration, but we
; can use the range imposed by the condition %c.1 when widening.
define void @loop_with_header_1(i32 %x) {
; CHECK-LABEL: @loop_with_header_1(
; CHECK-NEXT: entry:
; CHECK-NEXT: br label [[LOOP_HEADER:%.*]]
; CHECK: loop.header:
; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP_BODY:%.*]] ]
; CHECK-NEXT: [[C_1:%.*]] = icmp slt i32 [[IV]], 2
; CHECK-NEXT: br i1 [[C_1]], label [[LOOP_BODY]], label [[EXIT:%.*]]
; CHECK: loop.body:
; CHECK-NEXT: call void @use(i1 true)
; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i32 [[IV]], 1
; CHECK-NEXT: br label [[LOOP_HEADER]]
; CHECK: exit:
; CHECK-NEXT: ret void
;
entry:
br label %loop.header
loop.header:
%iv = phi i32 [0, %entry], [%iv.next, %loop.body]
%c.1 = icmp slt i32 %iv, 2
br i1 %c.1, label %loop.body, label %exit
loop.body:
%t.1 = icmp slt i32 %iv, 2
call void @use(i1 %t.1)
%iv.next = add nsw i32 %iv, 1
br label %loop.header
exit:
ret void
}
define void @loop_with_header_2(i32 %x) {
; CHECK-LABEL: @loop_with_header_2(
; CHECK-NEXT: entry:
; CHECK-NEXT: br label [[LOOP_HEADER:%.*]]
; CHECK: loop.header:
; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP_BODY:%.*]] ]
; CHECK-NEXT: [[C_1:%.*]] = icmp slt i32 [[IV]], 200
; CHECK-NEXT: br i1 [[C_1]], label [[LOOP_BODY]], label [[EXIT:%.*]]
; CHECK: loop.body:
; CHECK-NEXT: call void @use(i1 true)
; CHECK-NEXT: [[IV_NEXT]] = add nsw i32 [[IV]], 1
; CHECK-NEXT: br label [[LOOP_HEADER]]
; CHECK: exit:
; CHECK-NEXT: ret void
;
entry:
br label %loop.header
loop.header:
%iv = phi i32 [0, %entry], [%iv.next, %loop.body]
%c.1 = icmp slt i32 %iv, 200
br i1 %c.1, label %loop.body, label %exit
loop.body:
%t.1 = icmp slt i32 %iv, 200
call void @use(i1 %t.1)
%iv.next = add nsw i32 %iv, 1
br label %loop.header
exit:
ret void
}
; In the function below, the condition %c.1 results in a range [7, 6), which
; can be used as a widening bound. It does not fully contain the range we get
; from combining it with the information from %tmp12.
define void @foo(ptr %arg, i8 %x) {
; CHECK-LABEL: @foo(
; CHECK-NEXT: bb:
; CHECK-NEXT: [[TMP:%.*]] = zext i8 [[X:%.*]] to i32
; CHECK-NEXT: [[TMP2:%.*]] = load i64, ptr [[ARG:%.*]], align 8
; CHECK-NEXT: switch i32 [[TMP]], label [[BB20:%.*]] [
; CHECK-NEXT: i32 1, label [[BB3:%.*]]
; CHECK-NEXT: i32 2, label [[BB4:%.*]]
; CHECK-NEXT: i32 4, label [[BB19:%.*]]
; CHECK-NEXT: ]
; CHECK: bb3:
; CHECK-NEXT: unreachable
; CHECK: bb4:
; CHECK-NEXT: [[TMP5:%.*]] = add i64 [[TMP2]], 3
; CHECK-NEXT: [[TMP6:%.*]] = and i64 [[TMP5]], 3
; CHECK-NEXT: [[TMP7:%.*]] = sub nuw nsw i64 3, [[TMP6]]
; CHECK-NEXT: [[TMP8:%.*]] = shl nuw nsw i64 [[TMP7]], 1
; CHECK-NEXT: [[TMP9:%.*]] = trunc nuw nsw i64 [[TMP8]] to i32
; CHECK-NEXT: [[TMP10:%.*]] = zext nneg i32 [[TMP9]] to i64
; CHECK-NEXT: br label [[BB11:%.*]]
; CHECK: bb11:
; CHECK-NEXT: [[TMP12:%.*]] = phi i64 [ [[TMP10]], [[BB4]] ], [ [[TMP17:%.*]], [[BB18:%.*]] ]
; CHECK-NEXT: br label [[BB13:%.*]]
; CHECK: bb13:
; CHECK-NEXT: [[C_1:%.*]] = icmp eq i64 [[TMP12]], 6
; CHECK-NEXT: br i1 [[C_1]], label [[BB15:%.*]], label [[BB16:%.*]]
; CHECK: bb15:
; CHECK-NEXT: unreachable
; CHECK: bb16:
; CHECK-NEXT: [[TMP17]] = add i64 [[TMP12]], 2
; CHECK-NEXT: br label [[BB18]]
; CHECK: bb18:
; CHECK-NEXT: br label [[BB11]]
; CHECK: bb19:
; CHECK-NEXT: unreachable
; CHECK: bb20:
; CHECK-NEXT: ret void
;
bb:
%tmp = zext i8 %x to i32
%tmp2 = load i64, ptr %arg, align 8
switch i32 %tmp, label %bb20 [
i32 1, label %bb3
i32 2, label %bb4
i32 4, label %bb19
]
bb3: ; preds = %bb
unreachable
bb4: ; preds = %bb
%tmp5 = add i64 %tmp2, 3
%tmp6 = and i64 %tmp5, 3
%tmp7 = sub i64 3, %tmp6
%tmp8 = shl i64 %tmp7, 1
%tmp9 = trunc i64 %tmp8 to i32
%tmp10 = sext i32 %tmp9 to i64
br label %bb11
bb11: ; preds = %bb18, %bb4
%tmp12 = phi i64 [ %tmp10, %bb4 ], [ %tmp17, %bb18 ]
br label %bb13
bb13: ; preds = %bb11
%c.1 = icmp eq i64 %tmp12, 6
br i1 %c.1, label %bb15, label %bb16
bb15: ; preds = %bb13
unreachable
bb16: ; preds = %bb13
%tmp17 = add i64 %tmp12, 2
br label %bb18
bb18: ; preds = %bb16
br label %bb11
bb19: ; preds = %bb
unreachable
bb20: ; preds = %bb
ret void
}
; The functions below check that widening with an upper bound does correctly
; return whether the range changed. Make sure we do not eliminate %c.2.
%struct.baz.1 = type { i32, i32, ptr, ptr }
%struct.blam.2 = type <{ %struct.baz.1, i32, [4 x i8] }>
@global.11 = linkonce_odr global [4 x i8] zeroinitializer, align 1
declare void @llvm.memcpy.p0.p0.i64(ptr noalias nocapture writeonly, ptr noalias nocapture readonly, i64, i1 immarg) #1
define linkonce_odr dereferenceable(1) ptr @spam(ptr %arg, i32 %arg1) align 2 {
; CHECK-LABEL: @spam(
; CHECK-NEXT: bb:
; CHECK-NEXT: [[TMP:%.*]] = getelementptr inbounds nuw [[STRUCT_BAZ_1:%.*]], ptr [[ARG:%.*]], i32 0, i32 3
; CHECK-NEXT: [[TMP2:%.*]] = load ptr, ptr [[TMP]], align 8
; CHECK-NEXT: [[TMP3:%.*]] = sext i32 [[ARG1:%.*]] to i64
; CHECK-NEXT: [[TMP4:%.*]] = getelementptr inbounds i8, ptr [[TMP2]], i64 [[TMP3]]
; CHECK-NEXT: ret ptr [[TMP4]]
;
bb:
%tmp = getelementptr inbounds %struct.baz.1, ptr %arg, i32 0, i32 3
%tmp2 = load ptr, ptr %tmp, align 8
%tmp3 = sext i32 %arg1 to i64
%tmp4 = getelementptr inbounds i8, ptr %tmp2, i64 %tmp3
ret ptr %tmp4
}
define ptr @wobble(ptr %arg, i32 %arg1) align 2 {
; CHECK-LABEL: @wobble(
; CHECK-NEXT: bb:
; CHECK-NEXT: [[TMP:%.*]] = lshr i32 [[ARG1:%.*]], 16
; CHECK-NEXT: [[TMP2:%.*]] = xor i32 [[TMP]], [[ARG1]]
; CHECK-NEXT: [[TMP3:%.*]] = and i32 [[TMP2]], 65535
; CHECK-NEXT: [[TMP4:%.*]] = mul i32 [[ARG1]], 8
; CHECK-NEXT: [[TMP5:%.*]] = getelementptr inbounds nuw [[STRUCT_BLAM_2:%.*]], ptr [[ARG:%.*]], i32 0, i32 1
; CHECK-NEXT: [[TMP6:%.*]] = load i32, ptr [[TMP5]], align 8
; CHECK-NEXT: [[TMP7:%.*]] = and i32 [[TMP4]], [[TMP6]]
; CHECK-NEXT: br label [[BB8:%.*]]
; CHECK: bb8:
; CHECK-NEXT: [[TMP9:%.*]] = phi ptr [ undef, [[BB:%.*]] ], [ [[TMP17:%.*]], [[BB29:%.*]] ]
; CHECK-NEXT: [[TMP10:%.*]] = phi ptr [ undef, [[BB]] ], [ [[TMP17]], [[BB29]] ]
; CHECK-NEXT: [[TMP11:%.*]] = phi i32 [ 0, [[BB]] ], [ [[TMP30:%.*]], [[BB29]] ]
; CHECK-NEXT: [[C_1:%.*]] = icmp slt i32 [[TMP11]], 8
; CHECK-NEXT: br i1 [[C_1]], label [[BB13:%.*]], label [[BB31:%.*]]
; CHECK: bb13:
; CHECK-NEXT: [[TMP15:%.*]] = add i32 [[TMP7]], [[TMP11]]
; CHECK-NEXT: [[TMP16:%.*]] = mul i32 [[TMP15]], 4
; CHECK-NEXT: [[TMP17]] = call dereferenceable(1) ptr @spam(ptr [[ARG]], i32 [[TMP16]])
; CHECK-NEXT: [[TMP19:%.*]] = getelementptr inbounds nuw i8, ptr [[TMP17]], i64 2
; CHECK-NEXT: [[TMP20:%.*]] = load i8, ptr [[TMP19]], align 1
; CHECK-NEXT: [[TMP21:%.*]] = zext i8 [[TMP20]] to i32
; CHECK-NEXT: [[TMP22:%.*]] = icmp eq i32 [[TMP21]], 0
; CHECK-NEXT: br i1 [[TMP22]], label [[BB23:%.*]], label [[BB25:%.*]]
; CHECK: bb23:
; CHECK-NEXT: [[TMP24:%.*]] = trunc nuw i32 [[TMP3]] to i16
; CHECK-NEXT: store i16 [[TMP24]], ptr [[TMP17]], align 2
; CHECK-NEXT: br label [[BB31]]
; CHECK: bb25:
; CHECK-NEXT: [[TMP26:%.*]] = load i16, ptr [[TMP17]], align 2
; CHECK-NEXT: [[TMP27:%.*]] = zext i16 [[TMP26]] to i32
; CHECK-NEXT: [[TMP28:%.*]] = icmp eq i32 [[TMP27]], [[TMP3]]
; CHECK-NEXT: br i1 [[TMP28]], label [[BB31]], label [[BB29]]
; CHECK: bb29:
; CHECK-NEXT: [[TMP30]] = add nsw i32 [[TMP11]], 1
; CHECK-NEXT: br label [[BB8]]
; CHECK: bb31:
; CHECK-NEXT: [[TMP32:%.*]] = phi ptr [ [[TMP17]], [[BB23]] ], [ [[TMP17]], [[BB25]] ], [ [[TMP9]], [[BB8]] ]
; CHECK-NEXT: [[TMP33:%.*]] = phi ptr [ [[TMP17]], [[BB23]] ], [ [[TMP17]], [[BB25]] ], [ [[TMP10]], [[BB8]] ]
; CHECK-NEXT: [[TMP34:%.*]] = icmp eq i32 [[TMP11]], 0
; CHECK-NEXT: br i1 [[TMP34]], label [[BB35:%.*]], label [[BB37:%.*]]
; CHECK: bb35:
; CHECK-NEXT: [[TMP36:%.*]] = getelementptr inbounds nuw i8, ptr [[TMP32]], i64 1
; CHECK-NEXT: br label [[BB66:%.*]]
; CHECK: bb37:
; CHECK-NEXT: [[C_2:%.*]] = icmp eq i32 [[TMP11]], 8
; CHECK-NEXT: br i1 [[C_2]], label [[BB39:%.*]], label [[BB58:%.*]]
; CHECK: bb39:
; CHECK-NEXT: [[TMP41:%.*]] = trunc nuw i32 [[TMP3]] to i16
; CHECK-NEXT: store i16 [[TMP41]], ptr @global.11, align 1
; CHECK-NEXT: [[TMP43:%.*]] = add i32 [[TMP7]], 7
; CHECK-NEXT: [[TMP44:%.*]] = mul i32 [[TMP43]], 4
; CHECK-NEXT: [[TMP45:%.*]] = add i32 [[TMP44]], 2
; CHECK-NEXT: [[TMP46:%.*]] = call dereferenceable(1) ptr @spam(ptr [[ARG]], i32 [[TMP45]])
; CHECK-NEXT: [[TMP47:%.*]] = load i8, ptr [[TMP46]], align 1
; CHECK-NEXT: [[TMP48:%.*]] = zext i8 [[TMP47]] to i32
; CHECK-NEXT: [[TMP49:%.*]] = sub i32 [[TMP43]], 1
; CHECK-NEXT: [[TMP50:%.*]] = mul i32 [[TMP49]], 4
; CHECK-NEXT: [[TMP51:%.*]] = add i32 [[TMP50]], 2
; CHECK-NEXT: [[TMP52:%.*]] = call dereferenceable(1) ptr @spam(ptr [[ARG]], i32 [[TMP51]])
; CHECK-NEXT: [[TMP53:%.*]] = load i8, ptr [[TMP52]], align 1
; CHECK-NEXT: [[TMP54:%.*]] = zext i8 [[TMP53]] to i32
; CHECK-NEXT: [[TMP55:%.*]] = icmp sgt i32 [[TMP48]], [[TMP54]]
; CHECK-NEXT: br i1 [[TMP55]], label [[BB56:%.*]], label [[BB60:%.*]]
; CHECK: bb56:
; CHECK-NEXT: br label [[BB60]]
; CHECK: bb58:
; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 1 @global.11, ptr align 2 [[TMP33]], i64 4, i1 false)
; CHECK-NEXT: br label [[BB60]]
; CHECK: bb60:
; CHECK-NEXT: [[TMP61:%.*]] = phi i32 [ 6, [[BB56]] ], [ 7, [[BB39]] ], [ [[TMP11]], [[BB58]] ]
; CHECK-NEXT: [[TMP63:%.*]] = add i32 [[TMP7]], 1
; CHECK-NEXT: [[TMP64:%.*]] = mul i32 [[TMP63]], 4
; CHECK-NEXT: [[TMP65:%.*]] = call dereferenceable(1) ptr @spam(ptr [[ARG]], i32 [[TMP64]])
; CHECK-NEXT: br label [[BB66]]
; CHECK: bb66:
; CHECK-NEXT: [[TMP67:%.*]] = phi ptr [ [[TMP36]], [[BB35]] ], [ null, [[BB60]] ]
; CHECK-NEXT: ret ptr [[TMP67]]
;
bb:
%tmp = lshr i32 %arg1, 16
%tmp2 = xor i32 %tmp, %arg1
%tmp3 = and i32 %tmp2, 65535
%tmp4 = mul i32 %arg1, 8
%tmp5 = getelementptr inbounds %struct.blam.2, ptr %arg, i32 0, i32 1
%tmp6 = load i32, ptr %tmp5, align 8
%tmp7 = and i32 %tmp4, %tmp6
br label %bb8
bb8: ; preds = %bb29, %bb
%tmp9 = phi ptr [ undef, %bb ], [ %tmp17, %bb29 ]
%tmp10 = phi ptr [ undef, %bb ], [ %tmp17, %bb29 ]
%tmp11 = phi i32 [ 0, %bb ], [ %tmp30, %bb29 ]
%c.1 = icmp slt i32 %tmp11, 8
br i1 %c.1, label %bb13, label %bb31
bb13: ; preds = %bb8
%tmp15 = add i32 %tmp7, %tmp11
%tmp16 = mul i32 %tmp15, 4
%tmp17 = call dereferenceable(1) ptr @spam(ptr %arg, i32 %tmp16)
%tmp19 = getelementptr inbounds i8, ptr %tmp17, i64 2
%tmp20 = load i8, ptr %tmp19, align 1
%tmp21 = zext i8 %tmp20 to i32
%tmp22 = icmp eq i32 %tmp21, 0
br i1 %tmp22, label %bb23, label %bb25
bb23: ; preds = %bb13
%tmp24 = trunc i32 %tmp3 to i16
store i16 %tmp24, ptr %tmp17, align 2
br label %bb31
bb25: ; preds = %bb13
%tmp26 = load i16, ptr %tmp17, align 2
%tmp27 = zext i16 %tmp26 to i32
%tmp28 = icmp eq i32 %tmp27, %tmp3
br i1 %tmp28, label %bb31, label %bb29
bb29: ; preds = %bb25
%tmp30 = add nsw i32 %tmp11, 1
br label %bb8
bb31: ; preds = %bb25, %bb23, %bb8
%tmp32 = phi ptr [ %tmp17, %bb23 ], [ %tmp17, %bb25 ], [ %tmp9, %bb8 ]
%tmp33 = phi ptr [ %tmp17, %bb23 ], [ %tmp17, %bb25 ], [ %tmp10, %bb8 ]
%tmp34 = icmp eq i32 %tmp11, 0
br i1 %tmp34, label %bb35, label %bb37
bb35: ; preds = %bb31
%tmp36 = getelementptr inbounds i8, ptr %tmp32, i64 1
br label %bb66
bb37: ; preds = %bb31
%c.2 = icmp eq i32 %tmp11, 8
br i1 %c.2, label %bb39, label %bb58
bb39: ; preds = %bb37
%tmp40 = add nsw i32 %tmp11, -1
%tmp41 = trunc i32 %tmp3 to i16
store i16 %tmp41, ptr @global.11, align 1
%tmp43 = add i32 %tmp7, %tmp40
%tmp44 = mul i32 %tmp43, 4
%tmp45 = add i32 %tmp44, 2
%tmp46 = call dereferenceable(1) ptr @spam(ptr %arg, i32 %tmp45)
%tmp47 = load i8, ptr %tmp46, align 1
%tmp48 = zext i8 %tmp47 to i32
%tmp49 = sub i32 %tmp43, 1
%tmp50 = mul i32 %tmp49, 4
%tmp51 = add i32 %tmp50, 2
%tmp52 = call dereferenceable(1) ptr @spam(ptr %arg, i32 %tmp51)
%tmp53 = load i8, ptr %tmp52, align 1
%tmp54 = zext i8 %tmp53 to i32
%tmp55 = icmp sgt i32 %tmp48, %tmp54
br i1 %tmp55, label %bb56, label %bb60
bb56: ; preds = %bb39
%tmp57 = add nsw i32 %tmp40, -1
br label %bb60
bb58: ; preds = %bb37
call void @llvm.memcpy.p0.p0.i64(ptr align 1 @global.11, ptr align 2 %tmp33, i64 4, i1 false)
br label %bb60
bb60: ; preds = %bb58, %bb56, %bb39
%tmp61 = phi i32 [ %tmp57, %bb56 ], [ %tmp40, %bb39 ], [ %tmp11, %bb58 ]
%tmp63 = add i32 %tmp7, 1
%tmp64 = mul i32 %tmp63, 4
%tmp65 = call dereferenceable(1) ptr @spam(ptr %arg, i32 %tmp64)
br label %bb66
bb66: ; preds = %bb60, %bb35
%tmp67 = phi ptr [ %tmp36, %bb35 ], [ null, %bb60 ]
ret ptr %tmp67
}
define i32 @loop_with_multiple_euqal_incomings(i32 %N) {
; CHECK-LABEL: @loop_with_multiple_euqal_incomings(
; CHECK-NEXT: entry:
; CHECK-NEXT: br label [[LOOP:%.*]]
; CHECK: loop:
; CHECK-NEXT: [[P:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[P_NEXT:%.*]], [[BB3:%.*]] ], [ 0, [[BB4:%.*]] ], [ 0, [[BB5:%.*]] ], [ 0, [[BB6:%.*]] ]
; CHECK-NEXT: [[C_1:%.*]] = call i1 @cond()
; CHECK-NEXT: br i1 [[C_1]], label [[BB1:%.*]], label [[BB2:%.*]]
; CHECK: bb1:
; CHECK-NEXT: [[C_2:%.*]] = call i1 @cond()
; CHECK-NEXT: br i1 [[C_2]], label [[BB3]], label [[BB4]]
; CHECK: bb2:
; CHECK-NEXT: [[C_4:%.*]] = call i1 @cond()
; CHECK-NEXT: br i1 [[C_4]], label [[BB5]], label [[BB6]]
; CHECK: bb3:
; CHECK-NEXT: [[P_NEXT]] = add i32 [[P]], 1
; CHECK-NEXT: br label [[LOOP]]
; CHECK: bb4:
; CHECK-NEXT: [[C_3:%.*]] = call i1 @cond()
; CHECK-NEXT: br i1 [[C_3]], label [[LOOP]], label [[END:%.*]]
; CHECK: bb5:
; CHECK-NEXT: br label [[LOOP]]
; CHECK: bb6:
; CHECK-NEXT: br label [[LOOP]]
; CHECK: end:
; CHECK-NEXT: ret i32 [[P]]
;
entry:
br label %loop
loop:
%p = phi i32 [ 0, %entry ], [ %p.next, %bb3 ], [ 0, %bb4 ], [ 0, %bb5], [ 0, %bb6 ]
%c.1 = call i1 @cond()
br i1 %c.1, label %bb1, label %bb2
bb1:
%c.2 = call i1 @cond()
br i1 %c.2, label %bb3, label %bb4
bb2:
%c.4 = call i1 @cond()
br i1 %c.4, label %bb5, label %bb6
bb3:
%p.next = add i32 %p, 1
br label %loop
bb4:
%c.3 = call i1 @cond()
br i1 %c.3, label %loop, label %end
bb5:
br label %loop
bb6:
br label %loop
end:
ret i32 %p
}
;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
; IPSCCP: {{.*}}
; SCCP: {{.*}}