[llvm] dee28f9 - [InstCombine] Rotate transformation port from SelectionDAG to InstCombine (#160628)
via llvm-commits
llvm-commits at lists.llvm.org
Fri Sep 26 21:04:56 PDT 2025
Author: Axel Sorenson
Date: 2025-09-26T21:04:52-07:00
New Revision: dee28f955583c5baa69ece5bf499a447cf3c6d29
URL: https://github.com/llvm/llvm-project/commit/dee28f955583c5baa69ece5bf499a447cf3c6d29
DIFF: https://github.com/llvm/llvm-project/commit/dee28f955583c5baa69ece5bf499a447cf3c6d29.diff
LOG: [InstCombine] Rotate transformation port from SelectionDAG to InstCombine (#160628)
The rotate transformation from
https://github.com/llvm/llvm-project/blob/72c04bb882ad70230bce309c3013d9cc2c99e9a7/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp#L10312-L10337
has no middle-end equivalent in InstCombine. The following is a port of
that transformation to InstCombine.
---------
Co-authored-by: Yingwei Zheng <dtcxzyw at qq.com>
Added:
Modified:
llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
llvm/test/Transforms/InstCombine/fsh.ll
Removed:
################################################################################
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
index 04f787aae11aa..c13c6cc9913ae 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
@@ -2405,6 +2405,22 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) {
matchBSwapOrBitReverse(*II, /*MatchBSwaps*/ true,
/*MatchBitReversals*/ true))
return BitOp;
+
+ // R = fshl(X, X, C2)
+ // fshl(R, R, C1) --> fshl(X, X, (C1 + C2) % bitsize)
+ Value *InnerOp;
+ const APInt *ShAmtInnerC, *ShAmtOuterC;
+ if (match(Op0, m_FShl(m_Value(InnerOp), m_Deferred(InnerOp),
+ m_APInt(ShAmtInnerC))) &&
+ match(ShAmtC, m_APInt(ShAmtOuterC)) && Op0 == Op1) {
+ APInt Sum = *ShAmtOuterC + *ShAmtInnerC;
+ APInt Modulo = Sum.urem(APInt(Sum.getBitWidth(), BitWidth));
+ if (Modulo.isZero())
+ return replaceInstUsesWith(*II, InnerOp);
+ Constant *ModuloC = ConstantInt::get(Ty, Modulo);
+ return CallInst::Create(cast<IntrinsicInst>(Op0)->getCalledFunction(),
+ {InnerOp, InnerOp, ModuloC});
+ }
}
// fshl(X, X, Neg(Y)) --> fshr(X, X, Y)
diff --git a/llvm/test/Transforms/InstCombine/fsh.ll b/llvm/test/Transforms/InstCombine/fsh.ll
index 0325c60997dfd..28c541e1a9eb2 100644
--- a/llvm/test/Transforms/InstCombine/fsh.ll
+++ b/llvm/test/Transforms/InstCombine/fsh.ll
@@ -1214,3 +1214,75 @@ define i31 @fshr_neg_amount_non_power_two(i31 %x, i31 %y) {
%r = call i31 @llvm.fshr.i31(i31 %x, i31 %x, i31 %n)
ret i31 %r
}
+
+define i32 @rot_const_consecutive(i32 %x) {
+; CHECK-LABEL: @rot_const_consecutive(
+; CHECK-NEXT: [[R2:%.*]] = call i32 @llvm.fshl.i32(i32 [[X:%.*]], i32 [[X]], i32 8)
+; CHECK-NEXT: ret i32 [[R2]]
+;
+ %r = call i32 @llvm.fshl.i32(i32 %x, i32 %x, i32 13)
+ %r2 = call i32 @llvm.fshl.i32(i32 %r, i32 %r, i32 27)
+ ret i32 %r2
+}
+
+define i32 @rot_const_consecutive_multi_use(i32 %x) {
+; CHECK-LABEL: @rot_const_consecutive_multi_use(
+; CHECK-NEXT: [[R:%.*]] = call i32 @llvm.fshl.i32(i32 [[X:%.*]], i32 [[X]], i32 7)
+; CHECK-NEXT: [[R3:%.*]] = call i32 @llvm.fshl.i32(i32 [[X]], i32 [[X]], i32 11)
+; CHECK-NEXT: [[R2:%.*]] = and i32 [[R]], [[R3]]
+; CHECK-NEXT: ret i32 [[R2]]
+;
+ %r = call i32 @llvm.fshl.i32(i32 %x, i32 %x, i32 7)
+ %r2 = call i32 @llvm.fshl.i32(i32 %r, i32 %r, i32 4)
+ %and = and i32 %r, %r2
+ ret i32 %and
+}
+
+define i32 @rot_const_consecutive_cancel_out(i32 %x) {
+; CHECK-LABEL: @rot_const_consecutive_cancel_out(
+; CHECK-NEXT: ret i32 [[X:%.*]]
+;
+ %r = call i32 @llvm.fshl.i32(i32 %x, i32 %x, i32 7)
+ %r2 = call i32 @llvm.fshl.i32(i32 %r, i32 %r, i32 25)
+ ret i32 %r2
+}
+
+;; negative test, consecutive rotates only fold if shift amounts are const
+
+define i32 @rot_nonconst_shift(i32 %x, i32 %amt) {
+; CHECK-LABEL: @rot_nonconst_shift(
+; CHECK-NEXT: [[R:%.*]] = call i32 @llvm.fshl.i32(i32 [[X:%.*]], i32 [[X]], i32 7)
+; CHECK-NEXT: [[R2:%.*]] = call i32 @llvm.fshl.i32(i32 [[R]], i32 [[R]], i32 [[AMT:%.*]])
+; CHECK-NEXT: ret i32 [[R2]]
+;
+ %r = call i32 @llvm.fshl.i32(i32 %x, i32 %x, i32 7)
+ %r2 = call i32 @llvm.fshl.i32(i32 %r, i32 %r, i32 %amt)
+ ret i32 %r2
+}
+
+;; negative test, 1st funnel shift isn't a rotate.
+
+define i32 @fsh_rot(i32 %x, i32 %y) {
+; CHECK-LABEL: @fsh_rot(
+; CHECK-NEXT: [[FSH:%.*]] = call i32 @llvm.fshl.i32(i32 [[X:%.*]], i32 [[Y:%.*]], i32 7)
+; CHECK-NEXT: [[R:%.*]] = call i32 @llvm.fshl.i32(i32 [[FSH]], i32 [[FSH]], i32 4)
+; CHECK-NEXT: ret i32 [[R]]
+;
+ %fsh = call i32 @llvm.fshl.i32(i32 %x, i32 %y, i32 7)
+ %r = call i32 @llvm.fshl.i32(i32 %fsh, i32 %fsh, i32 4)
+ ret i32 %r
+}
+
+;; negative test, 2nd funnel shift isn't a rotate.
+
+define i32 @rot_fsh(i32 %x, i32 %y) {
+; CHECK-LABEL: @rot_fsh(
+; CHECK-NEXT: [[Y:%.*]] = call i32 @llvm.fshl.i32(i32 [[X:%.*]], i32 [[X]], i32 7)
+; CHECK-NEXT: [[R2:%.*]] = call i32 @llvm.fshl.i32(i32 [[Y]], i32 [[R:%.*]], i32 4)
+; CHECK-NEXT: ret i32 [[R2]]
+;
+ %r = call i32 @llvm.fshl.i32(i32 %x, i32 %x, i32 7)
+ %r2 = call i32 @llvm.fshl.i32(i32 %r, i32 %y, i32 4)
+ ret i32 %r2
+}
+
More information about the llvm-commits
mailing list