diff options
Diffstat (limited to 'contrib/llvm-project/llvm/lib/Transforms/Utils/SSAUpdaterBulk.cpp')
| -rw-r--r-- | contrib/llvm-project/llvm/lib/Transforms/Utils/SSAUpdaterBulk.cpp | 184 | 
1 files changed, 184 insertions, 0 deletions
diff --git a/contrib/llvm-project/llvm/lib/Transforms/Utils/SSAUpdaterBulk.cpp b/contrib/llvm-project/llvm/lib/Transforms/Utils/SSAUpdaterBulk.cpp new file mode 100644 index 000000000000..7de76b86817b --- /dev/null +++ b/contrib/llvm-project/llvm/lib/Transforms/Utils/SSAUpdaterBulk.cpp @@ -0,0 +1,184 @@ +//===- SSAUpdaterBulk.cpp - Unstructured SSA Update Tool ------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file implements the SSAUpdaterBulk class. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Transforms/Utils/SSAUpdaterBulk.h" +#include "llvm/Analysis/IteratedDominanceFrontier.h" +#include "llvm/IR/BasicBlock.h" +#include "llvm/IR/Dominators.h" +#include "llvm/IR/IRBuilder.h" +#include "llvm/IR/Instructions.h" +#include "llvm/IR/Use.h" +#include "llvm/IR/Value.h" + +using namespace llvm; + +#define DEBUG_TYPE "ssaupdaterbulk" + +/// Helper function for finding a block which should have a value for the given +/// user. For PHI-nodes this block is the corresponding predecessor, for other +/// instructions it's their parent block. +static BasicBlock *getUserBB(Use *U) { +  auto *User = cast<Instruction>(U->getUser()); + +  if (auto *UserPN = dyn_cast<PHINode>(User)) +    return UserPN->getIncomingBlock(*U); +  else +    return User->getParent(); +} + +/// Add a new variable to the SSA rewriter. This needs to be called before +/// AddAvailableValue or AddUse calls. +unsigned SSAUpdaterBulk::AddVariable(StringRef Name, Type *Ty) { +  unsigned Var = Rewrites.size(); +  LLVM_DEBUG(dbgs() << "SSAUpdater: Var=" << Var << ": initialized with Ty = " +                    << *Ty << ", Name = " << Name << "\n"); +  RewriteInfo RI(Name, Ty); +  Rewrites.push_back(RI); +  return Var; +} + +/// Indicate that a rewritten value is available in the specified block with the +/// specified value. +void SSAUpdaterBulk::AddAvailableValue(unsigned Var, BasicBlock *BB, Value *V) { +  assert(Var < Rewrites.size() && "Variable not found!"); +  LLVM_DEBUG(dbgs() << "SSAUpdater: Var=" << Var +                    << ": added new available value" << *V << " in " +                    << BB->getName() << "\n"); +  Rewrites[Var].Defines[BB] = V; +} + +/// Record a use of the symbolic value. This use will be updated with a +/// rewritten value when RewriteAllUses is called. +void SSAUpdaterBulk::AddUse(unsigned Var, Use *U) { +  assert(Var < Rewrites.size() && "Variable not found!"); +  LLVM_DEBUG(dbgs() << "SSAUpdater: Var=" << Var << ": added a use" << *U->get() +                    << " in " << getUserBB(U)->getName() << "\n"); +  Rewrites[Var].Uses.push_back(U); +} + +// Compute value at the given block BB. We either should already know it, or we +// should be able to recursively reach it going up dominator tree. +Value *SSAUpdaterBulk::computeValueAt(BasicBlock *BB, RewriteInfo &R, +                                      DominatorTree *DT) { +  if (!R.Defines.count(BB)) { +    if (DT->isReachableFromEntry(BB) && PredCache.get(BB).size()) { +      BasicBlock *IDom = DT->getNode(BB)->getIDom()->getBlock(); +      Value *V = computeValueAt(IDom, R, DT); +      R.Defines[BB] = V; +    } else +      R.Defines[BB] = UndefValue::get(R.Ty); +  } +  return R.Defines[BB]; +} + +/// Given sets of UsingBlocks and DefBlocks, compute the set of LiveInBlocks. +/// This is basically a subgraph limited by DefBlocks and UsingBlocks. +static void +ComputeLiveInBlocks(const SmallPtrSetImpl<BasicBlock *> &UsingBlocks, +                    const SmallPtrSetImpl<BasicBlock *> &DefBlocks, +                    SmallPtrSetImpl<BasicBlock *> &LiveInBlocks, +                    PredIteratorCache &PredCache) { +  // To determine liveness, we must iterate through the predecessors of blocks +  // where the def is live.  Blocks are added to the worklist if we need to +  // check their predecessors.  Start with all the using blocks. +  SmallVector<BasicBlock *, 64> LiveInBlockWorklist(UsingBlocks.begin(), +                                                    UsingBlocks.end()); + +  // Now that we have a set of blocks where the phi is live-in, recursively add +  // their predecessors until we find the full region the value is live. +  while (!LiveInBlockWorklist.empty()) { +    BasicBlock *BB = LiveInBlockWorklist.pop_back_val(); + +    // The block really is live in here, insert it into the set.  If already in +    // the set, then it has already been processed. +    if (!LiveInBlocks.insert(BB).second) +      continue; + +    // Since the value is live into BB, it is either defined in a predecessor or +    // live into it to.  Add the preds to the worklist unless they are a +    // defining block. +    for (BasicBlock *P : PredCache.get(BB)) { +      // The value is not live into a predecessor if it defines the value. +      if (DefBlocks.count(P)) +        continue; + +      // Otherwise it is, add to the worklist. +      LiveInBlockWorklist.push_back(P); +    } +  } +} + +/// Perform all the necessary updates, including new PHI-nodes insertion and the +/// requested uses update. +void SSAUpdaterBulk::RewriteAllUses(DominatorTree *DT, +                                    SmallVectorImpl<PHINode *> *InsertedPHIs) { +  for (auto &R : Rewrites) { +    // Compute locations for new phi-nodes. +    // For that we need to initialize DefBlocks from definitions in R.Defines, +    // UsingBlocks from uses in R.Uses, then compute LiveInBlocks, and then use +    // this set for computing iterated dominance frontier (IDF). +    // The IDF blocks are the blocks where we need to insert new phi-nodes. +    ForwardIDFCalculator IDF(*DT); +    LLVM_DEBUG(dbgs() << "SSAUpdater: rewriting " << R.Uses.size() +                      << " use(s)\n"); + +    SmallPtrSet<BasicBlock *, 2> DefBlocks; +    for (auto &Def : R.Defines) +      DefBlocks.insert(Def.first); +    IDF.setDefiningBlocks(DefBlocks); + +    SmallPtrSet<BasicBlock *, 2> UsingBlocks; +    for (Use *U : R.Uses) +      UsingBlocks.insert(getUserBB(U)); + +    SmallVector<BasicBlock *, 32> IDFBlocks; +    SmallPtrSet<BasicBlock *, 32> LiveInBlocks; +    ComputeLiveInBlocks(UsingBlocks, DefBlocks, LiveInBlocks, PredCache); +    IDF.resetLiveInBlocks(); +    IDF.setLiveInBlocks(LiveInBlocks); +    IDF.calculate(IDFBlocks); + +    // We've computed IDF, now insert new phi-nodes there. +    SmallVector<PHINode *, 4> InsertedPHIsForVar; +    for (auto *FrontierBB : IDFBlocks) { +      IRBuilder<> B(FrontierBB, FrontierBB->begin()); +      PHINode *PN = B.CreatePHI(R.Ty, 0, R.Name); +      R.Defines[FrontierBB] = PN; +      InsertedPHIsForVar.push_back(PN); +      if (InsertedPHIs) +        InsertedPHIs->push_back(PN); +    } + +    // Fill in arguments of the inserted PHIs. +    for (auto *PN : InsertedPHIsForVar) { +      BasicBlock *PBB = PN->getParent(); +      for (BasicBlock *Pred : PredCache.get(PBB)) +        PN->addIncoming(computeValueAt(Pred, R, DT), Pred); +    } + +    // Rewrite actual uses with the inserted definitions. +    SmallPtrSet<Use *, 4> ProcessedUses; +    for (Use *U : R.Uses) { +      if (!ProcessedUses.insert(U).second) +        continue; +      Value *V = computeValueAt(getUserBB(U), R, DT); +      Value *OldVal = U->get(); +      assert(OldVal && "Invalid use!"); +      // Notify that users of the existing value that it is being replaced. +      if (OldVal != V && OldVal->hasValueHandle()) +        ValueHandleBase::ValueIsRAUWd(OldVal, V); +      LLVM_DEBUG(dbgs() << "SSAUpdater: replacing " << *OldVal << " with " << *V +                        << "\n"); +      U->set(V); +    } +  } +}  | 
