[llvm] [InstCombine] Funnel shift with negative amount folds to funnel shift in opposite direction (#138334) (PR #138763)

via llvm-commits llvm-commits at lists.llvm.org
Tue May 6 14:03:32 PDT 2025


https://github.com/sallto created https://github.com/llvm/llvm-project/pull/138763

Partially fixes #138334
Combine fshl(X,X,Neg(Y)) into fshr(X,X,Y) and
fshr(X,X,Neg(Y)) into fshl(X,X,Y)

I opened this as a non-draft PR, as the second item in #138334 is not directly related to this change, therefore they can be seperate PRs.

>From a2b3cd81b835d2bfd05320f048c4c37ab1882167 Mon Sep 17 00:00:00 2001
From: sallto <thomas at saller.com.de>
Date: Tue, 6 May 2025 20:40:56 +0000
Subject: [PATCH] [InstCombine]  Funnel shift with negative amount folds to
 funnel shift in opposite direction (#138334)

Combine fshl(X,X,Neg(Y)) into fshr(X,X,Y) and
fshr(X,X,Neg(Y)) into fshl(X,X,Y).

Confirmed here: https://alive2.llvm.org/ce/z/tX9iyE
---
 .../InstCombine/InstCombineCalls.cpp          | 10 ++++++++
 llvm/test/Transforms/InstCombine/fsh.ll       | 23 +++++++++++++++++++
 2 files changed, 33 insertions(+)

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
index 844e18dd7d8c5..26e7b83f37ca8 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
@@ -2306,6 +2306,16 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) {
         return BitOp;
     }
 
+    // fshl(X, X, Neg(Y)) --> fshr(X, X, Y)
+    // fshr(X, X, Neg(Y)) --> fshl(X, X, Y)
+    Value *Y;
+    if (Op0 == Op1 && match(II->getArgOperand(2), m_Neg(m_Value(Y)))) {
+      Module *Mod = II->getModule();
+      Function *OppositeShift = Intrinsic::getOrInsertDeclaration(
+          Mod, IID == Intrinsic::fshl ? Intrinsic::fshr : Intrinsic::fshl, Ty);
+      return CallInst::Create(OppositeShift, {Op0, Op1, Y});
+    }
+
     // fshl(X, 0, Y) --> shl(X, and(Y, BitWidth - 1)) if bitwidth is a
     // power-of-2
     if (IID == Intrinsic::fshl && isPowerOf2_32(BitWidth) &&
diff --git a/llvm/test/Transforms/InstCombine/fsh.ll b/llvm/test/Transforms/InstCombine/fsh.ll
index 3ff4f9a2abf33..f05212bccaed8 100644
--- a/llvm/test/Transforms/InstCombine/fsh.ll
+++ b/llvm/test/Transforms/InstCombine/fsh.ll
@@ -1084,3 +1084,26 @@ define i8 @fshl_range_trunc(i1 %x) {
   %tr = trunc nsw i32 %fshl to i8
   ret i8 %tr
 }
+
+;; Issue #138334 negative rotate amounts can be folded into the opposite direction
+define i32 @fshl_neg_amount(i32 %x, i32 %y) {
+; CHECK-LABEL: define i32 @fshl_neg_amount(
+; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
+; CHECK-NEXT:    [[R:%.*]] = call i32 @llvm.fshr.i32(i32 [[X]], i32 [[X]], i32 [[Y]])
+; CHECK-NEXT:    ret i32 [[R]]
+;
+  %n = sub i32 0, %y
+  %r = call i32 @llvm.fshl.i32(i32 %x, i32 %x, i32 %n)
+  ret i32 %r
+}
+
+define i32 @fshr_neg_amount(i32 %x, i32 %y) {
+; CHECK-LABEL: define i32 @fshr_neg_amount(
+; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
+; CHECK-NEXT:    [[R:%.*]] = call i32 @llvm.fshl.i32(i32 [[X]], i32 [[X]], i32 [[Y]])
+; CHECK-NEXT:    ret i32 [[R]]
+;
+  %n = sub i32 0, %y
+  %r = call i32 @llvm.fshr.i32(i32 %x, i32 %x, i32 %n)
+  ret i32 %r
+}



More information about the llvm-commits mailing list