[llvm] [InstCombine] Fix fold of comparison of rotates (PR #223263)
Benji Smith via llvm-commits
llvm-commits at lists.llvm.org
Sun Sep 13 11:14:17 PDT 2026
https://github.com/Benjins created https://github.com/llvm/llvm-project/pull/223263
rotate(X, AmtX) == rotate(Y, AmtY) -> rotate(X, AmtX - AmtY) == Y
This fold is usually valid, but implicitly assumed that the bit width was a power of two. This is now checked and the transform doesn't fire if the bit width isn't a power of two.
Fixes https://github.com/llvm/llvm-project/issues/223262
>From c38ae0e8a65cb8eaa5abecb0d0d3e4ce278c05de Mon Sep 17 00:00:00 2001
From: Benji Smith <benjsith at gmail.com>
Date: Sun, 13 Sep 2026 13:23:36 -0400
Subject: [PATCH] [InstCombine] Fix fold of comparison of rotates
rotate(X, AmtX) == rotate(Y, AmtY) -> rotate(X, AmtX - AmtY) == Y
This fold is usually valid, but implicitly assumed that the bit width was a power of two. This is now checked and the transform doesn't fire if the bit width isn't a power of two.
Fixes https://github.com/llvm/llvm-project/issues/223262
---
.../InstCombine/InstCombineCompares.cpp | 18 ++++++++++++------
.../test/Transforms/InstCombine/icmp-rotate.ll | 14 ++++++++++++++
2 files changed, 26 insertions(+), 6 deletions(-)
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
index a7015a9ddff1b..d0c9c159a335d 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
@@ -4070,16 +4070,22 @@ foldICmpIntrinsicWithIntrinsic(ICmpInst &Cmp,
// -> 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.
+ const unsigned BW = IIOp0->getType()->getScalarSizeInBits();
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);
+
+ // Only valid assuming (2**BW) % BW == 0, which only holds for powers
+ // of two.
+ if (isPowerOf2_32(BW)) {
+ 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:
diff --git a/llvm/test/Transforms/InstCombine/icmp-rotate.ll b/llvm/test/Transforms/InstCombine/icmp-rotate.ll
index c2d03b1786535..4d4d148b30abb 100644
--- a/llvm/test/Transforms/InstCombine/icmp-rotate.ll
+++ b/llvm/test/Transforms/InstCombine/icmp-rotate.ll
@@ -233,3 +233,17 @@ define i1 @wrong_pred2(i8 %x) {
%r = icmp ugt i8 %f, 2
ret i1 %r
}
+
+; negative test - non-power-of-two bit width
+define i1 @rol_eq_npot_bw(i6 %x, i6 %y, i6 %z, i6 %w) {
+; CHECK-LABEL: @rol_eq_npot_bw(
+; CHECK-NEXT: [[F:%.*]] = tail call i6 @llvm.fshl.i6(i6 [[X:%.*]], i6 [[X]], i6 [[Z:%.*]])
+; CHECK-NEXT: [[F2:%.*]] = tail call i6 @llvm.fshl.i6(i6 [[Y:%.*]], i6 [[Y]], i6 [[W:%.*]])
+; CHECK-NEXT: [[R:%.*]] = icmp eq i6 [[F]], [[F2]]
+; CHECK-NEXT: ret i1 [[R]]
+;
+ %f = tail call i6 @llvm.fshl.i6(i6 %x, i6 %x, i6 %z)
+ %f2 = tail call i6 @llvm.fshl.i6(i6 %y, i6 %y, i6 %w)
+ %r = icmp eq i6 %f, %f2
+ ret i1 %r
+}
More information about the llvm-commits
mailing list