X-Git-Url: http://plrg.eecs.uci.edu/git/?a=blobdiff_plain;f=lib%2FVMCore%2FAutoUpgrade.cpp;h=53e97f4807f10a373a6548060ab371741fe7156c;hb=ae9f3a3b7c915f725aef5a7250e88eaeddda03c6;hp=689a32f958d95e4ba423092f8f9d8b66a4a958ed;hpb=a758b8250d43902b32df9b16aa161622a7f1ef23;p=oota-llvm.git diff --git a/lib/VMCore/AutoUpgrade.cpp b/lib/VMCore/AutoUpgrade.cpp index 689a32f958d..53e97f4807f 100644 --- a/lib/VMCore/AutoUpgrade.cpp +++ b/lib/VMCore/AutoUpgrade.cpp @@ -2,8 +2,8 @@ // // The LLVM Compiler Infrastructure // -// This file was developed by Reid Spencer and is distributed under the -// University of Illinois Open Source License. See LICENSE.TXT for details. +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // @@ -11,220 +11,307 @@ // //===----------------------------------------------------------------------===// -#include "llvm/Assembly/AutoUpgrade.h" -#include "llvm/DerivedTypes.h" +#include "llvm/AutoUpgrade.h" +#include "llvm/Constants.h" #include "llvm/Function.h" #include "llvm/Module.h" #include "llvm/Instructions.h" +#include "llvm/ParameterAttributes.h" #include "llvm/Intrinsics.h" -#include "llvm/SymbolTable.h" -#include +#include using namespace llvm; -static Function *getUpgradedUnaryFn(Function *F) { - const std::string &Name = F->getName(); - Module *M = F->getParent(); - switch (F->getReturnType()->getTypeID()) { - default: return 0; - case Type::UByteTyID: - case Type::SByteTyID: - return M->getOrInsertFunction(Name+".i8", - Type::UByteTy, Type::UByteTy, NULL); - case Type::UShortTyID: - case Type::ShortTyID: - return M->getOrInsertFunction(Name+".i16", - Type::UShortTy, Type::UShortTy, NULL); - case Type::UIntTyID: - case Type::IntTyID: - return M->getOrInsertFunction(Name+".i32", - Type::UIntTy, Type::UIntTy, NULL); - case Type::ULongTyID: - case Type::LongTyID: - return M->getOrInsertFunction(Name+".i64", - Type::ULongTy, Type::ULongTy, NULL); - case Type::FloatTyID: - return M->getOrInsertFunction(Name+".f32", - Type::FloatTy, Type::FloatTy, NULL); - case Type::DoubleTyID: - return M->getOrInsertFunction(Name+".f64", - Type::DoubleTy, Type::DoubleTy, NULL); - } -} -static Function *getUpgradedIntrinsic(Function *F) { - // If there's no function, we can't get the argument type. - if (!F) return 0; +static bool UpgradeIntrinsicFunction1(Function *F, Function *&NewFn) { + 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; + return false; Module *M = F->getParent(); switch (Name[5]) { default: break; case 'b': - if (Name == "llvm.bswap") return getUpgradedUnaryFn(F); + // 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)); + NewFn = F; + return true; + } + } break; + case 'c': - if (Name == "llvm.ctpop" || Name == "llvm.ctlz" || Name == "llvm.cttz") - return getUpgradedUnaryFn(F); - break; - case 'i': - if (Name == "llvm.isunordered" && F->arg_begin() != F->arg_end()) { - if (F->arg_begin()->getType() == Type::FloatTy) - return M->getOrInsertFunction(Name+".f32", F->getFunctionType()); - if (F->arg_begin()->getType() == Type::DoubleTy) - return M->getOrInsertFunction(Name+".f64", F->getFunctionType()); + // 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. + NewFn = cast(M->getOrInsertFunction(Name, + FTy->getParamType(0), + FTy->getParamType(0), + (Type *)0)); + return true; } break; - case 'm': - if (Name == "llvm.memcpy" || Name == "llvm.memset" || - Name == "llvm.memmove") { - if (F->getFunctionType()->getParamType(2) == Type::UIntTy || - F->getFunctionType()->getParamType(2) == Type::IntTy) - return M->getOrInsertFunction(Name+".i32", Type::VoidTy, - PointerType::get(Type::SByteTy), - F->getFunctionType()->getParamType(1), - Type::UIntTy, Type::UIntTy, NULL); - if (F->getFunctionType()->getParamType(2) == Type::ULongTy || - F->getFunctionType()->getParamType(2) == Type::LongTy) - return M->getOrInsertFunction(Name+".i64", Type::VoidTy, - PointerType::get(Type::SByteTy), - F->getFunctionType()->getParamType(1), - Type::ULongTy, Type::UIntTy, NULL); + + 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)); + NewFn = F; + return true; + } + 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)); + NewFn = F; + return true; + } + break; + } + break; - case 's': - if (Name == "llvm.sqrt") - return getUpgradedUnaryFn(F); + case 'x': + // This fixes all MMX shift intrinsic instructions to take a + // v1i64 instead of a v2i32 as the second parameter. + if (Name.compare(5,10,"x86.mmx.ps",10) == 0 && + (Name.compare(13,4,"psll", 4) == 0 || + Name.compare(13,4,"psra", 4) == 0 || + Name.compare(13,4,"psrl", 4) == 0)) { + + const llvm::Type *VT = VectorType::get(IntegerType::get(64), 1); + + // We don't have to do anything if the parameter already has + // the correct type. + if (FTy->getParamType(1) == VT) + break; + + // 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(""); + + assert(FTy->getNumParams() == 2 && "MMX shift intrinsics take 2 args!"); + + // 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. + NewFn = cast(M->getOrInsertFunction(Name, + FTy->getReturnType(), + FTy->getParamType(0), + VT, + (Type *)0)); + return true; + } else if (Name.compare(5,16,"x86.sse2.movl.dq",16) == 0) { + // Calls to this intrinsic are transformed into ShuffleVector's. + NewFn = 0; + return true; + } + break; } - return 0; -} -// UpgradeIntrinsicFunction - Convert overloaded intrinsic function names to -// their non-overloaded variants by appending the appropriate suffix based on -// the argument types. -Function *llvm::UpgradeIntrinsicFunction(Function* F) { - // See if its one of the name's we're interested in. - if (Function *R = getUpgradedIntrinsic(F)) { - std::cerr << "WARNING: change " << F->getName() << " to " - << R->getName() << "\n"; - return R; - } - return 0; + // 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 false; } +bool llvm::UpgradeIntrinsicFunction(Function *F, Function *&NewFn) { + NewFn = 0; + bool Upgraded = UpgradeIntrinsicFunction1(F, NewFn); -Instruction* llvm::MakeUpgradedCall(Function *F, - const std::vector &Params, - BasicBlock *BB, bool isTailCall, - unsigned CallingConv) { - assert(F && "Need a Function to make a CallInst"); - assert(BB && "Need a BasicBlock to make a CallInst"); - - // Convert the params - bool signedArg = false; - std::vector Oprnds; - for (std::vector::const_iterator PI = Params.begin(), - PE = Params.end(); PI != PE; ++PI) { - const Type* opTy = (*PI)->getType(); - if (opTy->isSigned()) { - signedArg = true; - CastInst* cast = - new CastInst(*PI,opTy->getUnsignedVersion(), "autoupgrade_cast"); - BB->getInstList().push_back(cast); - Oprnds.push_back(cast); - } - else - Oprnds.push_back(*PI); - } - - Instruction *result = new CallInst(F, Oprnds); - if (result->getType() != Type::VoidTy) result->setName("autoupgrade_call"); - if (isTailCall) cast(result)->setTailCall(); - if (CallingConv) cast(result)->setCallingConv(CallingConv); - if (signedArg) { - const Type* newTy = F->getReturnType()->getUnsignedVersion(); - CastInst* final = new CastInst(result, newTy, "autoupgrade_uncast"); - BB->getInstList().push_back(result); - result = final; - } - return result; + // Upgrade intrinsic attributes. This does not change the function. + if (NewFn) + F = NewFn; + if (unsigned id = F->getIntrinsicID(true)) + F->setParamAttrs(Intrinsic::getParamAttrs((Intrinsic::ID)id)); + return Upgraded; } -// UpgradeIntrinsicCall - In the BC reader, change a call to some intrinsic to -// be a called to the specified intrinsic. We expect the callees to have the -// same number of arguments, but their types may be different. +// 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) { Function *F = CI->getCalledFunction(); + assert(F && "CallInst has no function associated with it."); - const FunctionType *NewFnTy = NewFn->getFunctionType(); - std::vector Oprnds; - for (unsigned i = 1, e = CI->getNumOperands(); i != e; ++i) { - Value *V = CI->getOperand(i); - if (V->getType() != NewFnTy->getParamType(i-1)) - V = new CastInst(V, NewFnTy->getParamType(i-1), V->getName(), CI); - Oprnds.push_back(V); + if (!NewFn) { + if (strcmp(F->getNameStart(), "llvm.x86.sse2.movl.dq") == 0) { + std::vector Idxs; + Constant *Zero = ConstantInt::get(Type::Int32Ty, 0); + Idxs.push_back(Zero); + Idxs.push_back(Zero); + Idxs.push_back(Zero); + Idxs.push_back(Zero); + Value *ZeroV = ConstantVector::get(Idxs); + + Idxs.clear(); + Idxs.push_back(ConstantInt::get(Type::Int32Ty, 4)); + Idxs.push_back(ConstantInt::get(Type::Int32Ty, 5)); + Idxs.push_back(ConstantInt::get(Type::Int32Ty, 2)); + Idxs.push_back(ConstantInt::get(Type::Int32Ty, 3)); + Value *Mask = ConstantVector::get(Idxs); + ShuffleVectorInst *SI = new ShuffleVectorInst(ZeroV, CI->getOperand(1), + Mask, "upgraded", CI); + + // Handle any uses of the old CallInst. + if (!CI->use_empty()) + // Replace all uses of the old call with the new cast which has the + // correct type. + CI->replaceAllUsesWith(SI); + + // Clean up the old call now that it has been completely upgraded. + CI->eraseFromParent(); + } else { + assert(0 && "Unknown function for CallInst upgrade."); + } + return; } - CallInst *NewCI = new CallInst(NewFn, Oprnds, CI->getName(), CI); - NewCI->setTailCall(CI->isTailCall()); - NewCI->setCallingConv(CI->getCallingConv()); - - if (!CI->use_empty()) { - Instruction *RetVal = NewCI; - if (F->getReturnType() != NewFn->getReturnType()) { - RetVal = new CastInst(NewCI, NewFn->getReturnType(), + + switch(NewFn->getIntrinsicID()) { + default: assert(0 && "Unknown function for CallInst upgrade."); + case Intrinsic::x86_mmx_psll_d: + case Intrinsic::x86_mmx_psll_q: + case Intrinsic::x86_mmx_psll_w: + case Intrinsic::x86_mmx_psra_d: + case Intrinsic::x86_mmx_psra_w: + case Intrinsic::x86_mmx_psrl_d: + case Intrinsic::x86_mmx_psrl_q: + case Intrinsic::x86_mmx_psrl_w: { + SmallVector Operands; + + Operands.push_back(CI->getOperand(1)); + + // Cast the second parameter to the correct type. + BitCastInst *BC = new BitCastInst(CI->getOperand(2), + NewFn->getFunctionType()->getParamType(1), + "upgraded", CI); + Operands.push_back(BC); + + // 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()) + // Replace all uses of the old call with the new cast which has the + // correct type. + CI->replaceAllUsesWith(NewCI); + + // Clean up the old call now that it has been completely upgraded. + CI->eraseFromParent(); + break; + } + case Intrinsic::ctlz: + case Intrinsic::ctpop: + case Intrinsic::cttz: + // Build a small vector of the 1..(N-1) operands, which are the + // parameters. + SmallVector 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 = NewFn->getParamAttrs() && + NewFn->getParamAttrs()->paramHasAttr(0,ParamAttr::SExt); + bool DestSExt = F->getParamAttrs() && + F->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(RetVal); + NewCI->moveBefore(RetCast); + + // Replace all uses of the old call with the new cast which has the + // correct type. + CI->replaceAllUsesWith(RetCast); } - CI->replaceAllUsesWith(RetVal); + + // Clean up the old call now that it has been completely upgraded. + CI->eraseFromParent(); + break; } - CI->eraseFromParent(); } -bool llvm::UpgradeCallsToIntrinsic(Function* F) { - if (Function* newF = UpgradeIntrinsicFunction(F)) { - for (Value::use_iterator UI = F->use_begin(), UE = F->use_end(); - UI != UE; ) { - if (CallInst* CI = dyn_cast(*UI++)) { - std::vector Oprnds; - User::op_iterator OI = CI->op_begin(); - ++OI; - for (User::op_iterator OE = CI->op_end(); OI != OE; ++OI) { - const Type* opTy = OI->get()->getType(); - if (opTy->isSigned()) { - Oprnds.push_back( - new CastInst(OI->get(),opTy->getUnsignedVersion(), - "autoupgrade_cast",CI)); - } else { - Oprnds.push_back(*OI); - } - } - CallInst* newCI = new CallInst(newF, Oprnds, - CI->hasName() ? "autoupcall" : "", CI); - newCI->setTailCall(CI->isTailCall()); - newCI->setCallingConv(CI->getCallingConv()); - if (CI->use_empty()) { - // noop - } else if (CI->getType() != newCI->getType()) { - CastInst *final = new CastInst(newCI, CI->getType(), - "autoupgrade_uncast", newCI); - newCI->moveBefore(final); - CI->replaceAllUsesWith(final); - } else { - CI->replaceAllUsesWith(newCI); - } - CI->eraseFromParent(); +// 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. + Function* NewFn; + if (UpgradeIntrinsicFunction(F, NewFn)) { + 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(*UI++)) + UpgradeIntrinsicCall(CI, NewFn); } - } - if (newF != F) + // Remove old function, no longer used, from the module. F->eraseFromParent(); - return true; + } } - return false; } +