mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
Doug found that the verifier would admit a DowncastInst that took an lvalue as the input, which is bogus. Refine the verifier rules for DowncastInst so it only admits class rvalues and destination types. Swift SVN r4685
695 lines
30 KiB
C++
695 lines
30 KiB
C++
//===--- Verifier.cpp - Verification of Swift SIL Code --------------------===//
|
|
//
|
|
// This source file is part of the Swift.org open source project
|
|
//
|
|
// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors
|
|
// Licensed under Apache License v2.0 with Runtime Library Exception
|
|
//
|
|
// See http://swift.org/LICENSE.txt for license information
|
|
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "swift/SIL/SILFunction.h"
|
|
#include "swift/SIL/SILVisitor.h"
|
|
#include "swift/AST/ASTContext.h"
|
|
#include "swift/AST/Types.h"
|
|
#include "swift/AST/Decl.h"
|
|
#include "swift/Basic/Range.h"
|
|
#include "llvm/Support/Debug.h"
|
|
|
|
using namespace swift;
|
|
|
|
// The verifier is basically all assertions, so don't compile it with NDEBUG to
|
|
// prevent release builds from triggering spurious unused variable warnings.
|
|
#ifndef NDEBUG
|
|
|
|
namespace {
|
|
/// SILVerifier class - This class implements the SIL verifier, which walks over
|
|
/// SIL, checking and enforcing its invariants.
|
|
class SILVerifier : public SILVisitor<SILVerifier> {
|
|
SILFunction const &F;
|
|
public:
|
|
SILVerifier(SILFunction const &F) : F(F) {}
|
|
|
|
void visit(SILInstruction *I) {
|
|
|
|
const SILBasicBlock *BB = I->getParent();
|
|
// Check that non-terminators look ok.
|
|
if (!isa<TermInst>(I)) {
|
|
assert(!BB->empty() &&
|
|
"Can't be in a parent block if it is empty");
|
|
assert(&*BB->getInsts().rbegin() != I &&
|
|
"Non-terminators cannot be the last in a block");
|
|
} else {
|
|
assert(&*BB->getInsts().rbegin() == I &&
|
|
"Terminator must be the last in block");
|
|
}
|
|
|
|
|
|
// Dispatch to our more-specialized instances below.
|
|
((SILVisitor<SILVerifier>*)this)->visit(I);
|
|
}
|
|
|
|
void visitAllocVarInst(AllocVarInst *AI) {
|
|
assert(AI->getType().isAddress() && "alloc_var must return address");
|
|
}
|
|
|
|
void visitAllocRefInst(AllocRefInst *AI) {
|
|
assert(AI->getType().hasReferenceSemantics() && !AI->getType().isAddress()
|
|
&& "alloc_ref must return reference type value");
|
|
}
|
|
|
|
void visitApplyInst(ApplyInst *AI) {
|
|
DEBUG(llvm::dbgs() << "verifying";
|
|
AI->print(llvm::dbgs()));
|
|
SILType calleeTy = AI->getCallee().getType();
|
|
DEBUG(llvm::dbgs() << "callee type: ";
|
|
AI->getCallee().getType().print(llvm::dbgs());
|
|
llvm::dbgs() << '\n');
|
|
assert(!calleeTy.isAddress() && "callee of apply cannot be an address");
|
|
assert(calleeTy.is<FunctionType>() &&
|
|
"callee of apply must have concrete function type");
|
|
SILFunctionTypeInfo *ti = calleeTy.getFunctionTypeInfo();
|
|
|
|
DEBUG(llvm::dbgs() << "function input types:\n";
|
|
for (SILType t : ti->getInputTypes()) {
|
|
llvm::dbgs() << " ";
|
|
t.print(llvm::dbgs());
|
|
llvm::dbgs() << '\n';
|
|
});
|
|
DEBUG(llvm::dbgs() << "function result type ";
|
|
ti->getResultType().print(llvm::dbgs());
|
|
llvm::dbgs() << '\n');
|
|
|
|
DEBUG(llvm::dbgs() << "argument types:\n";
|
|
for (SILValue arg : AI->getArguments()) {
|
|
llvm::dbgs() << " ";
|
|
arg.getType().print(llvm::dbgs());
|
|
llvm::dbgs() << '\n';
|
|
});
|
|
|
|
// Check that the arguments and result match.
|
|
assert(AI->getArguments().size() == ti->getInputTypes().size() &&
|
|
"apply doesn't have right number of arguments for function");
|
|
for (size_t i = 0, size = AI->getArguments().size(); i < size; ++i) {
|
|
DEBUG(llvm::dbgs() << " argument type ";
|
|
AI->getArguments()[i].getType().print(llvm::dbgs());
|
|
llvm::dbgs() << " for input type ";
|
|
ti->getInputTypes()[i].print(llvm::dbgs());
|
|
llvm::dbgs() << '\n');
|
|
assert(AI->getArguments()[i].getType() == ti->getInputTypes()[i] &&
|
|
"input types to apply don't match function input types");
|
|
}
|
|
DEBUG(llvm::dbgs() << "result type ";
|
|
AI->getType().print(llvm::dbgs());
|
|
llvm::dbgs() << '\n');
|
|
assert(AI->getType() == ti->getResultType() &&
|
|
"type of apply instruction doesn't match function result type");
|
|
}
|
|
|
|
void visitPartialApplyInst(PartialApplyInst *PAI) {
|
|
SILType calleeTy = PAI->getCallee().getType();
|
|
assert(!calleeTy.isAddress() && "callee of closure cannot be an address");
|
|
assert(calleeTy.is<FunctionType>() &&
|
|
"callee of closure must have concrete function type");
|
|
assert(calleeTy.castTo<FunctionType>()->isThin() &&
|
|
"callee of closure must have a thin function type");
|
|
SILType appliedTy = PAI->getType();
|
|
assert(!appliedTy.isAddress() && "result of closure cannot be an address");
|
|
assert(appliedTy.is<FunctionType>() &&
|
|
"result of closure must have concrete function type");
|
|
// FIXME: A "curry" with no arguments could remain thin.
|
|
assert(!appliedTy.castTo<FunctionType>()->isThin() &&
|
|
"result of closure cannot have a thin function type");
|
|
|
|
SILFunctionTypeInfo *ti = calleeTy.getFunctionTypeInfo();
|
|
|
|
// Check that the arguments match the curry levels.
|
|
assert(PAI->getArguments().size() == ti->getCurryInputTypes().size() &&
|
|
"closure doesn't have right number of curry arguments for function");
|
|
for (size_t i = 0, size = PAI->getArguments().size(); i < size; ++i) {
|
|
DEBUG(llvm::dbgs() << " argument type ";
|
|
PAI->getArguments()[i].getType().print(llvm::dbgs());
|
|
llvm::dbgs() << " for input type ";
|
|
ti->getCurryInputTypes()[i].print(llvm::dbgs());
|
|
llvm::dbgs() << '\n');
|
|
assert(PAI->getArguments()[i].getType() == ti->getCurryInputTypes()[i] &&
|
|
"input types to closure don't match function input types");
|
|
}
|
|
DEBUG(llvm::dbgs() << "result type ";
|
|
PAI->getType().print(llvm::dbgs());
|
|
llvm::dbgs() << '\n');
|
|
|
|
// The result type should match the uncurried type.
|
|
FunctionType *ft = calleeTy.castTo<FunctionType>();
|
|
for (unsigned i = 0; i < calleeTy.getUncurryLevel(); ++i)
|
|
ft = ft->getResult()->castTo<FunctionType>();
|
|
|
|
assert(PAI->getType().getSwiftType()->isEqual(ft)
|
|
&& PAI->getType().getUncurryLevel() == 0
|
|
&& "type of apply instruction doesn't match function result type");
|
|
|
|
}
|
|
|
|
void visitConstantRefInst(ConstantRefInst *CRI) {
|
|
if (CRI->getConstant().kind == SILConstant::Kind::GlobalAddress) {
|
|
assert(CRI->getType().isAddress() &&
|
|
"GlobalAddress SILConstant must have an address result type");
|
|
return;
|
|
}
|
|
|
|
assert(CRI->getType().is<AnyFunctionType>() &&
|
|
"constant_ref should have a function result");
|
|
assert(CRI->getType().castTo<AnyFunctionType>()->isThin() &&
|
|
"constant_ref should have a thin function result");
|
|
}
|
|
|
|
void visitIntegerLiteralInst(IntegerLiteralInst *ILI) {
|
|
assert(ILI->getType().is<BuiltinIntegerType>() &&
|
|
"invalid integer literal type");
|
|
}
|
|
void visitLoadInst(LoadInst *LI) {
|
|
assert(!LI->getType().isAddress() && "Can't load an address");
|
|
assert(LI->getLValue().getType().isAddress() &&
|
|
"Load operand must be an address");
|
|
assert(LI->getLValue().getType().getObjectType() == LI->getType() &&
|
|
"Load operand type and result type mismatch");
|
|
}
|
|
|
|
void visitStoreInst(StoreInst *SI) {
|
|
assert(!SI->getSrc().getType().isAddress() &&
|
|
"Can't store from an address source");
|
|
assert(SI->getDest().getType().isAddress() &&
|
|
"Must store to an address dest");
|
|
assert(SI->getDest().getType().getObjectType() == SI->getSrc().getType() &&
|
|
"Store operand type and dest type mismatch");
|
|
}
|
|
|
|
void visitCopyAddrInst(CopyAddrInst *SI) {
|
|
assert(SI->getSrc().getType().isAddress() &&
|
|
"Src value should be lvalue");
|
|
assert(SI->getDest().getType().isAddress() &&
|
|
"Dest address should be lvalue");
|
|
assert(SI->getDest().getType() == SI->getSrc().getType() &&
|
|
"Store operand type and dest type mismatch");
|
|
}
|
|
|
|
void visitInitializeVarInst(InitializeVarInst *ZI) {
|
|
assert(ZI->getDest().getType().isAddress() &&
|
|
"Dest address should be lvalue");
|
|
}
|
|
|
|
void visitSpecializeInst(SpecializeInst *SI) {
|
|
assert(SI->getType().is<FunctionType>() &&
|
|
"Specialize result should have a function type");
|
|
assert(SI->getType().castTo<FunctionType>()->isThin() &&
|
|
"Specialize result should have a thin function type");
|
|
|
|
SILType operandTy = SI->getOperand().getType();
|
|
assert((operandTy.is<PolymorphicFunctionType>()
|
|
|| (operandTy.is<FunctionType>()
|
|
&& operandTy.castTo<FunctionType>()->getResult()
|
|
->is<PolymorphicFunctionType>()))
|
|
&& "Specialize source should have a polymorphic function type");
|
|
assert(operandTy.castTo<AnyFunctionType>()->isThin()
|
|
&& "Specialize source should have a thin function type");
|
|
assert(SI->getType().getUncurryLevel()
|
|
== SI->getOperand().getType().getUncurryLevel()
|
|
&& "Specialize source and dest uncurry levels must match");
|
|
}
|
|
|
|
void visitTupleInst(TupleInst *TI) {
|
|
assert(TI->getType().is<TupleType>() && "TupleInst should return a tuple");
|
|
TupleType *ResTy = TI->getType().castTo<TupleType>();
|
|
|
|
assert(TI->getElements().size() == ResTy->getFields().size() &&
|
|
"Tuple field count mismatch!");
|
|
}
|
|
void visitMetatypeInst(MetatypeInst *MI) {
|
|
assert(MI->getType(0).is<MetaTypeType>() &&
|
|
"metatype instruction must be of metatype type");
|
|
}
|
|
void visitClassMetatypeInst(ClassMetatypeInst *MI) {
|
|
assert(MI->getType().is<MetaTypeType>() &&
|
|
"class_metatype instruction must be of metatype type");
|
|
assert(MI->getBase().getType().getSwiftType()->getClassOrBoundGenericClass() &&
|
|
"class_metatype base must be of class type");
|
|
assert(MI->getBase().getType().getSwiftType() ==
|
|
CanType(MI->getType().castTo<MetaTypeType>()->getInstanceType()) &&
|
|
"class_metatype result must be metatype of base class type");
|
|
}
|
|
void visitArchetypeMetatypeInst(ArchetypeMetatypeInst *MI) {
|
|
assert(MI->getType().is<MetaTypeType>() &&
|
|
"archetype_metatype instruction must be of metatype type");
|
|
assert(MI->getBase().getType().isAddress() &&
|
|
"archetype_metatype operand must be an address");
|
|
assert(MI->getBase().getType().getSwiftRValueType()->is<ArchetypeType>() &&
|
|
"archetype_metatype operand must be address of archetype type");
|
|
assert(MI->getBase().getType().getSwiftRValueType() ==
|
|
CanType(MI->getType().castTo<MetaTypeType>()->getInstanceType()) &&
|
|
"archetype_metatype result must be metatype of operand type");
|
|
}
|
|
void visitProtocolMetatypeInst(ProtocolMetatypeInst *MI) {
|
|
assert(MI->getType().is<MetaTypeType>() &&
|
|
"protocol_metatype instruction must be of metatype type");
|
|
assert(MI->getBase().getType().isAddress() &&
|
|
"protocol_metatype operand must be an address");
|
|
assert(MI->getBase().getType().getSwiftRValueType()->isExistentialType() &&
|
|
"protocol_metatype operand must be address of protocol type");
|
|
assert(MI->getBase().getType().getSwiftRValueType() ==
|
|
CanType(MI->getType().castTo<MetaTypeType>()->getInstanceType()) &&
|
|
"protocol_metatype result must be metatype of operand type");
|
|
}
|
|
void visitModuleInst(ModuleInst *MI) {
|
|
assert(MI->getType(0).is<ModuleType>() &&
|
|
"module instruction must be of module type");
|
|
}
|
|
void visitAssociatedMetatypeInst(AssociatedMetatypeInst *MI) {
|
|
assert(MI->getType(0).is<MetaTypeType>() &&
|
|
"associated_metatype instruction must be of metatype type");
|
|
assert(MI->getSourceMetatype().getType().is<MetaTypeType>() &&
|
|
"associated_metatype operand must be of metatype type");
|
|
}
|
|
|
|
void visitRetainInst(RetainInst *RI) {
|
|
assert(!RI->getOperand().getType().isAddress() &&
|
|
"Operand of retain must not be address");
|
|
assert(RI->getOperand().getType().hasReferenceSemantics() &&
|
|
"Operand of dealloc_ref must be reference type");
|
|
}
|
|
void visitReleaseInst(ReleaseInst *RI) {
|
|
assert(!RI->getOperand().getType().isAddress() &&
|
|
"Operand of release must not be address");
|
|
assert(RI->getOperand().getType().hasReferenceSemantics() &&
|
|
"Operand of dealloc_ref must be reference type");
|
|
}
|
|
void visitDeallocVarInst(DeallocVarInst *DI) {
|
|
assert(DI->getOperand().getType().isAddress() &&
|
|
"Operand of dealloc_var must be address");
|
|
}
|
|
void visitDeallocRefInst(DeallocRefInst *DI) {
|
|
assert(!DI->getOperand().getType().isAddress() &&
|
|
"Operand of dealloc_ref must not be address");
|
|
assert(DI->getOperand().getType().hasReferenceSemantics() &&
|
|
"Operand of dealloc_ref must be reference type");
|
|
}
|
|
void visitDestroyAddrInst(DestroyAddrInst *DI) {
|
|
assert(DI->getOperand().getType().isAddressOnly() &&
|
|
"Operand of destroy_addr must be address-only");
|
|
}
|
|
|
|
void visitIndexAddrInst(IndexAddrInst *IAI) {
|
|
assert(IAI->getType().isAddress() &&
|
|
IAI->getType() == IAI->getOperand().getType() &&
|
|
"invalid IndexAddrInst");
|
|
}
|
|
|
|
void visitExtractInst(ExtractInst *EI) {
|
|
SILType operandTy = EI->getOperand().getType();
|
|
assert(!operandTy.isAddress() &&
|
|
"cannot extract from address");
|
|
assert(!operandTy.hasReferenceSemantics() &&
|
|
"cannot extract from reference type");
|
|
assert(!EI->getType(0).isAddress() &&
|
|
"result of extract cannot be address");
|
|
}
|
|
|
|
void visitElementAddrInst(ElementAddrInst *EI) {
|
|
SILType operandTy = EI->getOperand().getType();
|
|
assert(operandTy.isAddress() &&
|
|
"must derive element_addr from address");
|
|
assert(!operandTy.hasReferenceSemantics() &&
|
|
"cannot derive element_addr from reference type");
|
|
assert(EI->getType(0).isAddress() &&
|
|
"result of element_addr must be lvalue");
|
|
}
|
|
|
|
void visitRefElementAddrInst(RefElementAddrInst *EI) {
|
|
SILType operandTy = EI->getOperand().getType();
|
|
assert(!operandTy.isAddress() &&
|
|
"must derive ref_element_addr from non-address");
|
|
assert(operandTy.hasReferenceSemantics() &&
|
|
"must derive ref_element_addr from reference type");
|
|
assert(EI->getType(0).isAddress() &&
|
|
"result of ref_element_addr must be lvalue");
|
|
}
|
|
|
|
void visitArchetypeMethodInst(ArchetypeMethodInst *AMI) {
|
|
DEBUG(llvm::dbgs() << "verifying";
|
|
AMI->print(llvm::dbgs()));
|
|
assert(AMI->getType(0).getUncurryLevel() == AMI->getMember().uncurryLevel &&
|
|
"result method must be at natural uncurry level of method");
|
|
FunctionType *methodType = AMI->getType(0).getAs<FunctionType>();
|
|
DEBUG(llvm::dbgs() << "method type ";
|
|
methodType->print(llvm::dbgs());
|
|
llvm::dbgs() << "\n");
|
|
assert(methodType &&
|
|
"result method must be of a concrete function type");
|
|
assert(methodType->isThin() &&
|
|
"result method must be of a thin function type");
|
|
SILType operandType = AMI->getOperand().getType();
|
|
DEBUG(llvm::dbgs() << "operand type ";
|
|
operandType.print(llvm::dbgs());
|
|
llvm::dbgs() << "\n");
|
|
assert(methodType->getInput()->isEqual(operandType.getSwiftType()) &&
|
|
"result must be a method of the operand");
|
|
assert(methodType->getResult()->is<FunctionType>() &&
|
|
"result must be a method");
|
|
if (operandType.isAddress()) {
|
|
assert(operandType.is<ArchetypeType>() &&
|
|
"archetype_method must apply to an archetype address");
|
|
} else if (MetaTypeType *mt = operandType.getAs<MetaTypeType>()) {
|
|
assert(mt->getInstanceType()->is<ArchetypeType>() &&
|
|
"archetype_method must apply to an archetype metatype");
|
|
} else
|
|
llvm_unreachable("method must apply to an address or metatype");
|
|
}
|
|
|
|
void visitProtocolMethodInst(ProtocolMethodInst *EMI) {
|
|
assert(EMI->getType(0).getUncurryLevel() == EMI->getMember().uncurryLevel &&
|
|
"result method must be at natural uncurry level of method");
|
|
assert(EMI->getType(0).getUncurryLevel() == 1 &&
|
|
"protocol method result must be at uncurry level 1");
|
|
FunctionType *methodType = EMI->getType(0).getAs<FunctionType>();
|
|
assert(methodType &&
|
|
"result method must be of a concrete function type");
|
|
assert(!methodType->isThin() &&
|
|
"result method must not be of a thin function type");
|
|
SILType operandType = EMI->getOperand().getType();
|
|
assert(methodType->getInput()->isEqual(
|
|
operandType.getASTContext().TheOpaquePointerType) &&
|
|
"result must be a method of opaque pointer");
|
|
assert(methodType->getResult()->is<FunctionType>() &&
|
|
"result must be a method");
|
|
assert(operandType.isAddress() &&
|
|
"protocol_method must apply to an existential address");
|
|
assert(operandType.isExistentialType() &&
|
|
"protocol_method must apply to an existential address");
|
|
}
|
|
|
|
static bool isClassOrClassMetatype(Type t) {
|
|
if (auto *meta = t->getAs<MetaTypeType>()) {
|
|
return bool(meta->getInstanceType()->getClassOrBoundGenericClass());
|
|
} else {
|
|
return bool(t->getClassOrBoundGenericClass());
|
|
}
|
|
}
|
|
|
|
void visitClassMethodInst(ClassMethodInst *CMI) {
|
|
assert(CMI->getType(0).getUncurryLevel() == CMI->getMember().uncurryLevel &&
|
|
"result method must be at natural uncurry level of method");
|
|
auto *methodType = CMI->getType(0).getAs<AnyFunctionType>();
|
|
assert(methodType &&
|
|
"result method must be of a function type");
|
|
assert(methodType->isThin() &&
|
|
"result method must be of a thin function type");
|
|
SILType operandType = CMI->getOperand().getType();
|
|
assert(isClassOrClassMetatype(operandType.getSwiftType()) &&
|
|
"operand must be of a class type");
|
|
assert(isClassOrClassMetatype(methodType->getInput()) &&
|
|
"result must be a method of a class");
|
|
assert(methodType->getResult()->is<AnyFunctionType>() &&
|
|
"result must be a method");
|
|
}
|
|
|
|
void visitSuperMethodInst(SuperMethodInst *CMI) {
|
|
assert(CMI->getType(0).getUncurryLevel() == CMI->getMember().uncurryLevel &&
|
|
"result method must be at natural uncurry level of method");
|
|
auto *methodType = CMI->getType(0).getAs<AnyFunctionType>();
|
|
assert(methodType &&
|
|
"result method must be of a function type");
|
|
assert(methodType->isThin() &&
|
|
"result method must be of a thin function type");
|
|
SILType operandType = CMI->getOperand().getType();
|
|
assert(isClassOrClassMetatype(operandType.getSwiftType()) &&
|
|
"operand must be of a class type");
|
|
assert(isClassOrClassMetatype(methodType->getInput()) &&
|
|
"result must be a method of a class");
|
|
assert(methodType->getResult()->is<AnyFunctionType>() &&
|
|
"result must be a method");
|
|
}
|
|
|
|
void visitProjectExistentialInst(ProjectExistentialInst *PEI) {
|
|
SILType operandType = PEI->getOperand().getType();
|
|
assert(operandType.isAddress() && "project_existential must be applied to address");
|
|
assert(operandType.isExistentialType() &&
|
|
"project_existential must be applied to address of existential");
|
|
}
|
|
|
|
void visitInitExistentialInst(InitExistentialInst *AEI) {
|
|
SILType exType = AEI->getExistential().getType();
|
|
assert(exType.isAddress() &&
|
|
"init_existential must be applied to an address");
|
|
assert(exType.isExistentialType() &&
|
|
"init_existential must be applied to address of existential");
|
|
assert(!AEI->getConcreteType()->isExistentialType() &&
|
|
"init_existential cannot put an existential container inside "
|
|
"an existential container");
|
|
}
|
|
|
|
void visitUpcastExistentialInst(UpcastExistentialInst *UEI) {
|
|
SILType srcType = UEI->getSrcExistential().getType();
|
|
SILType destType = UEI->getDestExistential().getType();
|
|
assert(srcType.isAddress() &&
|
|
"upcast_existential source must be an address");
|
|
assert(srcType.isExistentialType() &&
|
|
"upcast_existential source must be address of existential");
|
|
assert(destType.isAddress() &&
|
|
"upcast_existential dest must be an address");
|
|
assert(destType.isExistentialType() &&
|
|
"upcast_existential dest must be address of existential");
|
|
}
|
|
|
|
void visitDeinitExistentialInst(DeinitExistentialInst *DEI) {
|
|
SILType exType = DEI->getExistential().getType();
|
|
assert(exType.isAddress() &&
|
|
"deinit_existential must be applied to an address");
|
|
assert(exType.isExistentialType() &&
|
|
"deinit_existential must be applied to address of existential");
|
|
}
|
|
|
|
void visitArchetypeToSuperInst(ArchetypeToSuperInst *ASI) {
|
|
assert(ASI->getOperand().getType().isAddressOnly() &&
|
|
"archetype_to_super operand must be an address");
|
|
assert(ASI->getOperand().getType().is<ArchetypeType>() &&
|
|
"archetype_to_super operand must be archetype");
|
|
assert(ASI->getType().hasReferenceSemantics() &&
|
|
"archetype_to_super must convert to a reference type");
|
|
}
|
|
|
|
void visitThinToThickFunctionInst(ThinToThickFunctionInst *TTFI) {
|
|
assert(!TTFI->getOperand().getType().isAddress() &&
|
|
"thin_to_thick_function operand cannot be an address");
|
|
assert(!TTFI->getType().isAddress() &&
|
|
"thin_to_thick_function result cannot be an address");
|
|
assert(TTFI->getOperand().getType().is<AnyFunctionType>() &&
|
|
"thin_to_thick_function operand must be a function");
|
|
assert(TTFI->getType().is<AnyFunctionType>() &&
|
|
"thin_to_thick_function result must be a function");
|
|
if (auto *opFTy = dyn_cast<FunctionType>(
|
|
TTFI->getOperand().getType().getSwiftType())) {
|
|
auto *resFTy = dyn_cast<FunctionType>(TTFI->getType().getSwiftType());
|
|
assert(resFTy &&
|
|
opFTy->getInput()->isEqual(resFTy->getInput()) &&
|
|
opFTy->getResult()->isEqual(resFTy->getResult()) &&
|
|
opFTy->isAutoClosure() == resFTy->isAutoClosure() &&
|
|
opFTy->isBlock() == resFTy->isBlock() &&
|
|
"thin_to_thick_function operand and result type must differ only "
|
|
" in thinness");
|
|
assert(!resFTy->isThin() &&
|
|
"thin_to_thick_function result must not be thin");
|
|
assert(opFTy->isThin() &&
|
|
"thin_to_thick_function operand must be thin");
|
|
} else if (auto *opPTy = dyn_cast<PolymorphicFunctionType>(
|
|
TTFI->getOperand().getType().getSwiftType())) {
|
|
auto *resPTy = dyn_cast<PolymorphicFunctionType>(
|
|
TTFI->getType().getSwiftType());
|
|
assert(resPTy &&
|
|
opPTy->getInput()->isEqual(resPTy->getInput()) &&
|
|
opPTy->getResult()->isEqual(resPTy->getResult()) &&
|
|
"thin_to_thick_function operand and result type must differ only "
|
|
" in thinness");
|
|
assert(!resPTy->isThin() &&
|
|
"thin_to_thick_function result must not be thin");
|
|
assert(opPTy->isThin() &&
|
|
"thin_to_thick_function operand must be thin");
|
|
} else {
|
|
llvm_unreachable("invalid AnyFunctionType?!");
|
|
}
|
|
}
|
|
|
|
void visitSuperToArchetypeInst(SuperToArchetypeInst *SAI) {
|
|
assert(SAI->getSrcBase().getType().hasReferenceSemantics() &&
|
|
"super_to_archetype source must be a reference type");
|
|
assert(SAI->getDestArchetypeAddress().getType().is<ArchetypeType>() &&
|
|
"super_to_archetype dest must be an archetype address");
|
|
}
|
|
|
|
void visitUpcastInst(UpcastInst *UI) {
|
|
if (UI->getType().is<MetaTypeType>()) {
|
|
CanType instTy(UI->getType().castTo<MetaTypeType>()->getInstanceType());
|
|
assert(UI->getOperand().getType().is<MetaTypeType>()
|
|
&& "upcast operand must be a class or class metatype instance");
|
|
CanType opInstTy(UI->getOperand().getType().castTo<MetaTypeType>()
|
|
->getInstanceType());
|
|
assert(opInstTy->getClassOrBoundGenericClass()
|
|
&& "upcast operand must be a class or class metatype instance");
|
|
assert(instTy->getClassOrBoundGenericClass()
|
|
&& "upcast must convert a class metatype to a class metatype");
|
|
} else {
|
|
assert(UI->getOperand().getType().getSwiftType()
|
|
->getClassOrBoundGenericClass() &&
|
|
"upcast operand must be a class or class metatype instance");
|
|
assert(UI->getType().getSwiftType()->getClassOrBoundGenericClass() &&
|
|
"upcast must convert a class instance to a class type");
|
|
}
|
|
}
|
|
|
|
void visitDowncastInst(DowncastInst *DI) {
|
|
assert(DI->getOperand().getType().getSwiftType()
|
|
->getClassOrBoundGenericClass() &&
|
|
"downcast operand must be a class type");
|
|
assert(DI->getType().getSwiftType()->getClassOrBoundGenericClass() &&
|
|
"downcast must convert to a class type");
|
|
}
|
|
|
|
void visitAddressToPointerInst(AddressToPointerInst *AI) {
|
|
assert(AI->getOperand().getType().isAddress() &&
|
|
"address-to-pointer operand must be an address");
|
|
assert(AI->getType().getSwiftType()->isEqual(
|
|
AI->getType().getASTContext().TheRawPointerType)
|
|
&& "address-to-pointer result type must be RawPointer");
|
|
}
|
|
|
|
void visitConvertFunctionInst(ConvertFunctionInst *ICI) {
|
|
assert(!ICI->getOperand().getType().isAddress() &&
|
|
"conversion operand cannot be an address");
|
|
assert(!ICI->getType().isAddress() &&
|
|
"conversion result cannot be an address");
|
|
|
|
auto *opFTy = ICI->getOperand().getType().getAs<AnyFunctionType>();
|
|
auto *resFTy = ICI->getType().getAs<AnyFunctionType>();
|
|
|
|
assert(opFTy && "convert_function operand must be a function");
|
|
assert(resFTy && "convert_function result must be a function");
|
|
|
|
assert(opFTy->isThin() == resFTy->isThin() &&
|
|
"convert_function cannot change function thinness");
|
|
|
|
SILFunctionTypeInfo *opTI
|
|
= ICI->getOperand().getType().getFunctionTypeInfo();
|
|
SILFunctionTypeInfo *resTI = ICI->getType().getFunctionTypeInfo();
|
|
|
|
assert(opTI->getResultType() == resTI->getResultType() &&
|
|
"result types of convert_function operand and result do no match");
|
|
assert(opTI->getInputTypes().size() == resTI->getInputTypes().size() &&
|
|
"input types of convert_function operand and result do not match");
|
|
assert(std::equal(opTI->getInputTypes().begin(), opTI->getInputTypes().end(),
|
|
resTI->getInputTypes().begin()) &&
|
|
"input types of convert_function operand and result do not match");
|
|
}
|
|
|
|
void visitIntegerValueInst(IntegerValueInst *IVI) {
|
|
assert(IVI->getType().is<BuiltinIntegerType>() &&
|
|
"invalid integer value type");
|
|
}
|
|
|
|
void visitReturnInst(ReturnInst *RI) {
|
|
DEBUG(RI->print(llvm::dbgs()));
|
|
assert(RI->getReturnValue() && "Return of null value is invalid");
|
|
|
|
SILFunctionTypeInfo *ti =
|
|
F.getLoweredType().getFunctionTypeInfo();
|
|
SILType functionResultType = ti->getResultType();
|
|
SILType instResultType = RI->getReturnValue().getType();
|
|
DEBUG(llvm::dbgs() << "function return type: ";
|
|
functionResultType.dump();
|
|
llvm::dbgs() << "return inst type: ";
|
|
instResultType.dump(););
|
|
assert(functionResultType == instResultType &&
|
|
"return value type does not match return type of function");
|
|
}
|
|
|
|
void visitBranchInst(BranchInst *BI) {
|
|
assert(BI->getArgs().size() == BI->getDestBB()->bbarg_size() &&
|
|
"branch has wrong number of arguments for dest bb");
|
|
assert(std::equal(BI->getArgs().begin(), BI->getArgs().end(),
|
|
BI->getDestBB()->bbarg_begin(),
|
|
[](SILValue branchArg, SILArgument *bbArg) {
|
|
return branchArg.getType() == bbArg->getType();
|
|
}) &&
|
|
"branch argument types do not match arguments for dest bb");
|
|
}
|
|
|
|
void visitCondBranchInst(CondBranchInst *CBI) {
|
|
assert(CBI->getCondition() &&
|
|
"Condition of conditional branch can't be missing");
|
|
assert(CBI->getCondition().getType() ==
|
|
SILType::getBuiltinIntegerType(1,
|
|
CBI->getCondition().getType().getASTContext())
|
|
&& "condition of conditional branch must have Int1 type");
|
|
|
|
assert(CBI->getTrueArgs().size() == CBI->getTrueBB()->bbarg_size() &&
|
|
"true branch has wrong number of arguments for dest bb");
|
|
assert(std::equal(CBI->getTrueArgs().begin(), CBI->getTrueArgs().end(),
|
|
CBI->getTrueBB()->bbarg_begin(),
|
|
[](SILValue branchArg, SILArgument *bbArg) {
|
|
return branchArg.getType() == bbArg->getType();
|
|
}) &&
|
|
"true branch argument types do not match arguments for dest bb");
|
|
|
|
assert(CBI->getFalseArgs().size() == CBI->getFalseBB()->bbarg_size() &&
|
|
"false branch has wrong number of arguments for dest bb");
|
|
assert(std::equal(CBI->getFalseArgs().begin(), CBI->getFalseArgs().end(),
|
|
CBI->getFalseBB()->bbarg_begin(),
|
|
[](SILValue branchArg, SILArgument *bbArg) {
|
|
return branchArg.getType() == bbArg->getType();
|
|
}) &&
|
|
"false branch argument types do not match arguments for dest bb");
|
|
}
|
|
|
|
void verifyEntryPointArguments(SILBasicBlock *entry) {
|
|
SILType ty = F.getLoweredType();
|
|
SILFunctionTypeInfo *ti = ty.getFunctionTypeInfo();
|
|
|
|
assert(entry->bbarg_size() == ti->getInputTypes().size() &&
|
|
"entry point has wrong number of arguments");
|
|
DEBUG(llvm::dbgs() << "Argument types for entry point BB:\n";
|
|
for (auto *arg : make_range(entry->bbarg_begin(), entry->bbarg_end()))
|
|
arg->getType().dump();
|
|
llvm::dbgs() << "Input types for SIL function type:\n";
|
|
for (auto input : ti->getInputTypes())
|
|
input.dump(););
|
|
|
|
|
|
assert(std::equal(entry->bbarg_begin(), entry->bbarg_end(),
|
|
ti->getInputTypes().begin(),
|
|
[](SILArgument *bbarg, SILType ty) {
|
|
return bbarg->getType() == ty;
|
|
}) &&
|
|
"entry point argument types do not match function type");
|
|
}
|
|
|
|
void visitSILFunction(SILFunction *F) {
|
|
verifyEntryPointArguments(F->getBlocks().begin());
|
|
SILVisitor::visitSILFunction(F);
|
|
}
|
|
|
|
void verify() {
|
|
visitSILFunction(const_cast<SILFunction*>(&F));
|
|
}
|
|
};
|
|
} // end anonymous namespace
|
|
|
|
#endif //NDEBUG
|
|
|
|
/// verify - Run the SIL verifier to make sure that the SILFunction follows
|
|
/// invariants.
|
|
void SILFunction::verify() const {
|
|
#ifndef NDEBUG
|
|
SILVerifier(*this).verify();
|
|
#endif
|
|
}
|
|
|