Commit 7a0debeb authored by Aleksandr Popov's avatar Aleksandr Popov
Browse files

[NFC][LoopPredication] Extract guard parsing to GuardUtils

Extract logic of parsing guards and widenable branches in order to reuse
it in the GuardWidening

Reviewed By: anna

Differential Revision: https://reviews.llvm.org/D157276
parent bc2b1193
Loading
Loading
Loading
Loading
+12 −1
Original line number Diff line number Diff line
@@ -18,11 +18,16 @@ class BasicBlock;
class Use;
class User;
class Value;
template <typename T> class SmallVectorImpl;

/// Returns true iff \p U has semantics of a guard expressed in a form of call
/// of llvm.experimental.guard intrinsic.
bool isGuard(const User *U);

/// Returns true iff \p V has semantics of llvm.experimental.widenable.condition
/// call
bool isWidenableCondition(const Value *V);

/// Returns true iff \p U is a widenable branch (that is, parseWidenableBranch
/// returns true).
bool isWidenableBranch(const User *U);
@@ -49,6 +54,12 @@ bool parseWidenableBranch(const User *U, Value *&Condition,
bool parseWidenableBranch(User *U, Use *&Cond, Use *&WC, BasicBlock *&IfTrueBB,
                          BasicBlock *&IfFalseBB);

// The guard condition is expected to be in form of:
//   cond1 && cond2 && cond3 ...
// or in case of widenable branch:
//   cond1 && cond2 && cond3 && widenable_contidion ...
// Method collects the list of checks, but skips widenable_condition.
void parseWidenableGuard(const User *U, llvm::SmallVectorImpl<Value *> &Checks);
} // llvm

#endif // LLVM_ANALYSIS_GUARDUTILS_H
+35 −0
Original line number Diff line number Diff line
@@ -19,6 +19,10 @@ bool llvm::isGuard(const User *U) {
  return match(U, m_Intrinsic<Intrinsic::experimental_guard>());
}

bool llvm::isWidenableCondition(const Value *V) {
  return match(V, m_Intrinsic<Intrinsic::experimental_widenable_condition>());
}

bool llvm::isWidenableBranch(const User *U) {
  Value *Condition, *WidenableCondition;
  BasicBlock *GuardedBB, *DeoptBB;
@@ -111,3 +115,34 @@ bool llvm::parseWidenableBranch(User *U, Use *&C,Use *&WC,
  }
  return false;
}

template <typename CallbackType>
static void parseCondition(Value *Condition, CallbackType Callback) {
  SmallVector<Value *, 4> Worklist(1, Condition);
  SmallPtrSet<Value *, 4> Visited;
  Visited.insert(Condition);
  do {
    Value *Check = Worklist.pop_back_val();
    Value *LHS, *RHS;
    if (match(Check, m_And(m_Value(LHS), m_Value(RHS)))) {
      if (Visited.insert(LHS).second)
        Worklist.push_back(LHS);
      if (Visited.insert(RHS).second)
        Worklist.push_back(RHS);
      continue;
    }
    Callback(Check);
  } while (!Worklist.empty());
}

void llvm::parseWidenableGuard(const User *U,
                               llvm::SmallVectorImpl<Value *> &Checks) {
  assert((isGuard(U) || isWidenableBranch(U)) && "Should be");
  Value *Condition = isGuard(U) ? cast<IntrinsicInst>(U)->getArgOperand(0)
                                : cast<BranchInst>(U)->getCondition();

  parseCondition(Condition, [&](Value *Check) {
    if (!isWidenableCondition(Check))
      Checks.push_back(Check);
  });
}
+16 −54
Original line number Diff line number Diff line
@@ -307,8 +307,8 @@ class LoopPredication {
  widenICmpRangeCheckDecrementingLoop(LoopICmp LatchCheck, LoopICmp RangeCheck,
                                      SCEVExpander &Expander,
                                      Instruction *Guard);
  unsigned collectChecks(SmallVectorImpl<Value *> &Checks, Value *Condition,
                         SCEVExpander &Expander, Instruction *Guard);
  unsigned widenChecks(SmallVectorImpl<Value *> &Checks, SCEVExpander &Expander,
                       Instruction *Guard);
  bool widenGuardConditions(IntrinsicInst *II, SCEVExpander &Expander);
  bool widenWidenableBranchGuardConditions(BranchInst *Guard, SCEVExpander &Expander);
  // If the loop always exits through another block in the loop, we should not
@@ -754,57 +754,16 @@ LoopPredication::widenICmpRangeCheck(ICmpInst *ICI, SCEVExpander &Expander,
  }
}

unsigned LoopPredication::collectChecks(SmallVectorImpl<Value *> &Checks,
                                        Value *Condition,
unsigned LoopPredication::widenChecks(SmallVectorImpl<Value *> &Checks,
                                      SCEVExpander &Expander,
                                      Instruction *Guard) {
  unsigned NumWidened = 0;
  // The guard condition is expected to be in form of:
  //   cond1 && cond2 && cond3 ...
  // Iterate over subconditions looking for icmp conditions which can be
  // widened across loop iterations. Widening these conditions remember the
  // resulting list of subconditions in Checks vector.
  SmallVector<Value *, 4> Worklist(1, Condition);
  SmallPtrSet<Value *, 4> Visited;
  Visited.insert(Condition);
  Value *WideableCond = nullptr;
  do {
    Value *Condition = Worklist.pop_back_val();
    Value *LHS, *RHS;
    using namespace llvm::PatternMatch;
    if (match(Condition, m_And(m_Value(LHS), m_Value(RHS)))) {
      if (Visited.insert(LHS).second)
        Worklist.push_back(LHS);
      if (Visited.insert(RHS).second)
        Worklist.push_back(RHS);
      continue;
    }

    if (match(Condition,
              m_Intrinsic<Intrinsic::experimental_widenable_condition>())) {
      // Pick any, we don't care which
      WideableCond = Condition;
      continue;
    }

    if (ICmpInst *ICI = dyn_cast<ICmpInst>(Condition)) {
      if (auto NewRangeCheck = widenICmpRangeCheck(ICI, Expander,
                                                   Guard)) {
        Checks.push_back(*NewRangeCheck);
  for (auto &Check : Checks)
    if (ICmpInst *ICI = dyn_cast<ICmpInst>(Check))
      if (auto NewRangeCheck = widenICmpRangeCheck(ICI, Expander, Guard)) {
        NumWidened++;
        continue;
      }
        Check = *NewRangeCheck;
      }

    // Save the condition as is if we can't widen it
    Checks.push_back(Condition);
  } while (!Worklist.empty());
  // At the moment, our matching logic for wideable conditions implicitly
  // assumes we preserve the form: (br (and Cond, WC())).  FIXME
  // Note that if there were multiple calls to wideable condition in the
  // traversal, we only need to keep one, and which one is arbitrary.
  if (WideableCond)
    Checks.push_back(WideableCond);
  return NumWidened;
}

@@ -815,8 +774,8 @@ bool LoopPredication::widenGuardConditions(IntrinsicInst *Guard,

  TotalConsidered++;
  SmallVector<Value *, 4> Checks;
  unsigned NumWidened = collectChecks(Checks, Guard->getOperand(0), Expander,
                                      Guard);
  parseWidenableGuard(Guard, Checks);
  unsigned NumWidened = widenChecks(Checks, Expander, Guard);
  if (NumWidened == 0)
    return false;

@@ -851,8 +810,11 @@ bool LoopPredication::widenWidenableBranchGuardConditions(

  TotalConsidered++;
  SmallVector<Value *, 4> Checks;
  unsigned NumWidened = collectChecks(Checks, BI->getCondition(),
                                      Expander, BI);
  parseWidenableGuard(BI, Checks);
  // At the moment, our matching logic for wideable conditions implicitly
  // assumes we preserve the form: (br (and Cond, WC())).  FIXME
  Checks.push_back(WC);
  unsigned NumWidened = widenChecks(Checks, Expander, BI);
  if (NumWidened == 0)
    return false;