mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
205 lines
7.3 KiB
C++
205 lines
7.3 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/Types.h"
|
|
#include "swift/AST/Decl.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> {
|
|
SILModule &M;
|
|
public:
|
|
SILVerifier(SILModule &M) : M(M) {}
|
|
|
|
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 visitAllocInst(AllocInst *AI) {
|
|
assert(AI->getType()->is<LValueType>() &&"Allocation should return lvalue");
|
|
}
|
|
|
|
void visitAllocVarInst(AllocVarInst *AI) {
|
|
visitAllocInst(AI);
|
|
}
|
|
|
|
void visitApplyInst(ApplyInst *AI) {
|
|
assert(AI->getCallee().getType()->is<FunctionType>() &&
|
|
"Callee of ApplyInst should have function type");
|
|
FunctionType *FT = AI->getCallee().getType()->castTo<FunctionType>();
|
|
assert(AI->getType()->isEqual(FT->getResult()) &&
|
|
"ApplyInst result type mismatch");
|
|
|
|
// If there is a single argument to the apply, it might be a scalar or the
|
|
// whole tuple being presented all at once.
|
|
if (AI->getArguments().size() != 1 ||
|
|
!AI->getArguments()[0].getType()->isEqual(FT->getInput())) {
|
|
// Otherwise, we must have a decomposed tuple. Verify the arguments match
|
|
// up.
|
|
const TupleType *TT = FT->getInput()->castTo<TupleType>();
|
|
(void)TT;
|
|
assert(AI->getArguments().size() == TT->getFields().size() &&
|
|
"ApplyInst contains unexpected argument count for function");
|
|
for (unsigned i = 0, e = AI->getArguments().size(); i != e; ++i)
|
|
assert(AI->getArguments()[i].getType()
|
|
->isEqual(TT->getFields()[i].getType()) &&
|
|
"ApplyInst argument type mismatch");
|
|
}
|
|
}
|
|
|
|
void visitConstantRefInst(ConstantRefInst *DRI) {
|
|
(void)M; // suppress "unused private field" warning for release builds
|
|
assert(M.getConstantType(DRI->getConstant())->getCanonicalType() ==
|
|
DRI->getType()->getCanonicalType()
|
|
&& "ConstantRef type does not match constant's type");
|
|
}
|
|
|
|
void visitIntegerLiteralInst(IntegerLiteralInst *ILI) {
|
|
assert(ILI->getType()->is<BuiltinIntegerType>() &&
|
|
"invalid integer literal type");
|
|
}
|
|
void visitLoadInst(LoadInst *LI) {
|
|
assert(!LI->getType()->is<LValueType>() && "Load should produce rvalue");
|
|
assert(LI->getLValue().getType()->is<LValueType>() &&
|
|
"Load op should be lvalue");
|
|
assert(LI->getLValue().getType()->getRValueType()->isEqual(LI->getType()) &&
|
|
"Load operand type and result type mismatch");
|
|
}
|
|
|
|
void visitStoreInst(StoreInst *SI) {
|
|
assert(!SI->getSrc().getType()->is<LValueType>() &&
|
|
"Src value should be rvalue");
|
|
assert(SI->getDest().getType()->is<LValueType>() &&
|
|
"Dest address should be lvalue");
|
|
assert(SI->getDest().getType()->getRValueType()->
|
|
isEqual(SI->getSrc().getType()) &&
|
|
"Store operand type and dest type mismatch");
|
|
}
|
|
|
|
void visitCopyAddrInst(CopyAddrInst *SI) {
|
|
assert(SI->getSrc().getType()->is<LValueType>() &&
|
|
"Src value should be lvalue");
|
|
assert(SI->getDest().getType()->is<LValueType>() &&
|
|
"Dest address should be lvalue");
|
|
assert(SI->getDest().getType()->getRValueType()->
|
|
isEqual(SI->getSrc().getType()->getRValueType()) &&
|
|
"Store operand type and dest type mismatch");
|
|
}
|
|
|
|
void visitSpecializeInst(SpecializeInst *SI) {
|
|
assert(SI->getType()->is<FunctionType>() &&
|
|
SI->getOperand().getType()->is<PolymorphicFunctionType>() &&
|
|
"SpecializeInst only works on function types");
|
|
}
|
|
|
|
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) {
|
|
}
|
|
|
|
void visitRetainInst(RetainInst *RI) {
|
|
assert(!RI->getOperand().getType()->is<LValueType>() &&
|
|
"Operand of retain must not be lvalue");
|
|
}
|
|
void visitReleaseInst(ReleaseInst *RI) {
|
|
assert(!RI->getOperand().getType()->is<LValueType>() &&
|
|
"Operand of release must not be lvalue");
|
|
}
|
|
void visitDeallocVarInst(DeallocVarInst *DI) {
|
|
assert(DI->getOperand().getType()->is<LValueType>() &&
|
|
"Operand of dealloc must be lvalue");
|
|
}
|
|
void visitDestroyAddrInst(DestroyAddrInst *DI) {
|
|
assert(DI->getOperand().getType()->is<LValueType>() &&
|
|
"Operand of destroy must be lvalue");
|
|
}
|
|
|
|
void visitIndexAddrInst(IndexAddrInst *IAI) {
|
|
assert(IAI->getType()->is<LValueType>() &&
|
|
IAI->getType()->isEqual(IAI->getOperand().getType()) &&
|
|
"invalid IndexAddrInst");
|
|
}
|
|
|
|
void visitExtractInst(ExtractInst *EI) {
|
|
#ifndef NDEBUG
|
|
Type operandTy = EI->getOperand().getType();
|
|
assert(!operandTy->is<LValueType>() &&
|
|
"cannot extract from address");
|
|
assert(!operandTy->hasReferenceSemantics() &&
|
|
"cannot extract from reference type");
|
|
assert(!EI->getType(0)->is<LValueType>() &&
|
|
"result of extract cannot be address");
|
|
#endif
|
|
}
|
|
|
|
void visitElementAddrInst(ElementAddrInst *EI) {
|
|
#ifndef NDEBUG
|
|
Type operandTy = EI->getOperand().getType();
|
|
assert(operandTy->is<LValueType>() &&
|
|
"must derive element_addr from address");
|
|
assert(!operandTy->hasReferenceSemantics() &&
|
|
"cannot derive element_addr from reference type");
|
|
assert(EI->getType(0)->is<LValueType>() &&
|
|
"result of element_addr must be lvalue");
|
|
#endif
|
|
}
|
|
|
|
void visitIntegerValueInst(IntegerValueInst *IVI) {
|
|
assert(IVI->getType()->is<BuiltinIntegerType>());
|
|
}
|
|
|
|
void visitReturnInst(ReturnInst *RI) {
|
|
assert(RI->getReturnValue() && "Return of null value is invalid");
|
|
}
|
|
|
|
void visitBranchInst(BranchInst *BI) {
|
|
}
|
|
|
|
void visitCondBranchInst(CondBranchInst *CBI) {
|
|
assert(CBI->getCondition() &&
|
|
"Condition of conditional branch can't be missing");
|
|
}
|
|
};
|
|
} // end anonymous namespace
|
|
|
|
|
|
/// verify - Run the IR verifier to make sure that the Function follows
|
|
/// invariants.
|
|
void Function::verify() const {
|
|
SILVerifier(Module).visitFunction(const_cast<Function*>(this));
|
|
}
|