Files
swift-mirror/lib/SIL/Verifier.cpp
Joe Groff b7c03623a8 SIL: Properly type closure constants and insns.
I was being lazy by not mangling the context arguments onto the types of closure SIL constants and then having ClosureInst pass the type of its callee through T -> T. Now closure functions get emitted with the right types, ClosureInst properly partially applies the type, and the SIL Verifier properly checks that the argument types all line up correctly.

Swift SVN r3815
2013-01-20 19:50:04 +00:00

427 lines
16 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/Function.h"
#include "swift/SIL/SILVisitor.h"
#include "swift/AST/ASTContext.h"
#include "swift/AST/Types.h"
#include "swift/AST/Decl.h"
#include "llvm/Support/Debug.h"
using namespace swift;
namespace {
/// SILVerifier class - This class implements the SIL verifier, which walks over
/// SIL, checking and enforcing its invariants.
class SILVerifier : public SILVisitor<SILVerifier> {
Function const &F;
public:
SILVerifier(Function const &F) : F(F) {}
void visit(Instruction *I) {
const BasicBlock *BB = I->getParent();
(void)BB;
// 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 = F.getModule().getFunctionTypeInfo(calleeTy);
(void)ti;
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 (Value 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");
}
assert(AI->getType() == ti->getResultType() &&
"type of apply instruction doesn't match function result type");
}
void visitClosureInst(ClosureInst *CI) {
SILType calleeTy = CI->getCallee().getType();
assert(!calleeTy.isAddress() && "callee of closure cannot be an address");
assert(calleeTy.is<FunctionType>() &&
"callee of closure must have concrete function type");
SILType appliedTy = CI->getType();
assert(!appliedTy.isAddress() && "result of closure cannot be an address");
assert(appliedTy.is<FunctionType>() &&
"result of closure must have concrete function type");
SILFunctionTypeInfo *calleeTI = F.getModule().getFunctionTypeInfo(calleeTy);
SILFunctionTypeInfo *appliedTI
= F.getModule().getFunctionTypeInfo(appliedTy);
(void)calleeTI; (void)appliedTI;
// Check that the partially applied arguments match.
size_t allArgsCount = calleeTI->getInputTypes().size();
size_t appliedArgsCount = CI->getArguments().size();
size_t unappliedArgsCount = appliedTI->getInputTypes().size();
assert(allArgsCount >= unappliedArgsCount &&
"result type of closure has more arguments than callee");
assert(allArgsCount >= appliedArgsCount &&
"closure applies more arguments than callee has");
assert(unappliedArgsCount + appliedArgsCount == allArgsCount &&
"result type of closure does not have right amount of unapplied args");
for (size_t i = 0; i < unappliedArgsCount; ++i) {
assert(appliedTI->getInputTypes()[i] == calleeTI->getInputTypes()[i] &&
"result type's input types do not match callee's");
}
for (size_t i = 0; i < appliedArgsCount; ++i) {
assert(CI->getArguments()[i].getType() ==
calleeTI->getInputTypes()[i + unappliedArgsCount] &&
"closure argument types do not match callee's");
}
// Check that the result types match.
assert(calleeTI->getResultType() == appliedTI->getResultType() &&
"result type of closure does not match result type of callee");
}
void visitConstantRefInst(ConstantRefInst *CRI) {
assert(CRI->getType().is<AnyFunctionType>() &&
"constant_ref should have a 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 visitZeroAddrInst(ZeroAddrInst *ZI) {
assert(ZI->getDest().getType().isAddress() &&
"Dest address should be lvalue");
}
void visitZeroValueInst(ZeroValueInst *ZVI) {
assert(!ZVI->getType().isAddress() &&
"zero_value cannot create an address");
}
void visitSpecializeInst(SpecializeInst *SI) {
assert(SI->getType().is<FunctionType>() &&
"Specialize dest should be a function type");
assert(SI->getOperand().getType().is<PolymorphicFunctionType>() &&
"Specialize source should be a polymorphic function type");
}
void visitTupleInst(TupleInst *TI) {
assert(TI->getType().is<TupleType>() && "TupleInst should return a tuple");
TupleType *ResTy = TI->getType().castTo<TupleType>(); (void)ResTy;
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 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) {
#ifndef NDEBUG
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");
#endif
}
void visitElementAddrInst(ElementAddrInst *EI) {
#ifndef NDEBUG
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");
#endif
}
void visitRefElementAddrInst(RefElementAddrInst *EI) {
#ifndef NDEBUG
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");
#endif
}
void visitArchetypeMethodInst(ArchetypeMethodInst *AMI) {
#ifndef NDEBUG
DEBUG(llvm::dbgs() << "verifying";
AMI->print(llvm::dbgs()));
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");
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");
#endif
}
void visitProtocolMethodInst(ProtocolMethodInst *EMI) {
#ifndef NDEBUG
FunctionType *methodType = EMI->getType(0).getAs<FunctionType>();
assert(methodType &&
"result method must be of a concrete 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");
#endif
}
void visitProjectExistentialInst(ProjectExistentialInst *PEI) {
#ifndef NDEBUG
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");
#endif
}
void visitInitExistentialInst(InitExistentialInst *AEI) {
#ifndef NDEBUG
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");
#endif
}
void visitDeinitExistentialInst(DeinitExistentialInst *DEI) {
#ifndef NDEBUG
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");
#endif
}
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 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 visitDowncastInst(DowncastInst *DI) {
assert(DI->getOperand().getType().hasReferenceSemantics() &&
"downcast operand must be a reference type");
assert(DI->getType().hasReferenceSemantics() &&
"downcast must convert to a reference type");
}
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");
// FIXME: when curry entry points are typed properly, verify return type
// here.
/*
SILFunctionTypeInfo *ti =
F.getModule().getFunctionTypeInfo(F.getLoweredType());
DEBUG(llvm::dbgs() << " operand type ";
RI->getReturnValue().getType().print(llvm::dbgs());
llvm::dbgs() << " for return type ";
ti->getResultType().print(llvm::dbgs());
llvm::dbgs() << '\n');
assert(RI->getReturnValue().getType() == ti->getResultType() &&
"return value type does not match return type of function");
*/
}
void visitBranchInst(BranchInst *BI) {
}
void visitCondBranchInst(CondBranchInst *CBI) {
assert(CBI->getCondition() &&
"Condition of conditional branch can't be missing");
}
void verify() {
visitFunction(const_cast<Function*>(&F));
}
};
} // end anonymous namespace
/// verify - Run the IR verifier to make sure that the Function follows
/// invariants.
void Function::verify() const {
SILVerifier(*this).verify();
}