Files
swift-mirror/include/swift/SILOptimizer/Utils/SCCVisitor.h
John McCall ab3f77baf2 Make SILInstruction no longer a subclass of ValueBase and
introduce a common superclass, SILNode.

This is in preparation for allowing instructions to have multiple
results.  It is also a somewhat more elegant representation for
instructions that have zero results.  Instructions that are known
to have exactly one result inherit from a class, SingleValueInstruction,
that subclasses both ValueBase and SILInstruction.  Some care must be
taken when working with SILNode pointers and testing for equality;
please see the comment on SILNode for more information.

A number of SIL passes needed to be updated in order to handle this
new distinction between SIL values and SIL instructions.

Note that the SIL parser is now stricter about not trying to assign
a result value from an instruction (like 'return' or 'strong_retain')
that does not produce any.
2017-09-25 02:06:26 -04:00

215 lines
6.5 KiB
C++

//===--- 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) {}
~SCCVisitor() {
cleanup();
}
ImplClass &asImpl() { return static_cast<ImplClass &>(*this); }
void visit(llvm::SmallVectorImpl<SILNode *> &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)
maybeDFS(&I);
}
cleanup();
}
private:
struct DFSInfo {
SILNode *Node;
int DFSNum;
int LowNum;
DFSInfo(SILNode *node, int num) : Node(node), DFSNum(num), LowNum(num) {}
};
SILFunction &F;
int CurrentNum = 0;
llvm::DenseSet<SILNode *> Visited;
llvm::SetVector<SILNode *> DFSStack;
typedef llvm::DenseMap<SILNode *, DFSInfo *> ValueInfoMapType;
ValueInfoMapType ValueInfoMap;
void cleanup() {
Visited.clear();
DFSStack.clear();
for (auto &Entry : ValueInfoMap)
delete Entry.second;
ValueInfoMap.clear();
CurrentNum = 0;
}
DFSInfo &addDFSInfo(SILNode *node) {
assert(node->isCanonicalSILNodeInObject());
auto entry = std::make_pair(node, new DFSInfo(node, CurrentNum++));
auto insertion = ValueInfoMap.insert(entry);
assert(insertion.second && "Cannot add DFS info more than once!");
return *insertion.first->second;
}
DFSInfo &getDFSInfo(SILNode *node) {
assert(node->isCanonicalSILNodeInObject());
auto it = ValueInfoMap.find(node);
assert(it != ValueInfoMap.end() &&
"Expected to find value in DFS info map!");
return *it->second;
}
void getArgsForTerminator(TermInst *Term, SILBasicBlock *SuccBB, int Index,
llvm::SmallVectorImpl<SILValue> &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(SILNode *node,
llvm::SmallVectorImpl<SILValue> &Operands) {
if (auto *I = dyn_cast<SILInstruction>(node)) {
for (auto &O : I->getAllOperands())
Operands.push_back(O.get());
return;
}
if (auto *A = dyn_cast<SILArgument>(node)) {
auto *BB = A->getParent();
auto Index = A->getIndex();
for (auto *Pred : BB->getPredecessorBlocks())
getArgsForTerminator(Pred->getTerminator(), BB, Index, Operands);
return;
}
}
void maybeDFS(SILInstruction *inst) {
(void) maybeDFSCanonicalNode(inst->getCanonicalSILNodeInObject());
}
/// Continue a DFS from the given node, finding the strongly
/// component that User is a part of, calling visit() with that SCC,
/// and returning the DFSInfo for the node.
/// But if we've already visited the node, just return null.
DFSInfo *maybeDFSCanonicalNode(SILNode *node) {
assert(node->isCanonicalSILNodeInObject() && "should already be canonical");
if (!Visited.insert(node).second)
return nullptr;
DFSStack.insert(node);
auto &nodeInfo = addDFSInfo(node);
llvm::SmallVector<SILValue, 4> operands;
collectOperandsForUser(node, operands);
// Visit each unvisited operand, updating the lowest DFS number we've seen
// reachable in User's SCC.
for (SILValue operandValue : operands) {
SILNode *operandNode = operandValue->getCanonicalSILNodeInObject();
if (auto operandNodeInfo = maybeDFSCanonicalNode(operandNode)) {
nodeInfo.LowNum = std::min(nodeInfo.LowNum, operandNodeInfo->LowNum);
} else if (DFSStack.count(operandNode)) {
auto operandNodeInfo = &getDFSInfo(operandNode);
nodeInfo.LowNum = std::min(nodeInfo.LowNum, operandNodeInfo->DFSNum);
}
}
// If User is the head of its own SCC, pop that SCC off the DFS stack.
if (nodeInfo.DFSNum == nodeInfo.LowNum) {
llvm::SmallVector<SILNode *, 4> SCC;
SILNode *poppedNode;
do {
poppedNode = DFSStack.pop_back_val();
SCC.push_back(poppedNode);
} while (poppedNode != node);
asImpl().visit(SCC);
}
return &nodeInfo;
}
};
}
#endif