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
This commit is contained in:
Chris Lattner 2012-05-27 19:37:05 +00:00
parent f7f59b15aa
commit 144b619684
3 changed files with 106 additions and 402 deletions

View File

@ -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

View File

@ -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...
//===----------------------------------------------------------------------===//

View File

@ -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<CodeGenIntrinsic> &Ints,
OS << "#endif\n\n";
}
/// RecordListComparator - Provide a deterministic comparator for lists of
/// records.
namespace {
typedef std::pair<std::vector<Record*>, std::vector<Record*> > RecPair;
struct RecordListComparator {
bool operator()(const RecPair &LHS,
const RecPair &RHS) const {
unsigned i = 0;
const std::vector<Record*> *LHSVec = &LHS.first;
const std::vector<Record*> *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<CodeGenIntrinsic> &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<RecPair, std::vector<unsigned>, 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<Record*> &RetTys = ArgTypes.first;
const std::vector<Record*> &ParamTys = ArgTypes.second;
std::vector<unsigned> 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 {