blob: ffe135453a45531418e22a0929a31e0b29c81f0c [file] [log] [blame]
//===--- 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 <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::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<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