We should first try to constant fold the add expression and only strengthen nowrap flags afterwards. This allows us to determine stronger flags if e.g. only two operands are left after constant folding (and thus "guaranteed no wrap region" code applies) or the resulting operands are non-negative and thus nsw->nuw strengthening applies.
684 lines
22 KiB
LLVM
684 lines
22 KiB
LLVM
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
|
|
; RUN: opt -indvars -S -indvars-predicate-loops=0 < %s | FileCheck %s
|
|
|
|
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
|
|
target triple = "x86_64-unknown-linux-gnu"
|
|
|
|
; General case: without extra knowledge, trunc cannot be eliminated.
|
|
define void @test_00(i64 %start, i32 %n) {
|
|
;
|
|
; CHECK-LABEL: @test_00(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: br label [[LOOP:%.*]]
|
|
; CHECK: loop:
|
|
; CHECK-NEXT: [[IV:%.*]] = phi i64 [ [[START:%.*]], [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ]
|
|
; CHECK-NEXT: [[IV_NEXT]] = add i64 [[IV]], 1
|
|
; CHECK-NEXT: [[NARROW_IV:%.*]] = trunc i64 [[IV]] to i32
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[NARROW_IV]], [[N:%.*]]
|
|
; CHECK-NEXT: br i1 [[CMP]], label [[LOOP]], label [[EXIT:%.*]]
|
|
; CHECK: exit:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
entry:
|
|
br label %loop
|
|
loop:
|
|
%iv = phi i64 [ %start, %entry ], [ %iv.next, %loop ]
|
|
%iv.next = add i64 %iv, 1
|
|
%narrow.iv = trunc i64 %iv to i32
|
|
%cmp = icmp slt i32 %narrow.iv, %n
|
|
br i1 %cmp, label %loop, label %exit
|
|
exit:
|
|
ret void
|
|
}
|
|
|
|
|
|
define void @test_01(i32 %n) {
|
|
;
|
|
; CHECK-LABEL: @test_01(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[TMP0:%.*]] = icmp sgt i32 [[N:%.*]], 0
|
|
; CHECK-NEXT: [[SMAX:%.*]] = select i1 [[TMP0]], i32 [[N]], i32 0
|
|
; CHECK-NEXT: [[TMP1:%.*]] = add nuw i32 [[SMAX]], 1
|
|
; CHECK-NEXT: [[WIDE_TRIP_COUNT:%.*]] = zext i32 [[TMP1]] to i64
|
|
; CHECK-NEXT: br label [[LOOP:%.*]]
|
|
; CHECK: loop:
|
|
; CHECK-NEXT: [[IV:%.*]] = phi i64 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ]
|
|
; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i64 [[IV]], 1
|
|
; CHECK-NEXT: [[EXITCOND:%.*]] = icmp ne i64 [[IV_NEXT]], [[WIDE_TRIP_COUNT]]
|
|
; CHECK-NEXT: br i1 [[EXITCOND]], label [[LOOP]], label [[EXIT:%.*]]
|
|
; CHECK: exit:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
entry:
|
|
br label %loop
|
|
loop:
|
|
%iv = phi i64 [ 0, %entry ], [ %iv.next, %loop ]
|
|
%iv.next = add i64 %iv, 1
|
|
%narrow.iv = trunc i64 %iv to i32
|
|
%cmp = icmp slt i32 %narrow.iv, %n
|
|
br i1 %cmp, label %loop, label %exit
|
|
exit:
|
|
ret void
|
|
}
|
|
|
|
; Max value at which we can eliminate trunc: SINT_MAX - 1.
|
|
define void @test_02(i32 %n) {
|
|
;
|
|
; CHECK-LABEL: @test_02(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[TMP0:%.*]] = icmp sgt i32 [[N:%.*]], 2147483646
|
|
; CHECK-NEXT: [[SMAX:%.*]] = select i1 [[TMP0]], i32 [[N]], i32 2147483646
|
|
; CHECK-NEXT: [[TMP1:%.*]] = add nuw i32 [[SMAX]], 1
|
|
; CHECK-NEXT: [[WIDE_TRIP_COUNT:%.*]] = zext i32 [[TMP1]] to i64
|
|
; CHECK-NEXT: br label [[LOOP:%.*]]
|
|
; CHECK: loop:
|
|
; CHECK-NEXT: [[IV:%.*]] = phi i64 [ 2147483646, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ]
|
|
; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i64 [[IV]], 1
|
|
; CHECK-NEXT: [[EXITCOND:%.*]] = icmp ne i64 [[IV_NEXT]], [[WIDE_TRIP_COUNT]]
|
|
; CHECK-NEXT: br i1 [[EXITCOND]], label [[LOOP]], label [[EXIT:%.*]]
|
|
; CHECK: exit:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
entry:
|
|
br label %loop
|
|
loop:
|
|
%iv = phi i64 [ 2147483646, %entry ], [ %iv.next, %loop ]
|
|
%iv.next = add i64 %iv, 1
|
|
%narrow.iv = trunc i64 %iv to i32
|
|
%cmp = icmp slt i32 %narrow.iv, %n
|
|
br i1 %cmp, label %loop, label %exit
|
|
exit:
|
|
ret void
|
|
}
|
|
|
|
; If we start from SINT_MAX then the predicate is always false.
|
|
define void @test_03(i32 %n) {
|
|
;
|
|
; CHECK-LABEL: @test_03(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: br label [[LOOP:%.*]]
|
|
; CHECK: loop:
|
|
; CHECK-NEXT: br i1 false, label [[LOOP]], label [[EXIT:%.*]]
|
|
; CHECK: exit:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
entry:
|
|
br label %loop
|
|
loop:
|
|
%iv = phi i64 [2147483647, %entry], [%iv.next, %loop]
|
|
%iv.next = add i64 %iv, 1
|
|
%narrow.iv = trunc i64 %iv to i32
|
|
%cmp = icmp slt i32 %narrow.iv, %n
|
|
br i1 %cmp, label %loop, label %exit
|
|
exit:
|
|
ret void
|
|
}
|
|
|
|
; Minimum value at which we can apply the transform: SINT_MIN + 1.
|
|
define void @test_04(i32 %n) {
|
|
;
|
|
; CHECK-LABEL: @test_04(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[TMP0:%.*]] = icmp sgt i32 [[N:%.*]], -2147483647
|
|
; CHECK-NEXT: [[SMAX:%.*]] = select i1 [[TMP0]], i32 [[N]], i32 -2147483647
|
|
; CHECK-NEXT: [[TMP1:%.*]] = add i32 [[SMAX]], 1
|
|
; CHECK-NEXT: br label [[LOOP:%.*]]
|
|
; CHECK: loop:
|
|
; CHECK-NEXT: [[IV:%.*]] = phi i64 [ -2147483647, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ]
|
|
; CHECK-NEXT: [[IV_NEXT]] = add nsw i64 [[IV]], 1
|
|
; CHECK-NEXT: [[LFTR_WIDEIV:%.*]] = trunc i64 [[IV_NEXT]] to i32
|
|
; CHECK-NEXT: [[EXITCOND:%.*]] = icmp ne i32 [[LFTR_WIDEIV]], [[TMP1]]
|
|
; CHECK-NEXT: br i1 [[EXITCOND]], label [[LOOP]], label [[EXIT:%.*]]
|
|
; CHECK: exit:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
entry:
|
|
br label %loop
|
|
loop:
|
|
%iv = phi i64 [ -2147483647, %entry ], [ %iv.next, %loop ]
|
|
%iv.next = add i64 %iv, 1
|
|
%narrow.iv = trunc i64 %iv to i32
|
|
%cmp = icmp slt i32 %narrow.iv, %n
|
|
br i1 %cmp, label %loop, label %exit
|
|
exit:
|
|
ret void
|
|
}
|
|
|
|
; FIXME: Harmful LFTR should be thrown away.
|
|
define void @test_05(i32 %n) {
|
|
;
|
|
; CHECK-LABEL: @test_05(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[TMP0:%.*]] = add i32 [[N:%.*]], 1
|
|
; CHECK-NEXT: br label [[LOOP:%.*]]
|
|
; CHECK: loop:
|
|
; CHECK-NEXT: [[IV:%.*]] = phi i64 [ -2147483648, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ]
|
|
; CHECK-NEXT: [[IV_NEXT]] = add nsw i64 [[IV]], 1
|
|
; CHECK-NEXT: [[LFTR_WIDEIV:%.*]] = trunc i64 [[IV_NEXT]] to i32
|
|
; CHECK-NEXT: [[EXITCOND:%.*]] = icmp ne i32 [[LFTR_WIDEIV]], [[TMP0]]
|
|
; CHECK-NEXT: br i1 [[EXITCOND]], label [[LOOP]], label [[EXIT:%.*]]
|
|
; CHECK: exit:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
entry:
|
|
br label %loop
|
|
loop:
|
|
%iv = phi i64 [ -2147483648, %entry ], [ %iv.next, %loop ]
|
|
%iv.next = add i64 %iv, 1
|
|
%narrow.iv = trunc i64 %iv to i32
|
|
%cmp = icmp slt i32 %narrow.iv, %n
|
|
br i1 %cmp, label %loop, label %exit
|
|
exit:
|
|
ret void
|
|
}
|
|
|
|
; Trunc changes the actual value of the IV, so it is invalid to remove it: SINT_MIN - 1.
|
|
define void @test_06(i32 %n) {
|
|
;
|
|
; CHECK-LABEL: @test_06(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: br label [[LOOP:%.*]]
|
|
; CHECK: loop:
|
|
; CHECK-NEXT: br i1 false, label [[LOOP]], label [[EXIT:%.*]]
|
|
; CHECK: exit:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
entry:
|
|
br label %loop
|
|
loop:
|
|
%iv = phi i64 [ -2147483649, %entry ], [ %iv.next, %loop ]
|
|
%iv.next = add i64 %iv, 1
|
|
%narrow.iv = trunc i64 %iv to i32
|
|
%cmp = icmp slt i32 %narrow.iv, %n
|
|
br i1 %cmp, label %loop, label %exit
|
|
exit:
|
|
ret void
|
|
}
|
|
|
|
; General case: without extra knowledge, trunc cannot be eliminated.
|
|
define void @test_00_unsigned(i64 %start, i32 %n) {
|
|
; CHECK-LABEL: @test_00_unsigned(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: br label [[LOOP:%.*]]
|
|
; CHECK: loop:
|
|
; CHECK-NEXT: [[IV:%.*]] = phi i64 [ [[START:%.*]], [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ]
|
|
; CHECK-NEXT: [[IV_NEXT]] = add i64 [[IV]], 1
|
|
; CHECK-NEXT: [[NARROW_IV:%.*]] = trunc i64 [[IV]] to i32
|
|
; CHECK-NEXT: [[CMP:%.*]] = icmp ult i32 [[NARROW_IV]], [[N:%.*]]
|
|
; CHECK-NEXT: br i1 [[CMP]], label [[LOOP]], label [[EXIT:%.*]]
|
|
; CHECK: exit:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
entry:
|
|
br label %loop
|
|
loop:
|
|
%iv = phi i64 [ %start, %entry ], [ %iv.next, %loop ]
|
|
%iv.next = add i64 %iv, 1
|
|
%narrow.iv = trunc i64 %iv to i32
|
|
%cmp = icmp ult i32 %narrow.iv, %n
|
|
br i1 %cmp, label %loop, label %exit
|
|
exit:
|
|
ret void
|
|
}
|
|
|
|
; FIXME: Harmful LFTR should be thrown away.
|
|
define void @test_01_unsigned(i32 %n) {
|
|
; CHECK-LABEL: @test_01_unsigned(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[TMP0:%.*]] = add i32 [[N:%.*]], 1
|
|
; CHECK-NEXT: br label [[LOOP:%.*]]
|
|
; CHECK: loop:
|
|
; CHECK-NEXT: [[IV:%.*]] = phi i64 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ]
|
|
; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i64 [[IV]], 1
|
|
; CHECK-NEXT: [[LFTR_WIDEIV:%.*]] = trunc i64 [[IV_NEXT]] to i32
|
|
; CHECK-NEXT: [[EXITCOND:%.*]] = icmp ne i32 [[LFTR_WIDEIV]], [[TMP0]]
|
|
; CHECK-NEXT: br i1 [[EXITCOND]], label [[LOOP]], label [[EXIT:%.*]]
|
|
; CHECK: exit:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
entry:
|
|
br label %loop
|
|
loop:
|
|
%iv = phi i64 [ 0, %entry ], [ %iv.next, %loop ]
|
|
%iv.next = add i64 %iv, 1
|
|
%narrow.iv = trunc i64 %iv to i32
|
|
%cmp = icmp ult i32 %narrow.iv, %n
|
|
br i1 %cmp, label %loop, label %exit
|
|
exit:
|
|
ret void
|
|
}
|
|
|
|
; Max value at which we can eliminate trunc: UINT_MAX - 1.
|
|
define void @test_02_unsigned(i32 %n) {
|
|
; CHECK-LABEL: @test_02_unsigned(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[TMP0:%.*]] = icmp ugt i32 [[N:%.*]], -2
|
|
; CHECK-NEXT: [[UMAX:%.*]] = select i1 [[TMP0]], i32 [[N]], i32 -2
|
|
; CHECK-NEXT: [[TMP1:%.*]] = add nsw i32 [[UMAX]], 1
|
|
; CHECK-NEXT: br label [[LOOP:%.*]]
|
|
; CHECK: loop:
|
|
; CHECK-NEXT: [[IV:%.*]] = phi i64 [ 4294967294, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ]
|
|
; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i64 [[IV]], 1
|
|
; CHECK-NEXT: [[LFTR_WIDEIV:%.*]] = trunc i64 [[IV_NEXT]] to i32
|
|
; CHECK-NEXT: [[EXITCOND:%.*]] = icmp ne i32 [[LFTR_WIDEIV]], [[TMP1]]
|
|
; CHECK-NEXT: br i1 [[EXITCOND]], label [[LOOP]], label [[EXIT:%.*]]
|
|
; CHECK: exit:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
entry:
|
|
br label %loop
|
|
loop:
|
|
%iv = phi i64 [ 4294967294, %entry ], [ %iv.next, %loop ]
|
|
%iv.next = add i64 %iv, 1
|
|
%narrow.iv = trunc i64 %iv to i32
|
|
%cmp = icmp ult i32 %narrow.iv, %n
|
|
br i1 %cmp, label %loop, label %exit
|
|
exit:
|
|
ret void
|
|
}
|
|
|
|
; If we start from UINT_MAX then the predicate is always false.
|
|
define void @test_03_unsigned(i32 %n) {
|
|
; CHECK-LABEL: @test_03_unsigned(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: br label [[LOOP:%.*]]
|
|
; CHECK: loop:
|
|
; CHECK-NEXT: br i1 false, label [[LOOP]], label [[EXIT:%.*]]
|
|
; CHECK: exit:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
entry:
|
|
br label %loop
|
|
loop:
|
|
%iv = phi i64 [ 4294967295, %entry ], [ %iv.next, %loop ]
|
|
%iv.next = add i64 %iv, 1
|
|
%narrow.iv = trunc i64 %iv to i32
|
|
%cmp = icmp ult i32 %narrow.iv, %n
|
|
br i1 %cmp, label %loop, label %exit
|
|
exit:
|
|
ret void
|
|
}
|
|
|
|
; Minimum value at which we can apply the transform: UINT_MIN.
|
|
define void @test_04_unsigned(i32 %n) {
|
|
; CHECK-LABEL: @test_04_unsigned(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[TMP0:%.*]] = add i32 [[N:%.*]], 1
|
|
; CHECK-NEXT: br label [[LOOP:%.*]]
|
|
; CHECK: loop:
|
|
; CHECK-NEXT: [[IV:%.*]] = phi i64 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ]
|
|
; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i64 [[IV]], 1
|
|
; CHECK-NEXT: [[LFTR_WIDEIV:%.*]] = trunc i64 [[IV_NEXT]] to i32
|
|
; CHECK-NEXT: [[EXITCOND:%.*]] = icmp ne i32 [[LFTR_WIDEIV]], [[TMP0]]
|
|
; CHECK-NEXT: br i1 [[EXITCOND]], label [[LOOP]], label [[EXIT:%.*]]
|
|
; CHECK: exit:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
entry:
|
|
br label %loop
|
|
loop:
|
|
%iv = phi i64 [ 0, %entry ], [ %iv.next, %loop ]
|
|
%iv.next = add i64 %iv, 1
|
|
%narrow.iv = trunc i64 %iv to i32
|
|
%cmp = icmp ult i32 %narrow.iv, %n
|
|
br i1 %cmp, label %loop, label %exit
|
|
exit:
|
|
ret void
|
|
}
|
|
|
|
; Start from 1.
|
|
define void @test_05_unsigned(i32 %n) {
|
|
; CHECK-LABEL: @test_05_unsigned(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[TMP0:%.*]] = icmp ugt i32 [[N:%.*]], 1
|
|
; CHECK-NEXT: [[UMAX:%.*]] = select i1 [[TMP0]], i32 [[N]], i32 1
|
|
; CHECK-NEXT: [[TMP1:%.*]] = add i32 [[UMAX]], 1
|
|
; CHECK-NEXT: br label [[LOOP:%.*]]
|
|
; CHECK: loop:
|
|
; CHECK-NEXT: [[IV:%.*]] = phi i64 [ 1, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ]
|
|
; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i64 [[IV]], 1
|
|
; CHECK-NEXT: [[LFTR_WIDEIV:%.*]] = trunc i64 [[IV_NEXT]] to i32
|
|
; CHECK-NEXT: [[EXITCOND:%.*]] = icmp ne i32 [[LFTR_WIDEIV]], [[TMP1]]
|
|
; CHECK-NEXT: br i1 [[EXITCOND]], label [[LOOP]], label [[EXIT:%.*]]
|
|
; CHECK: exit:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
entry:
|
|
br label %loop
|
|
loop:
|
|
%iv = phi i64 [ 1, %entry ], [ %iv.next, %loop ]
|
|
%iv.next = add i64 %iv, 1
|
|
%narrow.iv = trunc i64 %iv to i32
|
|
%cmp = icmp ult i32 %narrow.iv, %n
|
|
br i1 %cmp, label %loop, label %exit
|
|
exit:
|
|
ret void
|
|
}
|
|
|
|
; Trunc changes the actual value of the IV, so it is invalid to remove it: UINT_MIN - 1.
|
|
define void @test_06_unsigned(i32 %n) {
|
|
; CHECK-LABEL: @test_06_unsigned(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: br label [[LOOP:%.*]]
|
|
; CHECK: loop:
|
|
; CHECK-NEXT: br i1 false, label [[LOOP]], label [[EXIT:%.*]]
|
|
; CHECK: exit:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
entry:
|
|
br label %loop
|
|
loop:
|
|
%iv = phi i64 [ -1, %entry ], [ %iv.next, %loop ]
|
|
%iv.next = add i64 %iv, 1
|
|
%narrow.iv = trunc i64 %iv to i32
|
|
%cmp = icmp ult i32 %narrow.iv, %n
|
|
br i1 %cmp, label %loop, label %exit
|
|
exit:
|
|
ret void
|
|
}
|
|
|
|
; Do not eliminate trunc if it is used by something different from icmp.
|
|
define void @test_07(i32* %p, i32 %n) {
|
|
; CHECK-LABEL: @test_07(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[TMP0:%.*]] = icmp sgt i32 [[N:%.*]], 0
|
|
; CHECK-NEXT: [[SMAX:%.*]] = select i1 [[TMP0]], i32 [[N]], i32 0
|
|
; CHECK-NEXT: [[TMP1:%.*]] = add nuw i32 [[SMAX]], 1
|
|
; CHECK-NEXT: [[WIDE_TRIP_COUNT:%.*]] = zext i32 [[TMP1]] to i64
|
|
; CHECK-NEXT: br label [[LOOP:%.*]]
|
|
; CHECK: loop:
|
|
; CHECK-NEXT: [[IV:%.*]] = phi i64 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ]
|
|
; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i64 [[IV]], 1
|
|
; CHECK-NEXT: [[NARROW_IV:%.*]] = trunc i64 [[IV]] to i32
|
|
; CHECK-NEXT: store i32 [[NARROW_IV]], i32* [[P:%.*]], align 4
|
|
; CHECK-NEXT: [[EXITCOND:%.*]] = icmp ne i64 [[IV_NEXT]], [[WIDE_TRIP_COUNT]]
|
|
; CHECK-NEXT: br i1 [[EXITCOND]], label [[LOOP]], label [[EXIT:%.*]]
|
|
; CHECK: exit:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
entry:
|
|
br label %loop
|
|
loop:
|
|
%iv = phi i64 [ 0, %entry ], [ %iv.next, %loop ]
|
|
%iv.next = add i64 %iv, 1
|
|
%narrow.iv = trunc i64 %iv to i32
|
|
store i32 %narrow.iv, i32* %p
|
|
%cmp = icmp slt i32 %narrow.iv, %n
|
|
br i1 %cmp, label %loop, label %exit
|
|
exit:
|
|
ret void
|
|
}
|
|
|
|
; Check that we can eliminate both signed and unsigned compare.
|
|
define void @test_08(i32 %n) {
|
|
; CHECK-LABEL: @test_08(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[ZEXT:%.*]] = zext i32 [[N:%.*]] to i64
|
|
; CHECK-NEXT: [[SEXT:%.*]] = sext i32 [[N]] to i64
|
|
; CHECK-NEXT: br label [[LOOP:%.*]]
|
|
; CHECK: loop:
|
|
; CHECK-NEXT: [[IV:%.*]] = phi i64 [ 1, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ]
|
|
; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i64 [[IV]], 1
|
|
; CHECK-NEXT: [[TMP0:%.*]] = icmp slt i64 [[IV]], [[SEXT]]
|
|
; CHECK-NEXT: [[TMP1:%.*]] = icmp ult i64 [[IV]], [[ZEXT]]
|
|
; CHECK-NEXT: [[CMP:%.*]] = and i1 [[TMP0]], [[TMP1]]
|
|
; CHECK-NEXT: br i1 [[CMP]], label [[LOOP]], label [[EXIT:%.*]]
|
|
; CHECK: exit:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
entry:
|
|
br label %loop
|
|
loop:
|
|
%iv = phi i64 [ 1, %entry ], [ %iv.next, %loop ]
|
|
%iv.next = add i64 %iv, 1
|
|
%narrow.iv = trunc i64 %iv to i32
|
|
%cmp1 = icmp slt i32 %narrow.iv, %n
|
|
%cmp2 = icmp ult i32 %narrow.iv, %n
|
|
%cmp = and i1 %cmp1, %cmp2
|
|
br i1 %cmp, label %loop, label %exit
|
|
exit:
|
|
ret void
|
|
}
|
|
|
|
; Widen NE as unsigned.
|
|
define void @test_09(i32 %n) {
|
|
; CHECK-LABEL: @test_09(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[ZEXT:%.*]] = zext i32 [[N:%.*]] to i64
|
|
; CHECK-NEXT: br label [[LOOP:%.*]]
|
|
; CHECK: loop:
|
|
; CHECK-NEXT: [[IV:%.*]] = phi i64 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ]
|
|
; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i64 [[IV]], 1
|
|
; CHECK-NEXT: [[TMP0:%.*]] = icmp ne i64 [[IV]], [[ZEXT]]
|
|
; CHECK-NEXT: br i1 [[TMP0]], label [[LOOP]], label [[EXIT:%.*]]
|
|
; CHECK: exit:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
entry:
|
|
br label %loop
|
|
loop:
|
|
%iv = phi i64 [ 0, %entry ], [ %iv.next, %loop ]
|
|
%iv.next = add i64 %iv, 1
|
|
%narrow.iv = trunc i64 %iv to i32
|
|
%cmp = icmp ne i32 %narrow.iv, %n
|
|
br i1 %cmp, label %loop, label %exit
|
|
exit:
|
|
ret void
|
|
}
|
|
|
|
; Widen NE as signed.
|
|
define void @test_10(i32 %n) {
|
|
; CHECK-LABEL: @test_10(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[TMP0:%.*]] = add i32 [[N:%.*]], 100
|
|
; CHECK-NEXT: [[TMP1:%.*]] = zext i32 [[TMP0]] to i64
|
|
; CHECK-NEXT: [[TMP2:%.*]] = icmp ult i64 [[TMP1]], 90
|
|
; CHECK-NEXT: [[UMIN:%.*]] = select i1 [[TMP2]], i64 [[TMP1]], i64 90
|
|
; CHECK-NEXT: [[TMP3:%.*]] = add nuw nsw i64 [[UMIN]], -99
|
|
; CHECK-NEXT: br label [[LOOP:%.*]]
|
|
; CHECK: loop:
|
|
; CHECK-NEXT: [[IV:%.*]] = phi i64 [ -100, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ]
|
|
; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i64 [[IV]], 1
|
|
; CHECK-NEXT: [[EXITCOND:%.*]] = icmp ne i64 [[IV_NEXT]], [[TMP3]]
|
|
; CHECK-NEXT: br i1 [[EXITCOND]], label [[LOOP]], label [[EXIT:%.*]]
|
|
; CHECK: exit:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
entry:
|
|
br label %loop
|
|
loop:
|
|
%iv = phi i64 [ -100, %entry ], [ %iv.next, %loop ]
|
|
%iv.next = add i64 %iv, 1
|
|
%narrow.iv = trunc i64 %iv to i32
|
|
%trunccmp = icmp ne i32 %narrow.iv, %n
|
|
%negcmp = icmp slt i64 %iv, -10
|
|
%cmp = and i1 %trunccmp, %negcmp
|
|
br i1 %cmp, label %loop, label %exit
|
|
exit:
|
|
ret void
|
|
}
|
|
|
|
define void @test_11() {
|
|
; CHECK-LABEL: @test_11(
|
|
; CHECK-NEXT: br label [[BB1:%.*]]
|
|
; CHECK: bb1:
|
|
; CHECK-NEXT: br i1 undef, label [[BB2:%.*]], label [[BB6:%.*]]
|
|
; CHECK: bb2:
|
|
; CHECK-NEXT: br i1 undef, label [[BB3:%.*]], label [[BB4:%.*]]
|
|
; CHECK: bb3:
|
|
; CHECK-NEXT: br label [[BB4]]
|
|
; CHECK: bb4:
|
|
; CHECK-NEXT: br label [[BB6]]
|
|
; CHECK: bb5:
|
|
; CHECK-NEXT: [[_TMP24:%.*]] = icmp slt i16 undef, 0
|
|
; CHECK-NEXT: br i1 [[_TMP24]], label [[BB5:%.*]], label [[BB5]]
|
|
; CHECK: bb6:
|
|
; CHECK-NEXT: br i1 false, label [[BB1]], label [[BB7:%.*]]
|
|
; CHECK: bb7:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
br label %bb1
|
|
|
|
bb1: ; preds = %bb6, %0
|
|
%e.5.0 = phi i32 [ 0, %0 ], [ %_tmp32, %bb6 ]
|
|
br i1 undef, label %bb2, label %bb6
|
|
|
|
bb2: ; preds = %bb1
|
|
%_tmp15 = trunc i32 %e.5.0 to i16
|
|
br i1 undef, label %bb3, label %bb4
|
|
|
|
bb3: ; preds = %bb2
|
|
br label %bb4
|
|
|
|
bb4: ; preds = %bb3, %bb2
|
|
br label %bb6
|
|
|
|
bb5: ; preds = %bb5, %bb5
|
|
%_tmp24 = icmp slt i16 %_tmp15, 0
|
|
br i1 %_tmp24, label %bb5, label %bb5
|
|
|
|
bb6: ; preds = %bb4, %bb1
|
|
%_tmp32 = add nuw nsw i32 %e.5.0, 1
|
|
br i1 false, label %bb1, label %bb7
|
|
|
|
bb7: ; preds = %bb6
|
|
ret void
|
|
}
|
|
|
|
; Show that we can turn signed comparison to unsigned and use zext while
|
|
; comparing non-negative values.
|
|
define void @test_12(i32* %p) {
|
|
; CHECK-LABEL: @test_12(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[N:%.*]] = load i32, i32* [[P:%.*]], align 4, [[RNG0:!range !.*]]
|
|
; CHECK-NEXT: [[TMP0:%.*]] = icmp sgt i32 [[N]], 1
|
|
; CHECK-NEXT: [[SMAX:%.*]] = select i1 [[TMP0]], i32 [[N]], i32 1
|
|
; CHECK-NEXT: [[WIDE_TRIP_COUNT:%.*]] = zext i32 [[SMAX]] to i64
|
|
; CHECK-NEXT: br label [[LOOP:%.*]]
|
|
; CHECK: loop:
|
|
; CHECK-NEXT: [[IV:%.*]] = phi i64 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ]
|
|
; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i64 [[IV]], 1
|
|
; CHECK-NEXT: [[EXITCOND:%.*]] = icmp ne i64 [[IV_NEXT]], [[WIDE_TRIP_COUNT]]
|
|
; CHECK-NEXT: br i1 [[EXITCOND]], label [[LOOP]], label [[EXIT:%.*]]
|
|
; CHECK: exit:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
entry:
|
|
%n = load i32, i32* %p, !range !0
|
|
br label %loop
|
|
loop:
|
|
%iv = phi i64 [ 0, %entry ], [ %iv.next, %loop ]
|
|
%iv.next = add i64 %iv, 1
|
|
%narrow.iv = trunc i64 %iv.next to i32
|
|
%cmp = icmp slt i32 %narrow.iv, %n
|
|
br i1 %cmp, label %loop, label %exit
|
|
exit:
|
|
ret void
|
|
}
|
|
|
|
define void @test_13a(i32 %n) {
|
|
;
|
|
; CHECK-LABEL: @test_13a(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[ZEXT:%.*]] = zext i32 1024 to i64
|
|
; CHECK-NEXT: br label [[LOOP:%.*]]
|
|
; CHECK: loop:
|
|
; CHECK-NEXT: [[IV:%.*]] = phi i64 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ]
|
|
; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i64 [[IV]], 2
|
|
; CHECK-NEXT: [[TMP0:%.*]] = icmp ne i64 [[IV]], [[ZEXT]]
|
|
; CHECK-NEXT: br i1 [[TMP0]], label [[LOOP]], label [[EXIT:%.*]]
|
|
; CHECK: exit:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
entry:
|
|
br label %loop
|
|
loop:
|
|
%iv = phi i64 [ 0, %entry ], [ %iv.next, %loop ]
|
|
%iv.next = add nsw nuw i64 %iv, 2
|
|
%narrow.iv = trunc i64 %iv to i32
|
|
%cmp = icmp ne i32 1024, %narrow.iv
|
|
br i1 %cmp, label %loop, label %exit
|
|
exit:
|
|
ret void
|
|
}
|
|
|
|
define void @test_13b(i32 %n) {
|
|
;
|
|
; CHECK-LABEL: @test_13b(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[ZEXT:%.*]] = zext i32 1024 to i64
|
|
; CHECK-NEXT: br label [[LOOP:%.*]]
|
|
; CHECK: loop:
|
|
; CHECK-NEXT: [[IV:%.*]] = phi i64 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ]
|
|
; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i64 [[IV]], 2
|
|
; CHECK-NEXT: [[TMP0:%.*]] = icmp ult i64 [[IV]], [[ZEXT]]
|
|
; CHECK-NEXT: br i1 [[TMP0]], label [[LOOP]], label [[EXIT:%.*]]
|
|
; CHECK: exit:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
entry:
|
|
br label %loop
|
|
loop:
|
|
%iv = phi i64 [ 0, %entry ], [ %iv.next, %loop ]
|
|
%iv.next = add nsw nuw i64 %iv, 2
|
|
%narrow.iv = trunc i64 %iv to i32
|
|
%cmp = icmp ugt i32 1024, %narrow.iv
|
|
br i1 %cmp, label %loop, label %exit
|
|
exit:
|
|
ret void
|
|
}
|
|
|
|
define void @test_13c(i32 %n) {
|
|
;
|
|
; CHECK-LABEL: @test_13c(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[ZEXT:%.*]] = zext i32 1024 to i64
|
|
; CHECK-NEXT: br label [[LOOP:%.*]]
|
|
; CHECK: loop:
|
|
; CHECK-NEXT: [[IV:%.*]] = phi i64 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ]
|
|
; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i64 [[IV]], 2
|
|
; CHECK-NEXT: [[TMP0:%.*]] = icmp ult i64 [[IV]], [[ZEXT]]
|
|
; CHECK-NEXT: br i1 [[TMP0]], label [[LOOP]], label [[EXIT:%.*]]
|
|
; CHECK: exit:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
entry:
|
|
br label %loop
|
|
loop:
|
|
%iv = phi i64 [ 0, %entry ], [ %iv.next, %loop ]
|
|
%iv.next = add nsw nuw i64 %iv, 2
|
|
%narrow.iv = trunc i64 %iv to i32
|
|
%cmp = icmp sgt i32 1024, %narrow.iv
|
|
br i1 %cmp, label %loop, label %exit
|
|
exit:
|
|
ret void
|
|
}
|
|
|
|
define void @test_13d(i32 %n) {
|
|
;
|
|
; CHECK-LABEL: @test_13d(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[SEXT:%.*]] = sext i32 1024 to i64
|
|
; CHECK-NEXT: br label [[LOOP:%.*]]
|
|
; CHECK: loop:
|
|
; CHECK-NEXT: [[IV:%.*]] = phi i64 [ -20, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[LOOP]] ]
|
|
; CHECK-NEXT: [[IV_NEXT]] = add nsw i64 [[IV]], 2
|
|
; CHECK-NEXT: [[TMP0:%.*]] = icmp slt i64 [[IV]], [[SEXT]]
|
|
; CHECK-NEXT: br i1 [[TMP0]], label [[LOOP]], label [[EXIT:%.*]]
|
|
; CHECK: exit:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
entry:
|
|
br label %loop
|
|
loop:
|
|
%iv = phi i64 [ -20, %entry ], [ %iv.next, %loop ]
|
|
%iv.next = add nsw i64 %iv, 2
|
|
%narrow.iv = trunc i64 %iv to i32
|
|
%cmp = icmp sgt i32 1024, %narrow.iv
|
|
br i1 %cmp, label %loop, label %exit
|
|
exit:
|
|
ret void
|
|
}
|
|
|
|
!0 = !{i32 0, i32 1000}
|