Fix auto-upgrade of intrinsics to work properly with both assembly and
authorReid Spencer <rspencer@reidspencer.com>
Fri, 27 Jan 2006 11:49:27 +0000 (11:49 +0000)
committerReid Spencer <rspencer@reidspencer.com>
Fri, 27 Jan 2006 11:49:27 +0000 (11:49 +0000)
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

include/llvm/Assembly/AutoUpgrade.h
lib/Bytecode/Reader/Reader.cpp
lib/Bytecode/Reader/Reader.h
lib/VMCore/AutoUpgrade.cpp

index 548068fb22c1a0cb90e4832655d715e7ede1150f..b8f9e22cca4775393fa9e2d15114fdbdee13d834 100644 (file)
 #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
index d142aacfa506d5581c5687868488cb923a38b0df..f9ac0bab1b9a04f4a20453118095b859b17b3ef6 100644 (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);
index 21eb8462fb2f03106f1a6558567014d84d11ead3..ffc251b64ef13f0c429f691829735fd388d44ca6 100644 (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
index b68b8b70fef8cb01362986fd93d751a1ea194691..91b0d31dff435fd595f0a7fc5d5cca5b1e150286 100644 (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) {
+
+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 = getTypeFromFunctionName(F)) {
-    Function* newF = UpgradeIntrinsicFunction(F);
+  if (const Type* Ty = 
+      (newF ? getTypeFromFunction(newF) : getTypeFromFunctionName(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;
+    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();
       }
     }