//===--- SCCVisitor.h - SIL SCC Visitor -------------------------*- C++ -*-===// // // This source file is part of the Swift.org open source project // // Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// #ifndef SWIFT_SIL_SCCVISITOR_H #define SWIFT_SIL_SCCVISITOR_H #include "swift/SILOptimizer/Analysis/Analysis.h" #include "swift/SIL/CFG.h" #include "swift/SIL/SILArgument.h" #include "swift/SIL/SILBasicBlock.h" #include "swift/SIL/SILFunction.h" #include "swift/SIL/SILInstruction.h" #include "swift/SIL/SILValue.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/PostOrderIterator.h" #include "llvm/ADT/SetVector.h" #include "llvm/ADT/SmallVector.h" #include #include namespace swift { /// A visitor class for visiting the instructions and basic block /// arguments of a SIL function one strongly connected component at a /// time in reverse post-order. /// /// Inherit from this in the usual CRTP fashion and define a visit() /// function. This function will get called with a vector of /// pointer-to-ValueBase which are the elements of the SCC. template class SCCVisitor { public: SCCVisitor(SILFunction &F) : F(F), CurrentNum(0) {} ~SCCVisitor() { cleanup(); } ImplClass &asImpl() { return static_cast(*this); } void visit(llvm::SmallVectorImpl &SCC) { } void run() { llvm::ReversePostOrderTraversal RPOT(&F); for (auto Iter = RPOT.begin(), E = RPOT.end(); Iter != E; ++Iter) { auto *BB = *Iter; for (auto &I : *BB) if (!Visited.count(&I)) DFS(&I); } cleanup(); } private: struct DFSInfo { ValueBase *Value; int DFSNum; int LowNum; DFSInfo(ValueBase *Value, int Num) : Value(Value), DFSNum(Num), LowNum(Num) {} }; SILFunction &F; int CurrentNum; llvm::DenseSet Visited; llvm::SetVector DFSStack; typedef llvm::DenseMap ValueInfoMapType; ValueInfoMapType ValueInfoMap; void cleanup() { Visited.clear(); DFSStack.clear(); for (auto &Entry : ValueInfoMap) delete Entry.second; ValueInfoMap.clear(); CurrentNum = 0; } DFSInfo &addDFSInfo(ValueBase *Value) { typename ValueInfoMapType::iterator Iter; bool Inserted; auto MapEntry = std::make_pair(Value, new DFSInfo(Value, CurrentNum++)); std::tie(Iter, Inserted) = ValueInfoMap.insert(MapEntry); assert(Inserted && "Cannot add DFS info more than once for a value!"); return *Iter->second; } DFSInfo &getDFSInfo(ValueBase *Value) { assert(ValueInfoMap.find(Value) != ValueInfoMap.end() && "Expected to find value in DFS info map!"); return *ValueInfoMap.find(Value)->second; } void getArgsForTerminator(TermInst *Term, SILBasicBlock *SuccBB, int Index, llvm::SmallVectorImpl &Operands) { switch (Term->getTermKind()) { case TermKind::BranchInst: return Operands.push_back(cast(Term)->getArg(Index)); case TermKind::CondBranchInst: { auto *CBI = cast(Term); if (SuccBB == CBI->getTrueBB()) return Operands.push_back(CBI->getTrueArgs()[Index]); assert(SuccBB == CBI->getFalseBB() && "Block is not a successor of terminator!"); Operands.push_back(CBI->getFalseArgs()[Index]); return; } case TermKind::SwitchEnumInst: case TermKind::SwitchEnumAddrInst: case TermKind::CheckedCastBranchInst: case TermKind::CheckedCastValueBranchInst: case TermKind::CheckedCastAddrBranchInst: case TermKind::DynamicMethodBranchInst: assert(Index == 0 && "Expected argument index to always be zero!"); return Operands.push_back(Term->getOperand(0)); case TermKind::UnreachableInst: case TermKind::ReturnInst: case TermKind::SwitchValueInst: case TermKind::ThrowInst: llvm_unreachable("Did not expect terminator that does not have args!"); case TermKind::TryApplyInst: for (auto &O : cast(Term)->getAllOperands()) Operands.push_back(O.get()); return; } } void collectOperandsForUser(ValueBase *User, llvm::SmallVectorImpl &Operands) { if (auto *I = dyn_cast(User)) { for (auto &O : I->getAllOperands()) Operands.push_back(O.get()); return; } if (auto *A = dyn_cast(User)) { auto *BB = A->getParent(); auto Index = A->getIndex(); for (auto *Pred : BB->getPredecessorBlocks()) getArgsForTerminator(Pred->getTerminator(), BB, Index, Operands); return; } } // Is Value currently on our DFS stack? bool onStack(ValueBase *Value) { return DFSStack.count(Value); } /// Do depth-first through the value graph, finding the strongly /// component that User is a part of, and call visit() with that SCC. void DFS(ValueBase *User) { assert(!Visited.count(User) && "Attempting to visit a value twice in DFS search!"); DFSStack.insert(User); Visited.insert(User); auto &UserInfo = addDFSInfo(User); llvm::SmallVector Operands; collectOperandsForUser(User, Operands); // Visit each unvisited operand, updating the lowest DFS number we've seen // reachable in User's SCC. for (auto *Opnd : Operands) { if (!Visited.count(Opnd)) { DFS(Opnd); UserInfo.LowNum = std::min(UserInfo.LowNum, getDFSInfo(Opnd).LowNum); } else if (onStack(Opnd)) { UserInfo.LowNum = std::min(UserInfo.LowNum, getDFSInfo(Opnd).DFSNum); } } // If User is the head of its own SCC, pop that SCC off the DFS stack. if (UserInfo.DFSNum == UserInfo.LowNum) { llvm::SmallVector SCC; ValueBase *PoppedValue; do { PoppedValue = DFSStack.pop_back_val(); SCC.push_back(PoppedValue); } while (PoppedValue != User); asImpl().visit(SCC); } } }; } #endif