123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420 |
- //===------ VirtualInstruction.cpp ------------------------------*- C++ -*-===//
- //
- // 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
- //
- //===----------------------------------------------------------------------===//
- //
- // Tools for determining which instructions are within a statement and the
- // nature of their operands.
- //
- //===----------------------------------------------------------------------===//
- #include "polly/Support/VirtualInstruction.h"
- using namespace polly;
- using namespace llvm;
- VirtualUse VirtualUse::create(Scop *S, const Use &U, LoopInfo *LI,
- bool Virtual) {
- auto *UserBB = getUseBlock(U);
- Loop *UserScope = LI->getLoopFor(UserBB);
- Instruction *UI = dyn_cast<Instruction>(U.getUser());
- ScopStmt *UserStmt = S->getStmtFor(UI);
- // Uses by PHI nodes are always reading values written by other statements,
- // except it is within a region statement.
- if (PHINode *PHI = dyn_cast<PHINode>(UI)) {
- // Handle PHI in exit block.
- if (S->getRegion().getExit() == PHI->getParent())
- return VirtualUse(UserStmt, U.get(), Inter, nullptr, nullptr);
- if (UserStmt->getEntryBlock() != PHI->getParent())
- return VirtualUse(UserStmt, U.get(), Intra, nullptr, nullptr);
- // The MemoryAccess is expected to be set if @p Virtual is true.
- MemoryAccess *IncomingMA = nullptr;
- if (Virtual) {
- if (const ScopArrayInfo *SAI =
- S->getScopArrayInfoOrNull(PHI, MemoryKind::PHI)) {
- IncomingMA = S->getPHIRead(SAI);
- assert(IncomingMA->getStatement() == UserStmt);
- }
- }
- return VirtualUse(UserStmt, U.get(), Inter, nullptr, IncomingMA);
- }
- return create(S, UserStmt, UserScope, U.get(), Virtual);
- }
- VirtualUse VirtualUse::create(Scop *S, ScopStmt *UserStmt, Loop *UserScope,
- Value *Val, bool Virtual) {
- assert(!isa<StoreInst>(Val) && "a StoreInst cannot be used");
- if (isa<BasicBlock>(Val))
- return VirtualUse(UserStmt, Val, Block, nullptr, nullptr);
- if (isa<llvm::Constant>(Val) || isa<MetadataAsValue>(Val) ||
- isa<InlineAsm>(Val))
- return VirtualUse(UserStmt, Val, Constant, nullptr, nullptr);
- // Is the value synthesizable? If the user has been pruned
- // (UserStmt == nullptr), it is either not used anywhere or is synthesizable.
- // We assume synthesizable which practically should have the same effect.
- auto *SE = S->getSE();
- if (SE->isSCEVable(Val->getType())) {
- auto *ScevExpr = SE->getSCEVAtScope(Val, UserScope);
- if (!UserStmt || canSynthesize(Val, *UserStmt->getParent(), SE, UserScope))
- return VirtualUse(UserStmt, Val, Synthesizable, ScevExpr, nullptr);
- }
- // FIXME: Inconsistency between lookupInvariantEquivClass and
- // getRequiredInvariantLoads. Querying one of them should be enough.
- auto &RIL = S->getRequiredInvariantLoads();
- if (S->lookupInvariantEquivClass(Val) || RIL.count(dyn_cast<LoadInst>(Val)))
- return VirtualUse(UserStmt, Val, Hoisted, nullptr, nullptr);
- // ReadOnly uses may have MemoryAccesses that we want to associate with the
- // use. This is why we look for a MemoryAccess here already.
- MemoryAccess *InputMA = nullptr;
- if (UserStmt && Virtual)
- InputMA = UserStmt->lookupValueReadOf(Val);
- // Uses are read-only if they have been defined before the SCoP, i.e., they
- // cannot be written to inside the SCoP. Arguments are defined before any
- // instructions, hence also before the SCoP. If the user has been pruned
- // (UserStmt == nullptr) and is not SCEVable, assume it is read-only as it is
- // neither an intra- nor an inter-use.
- if (!UserStmt || isa<Argument>(Val))
- return VirtualUse(UserStmt, Val, ReadOnly, nullptr, InputMA);
- auto Inst = cast<Instruction>(Val);
- if (!S->contains(Inst))
- return VirtualUse(UserStmt, Val, ReadOnly, nullptr, InputMA);
- // A use is inter-statement if either it is defined in another statement, or
- // there is a MemoryAccess that reads its value that has been written by
- // another statement.
- if (InputMA || (!Virtual && UserStmt != S->getStmtFor(Inst)))
- return VirtualUse(UserStmt, Val, Inter, nullptr, InputMA);
- return VirtualUse(UserStmt, Val, Intra, nullptr, nullptr);
- }
- void VirtualUse::print(raw_ostream &OS, bool Reproducible) const {
- OS << "User: [" << User->getBaseName() << "] ";
- switch (Kind) {
- case VirtualUse::Constant:
- OS << "Constant Op:";
- break;
- case VirtualUse::Block:
- OS << "BasicBlock Op:";
- break;
- case VirtualUse::Synthesizable:
- OS << "Synthesizable Op:";
- break;
- case VirtualUse::Hoisted:
- OS << "Hoisted load Op:";
- break;
- case VirtualUse::ReadOnly:
- OS << "Read-Only Op:";
- break;
- case VirtualUse::Intra:
- OS << "Intra Op:";
- break;
- case VirtualUse::Inter:
- OS << "Inter Op:";
- break;
- }
- if (Val) {
- OS << ' ';
- if (Reproducible)
- OS << '"' << Val->getName() << '"';
- else
- Val->print(OS, true);
- }
- if (ScevExpr) {
- OS << ' ';
- ScevExpr->print(OS);
- }
- if (InputMA && !Reproducible)
- OS << ' ' << InputMA;
- }
- #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
- LLVM_DUMP_METHOD void VirtualUse::dump() const {
- print(errs(), false);
- errs() << '\n';
- }
- #endif
- void VirtualInstruction::print(raw_ostream &OS, bool Reproducible) const {
- if (!Stmt || !Inst) {
- OS << "[null VirtualInstruction]";
- return;
- }
- OS << "[" << Stmt->getBaseName() << "]";
- Inst->print(OS, !Reproducible);
- }
- #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
- LLVM_DUMP_METHOD void VirtualInstruction::dump() const {
- print(errs(), false);
- errs() << '\n';
- }
- #endif
- /// Return true if @p Inst cannot be removed, even if it is nowhere referenced.
- static bool isRoot(const Instruction *Inst) {
- // The store is handled by its MemoryAccess. The load must be reached from the
- // roots in order to be marked as used.
- if (isa<LoadInst>(Inst) || isa<StoreInst>(Inst))
- return false;
- // Terminator instructions (in region statements) are required for control
- // flow.
- if (Inst->isTerminator())
- return true;
- // Writes to memory must be honored.
- if (Inst->mayWriteToMemory())
- return true;
- return false;
- }
- /// Return true for MemoryAccesses that cannot be removed because it represents
- /// an llvm::Value that is used after the SCoP.
- static bool isEscaping(MemoryAccess *MA) {
- assert(MA->isOriginalValueKind());
- Scop *S = MA->getStatement()->getParent();
- return S->isEscaping(cast<Instruction>(MA->getAccessValue()));
- }
- /// Add non-removable virtual instructions in @p Stmt to @p RootInsts.
- static void
- addInstructionRoots(ScopStmt *Stmt,
- SmallVectorImpl<VirtualInstruction> &RootInsts) {
- if (!Stmt->isBlockStmt()) {
- // In region statements the terminator statement and all statements that
- // are not in the entry block cannot be eliminated and consequently must
- // be roots.
- RootInsts.emplace_back(Stmt,
- Stmt->getRegion()->getEntry()->getTerminator());
- for (BasicBlock *BB : Stmt->getRegion()->blocks())
- if (Stmt->getRegion()->getEntry() != BB)
- for (Instruction &Inst : *BB)
- RootInsts.emplace_back(Stmt, &Inst);
- return;
- }
- for (Instruction *Inst : Stmt->getInstructions())
- if (isRoot(Inst))
- RootInsts.emplace_back(Stmt, Inst);
- }
- /// Add non-removable memory accesses in @p Stmt to @p RootInsts.
- ///
- /// @param Local If true, all writes are assumed to escape. markAndSweep
- /// algorithms can use this to be applicable to a single ScopStmt only without
- /// the risk of removing definitions required by other statements.
- /// If false, only writes for SCoP-escaping values are roots. This
- /// is global mode, where such writes must be marked by theirs uses
- /// in order to be reachable.
- static void addAccessRoots(ScopStmt *Stmt,
- SmallVectorImpl<MemoryAccess *> &RootAccs,
- bool Local) {
- for (auto *MA : *Stmt) {
- if (!MA->isWrite())
- continue;
- // Writes to arrays are always used.
- if (MA->isLatestArrayKind())
- RootAccs.push_back(MA);
- // Values are roots if they are escaping.
- else if (MA->isLatestValueKind()) {
- if (Local || isEscaping(MA))
- RootAccs.push_back(MA);
- }
- // Exit phis are, by definition, escaping.
- else if (MA->isLatestExitPHIKind())
- RootAccs.push_back(MA);
- // phi writes are only roots if we are not visiting the statement
- // containing the PHINode.
- else if (Local && MA->isLatestPHIKind())
- RootAccs.push_back(MA);
- }
- }
- /// Determine all instruction and access roots.
- static void addRoots(ScopStmt *Stmt,
- SmallVectorImpl<VirtualInstruction> &RootInsts,
- SmallVectorImpl<MemoryAccess *> &RootAccs, bool Local) {
- addInstructionRoots(Stmt, RootInsts);
- addAccessRoots(Stmt, RootAccs, Local);
- }
- /// Mark accesses and instructions as used if they are reachable from a root,
- /// walking the operand trees.
- ///
- /// @param S The SCoP to walk.
- /// @param LI The LoopInfo Analysis.
- /// @param RootInsts List of root instructions.
- /// @param RootAccs List of root accesses.
- /// @param UsesInsts[out] Receives all reachable instructions, including the
- /// roots.
- /// @param UsedAccs[out] Receives all reachable accesses, including the roots.
- /// @param OnlyLocal If non-nullptr, restricts walking to a single
- /// statement.
- static void walkReachable(Scop *S, LoopInfo *LI,
- ArrayRef<VirtualInstruction> RootInsts,
- ArrayRef<MemoryAccess *> RootAccs,
- DenseSet<VirtualInstruction> &UsedInsts,
- DenseSet<MemoryAccess *> &UsedAccs,
- ScopStmt *OnlyLocal = nullptr) {
- UsedInsts.clear();
- UsedAccs.clear();
- SmallVector<VirtualInstruction, 32> WorklistInsts;
- SmallVector<MemoryAccess *, 32> WorklistAccs;
- WorklistInsts.append(RootInsts.begin(), RootInsts.end());
- WorklistAccs.append(RootAccs.begin(), RootAccs.end());
- auto AddToWorklist = [&](VirtualUse VUse) {
- switch (VUse.getKind()) {
- case VirtualUse::Block:
- case VirtualUse::Constant:
- case VirtualUse::Synthesizable:
- case VirtualUse::Hoisted:
- break;
- case VirtualUse::ReadOnly:
- // Read-only scalars only have MemoryAccesses if ModelReadOnlyScalars is
- // enabled.
- if (!VUse.getMemoryAccess())
- break;
- [[fallthrough]];
- case VirtualUse::Inter:
- assert(VUse.getMemoryAccess());
- WorklistAccs.push_back(VUse.getMemoryAccess());
- break;
- case VirtualUse::Intra:
- WorklistInsts.emplace_back(VUse.getUser(),
- cast<Instruction>(VUse.getValue()));
- break;
- }
- };
- while (true) {
- // We have two worklists to process: Only when the MemoryAccess worklist is
- // empty, we process the instruction worklist.
- while (!WorklistAccs.empty()) {
- auto *Acc = WorklistAccs.pop_back_val();
- ScopStmt *Stmt = Acc->getStatement();
- if (OnlyLocal && Stmt != OnlyLocal)
- continue;
- auto Inserted = UsedAccs.insert(Acc);
- if (!Inserted.second)
- continue;
- if (Acc->isRead()) {
- const ScopArrayInfo *SAI = Acc->getScopArrayInfo();
- if (Acc->isLatestValueKind()) {
- MemoryAccess *DefAcc = S->getValueDef(SAI);
- // Accesses to read-only values do not have a definition.
- if (DefAcc)
- WorklistAccs.push_back(S->getValueDef(SAI));
- }
- if (Acc->isLatestAnyPHIKind()) {
- auto IncomingMAs = S->getPHIIncomings(SAI);
- WorklistAccs.append(IncomingMAs.begin(), IncomingMAs.end());
- }
- }
- if (Acc->isWrite()) {
- if (Acc->isOriginalValueKind() ||
- (Acc->isOriginalArrayKind() && Acc->getAccessValue())) {
- Loop *Scope = Stmt->getSurroundingLoop();
- VirtualUse VUse =
- VirtualUse::create(S, Stmt, Scope, Acc->getAccessValue(), true);
- AddToWorklist(VUse);
- }
- if (Acc->isOriginalAnyPHIKind()) {
- for (auto Incoming : Acc->getIncoming()) {
- VirtualUse VUse = VirtualUse::create(
- S, Stmt, LI->getLoopFor(Incoming.first), Incoming.second, true);
- AddToWorklist(VUse);
- }
- }
- if (Acc->isOriginalArrayKind())
- WorklistInsts.emplace_back(Stmt, Acc->getAccessInstruction());
- }
- }
- // If both worklists are empty, stop walking.
- if (WorklistInsts.empty())
- break;
- VirtualInstruction VInst = WorklistInsts.pop_back_val();
- ScopStmt *Stmt = VInst.getStmt();
- Instruction *Inst = VInst.getInstruction();
- // Do not process statements other than the local.
- if (OnlyLocal && Stmt != OnlyLocal)
- continue;
- auto InsertResult = UsedInsts.insert(VInst);
- if (!InsertResult.second)
- continue;
- // Add all operands to the worklists.
- PHINode *PHI = dyn_cast<PHINode>(Inst);
- if (PHI && PHI->getParent() == Stmt->getEntryBlock()) {
- if (MemoryAccess *PHIRead = Stmt->lookupPHIReadOf(PHI))
- WorklistAccs.push_back(PHIRead);
- } else {
- for (VirtualUse VUse : VInst.operands())
- AddToWorklist(VUse);
- }
- // If there is an array access, also add its MemoryAccesses to the worklist.
- const MemoryAccessList *Accs = Stmt->lookupArrayAccessesFor(Inst);
- if (!Accs)
- continue;
- for (MemoryAccess *Acc : *Accs)
- WorklistAccs.push_back(Acc);
- }
- }
- void polly::markReachable(Scop *S, LoopInfo *LI,
- DenseSet<VirtualInstruction> &UsedInsts,
- DenseSet<MemoryAccess *> &UsedAccs,
- ScopStmt *OnlyLocal) {
- SmallVector<VirtualInstruction, 32> RootInsts;
- SmallVector<MemoryAccess *, 32> RootAccs;
- if (OnlyLocal) {
- addRoots(OnlyLocal, RootInsts, RootAccs, true);
- } else {
- for (auto &Stmt : *S)
- addRoots(&Stmt, RootInsts, RootAccs, false);
- }
- walkReachable(S, LI, RootInsts, RootAccs, UsedInsts, UsedAccs, OnlyLocal);
- }
|