We already infer this in IPSCCP (which runs very early, so cannot benefit from inlining and simplifications) and SCCP (which runs without PredicateInfo, so does not use assumes). Do it in CVP as well, so it can handle cases that IPSCCP/SCCP can't. Fixes https://github.com/llvm/llvm-project/issues/98946 (everything apart from f2, where the assume is dropped by the frontend).
568 lines
15 KiB
LLVM
568 lines
15 KiB
LLVM
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 4
|
|
; RUN: opt < %s -passes=correlated-propagation -S | FileCheck %s
|
|
|
|
define void @test0(i32 %a) {
|
|
; CHECK-LABEL: define void @test0(
|
|
; CHECK-SAME: i32 [[A:%.*]]) {
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[A]], 100
|
|
; CHECK-NEXT: br i1 [[CMP]], label [[BB:%.*]], label [[EXIT:%.*]]
|
|
; CHECK: bb:
|
|
; CHECK-NEXT: [[ADD:%.*]] = add nsw i32 [[A]], 1
|
|
; CHECK-NEXT: br label [[EXIT]]
|
|
; CHECK: exit:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
entry:
|
|
%cmp = icmp slt i32 %a, 100
|
|
br i1 %cmp, label %bb, label %exit
|
|
|
|
bb:
|
|
%add = add i32 %a, 1
|
|
br label %exit
|
|
|
|
exit:
|
|
ret void
|
|
}
|
|
|
|
define void @test1(i32 %a) {
|
|
; CHECK-LABEL: define void @test1(
|
|
; CHECK-SAME: i32 [[A:%.*]]) {
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[A]], 100
|
|
; CHECK-NEXT: br i1 [[CMP]], label [[BB:%.*]], label [[EXIT:%.*]]
|
|
; CHECK: bb:
|
|
; CHECK-NEXT: [[ADD:%.*]] = add nuw nsw i32 [[A]], 1
|
|
; CHECK-NEXT: br label [[EXIT]]
|
|
; CHECK: exit:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
entry:
|
|
%cmp = icmp ult i32 %a, 100
|
|
br i1 %cmp, label %bb, label %exit
|
|
|
|
bb:
|
|
%add = add i32 %a, 1
|
|
br label %exit
|
|
|
|
exit:
|
|
ret void
|
|
}
|
|
|
|
define void @test2(i32 %a) {
|
|
; CHECK-LABEL: define void @test2(
|
|
; CHECK-SAME: i32 [[A:%.*]]) {
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[A]], -1
|
|
; CHECK-NEXT: br i1 [[CMP]], label [[BB:%.*]], label [[EXIT:%.*]]
|
|
; CHECK: bb:
|
|
; CHECK-NEXT: [[ADD:%.*]] = add nuw i32 [[A]], 1
|
|
; CHECK-NEXT: br label [[EXIT]]
|
|
; CHECK: exit:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
entry:
|
|
%cmp = icmp ult i32 %a, -1
|
|
br i1 %cmp, label %bb, label %exit
|
|
|
|
bb:
|
|
%add = add i32 %a, 1
|
|
br label %exit
|
|
|
|
exit:
|
|
ret void
|
|
}
|
|
|
|
define void @test3(i32 %a) {
|
|
; CHECK-LABEL: define void @test3(
|
|
; CHECK-SAME: i32 [[A:%.*]]) {
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp ule i32 [[A]], -1
|
|
; CHECK-NEXT: br i1 [[CMP]], label [[BB:%.*]], label [[EXIT:%.*]]
|
|
; CHECK: bb:
|
|
; CHECK-NEXT: [[ADD:%.*]] = add i32 [[A]], 1
|
|
; CHECK-NEXT: br label [[EXIT]]
|
|
; CHECK: exit:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
entry:
|
|
%cmp = icmp ule i32 %a, -1
|
|
br i1 %cmp, label %bb, label %exit
|
|
|
|
bb:
|
|
%add = add i32 %a, 1
|
|
br label %exit
|
|
|
|
exit:
|
|
ret void
|
|
}
|
|
|
|
define void @test4(i32 %a) {
|
|
; CHECK-LABEL: define void @test4(
|
|
; CHECK-SAME: i32 [[A:%.*]]) {
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[A]], 2147483647
|
|
; CHECK-NEXT: br i1 [[CMP]], label [[BB:%.*]], label [[EXIT:%.*]]
|
|
; CHECK: bb:
|
|
; CHECK-NEXT: [[ADD:%.*]] = add nsw i32 [[A]], 1
|
|
; CHECK-NEXT: br label [[EXIT]]
|
|
; CHECK: exit:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
entry:
|
|
%cmp = icmp slt i32 %a, 2147483647
|
|
br i1 %cmp, label %bb, label %exit
|
|
|
|
bb:
|
|
%add = add i32 %a, 1
|
|
br label %exit
|
|
|
|
exit:
|
|
ret void
|
|
}
|
|
|
|
define void @test5(i32 %a) {
|
|
; CHECK-LABEL: define void @test5(
|
|
; CHECK-SAME: i32 [[A:%.*]]) {
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp sle i32 [[A]], 2147483647
|
|
; CHECK-NEXT: br i1 [[CMP]], label [[BB:%.*]], label [[EXIT:%.*]]
|
|
; CHECK: bb:
|
|
; CHECK-NEXT: [[ADD:%.*]] = add i32 [[A]], 1
|
|
; CHECK-NEXT: br label [[EXIT]]
|
|
; CHECK: exit:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
entry:
|
|
%cmp = icmp sle i32 %a, 2147483647
|
|
br i1 %cmp, label %bb, label %exit
|
|
|
|
bb:
|
|
%add = add i32 %a, 1
|
|
br label %exit
|
|
|
|
exit:
|
|
ret void
|
|
}
|
|
|
|
; Check for a corner case where an integer value is represented with a constant
|
|
; LVILatticeValue instead of constantrange. Check that we don't fail with an
|
|
; assertion in this case.
|
|
@b = global i32 0, align 4
|
|
define void @test6(i32 %a) {
|
|
; CHECK-LABEL: define void @test6(
|
|
; CHECK-SAME: i32 [[A:%.*]]) {
|
|
; CHECK-NEXT: bb:
|
|
; CHECK-NEXT: [[ADD:%.*]] = add i32 [[A]], ptrtoint (ptr @b to i32)
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
bb:
|
|
%add = add i32 %a, ptrtoint (ptr @b to i32)
|
|
ret void
|
|
}
|
|
|
|
; Check that we can gather information for conditions is the form of
|
|
; and ( i s< 100, Unknown )
|
|
define void @test7(i32 %a, i1 %flag) {
|
|
; CHECK-LABEL: define void @test7(
|
|
; CHECK-SAME: i32 [[A:%.*]], i1 [[FLAG:%.*]]) {
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[CMP_1:%.*]] = icmp slt i32 [[A]], 100
|
|
; CHECK-NEXT: [[CMP:%.*]] = and i1 [[CMP_1]], [[FLAG]]
|
|
; CHECK-NEXT: br i1 [[CMP]], label [[BB:%.*]], label [[EXIT:%.*]]
|
|
; CHECK: bb:
|
|
; CHECK-NEXT: [[ADD:%.*]] = add nsw i32 [[A]], 1
|
|
; CHECK-NEXT: br label [[EXIT]]
|
|
; CHECK: exit:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
entry:
|
|
%cmp.1 = icmp slt i32 %a, 100
|
|
%cmp = and i1 %cmp.1, %flag
|
|
br i1 %cmp, label %bb, label %exit
|
|
|
|
bb:
|
|
%add = add i32 %a, 1
|
|
br label %exit
|
|
|
|
exit:
|
|
ret void
|
|
}
|
|
|
|
; Check that we can gather information for conditions is the form of
|
|
; and ( i s< 100, i s> 0 )
|
|
define void @test8(i32 %a) {
|
|
; CHECK-LABEL: define void @test8(
|
|
; CHECK-SAME: i32 [[A:%.*]]) {
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[CMP_1:%.*]] = icmp slt i32 [[A]], 100
|
|
; CHECK-NEXT: [[CMP_2:%.*]] = icmp sgt i32 [[A]], 0
|
|
; CHECK-NEXT: [[CMP:%.*]] = and i1 [[CMP_1]], [[CMP_2]]
|
|
; CHECK-NEXT: br i1 [[CMP]], label [[BB:%.*]], label [[EXIT:%.*]]
|
|
; CHECK: bb:
|
|
; CHECK-NEXT: [[ADD:%.*]] = add nuw nsw i32 [[A]], 1
|
|
; CHECK-NEXT: br label [[EXIT]]
|
|
; CHECK: exit:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
entry:
|
|
%cmp.1 = icmp slt i32 %a, 100
|
|
%cmp.2 = icmp sgt i32 %a, 0
|
|
%cmp = and i1 %cmp.1, %cmp.2
|
|
br i1 %cmp, label %bb, label %exit
|
|
|
|
bb:
|
|
%add = add i32 %a, 1
|
|
br label %exit
|
|
|
|
exit:
|
|
ret void
|
|
}
|
|
|
|
; Check that for conditions is the form of cond1 && cond2 we don't mistakenly
|
|
; assume that !cond1 && !cond2 holds down to false path.
|
|
define void @test8_neg(i32 %a) {
|
|
; CHECK-LABEL: define void @test8_neg(
|
|
; CHECK-SAME: i32 [[A:%.*]]) {
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[CMP_1:%.*]] = icmp sge i32 [[A]], 100
|
|
; CHECK-NEXT: [[CMP_2:%.*]] = icmp sle i32 [[A]], 0
|
|
; CHECK-NEXT: [[CMP:%.*]] = and i1 [[CMP_1]], [[CMP_2]]
|
|
; CHECK-NEXT: br i1 [[CMP]], label [[EXIT:%.*]], label [[BB:%.*]]
|
|
; CHECK: bb:
|
|
; CHECK-NEXT: [[ADD:%.*]] = add i32 [[A]], 1
|
|
; CHECK-NEXT: br label [[EXIT]]
|
|
; CHECK: exit:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
entry:
|
|
%cmp.1 = icmp sge i32 %a, 100
|
|
%cmp.2 = icmp sle i32 %a, 0
|
|
%cmp = and i1 %cmp.1, %cmp.2
|
|
br i1 %cmp, label %exit, label %bb
|
|
|
|
bb:
|
|
%add = add i32 %a, 1
|
|
br label %exit
|
|
|
|
exit:
|
|
ret void
|
|
}
|
|
|
|
; Check that we can gather information for conditions is the form of
|
|
; and ( i s< 100, and (i s> 0, Unknown )
|
|
define void @test9(i32 %a, i1 %flag) {
|
|
; CHECK-LABEL: define void @test9(
|
|
; CHECK-SAME: i32 [[A:%.*]], i1 [[FLAG:%.*]]) {
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[CMP_1:%.*]] = icmp slt i32 [[A]], 100
|
|
; CHECK-NEXT: [[CMP_2:%.*]] = icmp sgt i32 [[A]], 0
|
|
; CHECK-NEXT: [[CMP_3:%.*]] = and i1 [[CMP_2]], [[FLAG]]
|
|
; CHECK-NEXT: [[CMP:%.*]] = and i1 [[CMP_1]], [[CMP_3]]
|
|
; CHECK-NEXT: br i1 [[CMP]], label [[BB:%.*]], label [[EXIT:%.*]]
|
|
; CHECK: bb:
|
|
; CHECK-NEXT: [[ADD:%.*]] = add nuw nsw i32 [[A]], 1
|
|
; CHECK-NEXT: br label [[EXIT]]
|
|
; CHECK: exit:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
entry:
|
|
%cmp.1 = icmp slt i32 %a, 100
|
|
%cmp.2 = icmp sgt i32 %a, 0
|
|
%cmp.3 = and i1 %cmp.2, %flag
|
|
%cmp = and i1 %cmp.1, %cmp.3
|
|
br i1 %cmp, label %bb, label %exit
|
|
|
|
bb:
|
|
%add = add i32 %a, 1
|
|
br label %exit
|
|
|
|
exit:
|
|
ret void
|
|
}
|
|
|
|
; Check that we can gather information for conditions is the form of
|
|
; and ( i s< Unknown, ... )
|
|
define void @test10(i32 %a, i32 %b, i1 %flag) {
|
|
; CHECK-LABEL: define void @test10(
|
|
; CHECK-SAME: i32 [[A:%.*]], i32 [[B:%.*]], i1 [[FLAG:%.*]]) {
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[CMP_1:%.*]] = icmp slt i32 [[A]], [[B]]
|
|
; CHECK-NEXT: [[CMP:%.*]] = and i1 [[CMP_1]], [[FLAG]]
|
|
; CHECK-NEXT: br i1 [[CMP]], label [[BB:%.*]], label [[EXIT:%.*]]
|
|
; CHECK: bb:
|
|
; CHECK-NEXT: [[ADD:%.*]] = add nsw i32 [[A]], 1
|
|
; CHECK-NEXT: br label [[EXIT]]
|
|
; CHECK: exit:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
entry:
|
|
%cmp.1 = icmp slt i32 %a, %b
|
|
%cmp = and i1 %cmp.1, %flag
|
|
br i1 %cmp, label %bb, label %exit
|
|
|
|
bb:
|
|
%add = add i32 %a, 1
|
|
br label %exit
|
|
|
|
exit:
|
|
ret void
|
|
}
|
|
|
|
@limit = external global i32
|
|
define i32 @test11(ptr %p, i32 %i) {
|
|
; CHECK-LABEL: define range(i32 0, 2147483645) i32 @test11(
|
|
; CHECK-SAME: ptr [[P:%.*]], i32 [[I:%.*]]) {
|
|
; CHECK-NEXT: [[LIMIT:%.*]] = load i32, ptr [[P]], align 4, !range [[RNG0:![0-9]+]]
|
|
; CHECK-NEXT: [[WITHIN_1:%.*]] = icmp ugt i32 [[LIMIT]], [[I]]
|
|
; CHECK-NEXT: [[I_PLUS_7:%.*]] = add i32 [[I]], 7
|
|
; CHECK-NEXT: [[WITHIN_2:%.*]] = icmp ugt i32 [[LIMIT]], [[I_PLUS_7]]
|
|
; CHECK-NEXT: [[WITHIN:%.*]] = and i1 [[WITHIN_1]], [[WITHIN_2]]
|
|
; CHECK-NEXT: br i1 [[WITHIN]], label [[THEN:%.*]], label [[ELSE:%.*]]
|
|
; CHECK: then:
|
|
; CHECK-NEXT: [[I_PLUS_6:%.*]] = add nuw nsw i32 [[I]], 6
|
|
; CHECK-NEXT: ret i32 [[I_PLUS_6]]
|
|
; CHECK: else:
|
|
; CHECK-NEXT: ret i32 0
|
|
;
|
|
%limit = load i32, ptr %p, !range !{i32 0, i32 2147483647}
|
|
%within.1 = icmp ugt i32 %limit, %i
|
|
%i.plus.7 = add i32 %i, 7
|
|
%within.2 = icmp ugt i32 %limit, %i.plus.7
|
|
%within = and i1 %within.1, %within.2
|
|
br i1 %within, label %then, label %else
|
|
|
|
then:
|
|
%i.plus.6 = add i32 %i, 6
|
|
ret i32 %i.plus.6
|
|
|
|
else:
|
|
ret i32 0
|
|
}
|
|
|
|
; Check that we can gather information for conditions is the form of
|
|
; or ( i s>= 100, Unknown )
|
|
define void @test12(i32 %a, i1 %flag) {
|
|
; CHECK-LABEL: define void @test12(
|
|
; CHECK-SAME: i32 [[A:%.*]], i1 [[FLAG:%.*]]) {
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[CMP_1:%.*]] = icmp sge i32 [[A]], 100
|
|
; CHECK-NEXT: [[CMP:%.*]] = or i1 [[CMP_1]], [[FLAG]]
|
|
; CHECK-NEXT: br i1 [[CMP]], label [[EXIT:%.*]], label [[BB:%.*]]
|
|
; CHECK: bb:
|
|
; CHECK-NEXT: [[ADD:%.*]] = add nsw i32 [[A]], 1
|
|
; CHECK-NEXT: br label [[EXIT]]
|
|
; CHECK: exit:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
entry:
|
|
%cmp.1 = icmp sge i32 %a, 100
|
|
%cmp = or i1 %cmp.1, %flag
|
|
br i1 %cmp, label %exit, label %bb
|
|
|
|
bb:
|
|
%add = add i32 %a, 1
|
|
br label %exit
|
|
|
|
exit:
|
|
ret void
|
|
}
|
|
|
|
; Check that we can gather information for conditions is the form of
|
|
; or ( i s>= 100, i s<= 0 )
|
|
define void @test13(i32 %a) {
|
|
; CHECK-LABEL: define void @test13(
|
|
; CHECK-SAME: i32 [[A:%.*]]) {
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[CMP_1:%.*]] = icmp sge i32 [[A]], 100
|
|
; CHECK-NEXT: [[CMP_2:%.*]] = icmp sle i32 [[A]], 0
|
|
; CHECK-NEXT: [[CMP:%.*]] = or i1 [[CMP_1]], [[CMP_2]]
|
|
; CHECK-NEXT: br i1 [[CMP]], label [[EXIT:%.*]], label [[BB:%.*]]
|
|
; CHECK: bb:
|
|
; CHECK-NEXT: [[ADD:%.*]] = add nuw nsw i32 [[A]], 1
|
|
; CHECK-NEXT: br label [[EXIT]]
|
|
; CHECK: exit:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
entry:
|
|
%cmp.1 = icmp sge i32 %a, 100
|
|
%cmp.2 = icmp sle i32 %a, 0
|
|
%cmp = or i1 %cmp.1, %cmp.2
|
|
br i1 %cmp, label %exit, label %bb
|
|
|
|
bb:
|
|
%add = add i32 %a, 1
|
|
br label %exit
|
|
|
|
exit:
|
|
ret void
|
|
}
|
|
|
|
; Check that for conditions is the form of cond1 || cond2 we don't mistakenly
|
|
; assume that cond1 || cond2 holds down to true path.
|
|
define void @test13_neg(i32 %a) {
|
|
; CHECK-LABEL: define void @test13_neg(
|
|
; CHECK-SAME: i32 [[A:%.*]]) {
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[CMP_1:%.*]] = icmp slt i32 [[A]], 100
|
|
; CHECK-NEXT: [[CMP_2:%.*]] = icmp sgt i32 [[A]], 0
|
|
; CHECK-NEXT: [[CMP:%.*]] = or i1 [[CMP_1]], [[CMP_2]]
|
|
; CHECK-NEXT: br i1 [[CMP]], label [[BB:%.*]], label [[EXIT:%.*]]
|
|
; CHECK: bb:
|
|
; CHECK-NEXT: [[ADD:%.*]] = add i32 [[A]], 1
|
|
; CHECK-NEXT: br label [[EXIT]]
|
|
; CHECK: exit:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
entry:
|
|
%cmp.1 = icmp slt i32 %a, 100
|
|
%cmp.2 = icmp sgt i32 %a, 0
|
|
%cmp = or i1 %cmp.1, %cmp.2
|
|
br i1 %cmp, label %bb, label %exit
|
|
|
|
bb:
|
|
%add = add i32 %a, 1
|
|
br label %exit
|
|
|
|
exit:
|
|
ret void
|
|
}
|
|
|
|
; Check that we can gather information for conditions is the form of
|
|
; or ( i s>=100, or (i s<= 0, Unknown )
|
|
define void @test14(i32 %a, i1 %flag) {
|
|
; CHECK-LABEL: define void @test14(
|
|
; CHECK-SAME: i32 [[A:%.*]], i1 [[FLAG:%.*]]) {
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[CMP_1:%.*]] = icmp sge i32 [[A]], 100
|
|
; CHECK-NEXT: [[CMP_2:%.*]] = icmp sle i32 [[A]], 0
|
|
; CHECK-NEXT: [[CMP_3:%.*]] = or i1 [[CMP_2]], [[FLAG]]
|
|
; CHECK-NEXT: [[CMP:%.*]] = or i1 [[CMP_1]], [[CMP_3]]
|
|
; CHECK-NEXT: br i1 [[CMP]], label [[EXIT:%.*]], label [[BB:%.*]]
|
|
; CHECK: bb:
|
|
; CHECK-NEXT: [[ADD:%.*]] = add nuw nsw i32 [[A]], 1
|
|
; CHECK-NEXT: br label [[EXIT]]
|
|
; CHECK: exit:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
entry:
|
|
%cmp.1 = icmp sge i32 %a, 100
|
|
%cmp.2 = icmp sle i32 %a, 0
|
|
%cmp.3 = or i1 %cmp.2, %flag
|
|
%cmp = or i1 %cmp.1, %cmp.3
|
|
br i1 %cmp, label %exit, label %bb
|
|
|
|
bb:
|
|
%add = add i32 %a, 1
|
|
br label %exit
|
|
|
|
exit:
|
|
ret void
|
|
}
|
|
|
|
; Check that we can gather information for conditions is the form of
|
|
; or ( i s>= Unknown, ... )
|
|
define void @test15(i32 %a, i32 %b, i1 %flag) {
|
|
; CHECK-LABEL: define void @test15(
|
|
; CHECK-SAME: i32 [[A:%.*]], i32 [[B:%.*]], i1 [[FLAG:%.*]]) {
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[CMP_1:%.*]] = icmp sge i32 [[A]], [[B]]
|
|
; CHECK-NEXT: [[CMP:%.*]] = or i1 [[CMP_1]], [[FLAG]]
|
|
; CHECK-NEXT: br i1 [[CMP]], label [[EXIT:%.*]], label [[BB:%.*]]
|
|
; CHECK: bb:
|
|
; CHECK-NEXT: [[ADD:%.*]] = add nsw i32 [[A]], 1
|
|
; CHECK-NEXT: br label [[EXIT]]
|
|
; CHECK: exit:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
entry:
|
|
%cmp.1 = icmp sge i32 %a, %b
|
|
%cmp = or i1 %cmp.1, %flag
|
|
br i1 %cmp, label %exit, label %bb
|
|
|
|
bb:
|
|
%add = add i32 %a, 1
|
|
br label %exit
|
|
|
|
exit:
|
|
ret void
|
|
}
|
|
|
|
; single basic block loop
|
|
; because the loop exit condition is SLT, we can supplement the iv add
|
|
; (iv.next def) with an nsw.
|
|
define i32 @test16(ptr %n, ptr %a) {
|
|
; CHECK-LABEL: define i32 @test16(
|
|
; CHECK-SAME: ptr [[N:%.*]], ptr [[A:%.*]]) {
|
|
; CHECK-NEXT: preheader:
|
|
; CHECK-NEXT: br label [[LOOP:%.*]]
|
|
; CHECK: loop:
|
|
; CHECK-NEXT: [[IV:%.*]] = phi i32 [ 0, [[PREHEADER:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ]
|
|
; CHECK-NEXT: [[ACC:%.*]] = phi i32 [ 0, [[PREHEADER]] ], [ [[ACC_CURR:%.*]], [[LOOP]] ]
|
|
; CHECK-NEXT: [[X:%.*]] = load atomic i32, ptr [[A]] unordered, align 8
|
|
; CHECK-NEXT: fence acquire
|
|
; CHECK-NEXT: [[ACC_CURR]] = add i32 [[ACC]], [[X]]
|
|
; CHECK-NEXT: [[IV_NEXT]] = add nsw i32 [[IV]], 1
|
|
; CHECK-NEXT: [[NVAL:%.*]] = load atomic i32, ptr [[N]] unordered, align 8
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[IV_NEXT]], [[NVAL]]
|
|
; CHECK-NEXT: br i1 [[CMP]], label [[LOOP]], label [[EXIT:%.*]]
|
|
; CHECK: exit:
|
|
; CHECK-NEXT: ret i32 [[ACC_CURR]]
|
|
;
|
|
preheader:
|
|
br label %loop
|
|
|
|
loop:
|
|
%iv = phi i32 [ 0, %preheader ], [ %iv.next, %loop ]
|
|
%acc = phi i32 [ 0, %preheader ], [ %acc.curr, %loop ]
|
|
%x = load atomic i32, ptr %a unordered, align 8
|
|
fence acquire
|
|
%acc.curr = add i32 %acc, %x
|
|
%iv.next = add i32 %iv, 1
|
|
%nval = load atomic i32, ptr %n unordered, align 8
|
|
%cmp = icmp slt i32 %iv.next, %nval
|
|
br i1 %cmp, label %loop, label %exit
|
|
|
|
exit:
|
|
ret i32 %acc.curr
|
|
}
|
|
|
|
define i32 @test_undef_range(i32 %x) {
|
|
; CHECK-LABEL: define i32 @test_undef_range(
|
|
; CHECK-SAME: i32 [[X:%.*]]) {
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: switch i32 [[X]], label [[JOIN:%.*]] [
|
|
; CHECK-NEXT: i32 1, label [[CASE1:%.*]]
|
|
; CHECK-NEXT: i32 2, label [[CASE2:%.*]]
|
|
; CHECK-NEXT: ]
|
|
; CHECK: case1:
|
|
; CHECK-NEXT: br label [[JOIN]]
|
|
; CHECK: case2:
|
|
; CHECK-NEXT: br label [[JOIN]]
|
|
; CHECK: join:
|
|
; CHECK-NEXT: [[PHI:%.*]] = phi i32 [ 1, [[CASE1]] ], [ 2, [[CASE2]] ], [ undef, [[ENTRY:%.*]] ]
|
|
; CHECK-NEXT: [[ADD:%.*]] = add i32 [[PHI]], 1
|
|
; CHECK-NEXT: ret i32 [[ADD]]
|
|
;
|
|
entry:
|
|
switch i32 %x, label %join [
|
|
i32 1, label %case1
|
|
i32 2, label %case2
|
|
]
|
|
|
|
case1:
|
|
br label %join
|
|
|
|
case2:
|
|
br label %join
|
|
|
|
join:
|
|
%phi = phi i32 [ 1, %case1 ], [ 2, %case2 ], [ undef, %entry ]
|
|
%add = add i32 %phi, 1
|
|
ret i32 %add
|
|
}
|
|
|
|
;.
|
|
; CHECK: [[RNG0]] = !{i32 0, i32 2147483647}
|
|
;.
|