diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/Analysis/ConstantFolding.cpp | 6 | ||||
-rw-r--r-- | lib/AsmParser/llvmAsmParser.y | 6 | ||||
-rw-r--r-- | lib/Bitcode/Reader/BitcodeReader.cpp | 39 | ||||
-rw-r--r-- | lib/Bitcode/Reader/BitcodeReader.h | 5 | ||||
-rw-r--r-- | lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp | 12 | ||||
-rw-r--r-- | lib/Target/X86/X86TargetAsmInfo.cpp | 4 | ||||
-rw-r--r-- | lib/Transforms/Scalar/InstructionCombining.cpp | 4 | ||||
-rw-r--r-- | lib/VMCore/AutoUpgrade.cpp | 197 | ||||
-rw-r--r-- | lib/VMCore/Verifier.cpp | 133 |
9 files changed, 321 insertions, 85 deletions
diff --git a/lib/Analysis/ConstantFolding.cpp b/lib/Analysis/ConstantFolding.cpp index e85d150..dedeb4e 100644 --- a/lib/Analysis/ConstantFolding.cpp +++ b/lib/Analysis/ConstantFolding.cpp @@ -448,13 +448,13 @@ llvm::ConstantFoldCall(Function *F, Constant** Operands, unsigned NumOperands) { return ConstantInt::get(Op->getValue().byteSwap()); } else if (Name.size() > 11 && !memcmp(&Name[0],"llvm.ctpop",10)) { uint64_t ctpop = Op->getValue().countPopulation(); - return ConstantInt::get(Type::Int32Ty, ctpop); + return ConstantInt::get(Ty, ctpop); } else if (Name.size() > 10 && !memcmp(&Name[0], "llvm.cttz", 9)) { uint64_t cttz = Op->getValue().countTrailingZeros(); - return ConstantInt::get(Type::Int32Ty, cttz); + return ConstantInt::get(Ty, cttz); } else if (Name.size() > 10 && !memcmp(&Name[0], "llvm.ctlz", 9)) { uint64_t ctlz = Op->getValue().countLeadingZeros(); - return ConstantInt::get(Type::Int32Ty, ctlz); + return ConstantInt::get(Ty, ctlz); } } } else if (NumOperands == 2) { diff --git a/lib/AsmParser/llvmAsmParser.y b/lib/AsmParser/llvmAsmParser.y index f93fe06..9d7b063 100644 --- a/lib/AsmParser/llvmAsmParser.y +++ b/lib/AsmParser/llvmAsmParser.y @@ -18,6 +18,7 @@ #include "llvm/Instructions.h" #include "llvm/Module.h" #include "llvm/ValueSymbolTable.h" +#include "llvm/AutoUpgrade.h" #include "llvm/Support/GetElementPtrTypeIterator.h" #include "llvm/Support/CommandLine.h" #include "llvm/ADT/SmallVector.h" @@ -131,6 +132,11 @@ static struct PerModuleInfo { return; } + // Look for intrinsic functions and CallInst that need to be upgraded + for (Module::iterator FI = CurrentModule->begin(), + FE = CurrentModule->end(); FI != FE; ) + UpgradeCallsToIntrinsic(FI++); // must be post-increment, as we remove + Values.clear(); // Clear out function local definitions Types.clear(); CurrentModule = 0; diff --git a/lib/Bitcode/Reader/BitcodeReader.cpp b/lib/Bitcode/Reader/BitcodeReader.cpp index 9c1f49e..07a4279 100644 --- a/lib/Bitcode/Reader/BitcodeReader.cpp +++ b/lib/Bitcode/Reader/BitcodeReader.cpp @@ -19,6 +19,7 @@ #include "llvm/Instructions.h" #include "llvm/Module.h" #include "llvm/ParameterAttributes.h" +#include "llvm/AutoUpgrade.h" #include "llvm/ADT/SmallString.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/MemoryBuffer.h" @@ -857,6 +858,13 @@ bool BitcodeReader::ParseModule(const std::string &ModuleID) { if (!FunctionsWithBodies.empty()) return Error("Too few function bodies found"); + // Look for intrinsic functions which need to be upgraded at some point + for (Module::iterator FI = TheModule->begin(), FE = TheModule->end(); + FI != FE; ++FI) { + if (Function* NewFn = UpgradeIntrinsicFunction(FI)) + UpgradedIntrinsics.push_back(std::make_pair(FI, NewFn)); + } + // Force deallocation of memory for these vectors to favor the client that // want lazy deserialization. std::vector<std::pair<GlobalVariable*, unsigned> >().swap(GlobalInits); @@ -1588,6 +1596,18 @@ bool BitcodeReader::materializeFunction(Function *F, std::string *ErrInfo) { if (ErrInfo) *ErrInfo = ErrorString; return true; } + + // Upgrade any old intrinsic calls in the function. + for (UpgradedIntrinsicMap::iterator I = UpgradedIntrinsics.begin(), + E = UpgradedIntrinsics.end(); I != E; ++I) { + if (I->first != I->second) { + for (Value::use_iterator UI = I->first->use_begin(), + UE = I->first->use_end(); UI != UE; ) { + if (CallInst* CI = dyn_cast<CallInst>(*UI++)) + UpgradeIntrinsicCall(CI, I->second); + } + } + } return false; } @@ -1614,6 +1634,25 @@ Module *BitcodeReader::materializeModule(std::string *ErrInfo) { materializeFunction(F, ErrInfo)) return 0; } + + // Upgrade any intrinsic calls that slipped through (should not happen!) and + // delete the old functions to clean up. We can't do this unless the entire + // module is materialized because there could always be another function body + // with calls to the old function. + for (std::vector<std::pair<Function*, Function*> >::iterator I = + UpgradedIntrinsics.begin(), E = UpgradedIntrinsics.end(); I != E; ++I) { + if (I->first != I->second) { + for (Value::use_iterator UI = I->first->use_begin(), + UE = I->first->use_end(); UI != UE; ) { + if (CallInst* CI = dyn_cast<CallInst>(*UI++)) + UpgradeIntrinsicCall(CI, I->second); + } + ValueList.replaceUsesOfWith(I->first, I->second); + I->first->eraseFromParent(); + } + } + std::vector<std::pair<Function*, Function*> >().swap(UpgradedIntrinsics); + return TheModule; } diff --git a/lib/Bitcode/Reader/BitcodeReader.h b/lib/Bitcode/Reader/BitcodeReader.h index 2f61b06..0655a1a 100644 --- a/lib/Bitcode/Reader/BitcodeReader.h +++ b/lib/Bitcode/Reader/BitcodeReader.h @@ -102,6 +102,11 @@ class BitcodeReader : public ModuleProvider { // When reading the module header, this list is populated with functions that // have bodies later in the file. std::vector<Function*> FunctionsWithBodies; + + // When intrinsic functions are encountered which require upgrading they are + // stored here with their replacement function. + typedef std::vector<std::pair<Function*, Function*> > UpgradedIntrinsicMap; + UpgradedIntrinsicMap UpgradedIntrinsics; // After the module header has been read, the FunctionsWithBodies list is // reversed. This keeps track of whether we've done this yet. diff --git a/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp b/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp index d1f7669..afb681f 100644 --- a/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp +++ b/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp @@ -2814,10 +2814,6 @@ SelectionDAGLowering::visitIntrinsicCall(CallInst &I, unsigned Intrinsic) { SDOperand Arg = getValue(I.getOperand(1)); MVT::ValueType Ty = Arg.getValueType(); SDOperand result = DAG.getNode(ISD::CTTZ, Ty, Arg); - if (Ty < MVT::i32) - result = DAG.getNode(ISD::ZERO_EXTEND, MVT::i32, result); - else if (Ty > MVT::i32) - result = DAG.getNode(ISD::TRUNCATE, MVT::i32, result); setValue(&I, result); return 0; } @@ -2825,10 +2821,6 @@ SelectionDAGLowering::visitIntrinsicCall(CallInst &I, unsigned Intrinsic) { SDOperand Arg = getValue(I.getOperand(1)); MVT::ValueType Ty = Arg.getValueType(); SDOperand result = DAG.getNode(ISD::CTLZ, Ty, Arg); - if (Ty < MVT::i32) - result = DAG.getNode(ISD::ZERO_EXTEND, MVT::i32, result); - else if (Ty > MVT::i32) - result = DAG.getNode(ISD::TRUNCATE, MVT::i32, result); setValue(&I, result); return 0; } @@ -2836,10 +2828,6 @@ SelectionDAGLowering::visitIntrinsicCall(CallInst &I, unsigned Intrinsic) { SDOperand Arg = getValue(I.getOperand(1)); MVT::ValueType Ty = Arg.getValueType(); SDOperand result = DAG.getNode(ISD::CTPOP, Ty, Arg); - if (Ty < MVT::i32) - result = DAG.getNode(ISD::ZERO_EXTEND, MVT::i32, result); - else if (Ty > MVT::i32) - result = DAG.getNode(ISD::TRUNCATE, MVT::i32, result); setValue(&I, result); return 0; } diff --git a/lib/Target/X86/X86TargetAsmInfo.cpp b/lib/Target/X86/X86TargetAsmInfo.cpp index 79df32b..bf206b4 100644 --- a/lib/Target/X86/X86TargetAsmInfo.cpp +++ b/lib/Target/X86/X86TargetAsmInfo.cpp @@ -219,9 +219,9 @@ bool X86TargetAsmInfo::LowerToBSwap(CallInst *CI) const { return false; // Okay, we can do this xform, do so now. - const Type *Tys[] = { Ty, Ty }; + const Type *Tys[] = { Ty }; Module *M = CI->getParent()->getParent()->getParent(); - Constant *Int = Intrinsic::getDeclaration(M, Intrinsic::bswap, Tys, 2); + Constant *Int = Intrinsic::getDeclaration(M, Intrinsic::bswap, Tys, 1); Value *Op = CI->getOperand(1); Op = new CallInst(Int, Op, CI->getName(), CI); diff --git a/lib/Transforms/Scalar/InstructionCombining.cpp b/lib/Transforms/Scalar/InstructionCombining.cpp index e843074..4330b16 100644 --- a/lib/Transforms/Scalar/InstructionCombining.cpp +++ b/lib/Transforms/Scalar/InstructionCombining.cpp @@ -3717,9 +3717,9 @@ Instruction *InstCombiner::MatchBSwap(BinaryOperator &I) { for (unsigned i = 1, e = ByteValues.size(); i != e; ++i) if (ByteValues[i] != V) return 0; - const Type *Tys[] = { ITy, ITy }; + const Type *Tys[] = { ITy }; Module *M = I.getParent()->getParent()->getParent(); - Function *F = Intrinsic::getDeclaration(M, Intrinsic::bswap, Tys, 2); + Function *F = Intrinsic::getDeclaration(M, Intrinsic::bswap, Tys, 1); return new CallInst(F, V); } diff --git a/lib/VMCore/AutoUpgrade.cpp b/lib/VMCore/AutoUpgrade.cpp new file mode 100644 index 0000000..b56fe70 --- /dev/null +++ b/lib/VMCore/AutoUpgrade.cpp @@ -0,0 +1,197 @@ +//===-- AutoUpgrade.cpp - Implement auto-upgrade helper functions ---------===// +// +// The LLVM Compiler Infrastructure +// +// This file was developed by Chandler Carruth and is distributed under the +// University of Illinois Open Source License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the auto-upgrade helper functions +// +//===----------------------------------------------------------------------===// + +#include "llvm/AutoUpgrade.h" +#include "llvm/Function.h" +#include "llvm/Module.h" +#include "llvm/Instructions.h" +#include "llvm/ParameterAttributes.h" +#include "llvm/Intrinsics.h" +using namespace llvm; + + +Function* llvm::UpgradeIntrinsicFunction(Function *F) { + assert(F && "Illegal to upgrade a non-existent Function."); + + // Get the Function's name. + const std::string& Name = F->getName(); + + // Convenience + const FunctionType *FTy = F->getFunctionType(); + + // Quickly eliminate it, if it's not a candidate. + if (Name.length() <= 8 || Name[0] != 'l' || Name[1] != 'l' || + Name[2] != 'v' || Name[3] != 'm' || Name[4] != '.') + return 0; + + Module *M = F->getParent(); + switch (Name[5]) { + default: break; + case 'b': + // This upgrades the name of the llvm.bswap intrinsic function to only use + // a single type name for overloading. We only care about the old format + // 'llvm.bswap.i*.i*', so check for 'bswap.' and then for there being + // a '.' after 'bswap.' + if (Name.compare(5,6,"bswap.",6) == 0) { + std::string::size_type delim = Name.find('.',11); + + if (delim != std::string::npos) { + // Construct the new name as 'llvm.bswap' + '.i*' + F->setName(Name.substr(0,10)+Name.substr(delim)); + return F; + } + } + break; + + case 'c': + // We only want to fix the 'llvm.ct*' intrinsics which do not have the + // correct return type, so we check for the name, and then check if the + // return type does not match the parameter type. + if ( (Name.compare(5,5,"ctpop",5) == 0 || + Name.compare(5,4,"ctlz",4) == 0 || + Name.compare(5,4,"cttz",4) == 0) && + FTy->getReturnType() != FTy->getParamType(0)) { + // We first need to change the name of the old (bad) intrinsic, because + // its type is incorrect, but we cannot overload that name. We + // arbitrarily unique it here allowing us to construct a correctly named + // and typed function below. + F->setName(""); + + // Now construct the new intrinsic with the correct name and type. We + // leave the old function around in order to query its type, whatever it + // may be, and correctly convert up to the new type. + return cast<Function>(M->getOrInsertFunction(Name, + FTy->getParamType(0), + FTy->getParamType(0), + (Type *)0)); + } + break; + + case 'p': + // This upgrades the llvm.part.select overloaded intrinsic names to only + // use one type specifier in the name. We only care about the old format + // 'llvm.part.select.i*.i*', and solve as above with bswap. + if (Name.compare(5,12,"part.select.",12) == 0) { + std::string::size_type delim = Name.find('.',17); + + if (delim != std::string::npos) { + // Construct a new name as 'llvm.part.select' + '.i*' + F->setName(Name.substr(0,16)+Name.substr(delim)); + return F; + } + break; + } + + // This upgrades the llvm.part.set intrinsics similarly as above, however + // we care about 'llvm.part.set.i*.i*.i*', but only the first two types + // must match. There is an additional type specifier after these two + // matching types that we must retain when upgrading. Thus, we require + // finding 2 periods, not just one, after the intrinsic name. + if (Name.compare(5,9,"part.set.",9) == 0) { + std::string::size_type delim = Name.find('.',14); + + if (delim != std::string::npos && + Name.find('.',delim+1) != std::string::npos) { + // Construct a new name as 'llvm.part.select' + '.i*.i*' + F->setName(Name.substr(0,13)+Name.substr(delim)); + return F; + } + break; + } + + break; + } + + // This may not belong here. This function is effectively being overloaded + // to both detect an intrinsic which needs upgrading, and to provide the + // upgraded form of the intrinsic. We should perhaps have two separate + // functions for this. + return 0; +} + +// UpgradeIntrinsicCall - Upgrade a call to an old intrinsic to be a call the +// upgraded intrinsic. All argument and return casting must be provided in +// order to seamlessly integrate with existing context. +void llvm::UpgradeIntrinsicCall(CallInst *CI, Function *NewFn) { + assert(NewFn && "Cannot upgrade an intrinsic call without a new function."); + + Function *F = CI->getCalledFunction(); + assert(F && "CallInst has no function associated with it."); + + const FunctionType *FTy = F->getFunctionType(); + const FunctionType *NewFnTy = NewFn->getFunctionType(); + + switch(NewFn->getIntrinsicID()) { + default: assert(0 && "Unknown function for CallInst upgrade."); + case Intrinsic::ctlz: + case Intrinsic::ctpop: + case Intrinsic::cttz: + // Build a small vector of the 1..(N-1) operands, which are the + // parameters. + SmallVector<Value*, 8> Operands(CI->op_begin()+1, CI->op_end()); + + // Construct a new CallInst + CallInst *NewCI = new CallInst(NewFn, Operands.begin(), Operands.end(), + "upgraded."+CI->getName(), CI); + NewCI->setTailCall(CI->isTailCall()); + NewCI->setCallingConv(CI->getCallingConv()); + + // Handle any uses of the old CallInst. + if (!CI->use_empty()) { + // Check for sign extend parameter attributes on the return values. + bool SrcSExt = NewFnTy->getParamAttrs() && + NewFnTy->getParamAttrs()->paramHasAttr(0,ParamAttr::SExt); + bool DestSExt = FTy->getParamAttrs() && + FTy->getParamAttrs()->paramHasAttr(0,ParamAttr::SExt); + + // Construct an appropriate cast from the new return type to the old. + CastInst *RetCast = CastInst::create( + CastInst::getCastOpcode(NewCI, SrcSExt, + F->getReturnType(), + DestSExt), + NewCI, F->getReturnType(), + NewCI->getName(), CI); + NewCI->moveBefore(RetCast); + + // Replace all uses of the old call with the new cast which has the + // correct type. + CI->replaceAllUsesWith(RetCast); + } + + // Clean up the old call now that it has been completely upgraded. + CI->eraseFromParent(); + break; + } +} + +// This tests each Function to determine if it needs upgrading. When we find +// one we are interested in, we then upgrade all calls to reflect the new +// function. +void llvm::UpgradeCallsToIntrinsic(Function* F) { + assert(F && "Illegal attempt to upgrade a non-existent intrinsic."); + + // Upgrade the function and check if it is a totaly new function. + if (Function* NewFn = UpgradeIntrinsicFunction(F)) { + if (NewFn != F) { + // Replace all uses to the old function with the new one if necessary. + for (Value::use_iterator UI = F->use_begin(), UE = F->use_end(); + UI != UE; ) { + if (CallInst* CI = dyn_cast<CallInst>(*UI++)) + UpgradeIntrinsicCall(CI, NewFn); + } + // Remove old function, no longer used, from the module. + F->eraseFromParent(); + } + } +} + diff --git a/lib/VMCore/Verifier.cpp b/lib/VMCore/Verifier.cpp index 6d4aa98..86a72c4 100644 --- a/lib/VMCore/Verifier.cpp +++ b/lib/VMCore/Verifier.cpp @@ -53,6 +53,7 @@ #include "llvm/Intrinsics.h" #include "llvm/PassManager.h" #include "llvm/Analysis/Dominators.h" +#include "llvm/CodeGen/ValueTypes.h" #include "llvm/Support/CFG.h" #include "llvm/Support/InstVisitor.h" #include "llvm/Support/Streams.h" @@ -225,7 +226,8 @@ namespace { // Anonymous namespace for class void visitUserOp2(Instruction &I) { visitUserOp1(I); } void visitIntrinsicFunctionCall(Intrinsic::ID ID, CallInst &CI); - void VerifyIntrinsicPrototype(Intrinsic::ID ID, Function *F, ...); + void VerifyIntrinsicPrototype(Intrinsic::ID ID, Function *F, + unsigned Count, ...); void WriteValue(const Value *V) { if (!V) return; @@ -1075,9 +1077,11 @@ void Verifier::visitIntrinsicFunctionCall(Intrinsic::ID ID, CallInst &CI) { /// 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, ...) { +void Verifier::VerifyIntrinsicPrototype(Intrinsic::ID ID, + Function *F, + unsigned Count, ...) { va_list VA; - va_start(VA, F); + va_start(VA, Count); const FunctionType *FTy = F->getFunctionType(); @@ -1086,97 +1090,94 @@ void Verifier::VerifyIntrinsicPrototype(Intrinsic::ID ID, Function *F, ...) { // suffix, to be checked at the end. std::string Suffix; - // Note that "arg#0" is the return type. - for (unsigned ArgNo = 0; 1; ++ArgNo) { - int TypeID = va_arg(VA, int); + if (FTy->getNumParams() + FTy->isVarArg() != Count - 1) { + CheckFailed("Intrinsic prototype has incorrect number of arguments!", F); + return; + } - if (TypeID == -2) { - break; - } + // Note that "arg#0" is the return type. + for (unsigned ArgNo = 0; ArgNo < Count; ++ArgNo) { + MVT::ValueType VT = va_arg(VA, MVT::ValueType); - if (TypeID == -1) { - if (ArgNo != FTy->getNumParams()+1) - CheckFailed("Intrinsic prototype has too many arguments!", F); + if (VT == MVT::isVoid && ArgNo > 0) { + if (!FTy->isVarArg()) + CheckFailed("Intrinsic prototype has no '...'!", F); break; } - if (ArgNo == FTy->getNumParams()+1) { - CheckFailed("Intrinsic prototype has too few arguments!", F); - break; - } - const Type *Ty; if (ArgNo == 0) Ty = FTy->getReturnType(); else Ty = FTy->getParamType(ArgNo-1); - - if (TypeID != Ty->getTypeID()) { - if (ArgNo == 0) - CheckFailed("Intrinsic prototype has incorrect result type!", F); - else - CheckFailed("Intrinsic parameter #" + utostr(ArgNo-1) + " is wrong!",F); - break; - } - if (TypeID == Type::IntegerTyID) { - unsigned ExpectedBits = (unsigned) va_arg(VA, int); - unsigned GotBits = cast<IntegerType>(Ty)->getBitWidth(); - if (ExpectedBits == 0) { - Suffix += ".i" + utostr(GotBits); - } else if (GotBits != ExpectedBits) { - std::string bitmsg = " Expected " + utostr(ExpectedBits) + " but got "+ - utostr(GotBits) + " bits."; - if (ArgNo == 0) - CheckFailed("Intrinsic prototype has incorrect integer result width!" - + bitmsg, F); - else - CheckFailed("Intrinsic parameter #" + utostr(ArgNo-1) + " has " - "incorrect integer width!" + bitmsg, F); - break; + unsigned NumElts = 0; + const Type *EltTy = Ty; + if (const VectorType *VTy = dyn_cast<VectorType>(Ty)) { + EltTy = VTy->getElementType(); + NumElts = VTy->getNumElements(); + } + + if ((int)VT < 0) { + int Match = ~VT; + if (Match == 0) { + if (Ty != FTy->getReturnType()) { + CheckFailed("Intrinsic parameter #" + utostr(ArgNo-1) + " does not " + "match return type.", F); + break; + } + } else { + if (Ty != FTy->getParamType(Match-1)) { + CheckFailed("Intrinsic parameter #" + utostr(ArgNo-1) + " does not " + "match parameter %" + utostr(Match-1) + ".", F); + break; + } } + } else if (VT == MVT::iAny) { + 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); - /* FALL THROUGH */ - case Intrinsic::part_set: - case Intrinsic::part_select: - if (ArgNo == 1) { - unsigned ResultBits = - cast<IntegerType>(FTy->getReturnType())->getBitWidth(); - if (GotBits != ResultBits) - CheckFailed("Intrinsic requires the bit widths of the first " - "parameter and the result to match", F); - } break; } - } else if (TypeID == Type::VectorTyID) { + } else if (VT == MVT::iPTR) { + if (!isa<PointerType>(Ty)) { + CheckFailed("Intrinsic parameter #" + utostr(ArgNo-1) + " is not a " + "pointer and a pointer is required.", F); + break; + } + } else if (MVT::isVector(VT)) { // If this is a vector argument, verify the number and type of elements. - const VectorType *PTy = cast<VectorType>(Ty); - int ElemTy = va_arg(VA, int); - if (ElemTy != PTy->getElementType()->getTypeID()) { + if (MVT::getVectorElementType(VT) != MVT::getValueType(EltTy)) { CheckFailed("Intrinsic prototype has incorrect vector element type!", F); break; } - if (ElemTy == Type::IntegerTyID) { - unsigned NumBits = (unsigned)va_arg(VA, int); - unsigned ExpectedBits = - cast<IntegerType>(PTy->getElementType())->getBitWidth(); - if (NumBits != ExpectedBits) { - CheckFailed("Intrinsic prototype has incorrect vector element type!", - F); - break; - } - } - if ((unsigned)va_arg(VA, int) != PTy->getNumElements()) { + if (MVT::getVectorNumElements(VT) != NumElts) { CheckFailed("Intrinsic prototype has incorrect number of " "vector elements!",F); - break; + break; } + } else if (MVT::getTypeForValueType(VT) != EltTy) { + if (ArgNo == 0) + CheckFailed("Intrinsic prototype has incorrect result type!", F); + else + CheckFailed("Intrinsic parameter #" + utostr(ArgNo-1) + " is wrong!",F); + break; + } else if (EltTy != Ty) { + if (ArgNo == 0) + CheckFailed("Intrinsic result type is vector " + "and a scalar is required.", F); + else + CheckFailed("Intrinsic parameter #" + utostr(ArgNo-1) + " is vector " + "and a scalar is required.", F); } } |