Files
swift-mirror/include/swift/SIL/SILArgument.h
Michael Gottesman f196fc09e0 [sil] Create SILArgumentKind for allowing for one to exhaustively switch over all arguments.
This ensures that we can use exhaustive switches over arguments and thus get
missing case warnings when we add new argument types.

rdar://44807744
2018-09-26 14:27:33 -07:00

358 lines
14 KiB
C++

//===--- SILArgument.h - SIL BasicBlock Argument Representation -*- 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_SILARGUMENT_H
#define SWIFT_SIL_SILARGUMENT_H
#include "swift/Basic/Compiler.h"
#include "swift/SIL/SILArgumentConvention.h"
#include "swift/SIL/SILFunction.h"
#include "swift/SIL/SILValue.h"
namespace swift {
class SILBasicBlock;
class SILModule;
class SILUndef;
// Map an argument index onto a SILArgumentConvention.
inline SILArgumentConvention
SILFunctionConventions::getSILArgumentConvention(unsigned index) const {
assert(index <= getNumSILArguments());
if (index < getNumIndirectSILResults()) {
assert(silConv.loweredAddresses);
return SILArgumentConvention::Indirect_Out;
} else {
auto param = funcTy->getParameters()[index - getNumIndirectSILResults()];
return SILArgumentConvention(param.getConvention());
}
}
struct SILArgumentKind {
enum innerty : std::underlying_type<ValueKind>::type {
#define ARGUMENT(ID, PARENT) ID = unsigned(SILNodeKind::ID),
#define ARGUMENT_RANGE(ID, FIRST, LAST) First_##ID = FIRST, Last_##ID = LAST,
#include "swift/SIL/SILNodes.def"
} value;
explicit SILArgumentKind(ValueKind kind)
: value(*SILArgumentKind::fromValueKind(kind)) {}
SILArgumentKind(innerty value) : value(value) {}
operator innerty() const { return value; }
static Optional<SILArgumentKind> fromValueKind(ValueKind kind) {
switch (kind) {
#define ARGUMENT(ID, PARENT) \
case ValueKind::ID: \
return SILArgumentKind(ID);
#include "swift/SIL/SILNodes.def"
default:
return None;
}
}
};
class SILArgument : public ValueBase {
void operator=(const SILArgument &) = delete;
void operator delete(void *Ptr, size_t) SWIFT_DELETE_OPERATOR_DELETED
SILBasicBlock *ParentBB;
const ValueDecl *Decl;
public:
ValueOwnershipKind getOwnershipKind() const {
return static_cast<ValueOwnershipKind>(Bits.SILArgument.VOKind);
}
void setOwnershipKind(ValueOwnershipKind NewKind) {
Bits.SILArgument.VOKind = static_cast<unsigned>(NewKind);
}
SILBasicBlock *getParent() { return ParentBB; }
const SILBasicBlock *getParent() const { return ParentBB; }
SILFunction *getFunction();
const SILFunction *getFunction() const;
SILModule &getModule() const;
const ValueDecl *getDecl() const { return Decl; }
static bool classof(const SILInstruction *) = delete;
static bool classof(const SILUndef *) = delete;
static bool classof(const SILNode *node) {
return node->getKind() >= SILNodeKind::First_SILArgument &&
node->getKind() <= SILNodeKind::Last_SILArgument;
}
unsigned getIndex() const {
ArrayRef<SILArgument *> Args = getParent()->getArguments();
for (unsigned i = 0, e = Args.size(); i != e; ++i)
if (Args[i] == this)
return i;
llvm_unreachable("SILArgument not argument of its parent BB");
}
/// Return true if this block argument is actually a phi argument as
/// opposed to a cast or projection.
bool isPhiArgument();
/// If this argument is a phi, return the incoming phi value for the given
/// predecessor BB. If this argument is not a phi, return an invalid SILValue.
SILValue getIncomingPhiValue(SILBasicBlock *predBB);
/// If this argument is a phi, populate `OutArray` with the incoming phi
/// values for each predecessor BB. If this argument is not a phi, return
/// false.
bool getIncomingPhiValues(llvm::SmallVectorImpl<SILValue> &ReturnedPhiValues);
/// If this argument is a phi, populate `OutArray` with each predecessor block
/// and its incoming phi value. If this argument is not a phi, return false.
bool getIncomingPhiValues(
llvm::SmallVectorImpl<std::pair<SILBasicBlock *, SILValue>>
&ReturnedPredAndPhiValuePairs);
/// Returns true if we were able to find a single terminator operand value for
/// each predecessor of this arguments basic block. The found values are
/// stored in OutArray.
///
/// Note: this peeks through any projections or cast implied by the
/// terminator. e.g. the incoming value for a switch_enum payload argument is
/// the enum itself (the operand of the switch_enum).
bool getSingleTerminatorOperands(llvm::SmallVectorImpl<SILValue> &OutArray);
/// Returns true if we were able to find single terminator operand values for
/// each predecessor of this arguments basic block. The found values are
/// stored in OutArray alongside their predecessor block.
///
/// Note: this peeks through any projections or cast implied by the
/// terminator. e.g. the incoming value for a switch_enum payload argument is
/// the enum itself (the operand of the switch_enum).
bool getSingleTerminatorOperands(
llvm::SmallVectorImpl<std::pair<SILBasicBlock *, SILValue>> &OutArray);
/// If this SILArgument's parent block has a single predecessor whose
/// terminator has a single operand, return the incoming operand of the
/// predecessor's terminator. Returns SILValue() otherwise. Note that for
/// some predecessor terminators the incoming value is not exactly the
/// argument value. E.g. the incoming value for a switch_enum payload argument
/// is the enum itself (the operand of the switch_enum).
SILValue getSingleTerminatorOperand() const;
/// Return the SILArgumentKind of this argument.
SILArgumentKind getKind() const {
return SILArgumentKind(ValueBase::getKind());
}
protected:
SILArgument(ValueKind SubClassKind, SILBasicBlock *ParentBB, SILType Ty,
ValueOwnershipKind OwnershipKind,
const ValueDecl *D = nullptr);
SILArgument(ValueKind SubClassKind, SILBasicBlock *ParentBB,
SILBasicBlock::arg_iterator Pos, SILType Ty,
ValueOwnershipKind OwnershipKind,
const ValueDecl *D = nullptr);
// A special constructor, only intended for use in
// SILBasicBlock::replacePHIArg and replaceFunctionArg.
explicit SILArgument(ValueKind SubClassKind, SILType Ty,
ValueOwnershipKind OwnershipKind,
const ValueDecl *D = nullptr)
: ValueBase(SubClassKind, Ty, IsRepresentative::Yes), ParentBB(nullptr),
Decl(D) {
Bits.SILArgument.VOKind = static_cast<unsigned>(OwnershipKind);
}
void setParent(SILBasicBlock *P) { ParentBB = P; }
friend SILBasicBlock;
};
class SILPhiArgument : public SILArgument {
public:
/// Return true if this is block argument is actually a phi argument as
/// opposed to a cast or projection.
bool isPhiArgument();
/// If this argument is a phi, return the incoming phi value for the given
/// predecessor BB. If this argument is not a phi, return an invalid SILValue.
///
/// FIXME: Once SILPhiArgument actually implies that it is a phi argument,
/// this will be guaranteed to return a valid SILValue.
SILValue getIncomingPhiValue(SILBasicBlock *BB);
/// If this argument is a phi, populate `OutArray` with the incoming phi
/// values for each predecessor BB. If this argument is not a phi, return
/// false.
///
/// FIXME: Once SILPhiArgument actually implies that it is a phi argument,
/// this will always succeed.
bool getIncomingPhiValues(llvm::SmallVectorImpl<SILValue> &OutArray);
/// If this argument is a phi, populate `OutArray` with each predecessor block
/// and its incoming phi value. If this argument is not a phi, return false.
///
/// FIXME: Once SILPhiArgument actually implies that it is a phi argument,
/// this will always succeed.
bool getIncomingPhiValues(
llvm::SmallVectorImpl<std::pair<SILBasicBlock *, SILValue>> &OutArray);
/// Returns true if we were able to find a single terminator operand value for
/// each predecessor of this arguments basic block. The found values are
/// stored in OutArray.
///
/// Note: this peeks through any projections or cast implied by the
/// terminator. e.g. the incoming value for a switch_enum payload argument is
/// the enum itself (the operand of the switch_enum).
bool getSingleTerminatorOperands(llvm::SmallVectorImpl<SILValue> &OutArray);
/// Returns true if we were able to find single terminator operand values for
/// each predecessor of this arguments basic block. The found values are
/// stored in OutArray alongside their predecessor block.
///
/// Note: this peeks through any projections or cast implied by the
/// terminator. e.g. the incoming value for a switch_enum payload argument is
/// the enum itself (the operand of the switch_enum).
bool getSingleTerminatorOperands(
llvm::SmallVectorImpl<std::pair<SILBasicBlock *, SILValue>> &OutArray);
/// If this SILArgument's parent block has a single predecessor whose
/// terminator has a single operand, return the incoming operand of the
/// predecessor's terminator. Returns SILValue() otherwise. Note that for
/// some predecessor terminators the incoming value is not exactly the
/// argument value. E.g. the incoming value for a switch_enum payload argument
/// is the enum itself (the operand of the switch_enum).
SILValue getSingleTerminatorOperand() const;
static bool classof(const SILInstruction *) = delete;
static bool classof(const SILUndef *) = delete;
static bool classof(const SILNode *node) {
return node->getKind() == SILNodeKind::SILPhiArgument;
}
private:
friend SILBasicBlock;
SILPhiArgument(SILBasicBlock *ParentBB, SILType Ty, ValueOwnershipKind OwnershipKind,
const ValueDecl *D = nullptr)
: SILArgument(ValueKind::SILPhiArgument, ParentBB, Ty, OwnershipKind, D) {}
SILPhiArgument(SILBasicBlock *ParentBB, SILBasicBlock::arg_iterator Pos,
SILType Ty, ValueOwnershipKind OwnershipKind,
const ValueDecl *D = nullptr)
: SILArgument(ValueKind::SILPhiArgument, ParentBB, Pos, Ty, OwnershipKind, D) {}
// A special constructor, only intended for use in
// SILBasicBlock::replacePHIArg.
explicit SILPhiArgument(SILType Ty, ValueOwnershipKind OwnershipKind,
const ValueDecl *D = nullptr)
: SILArgument(ValueKind::SILPhiArgument, Ty, OwnershipKind, D) {}
};
class SILFunctionArgument : public SILArgument {
public:
bool isIndirectResult() const {
auto numIndirectResults =
getFunction()->getConventions().getNumIndirectSILResults();
return (getIndex() < numIndirectResults);
}
SILArgumentConvention getArgumentConvention() const {
return getFunction()->getConventions().getSILArgumentConvention(getIndex());
}
/// Given that this is an entry block argument, and given that it does
/// not correspond to an indirect result, return the corresponding
/// SILParameterInfo.
SILParameterInfo getKnownParameterInfo() const {
return getFunction()->getConventions().getParamInfoForSILArg(getIndex());
}
/// Returns true if this SILArgument is the self argument of its
/// function. This means that this will return false always for SILArguments
/// of SILFunctions that do not have self argument and for non-function
/// argument SILArguments.
bool isSelf() const;
/// Returns true if this SILArgument is passed via the given convention.
bool hasConvention(SILArgumentConvention P) const {
return getArgumentConvention() == P;
}
static bool classof(const SILInstruction *) = delete;
static bool classof(const SILUndef *) = delete;
static bool classof(const SILNode *node) {
return node->getKind() == SILNodeKind::SILFunctionArgument;
}
private:
friend SILBasicBlock;
SILFunctionArgument(SILBasicBlock *ParentBB, SILType Ty, ValueOwnershipKind OwnershipKind,
const ValueDecl *D = nullptr)
: SILArgument(ValueKind::SILFunctionArgument, ParentBB, Ty, OwnershipKind, D) {}
SILFunctionArgument(SILBasicBlock *ParentBB, SILBasicBlock::arg_iterator Pos,
SILType Ty, ValueOwnershipKind OwnershipKind, const ValueDecl *D = nullptr)
: SILArgument(ValueKind::SILFunctionArgument, ParentBB, Pos, Ty, OwnershipKind, D) {}
// A special constructor, only intended for use in
// SILBasicBlock::replaceFunctionArg.
explicit SILFunctionArgument(SILType Ty, ValueOwnershipKind OwnershipKind,
const ValueDecl *D = nullptr)
: SILArgument(ValueKind::SILFunctionArgument, Ty, OwnershipKind, D) {}
};
//===----------------------------------------------------------------------===//
// Out of line Definitions for SILArgument to avoid Forward Decl issues
//===----------------------------------------------------------------------===//
inline bool SILArgument::isPhiArgument() {
if (auto *phiArg = dyn_cast<SILPhiArgument>(this))
return phiArg->isPhiArgument();
return false;
}
inline SILValue SILArgument::getIncomingPhiValue(SILBasicBlock *BB) {
if (isa<SILFunctionArgument>(this))
return SILValue();
return cast<SILPhiArgument>(this)->getIncomingPhiValue(BB);
}
inline bool
SILArgument::getIncomingPhiValues(llvm::SmallVectorImpl<SILValue> &OutArray) {
if (isa<SILFunctionArgument>(this))
return false;
return cast<SILPhiArgument>(this)->getIncomingPhiValues(OutArray);
}
inline bool SILArgument::getIncomingPhiValues(
llvm::SmallVectorImpl<std::pair<SILBasicBlock *, SILValue>> &OutArray) {
if (isa<SILFunctionArgument>(this))
return false;
return cast<SILPhiArgument>(this)->getIncomingPhiValues(OutArray);
}
inline bool SILArgument::getSingleTerminatorOperands(
llvm::SmallVectorImpl<SILValue> &OutArray) {
if (isa<SILFunctionArgument>(this))
return false;
return cast<SILPhiArgument>(this)->getSingleTerminatorOperands(OutArray);
}
inline bool SILArgument::getSingleTerminatorOperands(
llvm::SmallVectorImpl<std::pair<SILBasicBlock *, SILValue>> &OutArray) {
if (isa<SILFunctionArgument>(this))
return false;
return cast<SILPhiArgument>(this)->getSingleTerminatorOperands(OutArray);
}
} // end swift namespace
#endif