X-Git-Url: http://plrg.eecs.uci.edu/git/?a=blobdiff_plain;f=lib%2FVMCore%2FAutoUpgrade.cpp;h=b56fe70235e031a1b167f0afb630167a1b83814d;hb=780164433250ebc6f42671f5fdd259db14d71c0e;hp=de9d91044c8071c942db098650a6119a387dc2b3;hpb=ffa987d3eeb04b69f356799e544a9bb7b0095541;p=oota-llvm.git diff --git a/lib/VMCore/AutoUpgrade.cpp b/lib/VMCore/AutoUpgrade.cpp index de9d91044c8..b56fe70235e 100644 --- a/lib/VMCore/AutoUpgrade.cpp +++ b/lib/VMCore/AutoUpgrade.cpp @@ -2,7 +2,7 @@ // // The LLVM Compiler Infrastructure // -// This file was developed by Reid Spencer and is distributed under the +// This file was developed by Chandler Carruth and is distributed under the // University of Illinois Open Source License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// @@ -11,62 +11,24 @@ // //===----------------------------------------------------------------------===// -#include "llvm/Assembly/AutoUpgrade.h" -#include "llvm/DerivedTypes.h" +#include "llvm/AutoUpgrade.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 - using namespace llvm; -// Utility function for getting the correct suffix given a type -static inline const char *getTypeSuffix(const Type* Ty) { - switch (Ty->getTypeID()) { - case Type::ULongTyID: return ".i64"; - case Type::UIntTyID: return ".i32"; - case Type::UShortTyID: return ".i16"; - case Type::UByteTyID: return ".i8"; - case Type::FloatTyID: return ".f32"; - case Type::DoubleTyID: return ".f64"; - default: break; - } - return 0; -} -static Function *getUpgradedUnaryFn(Function *F) { - std::string Name = F->getName()+getTypeSuffix(F->getReturnType()); - Module *M = F->getParent(); - switch (F->getReturnType()->getTypeID()) { - default: return 0; - case Type::UByteTyID: - case Type::SByteTyID: - return M->getOrInsertFunction(Name, - Type::UByteTy, Type::UByteTy, NULL); - case Type::UShortTyID: - case Type::ShortTyID: - return M->getOrInsertFunction(Name, - Type::UShortTy, Type::UShortTy, NULL); - case Type::UIntTyID: - case Type::IntTyID: - return M->getOrInsertFunction(Name, - Type::UIntTy, Type::UIntTy, NULL); - case Type::ULongTyID: - case Type::LongTyID: - return M->getOrInsertFunction(Name, - Type::ULongTy, Type::ULongTy, NULL); -} -} - -static Function *getUpgradedIntrinsic(Function *F) { - // If there's no function, we can't get the argument type. - if (!F) return 0; +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] != '.') @@ -76,173 +38,160 @@ static Function *getUpgradedIntrinsic(Function *F) { switch (Name[5]) { default: break; case 'b': - if (Name == "llvm.bswap") return getUpgradedUnaryFn(F); - 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()); + // 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 'm': - if (Name == "llvm.memcpy" || Name == "llvm.memset" || - Name == "llvm.memmove") { - if (F->getFunctionType()->getParamType(2) == Type::UIntTy) - return M->getOrInsertFunction(Name+".i32", F->getFunctionType()); - if (F->getFunctionType()->getParamType(2) == Type::ULongTy) - return M->getOrInsertFunction(Name+".i64", F->getFunctionType()); + + 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(M->getOrInsertFunction(Name, + FTy->getParamType(0), + FTy->getParamType(0), + (Type *)0)); } break; - case 's': - if (Name == "llvm.sqrt") - return getUpgradedUnaryFn(F); - break; - } - return 0; -} - -// This assumes the Function is one of the intrinsics we upgraded. -static inline const Type* getTypeFromFunction(Function *F) { - const Type* Ty = F->getReturnType(); - if (Ty->isFloatingPoint()) - return Ty; - if (Ty->isSigned()) - return Ty->getUnsignedVersion(); - if (Ty->isInteger()) - return Ty; - if (Ty == Type::BoolTy) { - Function::const_arg_iterator ArgIt = F->arg_begin(); - if (ArgIt != F->arg_end()) - return ArgIt->getType(); - } - 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; -} + 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; + } -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); + // 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; } - 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; + break; } - return result; + + // 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 - 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) { + 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(); - 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); - } - 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::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 = 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(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. + 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(*UI++)) + UpgradeIntrinsicCall(CI, NewFn); } - } - if (newF != F) + // Remove old function, no longer used, from the module. F->eraseFromParent(); - return true; + } } - return false; } +