diff options
author | Chris Lattner <sabre@nondot.org> | 2012-05-27 19:37:05 +0000 |
---|---|---|
committer | Chris Lattner <sabre@nondot.org> | 2012-05-27 19:37:05 +0000 |
commit | 55dc5c77a33bff5a902fec1b2133620064e1a256 (patch) | |
tree | cf3d0fdc0410f2796a13412806879d4734037d6c /lib/VMCore/Verifier.cpp | |
parent | c32cef6aa158a572dd42a4e15762ebb5c666c85e (diff) | |
download | llvm-55dc5c77a33bff5a902fec1b2133620064e1a256.tar.gz llvm-55dc5c77a33bff5a902fec1b2133620064e1a256.tar.bz2 llvm-55dc5c77a33bff5a902fec1b2133620064e1a256.tar.xz |
Reimplement the intrinsic verifier to use the same table as Intrinsic::getDefinition,
making it stronger and more sane.
Delete the code from tblgen that produced the old code.
Besides being a path forward in intrinsic sanity, this also eliminates a bunch of
machine generated code that was compiled into Function.o
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@157545 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/VMCore/Verifier.cpp')
-rw-r--r-- | lib/VMCore/Verifier.cpp | 371 |
1 files changed, 106 insertions, 265 deletions
diff --git a/lib/VMCore/Verifier.cpp b/lib/VMCore/Verifier.cpp index f11efff9f1..64b087631e 100644 --- a/lib/VMCore/Verifier.cpp +++ b/lib/VMCore/Verifier.cpp @@ -293,8 +293,9 @@ namespace { void VerifyCallSite(CallSite CS); bool PerformTypeCheck(Intrinsic::ID ID, Function *F, Type *Ty, int VT, unsigned ArgNo, std::string &Suffix); - void VerifyIntrinsicPrototype(Intrinsic::ID ID, Function *F, - unsigned RetNum, unsigned ParamNum, ...); + bool VerifyIntrinsicType(Type *Ty, + ArrayRef<Intrinsic::IITDescriptor> &Infos, + SmallVectorImpl<Type*> &ArgTys); void VerifyParameterAttrs(Attributes Attrs, Type *Ty, bool isReturnValue, const Value *V); void VerifyFunctionAttrs(FunctionType *FT, const AttrListPtr &Attrs, @@ -1687,10 +1688,85 @@ void Verifier::visitInstruction(Instruction &I) { InstsInThisBlock.insert(&I); } -// Flags used by TableGen to mark intrinsic parameters with the -// LLVMExtendedElementVectorType and LLVMTruncatedElementVectorType classes. -static const unsigned ExtendedElementVectorType = 0x40000000; -static const unsigned TruncatedElementVectorType = 0x20000000; +/// VerifyIntrinsicType - Verify that the specified type (which comes from an +/// intrinsic argument or return value) matches the type constraints specified +/// by the .td file (e.g. an "any integer" argument really is an integer). +/// +/// This return true on error but does not print a message. +bool Verifier::VerifyIntrinsicType(Type *Ty, + ArrayRef<Intrinsic::IITDescriptor> &Infos, + SmallVectorImpl<Type*> &ArgTys) { + using namespace Intrinsic; + + // If we ran out of descriptors, there are too many arguments. + if (Infos.empty()) return true; + IITDescriptor D = Infos.front(); + Infos = Infos.slice(1); + + switch (D.Kind) { + case IITDescriptor::Void: return !Ty->isVoidTy(); + case IITDescriptor::MMX: return !Ty->isX86_MMXTy(); + case IITDescriptor::Metadata: return !Ty->isMetadataTy(); + case IITDescriptor::Float: return !Ty->isFloatTy(); + case IITDescriptor::Double: return !Ty->isDoubleTy(); + case IITDescriptor::Integer: return !Ty->isIntegerTy(D.Integer_Width); + case IITDescriptor::Vector: { + VectorType *VT = dyn_cast<VectorType>(Ty); + return VT == 0 || VT->getNumElements() != D.Vector_Width || + VerifyIntrinsicType(VT->getElementType(), Infos, ArgTys); + } + case IITDescriptor::Pointer: { + PointerType *PT = dyn_cast<PointerType>(Ty); + return PT == 0 || PT->getAddressSpace() != D.Pointer_AddressSpace || + VerifyIntrinsicType(PT->getElementType(), Infos, ArgTys); + } + + case IITDescriptor::Struct: { + StructType *ST = dyn_cast<StructType>(Ty); + if (ST == 0 || ST->getNumElements() != D.Struct_NumElements) + return true; + + for (unsigned i = 0, e = D.Struct_NumElements; i != e; ++i) + if (VerifyIntrinsicType(ST->getElementType(i), Infos, ArgTys)) + return true; + return false; + } + + case IITDescriptor::Argument: + // Two cases here - If this is the second occurrance of an argument, verify + // that the later instance matches the previous instance. + if (D.getArgumentNumber() < ArgTys.size()) + return Ty != ArgTys[D.getArgumentNumber()]; + + // Otherwise, if this is the first instance of an argument, record it and + // verify the "Any" kind. + assert(D.getArgumentNumber() == ArgTys.size() && "Table consistency error"); + ArgTys.push_back(Ty); + + switch (D.getArgumentKind()) { + case IITDescriptor::AK_AnyInteger: return !Ty->isIntOrIntVectorTy(); + case IITDescriptor::AK_AnyFloat: return !Ty->isFPOrFPVectorTy(); + case IITDescriptor::AK_AnyVector: return !isa<VectorType>(Ty); + case IITDescriptor::AK_AnyPointer: return !isa<PointerType>(Ty); + } + llvm_unreachable("all argument kinds not covered"); + + case IITDescriptor::ExtendVecArgument: + // This may only be used when referring to a previous vector argument. + return D.getArgumentNumber() >= ArgTys.size() || + !isa<VectorType>(ArgTys[D.getArgumentNumber()]) || + VectorType::getExtendedElementVectorType( + cast<VectorType>(ArgTys[D.getArgumentNumber()])) != Ty; + + case IITDescriptor::TruncVecArgument: + // This may only be used when referring to a previous vector argument. + return D.getArgumentNumber() >= ArgTys.size() || + !isa<VectorType>(ArgTys[D.getArgumentNumber()]) || + VectorType::getTruncatedElementVectorType( + cast<VectorType>(ArgTys[D.getArgumentNumber()])) != Ty; + } + llvm_unreachable("unhandled"); +} /// visitIntrinsicFunction - Allow intrinsics to be verified in different ways. /// @@ -1699,10 +1775,30 @@ void Verifier::visitIntrinsicFunctionCall(Intrinsic::ID ID, CallInst &CI) { Assert1(IF->isDeclaration(), "Intrinsic functions should never be defined!", IF); -#define GET_INTRINSIC_VERIFIER -#include "llvm/Intrinsics.gen" -#undef GET_INTRINSIC_VERIFIER - + // Verify that the intrinsic prototype lines up with what the .td files + // describe. + FunctionType *IFTy = IF->getFunctionType(); + Assert1(!IFTy->isVarArg(), "Intrinsic prototypes are not varargs", IF); + + SmallVector<Intrinsic::IITDescriptor, 8> Table; + getIntrinsicInfoTableEntries(ID, Table); + ArrayRef<Intrinsic::IITDescriptor> TableRef = Table; + + SmallVector<Type *, 4> ArgTys; + Assert1(!VerifyIntrinsicType(IFTy->getReturnType(), TableRef, ArgTys), + "Intrinsic has incorrect return type!", IF); + for (unsigned i = 0, e = IFTy->getNumParams(); i != e; ++i) + Assert1(!VerifyIntrinsicType(IFTy->getParamType(i), TableRef, ArgTys), + "Intrinsic has incorrect argument type!", IF); + Assert1(TableRef.empty(), "Intrinsic has too few arguments!", IF); + + // Now that we have the intrinsic ID and the actual argument types (and we + // know they are legal for the intrinsic!) get the intrinsic name through the + // usual means. This allows us to verify the mangling of argument types into + // the name. + Assert1(Intrinsic::getName(ID, ArgTys) == IF->getName(), + "Intrinsic name not mangled correctly for type arguments!", IF); + // If the intrinsic takes MDNode arguments, verify that they are either global // or are local to *this* function. for (unsigned i = 0, e = CI.getNumArgOperands(); i != e; ++i) @@ -1786,261 +1882,6 @@ void Verifier::visitIntrinsicFunctionCall(Intrinsic::ID ID, CallInst &CI) { } } -/// Produce a string to identify an intrinsic parameter or return value. -/// The ArgNo value numbers the return values from 0 to NumRets-1 and the -/// parameters beginning with NumRets. -/// -static std::string IntrinsicParam(unsigned ArgNo, unsigned NumRets) { - if (ArgNo >= NumRets) - return "Intrinsic parameter #" + utostr(ArgNo - NumRets); - if (NumRets == 1) - return "Intrinsic result type"; - return "Intrinsic result type #" + utostr(ArgNo); -} - -bool Verifier::PerformTypeCheck(Intrinsic::ID ID, Function *F, Type *Ty, - int VT, unsigned ArgNo, std::string &Suffix) { - FunctionType *FTy = F->getFunctionType(); - - unsigned NumElts = 0; - Type *EltTy = Ty; - VectorType *VTy = dyn_cast<VectorType>(Ty); - if (VTy) { - EltTy = VTy->getElementType(); - NumElts = VTy->getNumElements(); - } - - Type *RetTy = FTy->getReturnType(); - StructType *ST = dyn_cast<StructType>(RetTy); - unsigned NumRetVals; - if (RetTy->isVoidTy()) - NumRetVals = 0; - else if (ST) - NumRetVals = ST->getNumElements(); - else - NumRetVals = 1; - - if (VT < 0) { - int Match = ~VT; - - // Check flags that indicate a type that is an integral vector type with - // elements that are larger or smaller than the elements of the matched - // type. - if ((Match & (ExtendedElementVectorType | - TruncatedElementVectorType)) != 0) { - IntegerType *IEltTy = dyn_cast<IntegerType>(EltTy); - if (!VTy || !IEltTy) { - CheckFailed(IntrinsicParam(ArgNo, NumRetVals) + " is not " - "an integral vector type.", F); - return false; - } - // Adjust the current Ty (in the opposite direction) rather than - // the type being matched against. - if ((Match & ExtendedElementVectorType) != 0) { - if ((IEltTy->getBitWidth() & 1) != 0) { - CheckFailed(IntrinsicParam(ArgNo, NumRetVals) + " vector " - "element bit-width is odd.", F); - return false; - } - Ty = VectorType::getTruncatedElementVectorType(VTy); - } else - Ty = VectorType::getExtendedElementVectorType(VTy); - Match &= ~(ExtendedElementVectorType | TruncatedElementVectorType); - } - - if (Match <= static_cast<int>(NumRetVals - 1)) { - if (ST) - RetTy = ST->getElementType(Match); - - if (Ty != RetTy) { - CheckFailed(IntrinsicParam(ArgNo, NumRetVals) + " does not " - "match return type.", F); - return false; - } - } else { - if (Ty != FTy->getParamType(Match - NumRetVals)) { - CheckFailed(IntrinsicParam(ArgNo, NumRetVals) + " does not " - "match parameter %" + utostr(Match - NumRetVals) + ".", F); - return false; - } - } - } else if (VT == MVT::iAny) { - if (!EltTy->isIntegerTy()) { - CheckFailed(IntrinsicParam(ArgNo, NumRetVals) + " is not " - "an integer type.", F); - return false; - } - - unsigned GotBits = cast<IntegerType>(EltTy)->getBitWidth(); - Suffix += "."; - - if (EltTy != Ty) - Suffix += "v" + utostr(NumElts); - - Suffix += "i" + utostr(GotBits); - - // Check some constraints on various intrinsics. - switch (ID) { - default: break; // Not everything needs to be checked. - case Intrinsic::bswap: - if (GotBits < 16 || GotBits % 16 != 0) { - CheckFailed("Intrinsic requires even byte width argument", F); - return false; - } - break; - } - } else if (VT == MVT::fAny) { - if (!EltTy->isFloatingPointTy()) { - CheckFailed(IntrinsicParam(ArgNo, NumRetVals) + " is not " - "a floating-point type.", F); - return false; - } - - Suffix += "."; - - if (EltTy != Ty) - Suffix += "v" + utostr(NumElts); - - Suffix += EVT::getEVT(EltTy).getEVTString(); - } else if (VT == MVT::vAny) { - if (!VTy) { - CheckFailed(IntrinsicParam(ArgNo, NumRetVals) + " is not a vector type.", - F); - return false; - } - Suffix += ".v" + utostr(NumElts) + EVT::getEVT(EltTy).getEVTString(); - } else if (VT == MVT::iPTR) { - if (!Ty->isPointerTy()) { - CheckFailed(IntrinsicParam(ArgNo, NumRetVals) + " is not a " - "pointer and a pointer is required.", F); - return false; - } - } else if (VT == MVT::iPTRAny) { - // Outside of TableGen, we don't distinguish iPTRAny (to any address space) - // and iPTR. In the verifier, we can not distinguish which case we have so - // allow either case to be legal. - if (PointerType* PTyp = dyn_cast<PointerType>(Ty)) { - EVT PointeeVT = EVT::getEVT(PTyp->getElementType(), true); - if (PointeeVT == MVT::Other) { - CheckFailed("Intrinsic has pointer to complex type."); - return false; - } - Suffix += ".p" + utostr(PTyp->getAddressSpace()) + - PointeeVT.getEVTString(); - } else { - CheckFailed(IntrinsicParam(ArgNo, NumRetVals) + " is not a " - "pointer and a pointer is required.", F); - return false; - } - } else if (EVT((MVT::SimpleValueType)VT).isVector()) { - EVT VVT = EVT((MVT::SimpleValueType)VT); - - // If this is a vector argument, verify the number and type of elements. - if (VVT.getVectorElementType() != EVT::getEVT(EltTy)) { - CheckFailed("Intrinsic prototype has incorrect vector element type!", F); - return false; - } - - if (VVT.getVectorNumElements() != NumElts) { - CheckFailed("Intrinsic prototype has incorrect number of " - "vector elements!", F); - return false; - } - } else if (EVT((MVT::SimpleValueType)VT).getTypeForEVT(Ty->getContext()) != - EltTy) { - CheckFailed(IntrinsicParam(ArgNo, NumRetVals) + " is wrong!", F); - return false; - } else if (EltTy != Ty) { - CheckFailed(IntrinsicParam(ArgNo, NumRetVals) + " is a vector " - "and a scalar is required.", F); - return false; - } - - return true; -} - -/// VerifyIntrinsicPrototype - TableGen emits calls to this function into -/// Intrinsics.gen. This implements a little state machine that verifies the -/// prototype of intrinsics. -void Verifier::VerifyIntrinsicPrototype(Intrinsic::ID ID, Function *F, - unsigned NumRetVals, - unsigned NumParams, ...) { - va_list VA; - va_start(VA, NumParams); - FunctionType *FTy = F->getFunctionType(); - - // For overloaded intrinsics, the Suffix of the function name must match the - // types of the arguments. This variable keeps track of the expected - // suffix, to be checked at the end. - std::string Suffix; - - if (FTy->getNumParams() + FTy->isVarArg() != NumParams) { - CheckFailed("Intrinsic prototype has incorrect number of arguments!", F); - return; - } - - Type *Ty = FTy->getReturnType(); - StructType *ST = dyn_cast<StructType>(Ty); - - if (NumRetVals == 0 && !Ty->isVoidTy()) { - CheckFailed("Intrinsic should return void", F); - return; - } - - // Verify the return types. - if (ST && ST->getNumElements() != NumRetVals) { - CheckFailed("Intrinsic prototype has incorrect number of return types!", F); - return; - } - - for (unsigned ArgNo = 0; ArgNo != NumRetVals; ++ArgNo) { - int VT = va_arg(VA, int); // An MVT::SimpleValueType when non-negative. - - if (ST) Ty = ST->getElementType(ArgNo); - if (!PerformTypeCheck(ID, F, Ty, VT, ArgNo, Suffix)) - break; - } - - // Verify the parameter types. - for (unsigned ArgNo = 0; ArgNo != NumParams; ++ArgNo) { - int VT = va_arg(VA, int); // An MVT::SimpleValueType when non-negative. - - if (VT == MVT::isVoid && ArgNo > 0) { - if (!FTy->isVarArg()) - CheckFailed("Intrinsic prototype has no '...'!", F); - break; - } - - if (!PerformTypeCheck(ID, F, FTy->getParamType(ArgNo), VT, - ArgNo + NumRetVals, Suffix)) - break; - } - - va_end(VA); - - // For intrinsics without pointer arguments, if we computed a Suffix then the - // intrinsic is overloaded and we need to make sure that the name of the - // function is correct. We add the suffix to the name of the intrinsic and - // compare against the given function name. If they are not the same, the - // function name is invalid. This ensures that overloading of intrinsics - // uses a sane and consistent naming convention. Note that intrinsics with - // pointer argument may or may not be overloaded so we will check assuming it - // has a suffix and not. - if (!Suffix.empty()) { - std::string Name(Intrinsic::getName(ID)); - if (Name + Suffix != F->getName()) { - CheckFailed("Overloaded intrinsic has incorrect suffix: '" + - F->getName().substr(Name.length()) + "'. It should be '" + - Suffix + "'", F); - } - } - - // Check parameter attributes. - Assert1(F->getAttributes() == Intrinsic::getAttributes(ID), - "Intrinsic has wrong parameter attributes!", F); -} - - //===----------------------------------------------------------------------===// // Implement the public interfaces to this file... //===----------------------------------------------------------------------===// |