summaryrefslogtreecommitdiff
path: root/lib/VMCore/Verifier.cpp
diff options
context:
space:
mode:
authorChris Lattner <sabre@nondot.org>2012-05-27 19:37:05 +0000
committerChris Lattner <sabre@nondot.org>2012-05-27 19:37:05 +0000
commit55dc5c77a33bff5a902fec1b2133620064e1a256 (patch)
treecf3d0fdc0410f2796a13412806879d4734037d6c /lib/VMCore/Verifier.cpp
parentc32cef6aa158a572dd42a4e15762ebb5c666c85e (diff)
downloadllvm-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.cpp371
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...
//===----------------------------------------------------------------------===//