1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-11-22 18:54:02 +01:00
llvm-mirror/test/Transforms/InstCombine/zext-or-icmp.ll
Sanjay Patel 47e77705f5 [InstCombine] avoid creating an extra instruction in zext fold and possible inf-loop
The structure of this fold is suspect vs. most of instcombine
because it creates instructions and tries to delete them
immediately after.

If we don't have the operand types for the icmps, then we are
not behaving as assumed. And as shown in PR49475, we can inf-loop.
2021-03-13 08:30:51 -05:00

169 lines
5.7 KiB
LLVM

; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt < %s -instcombine -S | FileCheck %s
; Remove an icmp by using its operand in the subsequent logic directly.
define i8 @zext_or_icmp_icmp(i8 %a, i8 %b) {
; CHECK-LABEL: @zext_or_icmp_icmp(
; CHECK-NEXT: [[MASK:%.*]] = and i8 [[A:%.*]], 1
; CHECK-NEXT: [[TOBOOL2:%.*]] = icmp eq i8 [[B:%.*]], 0
; CHECK-NEXT: [[TOBOOL22:%.*]] = zext i1 [[TOBOOL2]] to i8
; CHECK-NEXT: [[TMP1:%.*]] = xor i8 [[MASK]], 1
; CHECK-NEXT: [[ZEXT3:%.*]] = or i8 [[TMP1]], [[TOBOOL22]]
; CHECK-NEXT: ret i8 [[ZEXT3]]
;
%mask = and i8 %a, 1
%toBool1 = icmp eq i8 %mask, 0
%toBool2 = icmp eq i8 %b, 0
%bothCond = or i1 %toBool1, %toBool2
%zext = zext i1 %bothCond to i8
ret i8 %zext
}
define i8 @zext_or_icmp_icmp_logical(i8 %a, i8 %b) {
; CHECK-LABEL: @zext_or_icmp_icmp_logical(
; CHECK-NEXT: [[MASK:%.*]] = and i8 [[A:%.*]], 1
; CHECK-NEXT: [[TOBOOL2:%.*]] = icmp eq i8 [[B:%.*]], 0
; CHECK-NEXT: [[TOBOOL22:%.*]] = zext i1 [[TOBOOL2]] to i8
; CHECK-NEXT: [[TMP1:%.*]] = xor i8 [[MASK]], 1
; CHECK-NEXT: [[ZEXT3:%.*]] = or i8 [[TMP1]], [[TOBOOL22]]
; CHECK-NEXT: ret i8 [[ZEXT3]]
;
%mask = and i8 %a, 1
%toBool1 = icmp eq i8 %mask, 0
%toBool2 = icmp eq i8 %b, 0
%bothCond = select i1 %toBool1, i1 true, i1 %toBool2
%zext = zext i1 %bothCond to i8
ret i8 %zext
}
; Here, widening the or from i1 to i32 and removing one of the icmps would
; widen an undef value (created by the out-of-range shift), increasing the
; range of valid values for the return, so we can't do it.
define i32 @dont_widen_undef() {
; CHECK-LABEL: @dont_widen_undef(
; CHECK-NEXT: entry:
; CHECK-NEXT: br label [[BLOCK2:%.*]]
; CHECK: block1:
; CHECK-NEXT: br label [[BLOCK2]]
; CHECK: block2:
; CHECK-NEXT: [[CMP_I:%.*]] = phi i1 [ false, [[BLOCK1:%.*]] ], [ true, [[ENTRY:%.*]] ]
; CHECK-NEXT: [[CMP115:%.*]] = phi i1 [ true, [[BLOCK1]] ], [ false, [[ENTRY]] ]
; CHECK-NEXT: [[CMP1:%.*]] = or i1 [[CMP_I]], [[CMP115]]
; CHECK-NEXT: [[CONV2:%.*]] = zext i1 [[CMP1]] to i32
; CHECK-NEXT: ret i32 [[CONV2]]
;
entry:
br label %block2
block1:
br label %block2
block2:
%m.011 = phi i32 [ 33, %entry ], [ 0, %block1 ]
%cmp.i = icmp ugt i32 %m.011, 1
%m.1.op = lshr i32 1, %m.011
%sext.mask = and i32 %m.1.op, 65535
%cmp115 = icmp ne i32 %sext.mask, 0
%cmp1 = or i1 %cmp.i, %cmp115
%conv2 = zext i1 %cmp1 to i32
ret i32 %conv2
}
define i32 @dont_widen_undef_logical() {
; CHECK-LABEL: @dont_widen_undef_logical(
; CHECK-NEXT: entry:
; CHECK-NEXT: br label [[BLOCK2:%.*]]
; CHECK: block1:
; CHECK-NEXT: br label [[BLOCK2]]
; CHECK: block2:
; CHECK-NEXT: [[CMP_I:%.*]] = phi i1 [ false, [[BLOCK1:%.*]] ], [ true, [[ENTRY:%.*]] ]
; CHECK-NEXT: [[CMP115:%.*]] = phi i1 [ true, [[BLOCK1]] ], [ false, [[ENTRY]] ]
; CHECK-NEXT: [[CMP1:%.*]] = or i1 [[CMP_I]], [[CMP115]]
; CHECK-NEXT: [[CONV2:%.*]] = zext i1 [[CMP1]] to i32
; CHECK-NEXT: ret i32 [[CONV2]]
;
entry:
br label %block2
block1:
br label %block2
block2:
%m.011 = phi i32 [ 33, %entry ], [ 0, %block1 ]
%cmp.i = icmp ugt i32 %m.011, 1
%m.1.op = lshr i32 1, %m.011
%sext.mask = and i32 %m.1.op, 65535
%cmp115 = icmp ne i32 %sext.mask, 0
%cmp1 = select i1 %cmp.i, i1 true, i1 %cmp115
%conv2 = zext i1 %cmp1 to i32
ret i32 %conv2
}
; This should not end with more instructions than it started from.
define i32 @PR49475(i32 %x, i16 %y) {
; CHECK-LABEL: @PR49475(
; CHECK-NEXT: [[M:%.*]] = and i16 [[Y:%.*]], 1
; CHECK-NEXT: [[B1:%.*]] = icmp eq i32 [[X:%.*]], 0
; CHECK-NEXT: [[B2:%.*]] = icmp eq i16 [[M]], 0
; CHECK-NEXT: [[T1:%.*]] = or i1 [[B1]], [[B2]]
; CHECK-NEXT: [[Z:%.*]] = zext i1 [[T1]] to i32
; CHECK-NEXT: ret i32 [[Z]]
;
%m = and i16 %y, 1
%b1 = icmp eq i32 %x, 0
%b2 = icmp eq i16 %m, 0
%t1 = or i1 %b1, %b2
%z = zext i1 %t1 to i32
ret i32 %z
}
; This would infinite-loop.
define i8 @PR49475_infloop(i32 %t0, i16 %insert, i64 %e, i8 %i162) {
; CHECK-LABEL: @PR49475_infloop(
; CHECK-NEXT: [[B:%.*]] = icmp eq i32 [[T0:%.*]], 0
; CHECK-NEXT: [[B2:%.*]] = icmp eq i16 [[INSERT:%.*]], 0
; CHECK-NEXT: [[T1:%.*]] = or i1 [[B]], [[B2]]
; CHECK-NEXT: [[EXT:%.*]] = zext i1 [[T1]] to i32
; CHECK-NEXT: [[AND:%.*]] = and i32 [[EXT]], [[T0]]
; CHECK-NEXT: [[TMP1:%.*]] = or i32 [[AND]], 140
; CHECK-NEXT: [[XOR1:%.*]] = zext i32 [[TMP1]] to i64
; CHECK-NEXT: [[CONV16:%.*]] = sext i8 [[I162:%.*]] to i64
; CHECK-NEXT: [[SUB17:%.*]] = sub i64 [[CONV16]], [[E:%.*]]
; CHECK-NEXT: [[SEXT:%.*]] = shl i64 [[SUB17]], 32
; CHECK-NEXT: [[CONV18:%.*]] = ashr exact i64 [[SEXT]], 32
; CHECK-NEXT: [[CMP:%.*]] = icmp sle i64 [[CONV18]], [[XOR1]]
; CHECK-NEXT: [[CONV19:%.*]] = zext i1 [[CMP]] to i16
; CHECK-NEXT: [[OR21:%.*]] = or i16 [[CONV19]], [[INSERT]]
; CHECK-NEXT: [[TRUNC44:%.*]] = trunc i16 [[OR21]] to i8
; CHECK-NEXT: [[INC:%.*]] = or i8 [[TRUNC44]], [[I162]]
; CHECK-NEXT: [[TOBOOL23_NOT:%.*]] = icmp eq i16 [[OR21]], 0
; CHECK-NEXT: call void @llvm.assume(i1 [[TOBOOL23_NOT]])
; CHECK-NEXT: ret i8 [[INC]]
;
%b = icmp eq i32 %t0, 0
%b2 = icmp eq i16 %insert, 0
%t1 = or i1 %b, %b2
%ext = zext i1 %t1 to i32
%and = and i32 %t0, %ext
%conv13 = zext i32 %and to i64
%xor = xor i64 %conv13, 140
%conv16 = sext i8 %i162 to i64
%sub17 = sub i64 %conv16, %e
%sext = shl i64 %sub17, 32
%conv18 = ashr exact i64 %sext, 32
%cmp = icmp sge i64 %xor, %conv18
%conv19 = zext i1 %cmp to i16
%or21 = or i16 %insert, %conv19
%trunc44 = trunc i16 %or21 to i8
%inc = add i8 %i162, %trunc44
%tobool23.not = icmp eq i16 %or21, 0
call void @llvm.assume(i1 %tobool23.not)
ret i8 %inc
}
declare void @llvm.assume(i1 noundef)