summaryrefslogtreecommitdiffstats
path: root/llvm/lib/Transforms/InstCombine/InstCombineShifts.cpp
diff options
context:
space:
mode:
authorRoman Lebedev <lebedev.ri@gmail.com>2019-06-29 11:51:50 +0000
committerRoman Lebedev <lebedev.ri@gmail.com>2019-06-29 11:51:50 +0000
commite3a94ba4a928e7c2c94bb82bce0e525212fe38e1 (patch)
tree4021f71cfdc9a6e587492808bec5a5ef85be41ce /llvm/lib/Transforms/InstCombine/InstCombineShifts.cpp
parentfe107fcde4d29a5d76ccbe9141a2fc8b5dd990f3 (diff)
downloadbcm5719-llvm-e3a94ba4a928e7c2c94bb82bce0e525212fe38e1.tar.gz
bcm5719-llvm-e3a94ba4a928e7c2c94bb82bce0e525212fe38e1.zip
[InstCombine] Shift amount reassociation (PR42391)
Summary: Given pattern: `(x shiftopcode Q) shiftopcode K` we should rewrite it as `x shiftopcode (Q+K)` iff `(Q+K) u< bitwidth(x)` This is valid for any shift, but they must be identical. * https://rise4fun.com/Alive/9E2 * exact on both lshr => exact https://rise4fun.com/Alive/plHk * exact on both ashr => exact https://rise4fun.com/Alive/QDAA * nuw on both shl => nuw https://rise4fun.com/Alive/5Uk * nsw on both shl => nsw https://rise4fun.com/Alive/0plg Should fix [[ https://bugs.llvm.org/show_bug.cgi?id=42391 | PR42391]]. Reviewers: spatel, nikic, RKSimon Reviewed By: nikic Subscribers: llvm-commits Tags: #llvm Differential Revision: https://reviews.llvm.org/D63812 llvm-svn: 364712
Diffstat (limited to 'llvm/lib/Transforms/InstCombine/InstCombineShifts.cpp')
-rw-r--r--llvm/lib/Transforms/InstCombine/InstCombineShifts.cpp48
1 files changed, 48 insertions, 0 deletions
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineShifts.cpp b/llvm/lib/Transforms/InstCombine/InstCombineShifts.cpp
index 655f40a0de0..1558795b530 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineShifts.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineShifts.cpp
@@ -20,6 +20,50 @@ using namespace PatternMatch;
#define DEBUG_TYPE "instcombine"
+// Given pattern:
+// (x shiftopcode Q) shiftopcode K
+// we should rewrite it as
+// x shiftopcode (Q+K) iff (Q+K) u< bitwidth(x)
+// This is valid for any shift, but they must be identical.
+static Instruction *
+reassociateShiftAmtsOfTwoSameDirectionShifts(BinaryOperator *Sh0,
+ const SimplifyQuery &SQ) {
+ // Look for: (x shiftopcode ShAmt0) shiftopcode ShAmt1
+ Value *X, *ShAmt1, *Sh1Value, *ShAmt0;
+ if (!match(Sh0, m_Shift(m_CombineAnd(m_Shift(m_Value(X), m_Value(ShAmt1)),
+ m_Value(Sh1Value)),
+ m_Value(ShAmt0))))
+ return nullptr;
+ auto *Sh1 = cast<BinaryOperator>(Sh1Value);
+
+ // The shift opcodes must be identical.
+ Instruction::BinaryOps ShiftOpcode = Sh0->getOpcode();
+ if (ShiftOpcode != Sh1->getOpcode())
+ return nullptr;
+ // Can we fold (ShAmt0+ShAmt1) ?
+ Value *NewShAmt = SimplifyBinOp(Instruction::BinaryOps::Add, ShAmt0, ShAmt1,
+ SQ.getWithInstruction(Sh0));
+ if (!NewShAmt)
+ return nullptr; // Did not simplify.
+ // Is the new shift amount smaller than the bit width?
+ // FIXME: could also rely on ConstantRange.
+ unsigned BitWidth = X->getType()->getScalarSizeInBits();
+ if (!match(NewShAmt, m_SpecificInt_ULT(APInt(BitWidth, BitWidth))))
+ return nullptr;
+ // All good, we can do this fold.
+ BinaryOperator *NewShift = BinaryOperator::Create(ShiftOpcode, X, NewShAmt);
+ // If both of the original shifts had the same flag set, preserve the flag.
+ if (ShiftOpcode == Instruction::BinaryOps::Shl) {
+ NewShift->setHasNoUnsignedWrap(Sh0->hasNoUnsignedWrap() &&
+ Sh1->hasNoUnsignedWrap());
+ NewShift->setHasNoSignedWrap(Sh0->hasNoSignedWrap() &&
+ Sh1->hasNoSignedWrap());
+ } else {
+ NewShift->setIsExact(Sh0->isExact() && Sh1->isExact());
+ }
+ return NewShift;
+}
+
Instruction *InstCombiner::commonShiftTransforms(BinaryOperator &I) {
Value *Op0 = I.getOperand(0), *Op1 = I.getOperand(1);
assert(Op0->getType() == Op1->getType());
@@ -38,6 +82,10 @@ Instruction *InstCombiner::commonShiftTransforms(BinaryOperator &I) {
if (Instruction *Res = FoldShiftByConstant(Op0, CUI, I))
return Res;
+ if (Instruction *NewShift =
+ reassociateShiftAmtsOfTwoSameDirectionShifts(&I, SQ))
+ return NewShift;
+
// (C1 shift (A add C2)) -> (C1 shift C2) shift A)
// iff A and C2 are both positive.
Value *A;
OpenPOWER on IntegriCloud