mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
This was already done for getSuccessorBlocks() to distinguish getting successor blocks from getting the full list of SILSuccessors via getSuccessors(). This commit just makes all of the successor/predecessor code follow that naming convention. Some examples: getSingleSuccessor() => getSingleSuccessorBlock(). isSuccessor() => isSuccessorBlock(). getPreds() => getPredecessorBlocks(). Really, IMO, we should consider renaming SILSuccessor to a more verbose name so that it is clear that it is more of an internal detail of SILBasicBlock's implementation rather than something that one should consider as apart of one's mental model of the IR when one really wants to be thinking about predecessor and successor blocks. But that is not what this commit is trying to change, it is just trying to eliminate a bit of technical debt by making the naming conventions here consistent.
210 lines
6.2 KiB
C++
210 lines
6.2 KiB
C++
//===--- SCCVisitor.h - SIL SCC Visitor -------------------------*- C++ -*-===//
|
|
//
|
|
// This source file is part of the Swift.org open source project
|
|
//
|
|
// Copyright (c) 2014 - 2016 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 <algorithm>
|
|
#include <tuple>
|
|
|
|
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 <typename ImplClass>
|
|
class SCCVisitor {
|
|
public:
|
|
SCCVisitor(SILFunction &F) : F(F), CurrentNum(0) {}
|
|
~SCCVisitor() {
|
|
cleanup();
|
|
}
|
|
ImplClass &asImpl() { return static_cast<ImplClass &>(*this); }
|
|
|
|
void visit(llvm::SmallVectorImpl<ValueBase *> &SCC) { }
|
|
|
|
void run() {
|
|
llvm::ReversePostOrderTraversal<SILFunction *> 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<ValueBase *> Visited;
|
|
llvm::SetVector<ValueBase *> DFSStack;
|
|
typedef llvm::DenseMap<ValueBase *, DFSInfo *> 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<ValueBase *> &Operands) {
|
|
switch (Term->getTermKind()) {
|
|
case TermKind::BranchInst:
|
|
return Operands.push_back(cast<BranchInst>(Term)->getArg(Index));
|
|
|
|
case TermKind::CondBranchInst: {
|
|
auto *CBI = cast<CondBranchInst>(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::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<TryApplyInst>(Term)->getAllOperands())
|
|
Operands.push_back(O.get());
|
|
return;
|
|
}
|
|
}
|
|
|
|
void collectOperandsForUser(ValueBase *User,
|
|
llvm::SmallVectorImpl<ValueBase *> &Operands) {
|
|
if (auto *I = dyn_cast<SILInstruction>(User)) {
|
|
for (auto &O : I->getAllOperands())
|
|
Operands.push_back(O.get());
|
|
return;
|
|
}
|
|
|
|
if (auto *A = dyn_cast<SILArgument>(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<ValueBase *, 4> 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<ValueBase *, 4> SCC;
|
|
ValueBase *PoppedValue;
|
|
do {
|
|
PoppedValue = DFSStack.pop_back_val();
|
|
SCC.push_back(PoppedValue);
|
|
} while (PoppedValue != User);
|
|
|
|
asImpl().visit(SCC);
|
|
}
|
|
}
|
|
};
|
|
|
|
}
|
|
|
|
#endif
|