blob: 9e79db3f4706e4294d89b2166b414f7580280d01 [file] [log] [blame]
//===--- SILSSAUpdater.cpp - Unstructured SSA Update Tool -----------------===//
//
// 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
//
//===----------------------------------------------------------------------===//
#include "swift/SILOptimizer/Utils/SILSSAUpdater.h"
#include "swift/Basic/Malloc.h"
#include "swift/SIL/SILArgument.h"
#include "swift/SIL/SILBasicBlock.h"
#include "swift/SIL/SILBuilder.h"
#include "swift/SIL/SILModule.h"
#include "swift/SIL/SILUndef.h"
#include "swift/SILOptimizer/Utils/CFGOptUtils.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Transforms/Utils/SSAUpdaterImpl.h"
using namespace swift;
void *SILSSAUpdater::allocate(unsigned size, unsigned align) const {
return AlignedAlloc(size, align);
}
void SILSSAUpdater::deallocateSentinel(SILUndef *undef) {
AlignedFree(undef);
}
SILSSAUpdater::SILSSAUpdater(SmallVectorImpl<SILPhiArgument *> *phis)
: blockToAvailableValueMap(nullptr),
phiSentinel(nullptr, deallocateSentinel), insertedPhis(phis) {}
SILSSAUpdater::~SILSSAUpdater() = default;
void SILSSAUpdater::initialize(SILType inputType) {
type = inputType;
phiSentinel = std::unique_ptr<SILUndef, void (*)(SILUndef *)>(
SILUndef::getSentinelValue(inputType, this),
SILSSAUpdater::deallocateSentinel);
if (!blockToAvailableValueMap)
blockToAvailableValueMap.reset(new AvailableValsTy());
else
blockToAvailableValueMap->clear();
}
bool SILSSAUpdater::hasValueForBlock(SILBasicBlock *block) const {
return blockToAvailableValueMap->count(block);
}
/// Indicate that a rewritten value is available in the specified block with the
/// specified value.
void SILSSAUpdater::addAvailableValue(SILBasicBlock *block, SILValue value) {
(*blockToAvailableValueMap)[block] = value;
}
/// Construct SSA form, materializing a value that is live at the end of the
/// specified block.
SILValue SILSSAUpdater::getValueAtEndOfBlock(SILBasicBlock *block) {
return getValueAtEndOfBlockInternal(block);
}
/// Are all available values identicalTo each other.
static bool
areIdentical(llvm::DenseMap<SILBasicBlock *, SILValue> &availableValues) {
if (auto *firstInst =
dyn_cast<SingleValueInstruction>(availableValues.begin()->second)) {
for (auto value : availableValues) {
auto *svi = dyn_cast<SingleValueInstruction>(value.second);
if (!svi)
return false;
if (!svi->isIdenticalTo(firstInst))
return false;
}
return true;
}
auto *mvir =
dyn_cast<MultipleValueInstructionResult>(availableValues.begin()->second);
if (!mvir)
return false;
for (auto value : availableValues) {
auto *result = dyn_cast<MultipleValueInstructionResult>(value.second);
if (!result)
return false;
if (!result->getParent()->isIdenticalTo(mvir->getParent()) ||
result->getIndex() != mvir->getIndex()) {
return false;
}
}
return true;
}
/// This should be called in top-down order of each def that needs its uses
/// rewrited. The order that we visit uses for a given def is irrelevant.
void SILSSAUpdater::rewriteUse(Operand &use) {
// Replicate function_refs to their uses. SILGen can't build phi nodes for
// them and it would not make much sense anyways.
if (auto *fri = dyn_cast<FunctionRefInst>(use.get())) {
assert(areIdentical(*blockToAvailableValueMap) &&
"The function_refs need to have the same value");
SILInstruction *user = use.getUser();
use.set(cast<FunctionRefInst>(fri->clone(user)));
return;
} else if (auto *pdfri =
dyn_cast<PreviousDynamicFunctionRefInst>(use.get())) {
assert(areIdentical(*blockToAvailableValueMap) &&
"The function_refs need to have the same value");
SILInstruction *user = use.getUser();
use.set(cast<PreviousDynamicFunctionRefInst>(pdfri->clone(user)));
return;
} else if (auto *dfri = dyn_cast<DynamicFunctionRefInst>(use.get())) {
assert(areIdentical(*blockToAvailableValueMap) &&
"The function_refs need to have the same value");
SILInstruction *user = use.getUser();
use.set(cast<DynamicFunctionRefInst>(dfri->clone(user)));
return;
} else if (auto *ili = dyn_cast<IntegerLiteralInst>(use.get()))
if (areIdentical(*blockToAvailableValueMap)) {
// Some llvm intrinsics don't like phi nodes as their constant inputs (e.g
// ctlz).
SILInstruction *user = use.getUser();
use.set(cast<IntegerLiteralInst>(ili->clone(user)));
return;
}
// Again we need to be careful here, because ssa construction (with the
// existing representation) can change the operand from under us.
UseWrapper useWrapper(&use);
SILInstruction *user = use.getUser();
SILValue newVal = getValueInMiddleOfBlock(user->getParent());
assert(newVal && "Need a valid value");
static_cast<Operand *>(useWrapper)->set(newVal);
}
/// Get the edge values from the terminator to the destination basic block.
static OperandValueArrayRef getEdgeValuesForTerminator(TermInst *ti,
SILBasicBlock *toBlock) {
if (auto *br = dyn_cast<BranchInst>(ti)) {
assert(br->getDestBB() == toBlock &&
"Incoming edge block and phi block mismatch");
return br->getArgs();
}
if (auto *cbi = dyn_cast<CondBranchInst>(ti)) {
bool isTrueEdge = cbi->getTrueBB() == toBlock;
assert(((isTrueEdge && cbi->getTrueBB() == toBlock) ||
cbi->getFalseBB() == toBlock) &&
"Incoming edge block and phi block mismatch");
return isTrueEdge ? cbi->getTrueArgs() : cbi->getFalseArgs();
}
// We need a predecessor who is capable of holding outgoing branch
// arguments.
llvm_unreachable("Unrecognized terminator leading to phi block");
}
/// Check that the argument has the same incoming edge values as the value
/// map.
static bool
isEquivalentPHI(SILPhiArgument *phi,
llvm::SmallDenseMap<SILBasicBlock *, SILValue, 8> &valueMap) {
SILBasicBlock *phiBlock = phi->getParent();
size_t phiArgEdgeIndex = phi->getIndex();
for (auto *predBlock : phiBlock->getPredecessorBlocks()) {
auto desiredVal = valueMap[predBlock];
OperandValueArrayRef edgeValues =
getEdgeValuesForTerminator(predBlock->getTerminator(), phiBlock);
if (edgeValues[phiArgEdgeIndex] != desiredVal)
return false;
}
return true;
}
SILValue SILSSAUpdater::getValueInMiddleOfBlock(SILBasicBlock *block) {
// If this basic block does not define a value we can just use the value
// live at the end of the block.
if (!hasValueForBlock(block))
return getValueAtEndOfBlock(block);
/// Otherwise, we have to build SSA for the value defined in this block and
/// this block's predecessors.
SILValue singularValue;
SmallVector<std::pair<SILBasicBlock *, SILValue>, 4> predVals;
bool firstPred = true;
// SSAUpdater can modify TerminatorInst and therefore invalidate the
// predecessor iterator. Find all the predecessors before the SSA update.
SmallVector<SILBasicBlock *, 4> preds;
for (auto *predBlock : block->getPredecessorBlocks()) {
preds.push_back(predBlock);
}
for (auto *predBlock : preds) {
SILValue predVal = getValueAtEndOfBlock(predBlock);
predVals.push_back(std::make_pair(predBlock, predVal));
if (firstPred) {
singularValue = predVal;
firstPred = false;
} else if (singularValue != predVal)
singularValue = SILValue();
}
// Return undef for blocks without predecessor.
if (predVals.empty())
return SILUndef::get(type, *block->getParent());
if (singularValue)
return singularValue;
// Check if we already have an equivalent phi.
if (!block->getArguments().empty()) {
llvm::SmallDenseMap<SILBasicBlock *, SILValue, 8> valueMap(predVals.begin(),
predVals.end());
for (auto *arg : block->getSILPhiArguments())
if (isEquivalentPHI(arg, valueMap))
return arg;
}
// Create a new phi node.
SILPhiArgument *phiArg = block->createPhiArgument(type, OwnershipKind::Owned);
for (auto &pair : predVals)
addNewEdgeValueToBranch(pair.first->getTerminator(), block, pair.second);
if (insertedPhis)
insertedPhis->push_back(phiArg);
return phiArg;
}
namespace llvm {
/// Traits for the SSAUpdaterImpl specialized for SIL and the SILSSAUpdater.
template <>
class SSAUpdaterTraits<SILSSAUpdater> {
public:
using BlkT = SILBasicBlock;
using ValT = SILValue;
using PhiT = SILPhiArgument;
using BlkSucc_iterator = SILBasicBlock::succ_iterator;
static BlkSucc_iterator BlkSucc_begin(BlkT *block) {
return block->succ_begin();
}
static BlkSucc_iterator BlkSucc_end(BlkT *block) { return block->succ_end(); }
/// Iterator for PHI operands.
class PHI_iterator {
private:
SILBasicBlock::pred_iterator predBlockIter;
SILBasicBlock *phiBlock;
size_t phiArgEdgeIndex;
public:
explicit PHI_iterator(SILPhiArgument *phiArg) // begin iterator
: predBlockIter(phiArg->getParent()->pred_begin()),
phiBlock(phiArg->getParent()), phiArgEdgeIndex(phiArg->getIndex()) {}
PHI_iterator(SILPhiArgument *phiArg, bool) // end iterator
: predBlockIter(phiArg->getParent()->pred_end()),
phiBlock(phiArg->getParent()), phiArgEdgeIndex(phiArg->getIndex()) {}
PHI_iterator &operator++() {
++predBlockIter;
return *this;
}
bool operator==(const PHI_iterator &x) const {
return predBlockIter == x.predBlockIter;
}
bool operator!=(const PHI_iterator& x) const { return !operator==(x); }
SILValue getValueForBlock(size_t inputArgIndex, SILBasicBlock *block,
TermInst *ti) {
OperandValueArrayRef args = getEdgeValuesForTerminator(ti, block);
assert(inputArgIndex < args.size() &&
"Not enough values on incoming edge");
return args[inputArgIndex];
}
SILValue getIncomingValue() {
return getValueForBlock(phiArgEdgeIndex, phiBlock,
(*predBlockIter)->getTerminator());
}
SILBasicBlock *getIncomingBlock() { return *predBlockIter; }
};
static inline PHI_iterator PHI_begin(PhiT *phi) { return PHI_iterator(phi); }
static inline PHI_iterator PHI_end(PhiT *phi) {
return PHI_iterator(phi, true);
}
/// Put the predecessors of BB into the Preds vector.
static void
FindPredecessorBlocks(SILBasicBlock *block,
SmallVectorImpl<SILBasicBlock *> *predBlocks) {
llvm::copy(block->getPredecessorBlocks(), std::back_inserter(*predBlocks));
}
static SILValue GetUndefVal(SILBasicBlock *block, SILSSAUpdater *ssaUpdater) {
return SILUndef::get(ssaUpdater->type, *block->getParent());
}
/// Add an Argument to the basic block.
static SILValue CreateEmptyPHI(SILBasicBlock *block, unsigned numPreds,
SILSSAUpdater *ssaUpdater) {
// Add the argument to the block.
SILValue phi(
block->createPhiArgument(ssaUpdater->type, OwnershipKind::Owned));
// Mark all predecessor blocks with the sentinel undef value.
SmallVector<SILBasicBlock *, 4> predBlockList(
block->getPredecessorBlocks());
for (auto *predBlock : predBlockList) {
TermInst *ti = predBlock->getTerminator();
addNewEdgeValueToBranch(ti, block, ssaUpdater->phiSentinel.get());
}
return phi;
}
/// Add \p value as an operand of the phi argument \p phi for the specified
/// predecessor block \p predBlock.
static void AddPHIOperand(SILPhiArgument *phi, SILValue value,
SILBasicBlock *predBlock) {
auto *phiBlock = phi->getParent();
size_t phiArgIndex = phi->getIndex();
auto *ti = predBlock->getTerminator();
changeEdgeValue(ti, phiBlock, phiArgIndex, value);
}
/// Check if an instruction is a PHI.
static SILPhiArgument *InstrIsPHI(ValueBase *valueBase) {
return dyn_cast<SILPhiArgument>(valueBase);
}
/// Check if the instruction that defines the specified SILValue is a PHI
/// instruction.
static SILPhiArgument *ValueIsPHI(SILValue value, SILSSAUpdater *) {
return InstrIsPHI(value);
}
/// Like ValueIsPHI but also check if the PHI has no source
/// operands, i.e., it was just added.
static SILPhiArgument *ValueIsNewPHI(SILValue value,
SILSSAUpdater *ssaUpdater) {
SILPhiArgument *phiArg = ValueIsPHI(value, ssaUpdater);
if (!phiArg) {
return nullptr;
}
auto *phiBlock = phiArg->getParent();
size_t phiArgEdgeIndex = phiArg->getIndex();
// If all predecessor edges are 'not set' this is a new phi.
for (auto *predBlock : phiBlock->getPredecessorBlocks()) {
OperandValueArrayRef edgeValues =
getEdgeValuesForTerminator(predBlock->getTerminator(), phiBlock);
assert(phiArgEdgeIndex < edgeValues.size() && "Not enough edges!");
SILValue edgeValue = edgeValues[phiArgEdgeIndex];
// Check for the 'not set' sentinel.
if (edgeValue != ssaUpdater->phiSentinel.get())
return nullptr;
}
return phiArg;
}
static SILValue GetPHIValue(SILPhiArgument *phi) { return phi; }
};
} // namespace llvm
/// Check to see if AvailableVals has an entry for the specified BB and if so,
/// return it. If not, construct SSA form by first calculating the required
/// placement of PHIs and then inserting new PHIs where needed.
SILValue SILSSAUpdater::getValueAtEndOfBlockInternal(SILBasicBlock *block) {
AvailableValsTy &availableValues = *blockToAvailableValueMap;
auto iter = availableValues.find(block);
if (iter != availableValues.end())
return iter->second;
llvm::SSAUpdaterImpl<SILSSAUpdater> impl(this, &availableValues,
insertedPhis);
return impl.GetValue(block);
}
/// Construct a use wrapper. For branches we store information so that we
/// can reconstruct the use after the branch has been modified.
///
/// When a branch is modified existing pointers to the operand
/// (ValueUseIterator) become invalid as they point to freed operands. Instead
/// we store the branch's parent and the idx so that we can reconstruct the use.
UseWrapper::UseWrapper(Operand *inputUse) {
wrappedUse = nullptr;
type = kRegularUse;
SILInstruction *user = inputUse->getUser();
// Direct branch user.
if (auto *br = dyn_cast<BranchInst>(user)) {
for (auto pair : llvm::enumerate(user->getAllOperands())) {
if (inputUse == &pair.value()) {
index = pair.index();
type = kBranchUse;
parent = br->getParent();
return;
}
}
}
// Conditional branch user.
if (auto *cbi = dyn_cast<CondBranchInst>(user)) {
auto operands = user->getAllOperands();
auto numTrueArgs = cbi->getTrueArgs().size();
for (auto pair : llvm::enumerate(operands)) {
if (inputUse == &pair.value()) {
unsigned i = pair.index();
// We treat the condition as part of the true args.
if (i < numTrueArgs + 1) {
index = i;
type = kCondBranchUseTrue;
} else {
index = i - numTrueArgs - 1;
type = kCondBranchUseFalse;
}
parent = cbi->getParent();
return;
}
}
}
wrappedUse = inputUse;
}
/// Return the operand we wrap. Reconstructing branch operands.
Operand *UseWrapper::getOperand() {
switch (type) {
case kRegularUse:
return wrappedUse;
case kBranchUse: {
auto *br = cast<BranchInst>(parent->getTerminator());
assert(index < br->getNumArgs());
return &br->getAllOperands()[index];
}
case kCondBranchUseTrue:
case kCondBranchUseFalse: {
auto *cbi = cast<CondBranchInst>(parent->getTerminator());
auto indexToUse = [&]() -> unsigned {
if (type == kCondBranchUseTrue)
return index;
return cbi->getTrueArgs().size() + 1 + index;
}();
assert(indexToUse < cbi->getAllOperands().size());
return &cbi->getAllOperands()[indexToUse];
}
}
llvm_unreachable("uninitialize use type");
}
/// At least one value feeding the specified SILArgument is a Struct. Attempt to
/// replace the Argument with a new Struct in the same block.
///
/// When we handle more types of casts, this can become a template.
///
/// ArgValues are the values feeding the specified Argument from each
/// predecessor. They must be listed in order of Arg->getParent()->getPreds().
static StructInst *
replaceBBArgWithStruct(SILPhiArgument *phiArg,
SmallVectorImpl<SILValue> &argValues) {
SILBasicBlock *phiBlock = phiArg->getParent();
auto *firstSI = dyn_cast<StructInst>(argValues[0]);
if (!firstSI)
return nullptr;
// Collect the BBArg index of each struct oper.
// e.g.
// struct(A, B)
// br (B, A)
// : ArgIdxForOper => {1, 0}
SmallVector<unsigned, 4> argIdxForOper;
for (unsigned operIdx : indices(firstSI->getElements())) {
bool foundMatchingArgIdx = false;
for (unsigned argIdx : indices(phiBlock->getArguments())) {
auto avIter = argValues.begin();
bool tryNextArgIdx = false;
for (SILBasicBlock *predBlock : phiBlock->getPredecessorBlocks()) {
// All argument values must be StructInst.
auto *predSI = dyn_cast<StructInst>(*avIter++);
if (!predSI)
return nullptr;
OperandValueArrayRef edgeValues =
getEdgeValuesForTerminator(predBlock->getTerminator(), phiBlock);
if (edgeValues[argIdx] != predSI->getElements()[operIdx]) {
tryNextArgIdx = true;
break;
}
}
if (!tryNextArgIdx) {
assert(avIter == argValues.end() &&
"# ArgValues does not match # BB preds");
foundMatchingArgIdx = true;
argIdxForOper.push_back(argIdx);
break;
}
}
if (!foundMatchingArgIdx)
return nullptr;
}
SmallVector<SILValue, 4> structArgs;
for (auto argIdx : argIdxForOper)
structArgs.push_back(phiBlock->getArgument(argIdx));
// TODO: We probably want to use a SILBuilderWithScope here. What should we
// use?
SILBuilder builder(phiBlock, phiBlock->begin());
return builder.createStruct(cast<StructInst>(argValues[0])->getLoc(),
phiArg->getType(), structArgs);
}
/// Canonicalize BB arguments, replacing argument-of-casts with
/// cast-of-arguments. This only eliminates existing arguments, replacing them
/// with casts. No new arguments are created. This allows downstream pattern
/// detection like induction variable analysis to succeed.
///
/// If Arg is replaced, return the cast instruction. Otherwise return nullptr.
SILValue swift::replaceBBArgWithCast(SILPhiArgument *arg) {
SmallVector<SILValue, 4> argValues;
arg->getIncomingPhiValues(argValues);
if (isa<StructInst>(argValues[0]))
return replaceBBArgWithStruct(arg, argValues);
return nullptr;
}