Files
swift-mirror/include/swift/SILOptimizer/Utils/SILSSAUpdater.h
Michael Gottesman 11f0ff6e32 [sil] Ensure that all SILValues have a parent function by making it so that SILUndef is uniqued at the function instead of module level.
For years, optimizer engineers have been hitting a common bug caused by passes
assuming all SILValues have a parent function only to be surprised by SILUndef.
Generally we see SILUndef not that often so we see this come up later in
testing. This patch eliminates that problem by making SILUndef uniqued at the
function level instead of the module level. This ensures that it makes sense for
SILUndef to have a parent function, eliminating this possibility since we can
define an API to get its parent function.

rdar://123484595
2024-02-27 13:14:47 -08:00

159 lines
5.0 KiB
C++

//===--- SILSSAUpdater.h - Unstructured SSA Update Tool ---------*- 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_SILSSAUPDATER_H
#define SWIFT_SIL_SILSSAUPDATER_H
#include "llvm/Support/Allocator.h"
#include "swift/SILOptimizer/Utils/InstructionDeleter.h"
#include "swift/SIL/SILInstruction.h"
#include "swift/SIL/SILValue.h"
namespace llvm {
template <typename T>
class SSAUpdaterTraits;
template <typename T>
class SmallVectorImpl;
} // namespace llvm
namespace swift {
class SILPhiArgument;
class SILBasicBlock;
class SILType;
class SILUndef;
/// Independent utility that canonicalizes BB arguments by reusing structurally
/// equivalent arguments and replacing the original arguments with casts.
SILValue replaceBBArgWithCast(SILPhiArgument *arg);
/// This class updates SSA for a set of SIL instructions defined in multiple
/// blocks.
class SILSSAUpdater {
friend class llvm::SSAUpdaterTraits<SILSSAUpdater>;
// A map of basic block to available phi value.
using AvailableValsTy = llvm::DenseMap<SILBasicBlock *, SILValue>;
std::unique_ptr<AvailableValsTy> blockToAvailableValueMap;
SILType type;
ValueOwnershipKind ownershipKind;
// The SSAUpdaterTraits specialization uses this sentinel to mark 'new' phi
// nodes (all the incoming edge arguments have this sentinel set).
std::unique_ptr<SILUndef, void (*)(SILUndef *)> phiSentinel;
// If not null updated with inserted 'phi' nodes (SILArgument).
SmallVectorImpl<SILPhiArgument *> *insertedPhis;
// Used to delete branch instructions when they are replaced for adding
// phi arguments.
InstructionDeleter deleter;
// Not copyable.
void operator=(const SILSSAUpdater &) = delete;
SILSSAUpdater(const SILSSAUpdater &) = delete;
public:
explicit SILSSAUpdater(
SmallVectorImpl<SILPhiArgument *> *insertedPhis = nullptr);
~SILSSAUpdater();
InstructionDeleter &getDeleter() { return deleter; }
void setInsertedPhis(SmallVectorImpl<SILPhiArgument *> *inputInsertedPhis) {
insertedPhis = inputInsertedPhis;
}
/// Initialize for a use of a value of type and ownershipKind
void initialize(SILFunction *fn, SILType type,
ValueOwnershipKind ownershipKind);
bool hasValueForBlock(SILBasicBlock *block) const;
void addAvailableValue(SILBasicBlock *block, SILValue value);
/// Construct SSA for a value that is live at the *end* of a basic block.
SILValue getValueAtEndOfBlock(SILBasicBlock *block);
/// Construct SSA for a value that is live in the middle of a block.
/// This handles the case where the use is before a definition of the value.
/// BB1:
/// val_1 = def
/// br BB2:
/// BB2:
/// = use(val_?)
/// val_2 = def
/// cond_br ..., BB2, BB3
///
/// In this case we need to insert a 'PHI' node at the beginning of BB2
/// merging val_1 and val_2.
SILValue getValueInMiddleOfBlock(SILBasicBlock *block);
void rewriteUse(Operand &operand);
void *allocate(unsigned size, unsigned align) const;
static void deallocateSentinel(SILUndef *undef);
private:
SILValue getValueAtEndOfBlockInternal(SILBasicBlock *block);
};
/// Utility to wrap 'Operand's to deal with invalidation of
/// ValueUseIterators during SSA construction.
///
/// Uses in branches change under us - we need to identify them by an
/// indirection. A ValueUseIterator is just an Operand pointer. As we update SSA
/// form we change branches and invalidate (by deleting the old branch and
/// creating a new one) the Operand pointed to by the ValueUseIterator.
///
/// This class wraps such uses (uses in branches) to provide a level of
/// indirection. We can restore the information - the use - by looking at the
/// new branch and the operand index.
///
/// Uses in branches are stored as an index and the parent block to
/// identify the use allowing us to reconstruct the use after the branch has
/// been changed.
class UseWrapper {
Operand *wrappedUse;
SILBasicBlock *parent;
enum {
kRegularUse,
kBranchUse,
kCondBranchUseTrue,
kCondBranchUseFalse
} type;
unsigned index;
public:
/// 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(Operand *use);
Operand *getOperand();
/// Return the operand we wrap. Reconstructing branch operands.
operator Operand*() { return getOperand(); }
};
} // end namespace swift
#endif