mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
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.
448 lines
16 KiB
C++
448 lines
16 KiB
C++
//===--- SILBasicBlock.h - Basic blocks for SIL -----------------*- 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
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This file defines the high-level BasicBlocks used for Swift SIL code.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#ifndef SWIFT_SIL_BASICBLOCK_H
|
|
#define SWIFT_SIL_BASICBLOCK_H
|
|
|
|
#include "swift/Basic/Compiler.h"
|
|
#include "swift/Basic/Range.h"
|
|
#include "swift/Basic/TransformArrayRef.h"
|
|
#include "swift/SIL/SILInstruction.h"
|
|
|
|
namespace swift {
|
|
|
|
class SILFunction;
|
|
class SILArgument;
|
|
class SILPHIArgument;
|
|
class SILFunctionArgument;
|
|
class SILPrintContext;
|
|
|
|
class SILBasicBlock :
|
|
public llvm::ilist_node<SILBasicBlock>, public SILAllocated<SILBasicBlock> {
|
|
friend class SILSuccessor;
|
|
friend class SILFunction;
|
|
friend class SILGlobalVariable;
|
|
public:
|
|
using InstListType = llvm::iplist<SILInstruction>;
|
|
private:
|
|
/// A backreference to the containing SILFunction.
|
|
SILFunction *Parent;
|
|
|
|
/// PrevList - This is a list of all of the terminator operands that are
|
|
/// branching to this block, forming the predecessor list. This is
|
|
/// automatically managed by the SILSuccessor class.
|
|
SILSuccessor *PredList;
|
|
|
|
/// This is the list of basic block arguments for this block.
|
|
std::vector<SILArgument *> ArgumentList;
|
|
|
|
/// The ordered set of instructions in the SILBasicBlock.
|
|
InstListType InstList;
|
|
|
|
friend struct llvm::ilist_traits<SILBasicBlock>;
|
|
SILBasicBlock() : Parent(nullptr) {}
|
|
void operator=(const SILBasicBlock &) = delete;
|
|
|
|
void operator delete(void *Ptr, size_t) SWIFT_DELETE_OPERATOR_DELETED
|
|
|
|
SILBasicBlock(SILFunction *F, SILBasicBlock *afterBB = nullptr);
|
|
|
|
public:
|
|
~SILBasicBlock();
|
|
|
|
/// Gets the ID (= index in the function's block list) of the block.
|
|
///
|
|
/// Returns -1 if the block is not contained in a function.
|
|
/// Warning: This function is slow. Therefore it should only be used for
|
|
/// debug output.
|
|
int getDebugID();
|
|
|
|
SILFunction *getParent() { return Parent; }
|
|
const SILFunction *getParent() const { return Parent; }
|
|
|
|
SILModule &getModule() const;
|
|
|
|
/// This method unlinks 'self' from the containing SILFunction and deletes it.
|
|
void eraseFromParent();
|
|
|
|
//===--------------------------------------------------------------------===//
|
|
// SILInstruction List Inspection and Manipulation
|
|
//===--------------------------------------------------------------------===//
|
|
|
|
using iterator = InstListType::iterator;
|
|
using const_iterator = InstListType::const_iterator;
|
|
using reverse_iterator = InstListType::reverse_iterator;
|
|
using const_reverse_iterator = InstListType::const_reverse_iterator;
|
|
|
|
void insert(iterator InsertPt, SILInstruction *I);
|
|
void insert(SILInstruction *InsertPt, SILInstruction *I) {
|
|
insert(InsertPt->getIterator(), I);
|
|
}
|
|
|
|
void push_back(SILInstruction *I);
|
|
void push_front(SILInstruction *I);
|
|
void remove(SILInstruction *I);
|
|
iterator erase(SILInstruction *I);
|
|
|
|
SILInstruction &back() { return InstList.back(); }
|
|
const SILInstruction &back() const {
|
|
return const_cast<SILBasicBlock *>(this)->back();
|
|
}
|
|
|
|
SILInstruction &front() { return InstList.front(); }
|
|
const SILInstruction &front() const {
|
|
return const_cast<SILBasicBlock *>(this)->front();
|
|
}
|
|
|
|
/// Transfer the instructions from Other to the end of this block.
|
|
void spliceAtEnd(SILBasicBlock *Other) {
|
|
InstList.splice(end(), Other->InstList);
|
|
}
|
|
|
|
bool empty() const { return InstList.empty(); }
|
|
iterator begin() { return InstList.begin(); }
|
|
iterator end() { return InstList.end(); }
|
|
const_iterator begin() const { return InstList.begin(); }
|
|
const_iterator end() const { return InstList.end(); }
|
|
reverse_iterator rbegin() { return InstList.rbegin(); }
|
|
reverse_iterator rend() { return InstList.rend(); }
|
|
const_reverse_iterator rbegin() const { return InstList.rbegin(); }
|
|
const_reverse_iterator rend() const { return InstList.rend(); }
|
|
|
|
TermInst *getTerminator() {
|
|
assert(!InstList.empty() && "Can't get successors for malformed block");
|
|
return cast<TermInst>(&InstList.back());
|
|
}
|
|
|
|
const TermInst *getTerminator() const {
|
|
return const_cast<SILBasicBlock *>(this)->getTerminator();
|
|
}
|
|
|
|
/// \brief Splits a basic block into two at the specified instruction.
|
|
///
|
|
/// Note that all the instructions BEFORE the specified iterator
|
|
/// stay as part of the original basic block. The old basic block is left
|
|
/// without a terminator.
|
|
SILBasicBlock *split(iterator I);
|
|
|
|
/// \brief Move the basic block to after the specified basic block in the IR.
|
|
///
|
|
/// Assumes that the basic blocks must reside in the same function. In asserts
|
|
/// builds, an assert verifies that this is true.
|
|
void moveAfter(SILBasicBlock *After);
|
|
|
|
/// \brief Moves the instruction to the iterator in this basic block.
|
|
void moveTo(SILBasicBlock::iterator To, SILInstruction *I);
|
|
|
|
//===--------------------------------------------------------------------===//
|
|
// SILBasicBlock Argument List Inspection and Manipulation
|
|
//===--------------------------------------------------------------------===//
|
|
|
|
using arg_iterator = std::vector<SILArgument *>::iterator;
|
|
using const_arg_iterator = std::vector<SILArgument *>::const_iterator;
|
|
|
|
bool args_empty() const { return ArgumentList.empty(); }
|
|
size_t args_size() const { return ArgumentList.size(); }
|
|
arg_iterator args_begin() { return ArgumentList.begin(); }
|
|
arg_iterator args_end() { return ArgumentList.end(); }
|
|
const_arg_iterator args_begin() const { return ArgumentList.begin(); }
|
|
const_arg_iterator args_end() const { return ArgumentList.end(); }
|
|
|
|
ArrayRef<SILArgument *> getArguments() const { return ArgumentList; }
|
|
using PHIArgumentArrayRefTy =
|
|
TransformArrayRef<std::function<SILPHIArgument *(SILArgument *)>>;
|
|
PHIArgumentArrayRefTy getPHIArguments() const;
|
|
using FunctionArgumentArrayRefTy =
|
|
TransformArrayRef<std::function<SILFunctionArgument *(SILArgument *)>>;
|
|
FunctionArgumentArrayRefTy getFunctionArguments() const;
|
|
|
|
unsigned getNumArguments() const { return ArgumentList.size(); }
|
|
const SILArgument *getArgument(unsigned i) const { return ArgumentList[i]; }
|
|
SILArgument *getArgument(unsigned i) { return ArgumentList[i]; }
|
|
|
|
void cloneArgumentList(SILBasicBlock *Other);
|
|
|
|
/// Erase a specific argument from the arg list.
|
|
void eraseArgument(int Index);
|
|
|
|
/// Allocate a new argument of type \p Ty and append it to the argument
|
|
/// list. Optionally you can pass in a value decl parameter.
|
|
SILFunctionArgument *createFunctionArgument(SILType Ty,
|
|
const ValueDecl *D = nullptr);
|
|
|
|
SILFunctionArgument *insertFunctionArgument(unsigned Index, SILType Ty,
|
|
ValueOwnershipKind OwnershipKind,
|
|
const ValueDecl *D = nullptr) {
|
|
arg_iterator Pos = ArgumentList.begin();
|
|
std::advance(Pos, Index);
|
|
return insertFunctionArgument(Pos, Ty, OwnershipKind, D);
|
|
}
|
|
|
|
/// Replace the \p{i}th Function arg with a new Function arg with SILType \p
|
|
/// Ty and ValueDecl \p D.
|
|
SILFunctionArgument *replaceFunctionArgument(unsigned i, SILType Ty,
|
|
ValueOwnershipKind Kind,
|
|
const ValueDecl *D = nullptr);
|
|
|
|
/// Replace the \p{i}th BB arg with a new BBArg with SILType \p Ty and
|
|
/// ValueDecl
|
|
/// \p D.
|
|
SILPHIArgument *replacePHIArgument(unsigned i, SILType Ty,
|
|
ValueOwnershipKind Kind,
|
|
const ValueDecl *D = nullptr);
|
|
|
|
/// Allocate a new argument of type \p Ty and append it to the argument
|
|
/// list. Optionally you can pass in a value decl parameter.
|
|
SILPHIArgument *createPHIArgument(SILType Ty, ValueOwnershipKind Kind,
|
|
const ValueDecl *D = nullptr);
|
|
|
|
/// Insert a new SILPHIArgument with type \p Ty and \p Decl at position \p
|
|
/// Pos.
|
|
SILPHIArgument *insertPHIArgument(arg_iterator Pos, SILType Ty,
|
|
ValueOwnershipKind Kind,
|
|
const ValueDecl *D = nullptr);
|
|
|
|
SILPHIArgument *insertPHIArgument(unsigned Index, SILType Ty,
|
|
ValueOwnershipKind Kind,
|
|
const ValueDecl *D = nullptr) {
|
|
arg_iterator Pos = ArgumentList.begin();
|
|
std::advance(Pos, Index);
|
|
return insertPHIArgument(Pos, Ty, Kind, D);
|
|
}
|
|
|
|
/// \brief Remove all block arguments.
|
|
void dropAllArguments() { ArgumentList.clear(); }
|
|
|
|
//===--------------------------------------------------------------------===//
|
|
// Predecessors and Successors
|
|
//===--------------------------------------------------------------------===//
|
|
|
|
using SuccessorListTy = TermInst::SuccessorListTy;
|
|
using ConstSuccessorListTy = TermInst::ConstSuccessorListTy;
|
|
|
|
/// The successors of a SILBasicBlock are defined either explicitly as
|
|
/// a single successor as the branch targets of the terminator instruction.
|
|
ConstSuccessorListTy getSuccessors() const {
|
|
return getTerminator()->getSuccessors();
|
|
}
|
|
SuccessorListTy getSuccessors() {
|
|
return getTerminator()->getSuccessors();
|
|
}
|
|
|
|
using const_succ_iterator = ConstSuccessorListTy::const_iterator;
|
|
using succ_iterator = SuccessorListTy::iterator;
|
|
|
|
bool succ_empty() const { return getSuccessors().empty(); }
|
|
succ_iterator succ_begin() { return getSuccessors().begin(); }
|
|
succ_iterator succ_end() { return getSuccessors().end(); }
|
|
const_succ_iterator succ_begin() const { return getSuccessors().begin(); }
|
|
const_succ_iterator succ_end() const { return getSuccessors().end(); }
|
|
|
|
using succblock_iterator =
|
|
TransformIterator<SILSuccessor *,
|
|
std::function<SILBasicBlock *(const SILSuccessor &)>>;
|
|
using const_succblock_iterator = TransformIterator<
|
|
const SILSuccessor *,
|
|
std::function<const SILBasicBlock *(const SILSuccessor &)>>;
|
|
succblock_iterator succblock_begin() {
|
|
using FuncTy = std::function<SILBasicBlock *(const SILSuccessor &)>;
|
|
FuncTy F(&SILSuccessor::getBB);
|
|
return makeTransformIterator(getSuccessors().begin(), F);
|
|
}
|
|
succblock_iterator succblock_end() {
|
|
using FuncTy = std::function<SILBasicBlock *(const SILSuccessor &)>;
|
|
FuncTy F(&SILSuccessor::getBB);
|
|
return makeTransformIterator(getSuccessors().end(), F);
|
|
}
|
|
const_succblock_iterator succblock_begin() const {
|
|
using FuncTy = std::function<const SILBasicBlock *(const SILSuccessor &)>;
|
|
FuncTy F(&SILSuccessor::getBB);
|
|
return makeTransformIterator(getSuccessors().begin(), F);
|
|
}
|
|
const_succblock_iterator succblock_end() const {
|
|
using FuncTy = std::function<const SILBasicBlock *(const SILSuccessor &)>;
|
|
FuncTy F(&SILSuccessor::getBB);
|
|
return makeTransformIterator(getSuccessors().end(), F);
|
|
}
|
|
|
|
SILBasicBlock *getSingleSuccessorBlock() {
|
|
if (succ_empty() || std::next(succ_begin()) != succ_end())
|
|
return nullptr;
|
|
return *succ_begin();
|
|
}
|
|
|
|
const SILBasicBlock *getSingleSuccessorBlock() const {
|
|
return const_cast<SILBasicBlock *>(this)->getSingleSuccessorBlock();
|
|
}
|
|
|
|
/// \brief Returns true if \p BB is a successor of this block.
|
|
bool isSuccessorBlock(SILBasicBlock *BB) const {
|
|
auto Range = getSuccessorBlocks();
|
|
return any_of(Range, [&BB](const SILBasicBlock *SuccBB) -> bool {
|
|
return BB == SuccBB;
|
|
});
|
|
}
|
|
|
|
using SuccessorBlockListTy =
|
|
TransformRange<SuccessorListTy,
|
|
std::function<SILBasicBlock *(const SILSuccessor &)>>;
|
|
using ConstSuccessorBlockListTy =
|
|
TransformRange<ConstSuccessorListTy,
|
|
std::function<const SILBasicBlock *(const SILSuccessor &)>>;
|
|
|
|
/// Return the range of SILBasicBlocks that are successors of this block.
|
|
SuccessorBlockListTy getSuccessorBlocks() {
|
|
using FuncTy = std::function<SILBasicBlock *(const SILSuccessor &)>;
|
|
FuncTy F(&SILSuccessor::getBB);
|
|
return makeTransformRange(getSuccessors(), F);
|
|
}
|
|
|
|
/// Return the range of SILBasicBlocks that are successors of this block.
|
|
ConstSuccessorBlockListTy getSuccessorBlocks() const {
|
|
using FuncTy = std::function<const SILBasicBlock *(const SILSuccessor &)>;
|
|
FuncTy F(&SILSuccessor::getBB);
|
|
return makeTransformRange(getSuccessors(), F);
|
|
}
|
|
|
|
using pred_iterator = SILSuccessor::pred_iterator;
|
|
|
|
bool pred_empty() const { return PredList == nullptr; }
|
|
pred_iterator pred_begin() const { return pred_iterator(PredList); }
|
|
pred_iterator pred_end() const { return pred_iterator(); }
|
|
|
|
iterator_range<pred_iterator> getPredecessorBlocks() const {
|
|
return {pred_begin(), pred_end()};
|
|
}
|
|
|
|
bool isPredecessorBlock(SILBasicBlock *BB) const {
|
|
return any_of(
|
|
getPredecessorBlocks(),
|
|
[&BB](const SILBasicBlock *PredBB) -> bool { return BB == PredBB; });
|
|
}
|
|
|
|
SILBasicBlock *getSinglePredecessorBlock() {
|
|
if (pred_empty() || std::next(pred_begin()) != pred_end())
|
|
return nullptr;
|
|
return *pred_begin();
|
|
}
|
|
|
|
const SILBasicBlock *getSinglePredecessorBlock() const {
|
|
return const_cast<SILBasicBlock *>(this)->getSinglePredecessorBlock();
|
|
}
|
|
|
|
//===--------------------------------------------------------------------===//
|
|
// Utility
|
|
//===--------------------------------------------------------------------===//
|
|
|
|
/// Returns true if this BB is the entry BB of its parent.
|
|
bool isEntry() const;
|
|
|
|
/// Returns true if this block ends in an unreachable or an apply of a
|
|
/// no-return apply or builtin.
|
|
bool isNoReturn() const;
|
|
|
|
/// Returns true if this instruction only contains a branch instruction.
|
|
bool isTrampoline() const;
|
|
|
|
/// Returns true if it is legal to hoist instructions into this block.
|
|
///
|
|
/// Used by llvm::LoopInfo.
|
|
bool isLegalToHoistInto() const;
|
|
|
|
//===--------------------------------------------------------------------===//
|
|
// Debugging
|
|
//===--------------------------------------------------------------------===//
|
|
|
|
/// Pretty-print the SILBasicBlock.
|
|
void dump() const;
|
|
|
|
/// Pretty-print the SILBasicBlock with the designated stream.
|
|
void print(llvm::raw_ostream &OS) const;
|
|
|
|
/// Pretty-print the SILBasicBlock with the designated stream and context.
|
|
void print(llvm::raw_ostream &OS, SILPrintContext &Ctx) const;
|
|
|
|
void printAsOperand(raw_ostream &OS, bool PrintType = true);
|
|
|
|
/// getSublistAccess() - returns pointer to member of instruction list
|
|
static InstListType SILBasicBlock::*getSublistAccess() {
|
|
return &SILBasicBlock::InstList;
|
|
}
|
|
|
|
/// \brief Drops all uses that belong to this basic block.
|
|
void dropAllReferences() {
|
|
dropAllArguments();
|
|
for (SILInstruction &I : *this)
|
|
I.dropAllReferences();
|
|
}
|
|
|
|
void eraseInstructions();
|
|
|
|
private:
|
|
friend class SILArgument;
|
|
|
|
/// BBArgument's ctor adds it to the argument list of this block.
|
|
void insertArgument(arg_iterator Iter, SILArgument *Arg) {
|
|
ArgumentList.insert(Iter, Arg);
|
|
}
|
|
|
|
/// Insert a new SILFunctionArgument with type \p Ty and \p Decl at position
|
|
/// \p Pos.
|
|
SILFunctionArgument *insertFunctionArgument(arg_iterator Pos, SILType Ty,
|
|
ValueOwnershipKind OwnershipKind,
|
|
const ValueDecl *D = nullptr);
|
|
};
|
|
|
|
inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,
|
|
const SILBasicBlock &BB) {
|
|
BB.print(OS);
|
|
return OS;
|
|
}
|
|
} // end swift namespace
|
|
|
|
namespace llvm {
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// ilist_traits for SILBasicBlock
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
template <>
|
|
struct ilist_traits<::swift::SILBasicBlock>
|
|
: ilist_default_traits<::swift::SILBasicBlock> {
|
|
using SelfTy = ilist_traits<::swift::SILBasicBlock>;
|
|
using SILBasicBlock = ::swift::SILBasicBlock;
|
|
using SILFunction = ::swift::SILFunction;
|
|
using FunctionPtrTy = ::swift::NullablePtr<SILFunction>;
|
|
|
|
private:
|
|
friend class ::swift::SILFunction;
|
|
|
|
SILFunction *Parent;
|
|
using block_iterator = simple_ilist<SILBasicBlock>::iterator;
|
|
|
|
public:
|
|
static void deleteNode(SILBasicBlock *BB) { BB->~SILBasicBlock(); }
|
|
|
|
void transferNodesFromList(ilist_traits<SILBasicBlock> &SrcTraits,
|
|
block_iterator First, block_iterator Last);
|
|
private:
|
|
static void createNode(const SILBasicBlock &);
|
|
};
|
|
|
|
} // end llvm namespace
|
|
|
|
#endif
|