Skip to content

Commit

Permalink
[InstCombine] Transform (icmp eq/ne rotate(X,AX),rotate(Y,AY)) -> (ic…
Browse files Browse the repository at this point in the history
…mp eq/ne rotate(Y,AX-AY))

Only do so if we don't create more instructions, so either both
rotates have one use or one of the rotates has one use and both `AX`
and `AY` are constant.
Proof: https://alive2.llvm.org/ce/z/rVmJgz

Differential Revision: https://reviews.llvm.org/D152348
  • Loading branch information
goldsteinn committed Jun 10, 2023
1 parent 1ce0265 commit 2df6309
Show file tree
Hide file tree
Showing 3 changed files with 35 additions and 17 deletions.
30 changes: 24 additions & 6 deletions llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3443,7 +3443,9 @@ Instruction *InstCombinerImpl::foldICmpEqIntrinsicWithConstant(
}

/// 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();
Expand All @@ -3461,16 +3463,32 @@ static Instruction *foldICmpIntrinsicWithIntrinsic(ICmpInst &Cmp) {
// 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;
}
Expand Down Expand Up @@ -4970,7 +4988,7 @@ Instruction *InstCombinerImpl::foldICmpEquality(ICmpInst &I) {
}
}

if (Instruction *ICmp = foldICmpIntrinsicWithIntrinsic(I))
if (Instruction *ICmp = foldICmpIntrinsicWithIntrinsic(I, Builder))
return ICmp;

// Canonicalize checking for a power-of-2-or-zero value:
Expand Down
16 changes: 8 additions & 8 deletions llvm/test/Transforms/InstCombine/icmp-equality-rotate.ll
Original file line number Diff line number Diff line change
Expand Up @@ -63,9 +63,9 @@ define i1 @cmpeq_rorr_to_rorl_multiuse_fail(i8 %x, i8 %C) {

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)
Expand All @@ -76,9 +76,9 @@ define i1 @cmpne_rorr_rorr(i8 %x, i8 %C0, i8 %C1) {

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)
Expand Down Expand Up @@ -132,10 +132,10 @@ define i1 @cmpne_rorl_rorl_multiuse1_fail(i8 %x, i8 %C0) {

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)
Expand Down
6 changes: 3 additions & 3 deletions llvm/test/Transforms/InstCombine/icmp-rotate.ll
Original file line number Diff line number Diff line change
Expand Up @@ -211,9 +211,9 @@ define i1 @wrong_pred(i8 %x, i8 %y, i8 %z) {
; negative test - rotate amounts mismatch
define i1 @amounts_mismatch(i8 %x, i8 %y, i8 %z, i8 %w) {
; CHECK-LABEL: @amounts_mismatch(
; CHECK-NEXT: [[F:%.*]] = tail call i8 @llvm.fshl.i8(i8 [[X:%.*]], i8 [[X]], i8 [[Z:%.*]])
; CHECK-NEXT: [[F2:%.*]] = tail call i8 @llvm.fshl.i8(i8 [[Y:%.*]], i8 [[Y]], i8 [[W:%.*]])
; CHECK-NEXT: [[R:%.*]] = icmp eq i8 [[F]], [[F2]]
; CHECK-NEXT: [[TMP1:%.*]] = sub i8 [[Z:%.*]], [[W:%.*]]
; CHECK-NEXT: [[TMP2:%.*]] = call i8 @llvm.fshl.i8(i8 [[X:%.*]], i8 [[X]], i8 [[TMP1]])
; CHECK-NEXT: [[R:%.*]] = icmp eq i8 [[TMP2]], [[Y:%.*]]
; CHECK-NEXT: ret i1 [[R]]
;
%f = tail call i8 @llvm.fshl.i8(i8 %x, i8 %x, i8 %z)
Expand Down

0 comments on commit 2df6309

Please sign in to comment.