aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSanjay Patel <spatel@rotateright.com>2021-03-13 08:26:27 -0500
committerTom Stellard <tstellar@redhat.com>2021-03-30 14:28:12 -0700
commitff2cf8fafa5ad9a76e59fa086d969d4e2ecc3a39 (patch)
tree3f2489df82598976afdec93c536c95c3cfeb1722
parent[InstCombine] add test for zext-of-icmps; NFC (diff)
downloadllvm-project-ff2cf8fafa5ad9a76e59fa086d969d4e2ecc3a39.tar.gz
llvm-project-ff2cf8fafa5ad9a76e59fa086d969d4e2ecc3a39.tar.bz2
llvm-project-ff2cf8fafa5ad9a76e59fa086d969d4e2ecc3a39.zip
[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. (cherry picked from commit 4224a36957420744756d6a6450eb6502a1bfadc3)
-rw-r--r--llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp1
-rw-r--r--llvm/test/Transforms/InstCombine/zext-or-icmp.ll58
2 files changed, 53 insertions, 6 deletions
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp
index 0b53007bb6dc..07e68c44416d 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp
@@ -1270,6 +1270,7 @@ Instruction *InstCombinerImpl::visitZExt(ZExtInst &CI) {
ICmpInst *LHS = dyn_cast<ICmpInst>(SrcI->getOperand(0));
ICmpInst *RHS = dyn_cast<ICmpInst>(SrcI->getOperand(1));
if (LHS && RHS && LHS->hasOneUse() && RHS->hasOneUse() &&
+ LHS->getOperand(0)->getType() == RHS->getOperand(0)->getType() &&
(transformZExtICmp(LHS, CI, false) ||
transformZExtICmp(RHS, CI, false))) {
// zext (or icmp, icmp) -> or (zext icmp), (zext icmp)
diff --git a/llvm/test/Transforms/InstCombine/zext-or-icmp.ll b/llvm/test/Transforms/InstCombine/zext-or-icmp.ll
index 54ae0858aa67..5ae3d8ea0dba 100644
--- a/llvm/test/Transforms/InstCombine/zext-or-icmp.ll
+++ b/llvm/test/Transforms/InstCombine/zext-or-icmp.ll
@@ -107,17 +107,16 @@ block2:
ret i32 %conv2
}
-; FIXME: This should not end with more instructions than it started from.
+; 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: [[B11:%.*]] = zext i1 [[B1]] to i32
-; CHECK-NEXT: [[TMP1:%.*]] = xor i16 [[M]], 1
-; CHECK-NEXT: [[TMP2:%.*]] = zext i16 [[TMP1]] to i32
-; CHECK-NEXT: [[Z3:%.*]] = or i32 [[B11]], [[TMP2]]
-; CHECK-NEXT: ret i32 [[Z3]]
+; 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
@@ -126,3 +125,50 @@ define i32 @PR49475(i32 %x, i16 %y) {
%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)