Fix auto-upgrade of intrinsics to work properly with both assembly and

bytecode reading. This code is crufty, the result of much hacking to get things
working correctly. Cleanup patches will follow.


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@25682 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Reid Spencer 2006-01-27 11:49:27 +00:00
parent 2f81fb78dc
commit e2a5fb0e08
4 changed files with 145 additions and 49 deletions

View File

@ -15,11 +15,14 @@
#define LLVM_ASSEMBLY_AUTOUPGRADE_H
#include <string>
#include <vector>
namespace llvm {
class Function;
class CallInst;
class Instruction;
class Value;
class BasicBlock;
/// This function determines if the \p Name provides is a name for which the
/// auto-upgrade to a non-overloaded name applies.
@ -39,6 +42,14 @@ namespace llvm {
/// @brief Remove overloaded intrinsic function names.
Function* UpgradeIntrinsicFunction(Function* F);
Instruction* MakeUpgradedCall(
Function* F, ///< The function to call
const std::vector<Value*>& Params, ///< Operands of the call
BasicBlock* BB, ///< Basic block the caller will insert result to
bool isTailCall = false, ///< True if this is a tail call.
unsigned CallingConv = 0 ///< Calling convention to use
);
/// In LLVM 1.7, the overloading of intrinsic functions was replaced with
/// separate functions for each of the various argument sizes. This function
/// implements the auto-upgrade feature from old overloaded names to the new
@ -52,7 +63,7 @@ namespace llvm {
/// @param CI The CallInst to potentially auto-upgrade.
/// @returns An instrution to replace \p CI with.
/// @brief Get replacement instruction for overloaded intrinsic function call.
Instruction* UpgradeIntrinsicCall(CallInst* CI);
Instruction* UpgradeIntrinsicCall(CallInst* CI, Function* newF = 0);
/// Upgrade both the function and all the calls made to it, if that function
/// needs to be upgraded. This is like a combination of the above two

View File

@ -861,7 +861,6 @@ void BytecodeReader::ParseInstruction(std::vector<unsigned> &Oprnds,
Result = new CallInst(F, Params);
if (isTailCall) cast<CallInst>(Result)->setTailCall();
if (CallingConv) cast<CallInst>(Result)->setCallingConv(CallingConv);
isCall = true;
break;
}
case 56: // Invoke with encoded CC
@ -1034,13 +1033,6 @@ void BytecodeReader::ParseInstruction(std::vector<unsigned> &Oprnds,
BB->getInstList().push_back(Result);
if (this->hasUpgradedIntrinsicFunctions && isCall)
if (Instruction* inst = UpgradeIntrinsicCall(cast<CallInst>(Result))) {
Result->replaceAllUsesWith(inst);
Result->eraseFromParent();
Result = inst;
}
unsigned TypeSlot;
if (Result->getType() == InstTy)
TypeSlot = iType;
@ -1862,6 +1854,25 @@ void BytecodeReader::ParseFunctionBody(Function* F) {
delete PlaceHolder;
}
// If upgraded intrinsic functions were detected during reading of the
// module information, then we need to look for instructions that need to
// be upgraded. This can't be done while the instructions are read in because
// additional instructions inserted mess up the slot numbering.
if (!upgradedFunctions.empty()) {
for (Function::iterator BI = F->begin(), BE = F->end(); BI != BE; ++BI)
for (BasicBlock::iterator II = BI->begin(), IE = BI->end();
II != IE; ++II)
if (CallInst* CI = dyn_cast<CallInst>(II)) {
std::map<Function*,Function*>::iterator FI =
upgradedFunctions.find(CI->getCalledFunction());
if (FI != upgradedFunctions.end()) {
Instruction* newI = UpgradeIntrinsicCall(CI,FI->second);
CI->replaceAllUsesWith(newI);
CI->eraseFromParent();
}
}
}
// Clear out function-level types...
FunctionTypes.clear();
CompactionTypes.clear();
@ -1937,6 +1948,7 @@ void BytecodeReader::ParseAllFunctionBodies() {
++Fi;
}
LazyFunctionLoadMap.clear();
}
/// Parse the global type list
@ -2055,13 +2067,6 @@ void BytecodeReader::ParseModuleGlobalInfo() {
Function *Func = new Function(FTy, GlobalValue::ExternalLinkage,
"", TheModule);
// Replace with upgraded intrinsic function, if applicable.
if (Function* upgrdF = UpgradeIntrinsicFunction(Func)) {
hasUpgradedIntrinsicFunctions = true;
Func->eraseFromParent();
Func = upgrdF;
}
insertValue(Func, (FnSignature & (~0U >> 1)) >> 5, ModuleValues);
// Flags are not used yet.
@ -2433,6 +2438,16 @@ void BytecodeReader::ParseBytecode(BufPtr Buf, unsigned Length,
if (hasFunctions())
error("Function expected, but bytecode stream ended!");
// Look for intrinsic functions to upgrade, upgrade them, and save the
// mapping from old function to new for use later when instructions are
// converted.
for (Module::iterator FI = TheModule->begin(), FE = TheModule->end();
FI != FE; ++FI)
if (Function* newF = UpgradeIntrinsicFunction(FI)) {
upgradedFunctions.insert(std::make_pair(FI,newF));
FI->setName("");
}
// Tell the handler we're done with the module
if (Handler)
Handler->handleModuleEnd(ModuleID);

View File

@ -323,9 +323,9 @@ private:
/// In release 1.7 we changed intrinsic functions to not be overloaded. There
/// is no bytecode change for this, but to optimize the auto-upgrade of calls
/// to intrinsic functions, we set this flag to identify when a module has
/// been read that contains intrinsics that were upgraded.
bool hasUpgradedIntrinsicFunctions;
/// to intrinsic functions, we save a mapping of old function definitions to
/// the new ones so call instructions can be upgraded efficiently.
std::map<Function*,Function*> upgradedFunctions;
/// CompactionTypes - If a compaction table is active in the current function,
/// this is the mapping that it contains. We keep track of what resolved type

View File

@ -75,9 +75,26 @@ static inline const Type* getTypeFromFunctionName(Function* F) {
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;
}
bool llvm::IsUpgradeableIntrinsicName(const std::string& Name) {
// Quickly eliminate it, if it's not a candidate.
if (Name.length() <= 5 || Name[0] != 'l' || Name[1] != 'l' || Name[2] !=
if (Name.length() <= 8 || Name[0] != 'l' || Name[1] != 'l' || Name[2] !=
'v' || Name[3] != 'm' || Name[4] != '.')
return false;
@ -140,23 +157,68 @@ Function* llvm::UpgradeIntrinsicFunction(Function* F) {
return 0;
}
Instruction* llvm::UpgradeIntrinsicCall(CallInst *CI) {
Function *F = CI->getCalledFunction();
if (const Type* Ty = getTypeFromFunctionName(F)) {
Function* newF = UpgradeIntrinsicFunction(F);
std::vector<Value*> Oprnds;
for (User::op_iterator OI = CI->op_begin(), OE = CI->op_end();
OI != OE; ++OI)
Oprnds.push_back(CI);
CallInst* newCI = new CallInst(newF,Oprnds,"autoupgrade_call",CI);
if (Ty->isSigned()) {
const Type* newTy = Ty->getUnsignedVersion();
newCI->setOperand(1,new CastInst(newCI->getOperand(1), newTy,
"autoupgrade_cast", newCI));
CastInst* final = new CastInst(newCI, Ty, "autoupgrade_uncast",newCI);
newCI->moveBefore(final);
return final;
Instruction* llvm::MakeUpgradedCall(
Function* F, const std::vector<Value*>& 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<Value*> Oprnds;
for (std::vector<Value*>::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,"autoupgrade_call");
if (isTailCall) cast<CallInst>(result)->setTailCall();
if (CallingConv) cast<CallInst>(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;
}
Instruction* llvm::UpgradeIntrinsicCall(CallInst *CI, Function* newF) {
Function *F = CI->getCalledFunction();
if (const Type* Ty =
(newF ? getTypeFromFunction(newF) : getTypeFromFunctionName(F))) {
std::vector<Value*> 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?newF:F),Oprnds,"autoupgrade_call",CI);
newCI->setTailCall(CI->isTailCall());
newCI->setCallingConv(CI->getCallingConv());
if (const Type* oldType = CI->getCalledFunction()->getReturnType())
if (oldType->isSigned()) {
CastInst* final =
new CastInst(newCI, oldType, "autoupgrade_uncast",newCI);
newCI->moveBefore(final);
return final;
}
return newCI;
}
return 0;
@ -170,20 +232,28 @@ bool llvm::UpgradeCallsToIntrinsic(Function* F) {
std::vector<Value*> Oprnds;
User::op_iterator OI = CI->op_begin();
++OI;
for (User::op_iterator OE = CI->op_end(); OI != OE; ++OI)
Oprnds.push_back(*OI);
CallInst* newCI = new CallInst(newF,Oprnds,"autoupgrade_call",CI);
const Type* Ty = Oprnds[0]->getType();
if (Ty->isSigned()) {
const Type* newTy = Ty->getUnsignedVersion();
newCI->setOperand(1,new CastInst(newCI->getOperand(1), newTy,
"autoupgrade_cast", newCI));
CastInst* final = new CastInst(newCI, Ty, "autoupgrade_uncast",newCI);
newCI->moveBefore(final);
CI->replaceAllUsesWith(final);
} else {
CI->replaceAllUsesWith(newCI);
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,"autoupgrade_call",CI);
newCI->setTailCall(CI->isTailCall());
newCI->setCallingConv(CI->getCallingConv());
if (const Type* Ty = CI->getCalledFunction()->getReturnType())
if (Ty->isSigned()) {
CastInst* final =
new CastInst(newCI, Ty, "autoupgrade_uncast",newCI);
newCI->moveBefore(final);
CI->replaceAllUsesWith(final);
} else {
CI->replaceAllUsesWith(newCI);
}
CI->eraseFromParent();
}
}