From: Chris Lattner Date: Sun, 27 May 2012 19:37:05 +0000 (+0000) Subject: Reimplement the intrinsic verifier to use the same table as Intrinsic::getDefinition, X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=144b61968471b8de97b9d08d7575ef742bb9dd0a;p=platform%2Fupstream%2Fllvm.git 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 llvm-svn: 157545 --- diff --git a/llvm/lib/Transforms/Scalar/ObjCARC.cpp b/llvm/lib/Transforms/Scalar/ObjCARC.cpp index 15109b5..9eb1039 100644 --- a/llvm/lib/Transforms/Scalar/ObjCARC.cpp +++ b/llvm/lib/Transforms/Scalar/ObjCARC.cpp @@ -20,7 +20,7 @@ // This file also defines a simple ARC-aware AliasAnalysis. // // WARNING: This file knows about certain library functions. It recognizes them -// by name, and hardwires knowedge of their semantics. +// by name, and hardwires knowledge of their semantics. // // WARNING: This file knows about how certain Objective-C library functions are // used. Naive LLVM IR transformations which would otherwise be diff --git a/llvm/lib/VMCore/Verifier.cpp b/llvm/lib/VMCore/Verifier.cpp index f11efff..64b0876 100644 --- a/llvm/lib/VMCore/Verifier.cpp +++ b/llvm/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 &Infos, + SmallVectorImpl &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 &Infos, + SmallVectorImpl &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(Ty); + return VT == 0 || VT->getNumElements() != D.Vector_Width || + VerifyIntrinsicType(VT->getElementType(), Infos, ArgTys); + } + case IITDescriptor::Pointer: { + PointerType *PT = dyn_cast(Ty); + return PT == 0 || PT->getAddressSpace() != D.Pointer_AddressSpace || + VerifyIntrinsicType(PT->getElementType(), Infos, ArgTys); + } + + case IITDescriptor::Struct: { + StructType *ST = dyn_cast(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(Ty); + case IITDescriptor::AK_AnyPointer: return !isa(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(ArgTys[D.getArgumentNumber()]) || + VectorType::getExtendedElementVectorType( + cast(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(ArgTys[D.getArgumentNumber()]) || + VectorType::getTruncatedElementVectorType( + cast(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 Table; + getIntrinsicInfoTableEntries(ID, Table); + ArrayRef TableRef = Table; + + SmallVector 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(Ty); - if (VTy) { - EltTy = VTy->getElementType(); - NumElts = VTy->getNumElements(); - } - - Type *RetTy = FTy->getReturnType(); - StructType *ST = dyn_cast(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(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(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(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(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(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... //===----------------------------------------------------------------------===// diff --git a/llvm/utils/TableGen/IntrinsicEmitter.cpp b/llvm/utils/TableGen/IntrinsicEmitter.cpp index 9c024a4..941c053 100644 --- a/llvm/utils/TableGen/IntrinsicEmitter.cpp +++ b/llvm/utils/TableGen/IntrinsicEmitter.cpp @@ -46,9 +46,6 @@ void IntrinsicEmitter::run(raw_ostream &OS) { // Emit the function name recognizer. EmitFnNameRecognizer(Ints, OS); - // Emit the intrinsic verifier. - EmitVerifier(Ints, OS); - // Emit the intrinsic declaration generator. EmitGenerator(Ints, OS); @@ -175,140 +172,6 @@ EmitIntrinsicToOverloadTable(const std::vector &Ints, OS << "#endif\n\n"; } -/// RecordListComparator - Provide a deterministic comparator for lists of -/// records. -namespace { - typedef std::pair, std::vector > RecPair; - struct RecordListComparator { - bool operator()(const RecPair &LHS, - const RecPair &RHS) const { - unsigned i = 0; - const std::vector *LHSVec = &LHS.first; - const std::vector *RHSVec = &RHS.first; - unsigned RHSSize = RHSVec->size(); - unsigned LHSSize = LHSVec->size(); - - for (; i != LHSSize; ++i) { - if (i == RHSSize) return false; // RHS is shorter than LHS. - if ((*LHSVec)[i] != (*RHSVec)[i]) - return (*LHSVec)[i]->getName() < (*RHSVec)[i]->getName(); - } - - if (i != RHSSize) return true; - - i = 0; - LHSVec = &LHS.second; - RHSVec = &RHS.second; - RHSSize = RHSVec->size(); - LHSSize = LHSVec->size(); - - for (i = 0; i != LHSSize; ++i) { - if (i == RHSSize) return false; // RHS is shorter than LHS. - if ((*LHSVec)[i] != (*RHSVec)[i]) - return (*LHSVec)[i]->getName() < (*RHSVec)[i]->getName(); - } - - return i != RHSSize; - } - }; -} - -void IntrinsicEmitter::EmitVerifier(const std::vector &Ints, - raw_ostream &OS) { - OS << "// Verifier::visitIntrinsicFunctionCall code.\n"; - OS << "#ifdef GET_INTRINSIC_VERIFIER\n"; - OS << " switch (ID) {\n"; - OS << " default: llvm_unreachable(\"Invalid intrinsic!\");\n"; - - // This checking can emit a lot of very common code. To reduce the amount of - // code that we emit, batch up cases that have identical types. This avoids - // problems where GCC can run out of memory compiling Verifier.cpp. - typedef std::map, RecordListComparator> MapTy; - MapTy UniqueArgInfos; - - // Compute the unique argument type info. - for (unsigned i = 0, e = Ints.size(); i != e; ++i) - UniqueArgInfos[make_pair(Ints[i].IS.RetTypeDefs, - Ints[i].IS.ParamTypeDefs)].push_back(i); - - // Loop through the array, emitting one comparison for each batch. - for (MapTy::iterator I = UniqueArgInfos.begin(), - E = UniqueArgInfos.end(); I != E; ++I) { - for (unsigned i = 0, e = I->second.size(); i != e; ++i) - OS << " case Intrinsic::" << Ints[I->second[i]].EnumName << ":\t\t// " - << Ints[I->second[i]].Name << "\n"; - - const RecPair &ArgTypes = I->first; - const std::vector &RetTys = ArgTypes.first; - const std::vector &ParamTys = ArgTypes.second; - std::vector OverloadedTypeIndices; - - OS << " VerifyIntrinsicPrototype(ID, IF, " << RetTys.size() << ", " - << ParamTys.size(); - - // Emit return types. - for (unsigned j = 0, je = RetTys.size(); j != je; ++j) { - Record *ArgType = RetTys[j]; - OS << ", "; - - if (ArgType->isSubClassOf("LLVMMatchType")) { - unsigned Number = ArgType->getValueAsInt("Number"); - assert(Number < OverloadedTypeIndices.size() && - "Invalid matching number!"); - Number = OverloadedTypeIndices[Number]; - if (ArgType->isSubClassOf("LLVMExtendedElementVectorType")) - OS << "~(ExtendedElementVectorType | " << Number << ")"; - else if (ArgType->isSubClassOf("LLVMTruncatedElementVectorType")) - OS << "~(TruncatedElementVectorType | " << Number << ")"; - else - OS << "~" << Number; - } else { - MVT::SimpleValueType VT = getValueType(ArgType->getValueAsDef("VT")); - OS << getEnumName(VT); - - if (EVT(VT).isOverloaded()) - OverloadedTypeIndices.push_back(j); - - if (VT == MVT::isVoid && j != 0 && j != je - 1) - throw "Var arg type not last argument"; - } - } - - // Emit the parameter types. - for (unsigned j = 0, je = ParamTys.size(); j != je; ++j) { - Record *ArgType = ParamTys[j]; - OS << ", "; - - if (ArgType->isSubClassOf("LLVMMatchType")) { - unsigned Number = ArgType->getValueAsInt("Number"); - assert(Number < OverloadedTypeIndices.size() && - "Invalid matching number!"); - Number = OverloadedTypeIndices[Number]; - if (ArgType->isSubClassOf("LLVMExtendedElementVectorType")) - OS << "~(ExtendedElementVectorType | " << Number << ")"; - else if (ArgType->isSubClassOf("LLVMTruncatedElementVectorType")) - OS << "~(TruncatedElementVectorType | " << Number << ")"; - else - OS << "~" << Number; - } else { - MVT::SimpleValueType VT = getValueType(ArgType->getValueAsDef("VT")); - OS << getEnumName(VT); - - if (EVT(VT).isOverloaded()) - OverloadedTypeIndices.push_back(j + RetTys.size()); - - if (VT == MVT::isVoid && j != 0 && j != je - 1) - throw "Var arg type not last argument"; - } - } - - OS << ");\n"; - OS << " break;\n"; - } - OS << " }\n"; - OS << "#endif\n\n"; -} - // NOTE: This must be kept in synch with the copy in lib/VMCore/Function.cpp! enum IIT_Info {