Skip to content

Commit dee28f9

Browse files
[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 <[email protected]>
1 parent 0e72c3d commit dee28f9

File tree

2 files changed

+88
-0
lines changed

2 files changed

+88
-0
lines changed

llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2405,6 +2405,22 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) {
24052405
matchBSwapOrBitReverse(*II, /*MatchBSwaps*/ true,
24062406
/*MatchBitReversals*/ true))
24072407
return BitOp;
2408+
2409+
// R = fshl(X, X, C2)
2410+
// fshl(R, R, C1) --> fshl(X, X, (C1 + C2) % bitsize)
2411+
Value *InnerOp;
2412+
const APInt *ShAmtInnerC, *ShAmtOuterC;
2413+
if (match(Op0, m_FShl(m_Value(InnerOp), m_Deferred(InnerOp),
2414+
m_APInt(ShAmtInnerC))) &&
2415+
match(ShAmtC, m_APInt(ShAmtOuterC)) && Op0 == Op1) {
2416+
APInt Sum = *ShAmtOuterC + *ShAmtInnerC;
2417+
APInt Modulo = Sum.urem(APInt(Sum.getBitWidth(), BitWidth));
2418+
if (Modulo.isZero())
2419+
return replaceInstUsesWith(*II, InnerOp);
2420+
Constant *ModuloC = ConstantInt::get(Ty, Modulo);
2421+
return CallInst::Create(cast<IntrinsicInst>(Op0)->getCalledFunction(),
2422+
{InnerOp, InnerOp, ModuloC});
2423+
}
24082424
}
24092425

24102426
// fshl(X, X, Neg(Y)) --> fshr(X, X, Y)

llvm/test/Transforms/InstCombine/fsh.ll

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1214,3 +1214,75 @@ define i31 @fshr_neg_amount_non_power_two(i31 %x, i31 %y) {
12141214
%r = call i31 @llvm.fshr.i31(i31 %x, i31 %x, i31 %n)
12151215
ret i31 %r
12161216
}
1217+
1218+
define i32 @rot_const_consecutive(i32 %x) {
1219+
; CHECK-LABEL: @rot_const_consecutive(
1220+
; CHECK-NEXT: [[R2:%.*]] = call i32 @llvm.fshl.i32(i32 [[X:%.*]], i32 [[X]], i32 8)
1221+
; CHECK-NEXT: ret i32 [[R2]]
1222+
;
1223+
%r = call i32 @llvm.fshl.i32(i32 %x, i32 %x, i32 13)
1224+
%r2 = call i32 @llvm.fshl.i32(i32 %r, i32 %r, i32 27)
1225+
ret i32 %r2
1226+
}
1227+
1228+
define i32 @rot_const_consecutive_multi_use(i32 %x) {
1229+
; CHECK-LABEL: @rot_const_consecutive_multi_use(
1230+
; CHECK-NEXT: [[R:%.*]] = call i32 @llvm.fshl.i32(i32 [[X:%.*]], i32 [[X]], i32 7)
1231+
; CHECK-NEXT: [[R3:%.*]] = call i32 @llvm.fshl.i32(i32 [[X]], i32 [[X]], i32 11)
1232+
; CHECK-NEXT: [[R2:%.*]] = and i32 [[R]], [[R3]]
1233+
; CHECK-NEXT: ret i32 [[R2]]
1234+
;
1235+
%r = call i32 @llvm.fshl.i32(i32 %x, i32 %x, i32 7)
1236+
%r2 = call i32 @llvm.fshl.i32(i32 %r, i32 %r, i32 4)
1237+
%and = and i32 %r, %r2
1238+
ret i32 %and
1239+
}
1240+
1241+
define i32 @rot_const_consecutive_cancel_out(i32 %x) {
1242+
; CHECK-LABEL: @rot_const_consecutive_cancel_out(
1243+
; CHECK-NEXT: ret i32 [[X:%.*]]
1244+
;
1245+
%r = call i32 @llvm.fshl.i32(i32 %x, i32 %x, i32 7)
1246+
%r2 = call i32 @llvm.fshl.i32(i32 %r, i32 %r, i32 25)
1247+
ret i32 %r2
1248+
}
1249+
1250+
;; negative test, consecutive rotates only fold if shift amounts are const
1251+
1252+
define i32 @rot_nonconst_shift(i32 %x, i32 %amt) {
1253+
; CHECK-LABEL: @rot_nonconst_shift(
1254+
; CHECK-NEXT: [[R:%.*]] = call i32 @llvm.fshl.i32(i32 [[X:%.*]], i32 [[X]], i32 7)
1255+
; CHECK-NEXT: [[R2:%.*]] = call i32 @llvm.fshl.i32(i32 [[R]], i32 [[R]], i32 [[AMT:%.*]])
1256+
; CHECK-NEXT: ret i32 [[R2]]
1257+
;
1258+
%r = call i32 @llvm.fshl.i32(i32 %x, i32 %x, i32 7)
1259+
%r2 = call i32 @llvm.fshl.i32(i32 %r, i32 %r, i32 %amt)
1260+
ret i32 %r2
1261+
}
1262+
1263+
;; negative test, 1st funnel shift isn't a rotate.
1264+
1265+
define i32 @fsh_rot(i32 %x, i32 %y) {
1266+
; CHECK-LABEL: @fsh_rot(
1267+
; CHECK-NEXT: [[FSH:%.*]] = call i32 @llvm.fshl.i32(i32 [[X:%.*]], i32 [[Y:%.*]], i32 7)
1268+
; CHECK-NEXT: [[R:%.*]] = call i32 @llvm.fshl.i32(i32 [[FSH]], i32 [[FSH]], i32 4)
1269+
; CHECK-NEXT: ret i32 [[R]]
1270+
;
1271+
%fsh = call i32 @llvm.fshl.i32(i32 %x, i32 %y, i32 7)
1272+
%r = call i32 @llvm.fshl.i32(i32 %fsh, i32 %fsh, i32 4)
1273+
ret i32 %r
1274+
}
1275+
1276+
;; negative test, 2nd funnel shift isn't a rotate.
1277+
1278+
define i32 @rot_fsh(i32 %x, i32 %y) {
1279+
; CHECK-LABEL: @rot_fsh(
1280+
; CHECK-NEXT: [[Y:%.*]] = call i32 @llvm.fshl.i32(i32 [[X:%.*]], i32 [[X]], i32 7)
1281+
; CHECK-NEXT: [[R2:%.*]] = call i32 @llvm.fshl.i32(i32 [[Y]], i32 [[R:%.*]], i32 4)
1282+
; CHECK-NEXT: ret i32 [[R2]]
1283+
;
1284+
%r = call i32 @llvm.fshl.i32(i32 %x, i32 %x, i32 7)
1285+
%r2 = call i32 @llvm.fshl.i32(i32 %r, i32 %y, i32 4)
1286+
ret i32 %r2
1287+
}
1288+

0 commit comments

Comments
 (0)