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(); @@ -3468,9 +3470,30 @@ 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, Amt0) == rotate(X, Amt1) + // -> rotate(X, Amt0 - Amt1) == X + // Do this if either both rotates have one use or if only one has one use + // and Amt0/Amt1 are constants. + if (IIOp0->getOperand(0) == IIOp1->getOperand(0)) { + unsigned OneUses = IIOp0->hasOneUse() + IIOp1->hasOneUse(); + if (OneUses == 2 || + (OneUses == 1 && match(IIOp0->getOperand(2), m_ImmConstant()) && + match(IIOp1->getOperand(2), m_ImmConstant()))) { + Module *Mod = Cmp.getModule(); + Function *Rotate = Intrinsic::getDeclaration( + Mod, IIOp0->getIntrinsicID(), Op0->getType()); + Value *SubAmt = + Builder.CreateSub(IIOp0->getOperand(2), IIOp1->getOperand(2)); + return new ICmpInst( + Pred, IIOp0->getOperand(0), + Builder.CreateCall( + Rotate, {IIOp0->getOperand(0), IIOp0->getOperand(0), SubAmt})); + } + } + break; default: break; } @@ -4970,7 +4993,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 @@ -30,9 +30,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) @@ -71,10 +71,10 @@ define i1 @cmpeq_rorlC_rorlC_multiuse1(i8 %x, i8 %C0) { ; CHECK-LABEL: @cmpeq_rorlC_rorlC_multiuse1( -; CHECK-NEXT: [[X_RORL0:%.*]] = call i8 @llvm.fshl.i8(i8 [[X:%.*]], i8 [[X]], i8 6) -; CHECK-NEXT: [[X_RORL1:%.*]] = call i8 @llvm.fshl.i8(i8 [[X]], i8 [[X]], i8 3) +; CHECK-NEXT: [[X_RORL1:%.*]] = call i8 @llvm.fshl.i8(i8 [[X:%.*]], i8 [[X]], i8 3) ; CHECK-NEXT: call void @use.i8(i8 [[X_RORL1]]) -; CHECK-NEXT: [[R:%.*]] = icmp eq i8 [[X_RORL0]], [[X_RORL1]] +; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.fshl.i8(i8 [[X]], i8 [[X]], i8 3) +; CHECK-NEXT: [[R:%.*]] = icmp eq i8 [[TMP1]], [[X]] ; CHECK-NEXT: ret i1 [[R]] ; %x_rorl0 = call i8 @llvm.fshl.i8(i8 %x, i8 %x, i8 6)