diff options
| author | Roman Lebedev <lebedev.ri@gmail.com> | 2019-07-31 12:06:51 +0000 | 
|---|---|---|
| committer | Roman Lebedev <lebedev.ri@gmail.com> | 2019-07-31 12:06:51 +0000 | 
| commit | a686c60c45d516cc8870b77af97fa66e3578807d (patch) | |
| tree | b158455439964c51d42501f5eb53a60cf4850086 /llvm/lib | |
| parent | a9d58436af83eeeca376a0686bb13fc43d3f8ece (diff) | |
| download | bcm5719-llvm-a686c60c45d516cc8870b77af97fa66e3578807d.tar.gz bcm5719-llvm-a686c60c45d516cc8870b77af97fa66e3578807d.zip | |
[DivRemPairs] Recommit: Handling for expanded-form rem - recomposition (PR42673)
Summary:
While `-div-rem-pairs` pass can decompose rem in div+rem pair when div-rem pair
is unsupported by target, nothing performs the opposite fold.
We can't do that in InstCombine or DAGCombine since neither of those has access to TTI.
So it makes most sense to teach `-div-rem-pairs` about it.
If we matched rem in expanded form, we know we will be able to place div-rem pair
next to each other so we won't regress the situation.
Also, we shouldn't decompose rem if we matched already-decomposed form.
This is surprisingly straight-forward otherwise.
The original patch was committed in rL367288 but was reverted in rL367289
because it exposed pre-existing RAUW issues in internal data structures
of the pass; those now have been addressed in a previous patch.
https://bugs.llvm.org/show_bug.cgi?id=42673
Reviewers: spatel, RKSimon, efriedma, ZaMaZaN4iK, bogner
Reviewed By: bogner
Subscribers: bogner, hiraditya, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D65298
llvm-svn: 367419
Diffstat (limited to 'llvm/lib')
| -rw-r--r-- | llvm/lib/Transforms/Scalar/DivRemPairs.cpp | 106 | 
1 files changed, 100 insertions, 6 deletions
| diff --git a/llvm/lib/Transforms/Scalar/DivRemPairs.cpp b/llvm/lib/Transforms/Scalar/DivRemPairs.cpp index e64651d9749..5dd65d0ab0b 100644 --- a/llvm/lib/Transforms/Scalar/DivRemPairs.cpp +++ b/llvm/lib/Transforms/Scalar/DivRemPairs.cpp @@ -1,4 +1,4 @@ -//===- DivRemPairs.cpp - Hoist/decompose division and remainder -*- C++ -*-===// +//===- DivRemPairs.cpp - Hoist/[dr]ecompose division and remainder --------===//  //  // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.  // See https://llvm.org/LICENSE.txt for license information. @@ -6,7 +6,7 @@  //  //===----------------------------------------------------------------------===//  // -// This pass hoists and/or decomposes integer division and remainder +// This pass hoists and/or decomposes/recomposes integer division and remainder  // instructions to enable CFG improvements and better codegen.  //  //===----------------------------------------------------------------------===// @@ -19,20 +19,57 @@  #include "llvm/Analysis/TargetTransformInfo.h"  #include "llvm/IR/Dominators.h"  #include "llvm/IR/Function.h" +#include "llvm/IR/PatternMatch.h"  #include "llvm/Pass.h"  #include "llvm/Support/DebugCounter.h"  #include "llvm/Transforms/Scalar.h"  #include "llvm/Transforms/Utils/BypassSlowDivision.h"  using namespace llvm; +using namespace llvm::PatternMatch;  #define DEBUG_TYPE "div-rem-pairs"  STATISTIC(NumPairs, "Number of div/rem pairs"); +STATISTIC(NumRecomposed, "Number of instructions recomposed");  STATISTIC(NumHoisted, "Number of instructions hoisted");  STATISTIC(NumDecomposed, "Number of instructions decomposed");  DEBUG_COUNTER(DRPCounter, "div-rem-pairs-transform",                "Controls transformations in div-rem-pairs pass"); +namespace { +struct ExpandedMatch { +  DivRemMapKey Key; +  Instruction *Value; +}; +} // namespace + +/// See if we can match: (which is the form we expand into) +///   X - ((X ?/ Y) * Y) +/// which is equivalent to: +///   X ?% Y +static llvm::Optional<ExpandedMatch> matchExpandedRem(Instruction &I) { +  Value *Dividend, *XroundedDownToMultipleOfY; +  if (!match(&I, m_Sub(m_Value(Dividend), m_Value(XroundedDownToMultipleOfY)))) +    return llvm::None; + +  Value *Divisor; +  Instruction *Div; +  // Look for  ((X / Y) * Y) +  if (!match( +          XroundedDownToMultipleOfY, +          m_c_Mul(m_CombineAnd(m_IDiv(m_Specific(Dividend), m_Value(Divisor)), +                               m_Instruction(Div)), +                  m_Deferred(Divisor)))) +    return llvm::None; + +  ExpandedMatch M; +  M.Key.SignedOp = Div->getOpcode() == Instruction::SDiv; +  M.Key.Dividend = Dividend; +  M.Key.Divisor = Divisor; +  M.Value = &I; +  return M; +} +  /// A thin wrapper to store two values that we matched as div-rem pair.  /// We want this extra indirection to avoid dealing with RAUW'ing the map keys.  struct DivRemPairWorklistEntry { @@ -62,6 +99,16 @@ struct DivRemPairWorklistEntry {    /// In this pair, what are the divident and divisor?    Value *getDividend() const { return DivInst->getOperand(0); }    Value *getDivisor() const { return DivInst->getOperand(1); } + +  bool isRemExpanded() const { +    switch (RemInst->getOpcode()) { +    case Instruction::SRem: +    case Instruction::URem: +      return false; // single 'rem' instruction - unexpanded form. +    default: +      return true; // anything else means we have remainder in expanded form. +    } +  }  };  using DivRemWorklistTy = SmallVector<DivRemPairWorklistEntry, 4>; @@ -87,6 +134,8 @@ static DivRemWorklistTy getWorklist(Function &F) {          RemMap[DivRemMapKey(true, I.getOperand(0), I.getOperand(1))] = &I;        else if (I.getOpcode() == Instruction::URem)          RemMap[DivRemMapKey(false, I.getOperand(0), I.getOperand(1))] = &I; +      else if (auto Match = matchExpandedRem(I)) +        RemMap[Match->Key] = Match->Value;      }    } @@ -137,11 +186,42 @@ static bool optimizeDivRem(Function &F, const TargetTransformInfo &TTI,    // Process each entry in the worklist.    for (DivRemPairWorklistEntry &E : Worklist) { +    if (!DebugCounter::shouldExecute(DRPCounter)) +      continue; +      bool HasDivRemOp = TTI.hasDivRemOp(E.getType(), E.isSigned());      auto &DivInst = E.DivInst;      auto &RemInst = E.RemInst; +    const bool RemOriginallyWasInExpandedForm = E.isRemExpanded(); + +    if (HasDivRemOp && E.isRemExpanded()) { +      // The target supports div+rem but the rem is expanded. +      // We should recompose it first. +      Value *X = E.getDividend(); +      Value *Y = E.getDivisor(); +      Instruction *RealRem = E.isSigned() ? BinaryOperator::CreateSRem(X, Y) +                                          : BinaryOperator::CreateURem(X, Y); +      // Note that we place it right next to the original expanded instruction, +      // and letting further handling to move it if needed. +      RealRem->setName(RemInst->getName() + ".recomposed"); +      RealRem->insertAfter(RemInst); +      Instruction *OrigRemInst = RemInst; +      // Update AssertingVH<> with new instruction so it doesn't assert. +      RemInst = RealRem; +      // And replace the original instruction with the new one. +      OrigRemInst->replaceAllUsesWith(RealRem); +      OrigRemInst->eraseFromParent(); +      NumRecomposed++; +      // Note that we have left ((X / Y) * Y) around. +      // If it had other uses we could rewrite it as X - X % Y +    } + +    assert((!E.isRemExpanded() || !HasDivRemOp) && +           "*If* the target supports div-rem, then by now the RemInst *is* " +           "Instruction::[US]Rem."); +      // If the target supports div+rem and the instructions are in the same block      // already, there's nothing to do. The backend should handle this. If the      // target does not support div+rem, then we will decompose the rem. @@ -149,10 +229,18 @@ static bool optimizeDivRem(Function &F, const TargetTransformInfo &TTI,        continue;      bool DivDominates = DT.dominates(DivInst, RemInst); -    if (!DivDominates && !DT.dominates(RemInst, DivInst)) +    if (!DivDominates && !DT.dominates(RemInst, DivInst)) { +      // We have matching div-rem pair, but they are in two different blocks, +      // neither of which dominates one another. +      assert(!RemOriginallyWasInExpandedForm && +             "Won't happen for expanded-form rem."); +      // FIXME: We could hoist both ops to the common predecessor block?        continue; +    } -    if (!DebugCounter::shouldExecute(DRPCounter)) +    // The target does not have a single div/rem operation, +    // and the rem is already in expanded form. Nothing to do. +    if (!HasDivRemOp && E.isRemExpanded())        continue;      if (HasDivRemOp) { @@ -164,9 +252,15 @@ static bool optimizeDivRem(Function &F, const TargetTransformInfo &TTI,          DivInst->moveAfter(RemInst);        NumHoisted++;      } else { -      // The target does not have a single div/rem operation. Decompose the -      // remainder calculation as: +      // The target does not have a single div/rem operation, +      // and the rem is *not* in a already-expanded form. +      // Decompose the remainder calculation as:        // X % Y --> X - ((X / Y) * Y). + +      assert(!RemOriginallyWasInExpandedForm && +             "We should not be expanding if the rem was in expanded form to " +             "begin with."); +        Value *X = E.getDividend();        Value *Y = E.getDivisor();        Instruction *Mul = BinaryOperator::CreateMul(DivInst, Y); | 

