forked from OSchip/llvm-project
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:
parent
f7f59b15aa
commit
144b619684
|
@ -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
|
||||
|
|
|
@ -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...
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
|
|
@ -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 {
|
||||
|
|
Loading…
Reference in New Issue