diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp --- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp @@ -3443,7 +3443,9 @@ } /// Fold an icmp with LLVM intrinsics -static Instruction *foldICmpIntrinsicWithIntrinsic(ICmpInst &Cmp) { +static Instruction * +foldICmpIntrinsicWithIntrinsic(ICmpInst &Cmp, + InstCombiner::BuilderTy &Builder) { assert(Cmp.isEquality()); ICmpInst::Predicate Pred = Cmp.getPredicate(); @@ -3461,16 +3463,32 @@ // original values. return new ICmpInst(Pred, IIOp0->getOperand(0), IIOp1->getOperand(0)); case Intrinsic::fshl: - case Intrinsic::fshr: + case Intrinsic::fshr: { // If both operands are rotated by same amount, just compare the // original values. if (IIOp0->getOperand(0) != IIOp0->getOperand(1)) break; if (IIOp1->getOperand(0) != IIOp1->getOperand(1)) break; - if (IIOp0->getOperand(2) != IIOp1->getOperand(2)) - break; - return new ICmpInst(Pred, IIOp0->getOperand(0), IIOp1->getOperand(0)); + if (IIOp0->getOperand(2) == IIOp1->getOperand(2)) + return new ICmpInst(Pred, IIOp0->getOperand(0), IIOp1->getOperand(0)); + + // rotate(X, AmtX) == rotate(Y, AmtY) + // -> rotate(X, AmtX - AmtY) == Y + // Do this if either both rotates have one use or if only one has one use + // and AmtX/AmtY are constants. + unsigned OneUses = IIOp0->hasOneUse() + IIOp1->hasOneUse(); + if (OneUses == 2 || + (OneUses == 1 && match(IIOp0->getOperand(2), m_ImmConstant()) && + match(IIOp1->getOperand(2), m_ImmConstant()))) { + Value *SubAmt = + Builder.CreateSub(IIOp0->getOperand(2), IIOp1->getOperand(2)); + Value *CombinedRotate = Builder.CreateIntrinsic( + Op0->getType(), IIOp0->getIntrinsicID(), + {IIOp0->getOperand(0), IIOp0->getOperand(0), SubAmt}); + return new ICmpInst(Pred, IIOp1->getOperand(0), CombinedRotate); + } + } break; default: break; } @@ -4970,7 +4988,7 @@ } } - if (Instruction *ICmp = foldICmpIntrinsicWithIntrinsic(I)) + if (Instruction *ICmp = foldICmpIntrinsicWithIntrinsic(I, Builder)) return ICmp; // Canonicalize checking for a power-of-2-or-zero value: diff --git a/llvm/test/Transforms/InstCombine/icmp-equality-rotate.ll b/llvm/test/Transforms/InstCombine/icmp-equality-rotate.ll --- a/llvm/test/Transforms/InstCombine/icmp-equality-rotate.ll +++ b/llvm/test/Transforms/InstCombine/icmp-equality-rotate.ll @@ -41,9 +41,9 @@ define i1 @cmpne_rorr_rorr(i8 %x, i8 %C0, i8 %C1) { ; CHECK-LABEL: @cmpne_rorr_rorr( -; CHECK-NEXT: [[X_RORR0:%.*]] = call i8 @llvm.fshr.i8(i8 [[X:%.*]], i8 [[X]], i8 [[C0:%.*]]) -; CHECK-NEXT: [[X_RORR1:%.*]] = call i8 @llvm.fshr.i8(i8 [[X]], i8 [[X]], i8 [[C1:%.*]]) -; CHECK-NEXT: [[R:%.*]] = icmp ne i8 [[X_RORR0]], [[X_RORR1]] +; CHECK-NEXT: [[TMP1:%.*]] = sub i8 [[C0:%.*]], [[C1:%.*]] +; CHECK-NEXT: [[TMP2:%.*]] = call i8 @llvm.fshr.i8(i8 [[X:%.*]], i8 [[X]], i8 [[TMP1]]) +; CHECK-NEXT: [[R:%.*]] = icmp ne i8 [[TMP2]], [[X]] ; CHECK-NEXT: ret i1 [[R]] ; %x_rorr0 = call i8 @llvm.fshr.i8(i8 %x, i8 %x, i8 %C0) @@ -54,9 +54,9 @@ define i1 @cmpne_rorrX_rorrY(i8 %x, i8 %y, i8 %C0, i8 %C1) { ; CHECK-LABEL: @cmpne_rorrX_rorrY( -; CHECK-NEXT: [[X_RORR0:%.*]] = call i8 @llvm.fshr.i8(i8 [[X:%.*]], i8 [[X]], i8 [[C0:%.*]]) -; CHECK-NEXT: [[Y_RORR1:%.*]] = call i8 @llvm.fshr.i8(i8 [[Y:%.*]], i8 [[Y]], i8 [[C1:%.*]]) -; CHECK-NEXT: [[R:%.*]] = icmp ne i8 [[X_RORR0]], [[Y_RORR1]] +; CHECK-NEXT: [[TMP1:%.*]] = sub i8 [[C0:%.*]], [[C1:%.*]] +; CHECK-NEXT: [[TMP2:%.*]] = call i8 @llvm.fshr.i8(i8 [[X:%.*]], i8 [[X]], i8 [[TMP1]]) +; CHECK-NEXT: [[R:%.*]] = icmp ne i8 [[TMP2]], [[Y:%.*]] ; CHECK-NEXT: ret i1 [[R]] ; %x_rorr0 = call i8 @llvm.fshr.i8(i8 %x, i8 %x, i8 %C0) @@ -110,10 +110,10 @@ define i1 @cmpeq_rorlXC_rorlYC_multiuse1(i8 %x, i8 %y) { ; CHECK-LABEL: @cmpeq_rorlXC_rorlYC_multiuse1( -; CHECK-NEXT: [[X_RORL0:%.*]] = call i8 @llvm.fshl.i8(i8 [[X:%.*]], i8 [[X]], i8 6) ; CHECK-NEXT: [[Y_RORL1:%.*]] = call i8 @llvm.fshl.i8(i8 [[Y:%.*]], i8 [[Y]], i8 3) ; CHECK-NEXT: call void @use.i8(i8 [[Y_RORL1]]) -; CHECK-NEXT: [[R:%.*]] = icmp eq i8 [[X_RORL0]], [[Y_RORL1]] +; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.fshl.i8(i8 [[X:%.*]], i8 [[X]], i8 3) +; CHECK-NEXT: [[R:%.*]] = icmp eq i8 [[TMP1]], [[Y]] ; CHECK-NEXT: ret i1 [[R]] ; %x_rorl0 = call i8 @llvm.fshl.i8(i8 %x, i8 %x, i8 6)