[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