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.
This commit is contained in:
John McCall
2017-09-21 00:17:10 -07:00
parent 6d9294f565
commit ab3f77baf2
195 changed files with 6114 additions and 4985 deletions

View File

@@ -94,8 +94,8 @@ transferNodesFromList(llvm::ilist_traits<SILInstruction> &L2,
//===----------------------------------------------------------------------===//
// Assert that all subclasses of ValueBase implement classof.
#define VALUE(CLASS, PARENT) \
ASSERT_IMPLEMENTS_STATIC(CLASS, PARENT, classof, bool(const ValueBase*));
#define NODE(CLASS, PARENT) \
ASSERT_IMPLEMENTS_STATIC(CLASS, PARENT, classof, bool(const SILNode*));
#include "swift/SIL/SILNodes.def"
SILFunction *SILInstruction::getFunction() {
@@ -113,7 +113,11 @@ SILModule &SILInstruction::getModule() const {
/// block and deletes it.
///
void SILInstruction::eraseFromParent() {
assert(use_empty() && "There are uses of instruction being deleted.");
#ifndef NDEBUG
for (auto result : getResults()) {
assert(result->use_empty() && "Uses of SILInstruction remain at deletion.");
}
#endif
getParent()->erase(this);
}
@@ -168,16 +172,33 @@ void SILInstruction::dropAllReferences() {
}
}
ArrayRef<ValueBase> SILInstruction::getResultsImpl() const {
switch (getKind()) {
#define NON_VALUE_INST(ID, NAME, PARENT, MEMBEHAVIOR, MAYRELEASE) \
case SILInstructionKind::ID:
#include "swift/SIL/SILNodes.def"
return {};
#define SINGLE_VALUE_INST(ID, NAME, PARENT, MEMBEHAVIOR, MAYRELEASE) \
case SILInstructionKind::ID:
#include "swift/SIL/SILNodes.def"
return static_cast<const SingleValueInstruction *>(this)->getResultsImpl();
// add any multi-result instructions here...
}
llvm_unreachable("bad kind");
}
// Initialize the static members of SILInstruction.
int SILInstruction::NumCreatedInstructions = 0;
int SILInstruction::NumDeletedInstructions = 0;
/// Map a SILInstruction name to its SILInstructionKind.
SILInstructionKind swift::getSILInstructionKind(StringRef InstName) {
auto Kind = getSILValueKind(InstName);
if (Kind >= ValueKind::First_SILInstruction &&
Kind <= ValueKind::Last_SILInstruction)
return SILInstructionKind(Kind);
SILInstructionKind swift::getSILInstructionKind(StringRef name) {
#define FULL_INST(ID, NAME, PARENT, MEMBEHAVIOR, MAYRELEASE) \
if (name == #NAME) \
return SILInstructionKind::ID;
#include "swift/SIL/SILNodes.def"
#ifdef NDEBUG
llvm::errs() << "Unknown SIL instruction name\n";
@@ -187,15 +208,45 @@ SILInstructionKind swift::getSILInstructionKind(StringRef InstName) {
}
/// Map SILInstructionKind to a corresponding SILInstruction name.
StringRef swift::getSILInstructionName(SILInstructionKind Kind) {
return getSILValueName(ValueKind(Kind));
StringRef swift::getSILInstructionName(SILInstructionKind kind) {
switch (kind) {
#define FULL_INST(ID, NAME, PARENT, MEMBEHAVIOR, MAYRELEASE) \
case SILInstructionKind::ID: \
return #NAME;
#include "swift/SIL/SILNodes.def"
}
llvm_unreachable("bad kind");
}
void SILInstruction::replaceAllUsesOfAllResultsWithUndef() {
for (auto result : getResults()) {
result->replaceAllUsesWithUndef();
}
}
void SILInstruction::replaceAllUsesPairwiseWith(SILInstruction *other) {
auto results = getResults();
// If we don't have any results, fast-path out without asking the other
// instruction for its results.
if (results.empty()) {
assert(other->getResults().empty());
return;
}
// Replace values with the corresponding values of the other instruction.
auto otherResults = other->getResults();
assert(results.size() == otherResults.size());
for (auto i : indices(results)) {
results[i]->replaceAllUsesWith(otherResults[i]);
}
}
namespace {
class InstructionDestroyer
: public SILInstructionVisitor<InstructionDestroyer> {
public:
#define INST(CLASS, PARENT, TEXTUALNAME, MEMBEHAVIOR, MAYRELEASE) \
#define INST(CLASS, PARENT) \
void visit##CLASS(CLASS *I) { I->~CLASS(); }
#include "swift/SIL/SILNodes.def"
};
@@ -216,7 +267,7 @@ namespace {
InstructionIdentityComparer(const SILInstruction *L) : LHS(L) { }
/// Make sure we only process instructions we know how to process.
bool visitValueBase(const ValueBase *RHS) {
bool visitSILInstruction(const SILInstruction *RHS) {
return false;
}
@@ -735,14 +786,10 @@ bool SILInstruction::hasIdenticalState(const SILInstruction *RHS) const {
}
namespace {
class AllOperandsAccessor : public SILVisitor<AllOperandsAccessor,
ArrayRef<Operand> > {
class AllOperandsAccessor : public SILInstructionVisitor<AllOperandsAccessor,
ArrayRef<Operand> > {
public:
#define VALUE(CLASS, PARENT) \
ArrayRef<Operand> visit##CLASS(const CLASS *I) { \
llvm_unreachable("accessing non-instruction " #CLASS); \
}
#define INST(CLASS, PARENT, TEXTUALNAME, MEMBEHAVIOR, RELEASINGBEHAVIOR) \
#define INST(CLASS, PARENT) \
ArrayRef<Operand> visit##CLASS(const CLASS *I) { \
ASSERT_IMPLEMENTS(CLASS, SILInstruction, getAllOperands, \
ArrayRef<Operand>() const); \
@@ -752,14 +799,10 @@ namespace {
};
class AllOperandsMutableAccessor
: public SILVisitor<AllOperandsMutableAccessor,
MutableArrayRef<Operand> > {
: public SILInstructionVisitor<AllOperandsMutableAccessor,
MutableArrayRef<Operand> > {
public:
#define VALUE(CLASS, PARENT) \
MutableArrayRef<Operand> visit##CLASS(const CLASS *I) { \
llvm_unreachable("accessing non-instruction " #CLASS); \
}
#define INST(CLASS, PARENT, TEXTUALNAME, MEMBEHAVIOR, RELEASINGBEHAVIOR) \
#define INST(CLASS, PARENT) \
MutableArrayRef<Operand> visit##CLASS(CLASS *I) { \
ASSERT_IMPLEMENTS(CLASS, SILInstruction, getAllOperands, \
MutableArrayRef<Operand>()); \
@@ -773,14 +816,10 @@ namespace {
ExpectedType)>::value)
class TypeDependentOperandsAccessor
: public SILVisitor<TypeDependentOperandsAccessor,
ArrayRef<Operand>> {
: public SILInstructionVisitor<TypeDependentOperandsAccessor,
ArrayRef<Operand>> {
public:
#define VALUE(CLASS, PARENT) \
ArrayRef<Operand> visit##CLASS(const CLASS *I) { \
llvm_unreachable("accessing non-instruction " #CLASS); \
}
#define INST(CLASS, PARENT, TEXTUALNAME, MEMBEHAVIOR, RELEASINGBEHAVIOR) \
#define INST(CLASS, PARENT) \
ArrayRef<Operand> visit##CLASS(const CLASS *I) { \
if (!IMPLEMENTS_METHOD(CLASS, SILInstruction, getTypeDependentOperands, \
ArrayRef<Operand>() const)) \
@@ -791,14 +830,10 @@ namespace {
};
class TypeDependentOperandsMutableAccessor
: public SILVisitor<TypeDependentOperandsMutableAccessor,
MutableArrayRef<Operand> > {
: public SILInstructionVisitor<TypeDependentOperandsMutableAccessor,
MutableArrayRef<Operand> > {
public:
#define VALUE(CLASS, PARENT) \
MutableArrayRef<Operand> visit##CLASS(const CLASS *I) { \
llvm_unreachable("accessing non-instruction " #CLASS); \
}
#define INST(CLASS, PARENT, TEXTUALNAME, MEMBEHAVIOR, RELEASINGBEHAVIOR) \
#define INST(CLASS, PARENT) \
MutableArrayRef<Operand> visit##CLASS(CLASS *I) { \
if (!IMPLEMENTS_METHOD(CLASS, SILInstruction, getTypeDependentOperands, \
MutableArrayRef<Operand>())) \
@@ -868,28 +903,20 @@ SILInstruction::MemoryBehavior SILInstruction::getMemoryBehavior() const {
}
switch (getKind()) {
#define INST(CLASS, PARENT, TEXTUALNAME, MEMBEHAVIOR, RELEASINGBEHAVIOR) \
case ValueKind::CLASS: \
#define FULL_INST(CLASS, TEXTUALNAME, PARENT, MEMBEHAVIOR, RELEASINGBEHAVIOR) \
case SILInstructionKind::CLASS: \
return MemoryBehavior::MEMBEHAVIOR;
#include "swift/SIL/SILNodes.def"
case ValueKind::SILPHIArgument:
case ValueKind::SILFunctionArgument:
case ValueKind::SILUndef:
llvm_unreachable("Non-instructions are unreachable.");
}
llvm_unreachable("We've just exhausted the switch.");
}
SILInstruction::ReleasingBehavior SILInstruction::getReleasingBehavior() const {
switch (getKind()) {
#define INST(CLASS, PARENT, TEXTUALNAME, MEMBEHAVIOR, RELEASINGBEHAVIOR) \
case ValueKind::CLASS: \
#define FULL_INST(CLASS, TEXTUALNAME, PARENT, MEMBEHAVIOR, RELEASINGBEHAVIOR) \
case SILInstructionKind::CLASS: \
return ReleasingBehavior::RELEASINGBEHAVIOR;
#include "swift/SIL/SILNodes.def"
case ValueKind::SILPHIArgument:
case ValueKind::SILFunctionArgument:
case ValueKind::SILUndef:
llvm_unreachable("Non-instructions are unreachable.");
}
llvm_unreachable("We've just exhausted the switch.");
}
@@ -914,37 +941,37 @@ bool SILInstruction::mayRelease() const {
default:
llvm_unreachable("Unhandled releasing instruction!");
case ValueKind::ApplyInst:
case ValueKind::TryApplyInst:
case ValueKind::DestroyAddrInst:
case ValueKind::StrongReleaseInst:
case ValueKind::UnownedReleaseInst:
case ValueKind::ReleaseValueInst:
case ValueKind::ReleaseValueAddrInst:
case SILInstructionKind::ApplyInst:
case SILInstructionKind::TryApplyInst:
case SILInstructionKind::DestroyAddrInst:
case SILInstructionKind::StrongReleaseInst:
case SILInstructionKind::UnownedReleaseInst:
case SILInstructionKind::ReleaseValueInst:
case SILInstructionKind::ReleaseValueAddrInst:
return true;
case ValueKind::DestroyValueInst:
case SILInstructionKind::DestroyValueInst:
assert(!SILModuleConventions(getModule()).useLoweredAddresses());
return true;
case ValueKind::UnconditionalCheckedCastAddrInst:
case ValueKind::UnconditionalCheckedCastValueInst:
case SILInstructionKind::UnconditionalCheckedCastAddrInst:
case SILInstructionKind::UnconditionalCheckedCastValueInst:
return true;
case ValueKind::CheckedCastAddrBranchInst: {
case SILInstructionKind::CheckedCastAddrBranchInst: {
// Failing casts with take_always can release.
auto *Cast = cast<CheckedCastAddrBranchInst>(this);
return Cast->getConsumptionKind() == CastConsumptionKind::TakeAlways;
}
case ValueKind::CopyAddrInst: {
case SILInstructionKind::CopyAddrInst: {
auto *CopyAddr = cast<CopyAddrInst>(this);
// copy_addr without initialization can cause a release.
return CopyAddr->isInitializationOfDest() ==
IsInitialization_t::IsNotInitialization;
}
case ValueKind::BuiltinInst: {
case SILInstructionKind::BuiltinInst: {
auto *BI = cast<BuiltinInst>(this);
// Builtins without side effects also do not release.
if (!BI->mayHaveSideEffects())
@@ -976,8 +1003,8 @@ bool SILInstruction::mayRelease() const {
bool SILInstruction::mayReleaseOrReadRefCount() const {
switch (getKind()) {
case ValueKind::IsUniqueInst:
case ValueKind::IsUniqueOrPinnedInst:
case SILInstructionKind::IsUniqueInst:
case SILInstructionKind::IsUniqueOrPinnedInst:
return true;
default:
return mayRelease();
@@ -987,7 +1014,7 @@ bool SILInstruction::mayReleaseOrReadRefCount() const {
namespace {
class TrivialCloner : public SILCloner<TrivialCloner> {
friend class SILCloner<TrivialCloner>;
friend class SILVisitor<TrivialCloner>;
friend class SILInstructionVisitor<TrivialCloner>;
SILInstruction *Result = nullptr;
TrivialCloner(SILFunction *F) : SILCloner(*F) {}
public:
@@ -1084,9 +1111,9 @@ bool SILInstruction::isTriviallyDuplicatable() const {
bool SILInstruction::mayTrap() const {
switch(getKind()) {
case ValueKind::CondFailInst:
case ValueKind::UnconditionalCheckedCastInst:
case ValueKind::UnconditionalCheckedCastAddrInst:
case SILInstructionKind::CondFailInst:
case SILInstructionKind::UnconditionalCheckedCastInst:
case SILInstructionKind::UnconditionalCheckedCastAddrInst:
return true;
default:
return false;