From 1772f0a5a32b1de62c28020c904c8f3a1fd8f172 Mon Sep 17 00:00:00 2001 From: Sanjay Patel Date: Mon, 18 Mar 2019 14:10:11 +0000 Subject: [PATCH] [InstCombine] extend rotate-left-by-constant canonicalization to funnel shift Follow-up to: rL356338 Rotates are a special case of funnel shift where the 2 input operands are the same value, but that does not need to be a restriction for the canonicalization when the shift amount is a constant. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@356369 91177308-0d34-0410-b5e6-96231b3b80d8 --- .../InstCombine/InstCombineCalls.cpp | 19 ++++++++++--------- test/Transforms/InstCombine/fsh.ll | 10 +++++----- 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/lib/Transforms/InstCombine/InstCombineCalls.cpp b/lib/Transforms/InstCombine/InstCombineCalls.cpp index bdc235f247d..938517e64c3 100644 --- a/lib/Transforms/InstCombine/InstCombineCalls.cpp +++ b/lib/Transforms/InstCombine/InstCombineCalls.cpp @@ -2006,28 +2006,29 @@ Instruction *InstCombiner::visitCallInst(CallInst &CI) { II->setArgOperand(2, ModuloC); return II; } - // Canonicalize rotate right by constant to rotate left. This is not - // entirely arbitrary. For historical reasons, the backend may recognize - // rotate left patterns but miss rotate right patterns. - if (II->getIntrinsicID() == Intrinsic::fshr && Op0 == Op1) { - // fshr X, X, C --> fshl X, X, (BitWidth - C) + // Canonicalize funnel shift right by constant to funnel shift left. This + // is not entirely arbitrary. For historical reasons, the backend may + // recognize rotate left patterns but miss rotate right patterns. + if (II->getIntrinsicID() == Intrinsic::fshr) { + // fshr X, Y, C --> fshl X, Y, (BitWidth - C) assert(ConstantExpr::getICmp(ICmpInst::ICMP_UGT, WidthC, ShAmtC) == ConstantInt::getTrue(CmpInst::makeCmpResultType(Ty)) && "Shift amount expected to be modulo bitwidth"); Constant *LeftShiftC = ConstantExpr::getSub(WidthC, ShAmtC); Module *Mod = II->getModule(); Function *Fshl = Intrinsic::getDeclaration(Mod, Intrinsic::fshl, Ty); - return CallInst::Create(Fshl, { Op0, Op0, LeftShiftC }); + return CallInst::Create(Fshl, { Op0, Op1, LeftShiftC }); } } + // TODO: Pull this into the block above. We can handle semi-arbitrary vector + // shift amount constants as well as splats. const APInt *SA; if (match(II->getArgOperand(2), m_APInt(SA))) { uint64_t ShiftAmt = SA->urem(BitWidth); assert(ShiftAmt != 0 && "SimplifyCall should have handled zero shift"); - // Normalize to funnel shift left. - if (II->getIntrinsicID() == Intrinsic::fshr) - ShiftAmt = BitWidth - ShiftAmt; + assert(II->getIntrinsicID() == Intrinsic::fshl && + "All funnel shifts by simple constants should go left"); // fshl(X, 0, C) -> shl X, C // fshl(X, undef, C) -> shl X, C diff --git a/test/Transforms/InstCombine/fsh.ll b/test/Transforms/InstCombine/fsh.ll index 2a91a60e2c8..5aa3c63f1f5 100644 --- a/test/Transforms/InstCombine/fsh.ll +++ b/test/Transforms/InstCombine/fsh.ll @@ -271,7 +271,7 @@ define <2 x i31> @fshl_op1_undef_vec(<2 x i31> %x) { define <2 x i32> @fshr_op0_undef_vec(<2 x i32> %x) { ; CHECK-LABEL: @fshr_op0_undef_vec( -; CHECK-NEXT: [[R:%.*]] = call <2 x i32> @llvm.fshr.v2i32(<2 x i32> undef, <2 x i32> [[X:%.*]], <2 x i32> ) +; CHECK-NEXT: [[R:%.*]] = call <2 x i32> @llvm.fshl.v2i32(<2 x i32> undef, <2 x i32> [[X:%.*]], <2 x i32> ) ; CHECK-NEXT: ret <2 x i32> [[R]] ; %r = call <2 x i32> @llvm.fshr.v2i32(<2 x i32> undef, <2 x i32> %x, <2 x i32> ) @@ -280,7 +280,7 @@ define <2 x i32> @fshr_op0_undef_vec(<2 x i32> %x) { define <2 x i32> @fshr_op1_zero_vec(<2 x i32> %x) { ; CHECK-LABEL: @fshr_op1_zero_vec( -; CHECK-NEXT: [[R:%.*]] = call <2 x i32> @llvm.fshr.v2i32(<2 x i32> [[X:%.*]], <2 x i32> zeroinitializer, <2 x i32> ) +; CHECK-NEXT: [[R:%.*]] = call <2 x i32> @llvm.fshl.v2i32(<2 x i32> [[X:%.*]], <2 x i32> zeroinitializer, <2 x i32> ) ; CHECK-NEXT: ret <2 x i32> [[R]] ; %r = call <2 x i32> @llvm.fshr.v2i32(<2 x i32> %x, <2 x i32> zeroinitializer, <2 x i32> ) @@ -355,7 +355,7 @@ define i32 @fshl_constant_shift_amount_modulo_bitwidth(i32 %x, i32 %y) { define i33 @fshr_constant_shift_amount_modulo_bitwidth(i33 %x, i33 %y) { ; CHECK-LABEL: @fshr_constant_shift_amount_modulo_bitwidth( -; CHECK-NEXT: [[R:%.*]] = call i33 @llvm.fshr.i33(i33 [[X:%.*]], i33 [[Y:%.*]], i33 1) +; CHECK-NEXT: [[R:%.*]] = call i33 @llvm.fshl.i33(i33 [[X:%.*]], i33 [[Y:%.*]], i33 32) ; CHECK-NEXT: ret i33 [[R]] ; %r = call i33 @llvm.fshr.i33(i33 %x, i33 %y, i33 34) @@ -376,7 +376,7 @@ define i33 @fshr_constant_shift_amount_modulo_bitwidth_constexpr(i33 %x, i33 %y) define <2 x i32> @fshr_constant_shift_amount_modulo_bitwidth_vec(<2 x i32> %x, <2 x i32> %y) { ; CHECK-LABEL: @fshr_constant_shift_amount_modulo_bitwidth_vec( -; CHECK-NEXT: [[R:%.*]] = call <2 x i32> @llvm.fshr.v2i32(<2 x i32> [[X:%.*]], <2 x i32> [[Y:%.*]], <2 x i32> ) +; CHECK-NEXT: [[R:%.*]] = call <2 x i32> @llvm.fshl.v2i32(<2 x i32> [[X:%.*]], <2 x i32> [[Y:%.*]], <2 x i32> ) ; CHECK-NEXT: ret <2 x i32> [[R]] ; %r = call <2 x i32> @llvm.fshr.v2i32(<2 x i32> %x, <2 x i32> %y, <2 x i32> ) @@ -466,7 +466,7 @@ define i32 @fshl_both_ops_demanded(i32 %x, i32 %y) { define i33 @fshr_both_ops_demanded(i33 %x, i33 %y) { ; CHECK-LABEL: @fshr_both_ops_demanded( -; CHECK-NEXT: [[Z:%.*]] = call i33 @llvm.fshr.i33(i33 [[X:%.*]], i33 [[Y:%.*]], i33 26) +; CHECK-NEXT: [[Z:%.*]] = call i33 @llvm.fshl.i33(i33 [[X:%.*]], i33 [[Y:%.*]], i33 7) ; CHECK-NEXT: [[R:%.*]] = and i33 [[Z]], 192 ; CHECK-NEXT: ret i33 [[R]] ; -- 2.50.1