From 364359e4fc0a0673574a8b4e8a04039abbe9ce5e Mon Sep 17 00:00:00 2001 From: Craig Topper Date: Tue, 8 Aug 2017 20:14:11 +0000 Subject: [PATCH] [InstCombine] Support pulling left shifts through a subtract with constant LHS We already support pulling through an add with constant RHS. We can do the same for subtract. Differential Revision: https://reviews.llvm.org/D36443 llvm-svn: 310407 --- .../Transforms/InstCombine/InstCombineShifts.cpp | 14 +++++++ llvm/test/Transforms/InstCombine/sub.ll | 44 ++++++++++++++++++++++ 2 files changed, 58 insertions(+) diff --git a/llvm/lib/Transforms/InstCombine/InstCombineShifts.cpp b/llvm/lib/Transforms/InstCombine/InstCombineShifts.cpp index 5f21666..098079a 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineShifts.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineShifts.cpp @@ -510,6 +510,20 @@ Instruction *InstCombiner::FoldShiftByConstant(Value *Op0, Constant *Op1, NewRHS); } } + + // If the operand is a subtract with a constant LHS, and the shift + // is the only use, we can pull it out of the shift. + // This folds (shl (sub C1, X), C2) -> (sub (C1 << C2), (shl X, C2)) + if (isLeftShift && Op0BO->getOpcode() == Instruction::Sub && + match(Op0BO->getOperand(0), m_APInt(Op0C))) { + Constant *NewRHS = ConstantExpr::get(I.getOpcode(), + cast(Op0BO->getOperand(0)), Op1); + + Value *NewShift = Builder.CreateShl(Op0BO->getOperand(1), Op1); + NewShift->takeName(Op0BO); + + return BinaryOperator::CreateSub(NewRHS, NewShift); + } } } diff --git a/llvm/test/Transforms/InstCombine/sub.ll b/llvm/test/Transforms/InstCombine/sub.ll index d20668f..5d6d5be 100644 --- a/llvm/test/Transforms/InstCombine/sub.ll +++ b/llvm/test/Transforms/InstCombine/sub.ll @@ -1070,3 +1070,47 @@ define i64 @test61([100 x [100 x i8]]* %foo, i64 %i, i64 %j) { store i8* %gep2, i8** @dummy_global2 ret i64 %sub } + +define i32 @test62(i32 %A) { +; CHECK-LABEL: @test62( +; CHECK-NEXT: [[B:%.*]] = shl i32 [[A:%.*]], 1 +; CHECK-NEXT: [[C:%.*]] = sub i32 2, [[B]] +; CHECK-NEXT: ret i32 [[C]] +; + %B = sub i32 1, %A + %C = shl i32 %B, 1 + ret i32 %C +} + +define <2 x i32> @test62vec(<2 x i32> %A) { +; CHECK-LABEL: @test62vec( +; CHECK-NEXT: [[B:%.*]] = shl <2 x i32> [[A:%.*]], +; CHECK-NEXT: [[C:%.*]] = sub <2 x i32> , [[B]] +; CHECK-NEXT: ret <2 x i32> [[C]] +; + %B = sub <2 x i32> , %A + %C = shl <2 x i32> %B, + ret <2 x i32> %C +} + +define i32 @test63(i32 %A) { +; CHECK-LABEL: @test63( +; CHECK-NEXT: [[B:%.*]] = shl i32 [[A:%.*]], 1 +; CHECK-NEXT: ret i32 [[B]] +; + %B = sub i32 1, %A + %C = shl i32 %B, 1 + %D = sub i32 2, %C + ret i32 %D +} + +define <2 x i32> @test63vec(<2 x i32> %A) { +; CHECK-LABEL: @test63vec( +; CHECK-NEXT: [[B:%.*]] = shl <2 x i32> [[A:%.*]], +; CHECK-NEXT: ret <2 x i32> [[B]] +; + %B = sub <2 x i32> , %A + %C = shl <2 x i32> %B, + %D = sub <2 x i32> , %C + ret <2 x i32> %D +} -- 2.7.4