Implement PR135, lazy emission of global variables
authorChris Lattner <sabre@nondot.org>
Sat, 20 Dec 2003 03:36:47 +0000 (03:36 +0000)
committerChris Lattner <sabre@nondot.org>
Sat, 20 Dec 2003 03:36:47 +0000 (03:36 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@10549 91177308-0d34-0410-b5e6-96231b3b80d8

lib/ExecutionEngine/ExecutionEngine.cpp
lib/ExecutionEngine/JIT/JIT.cpp
lib/ExecutionEngine/JIT/JIT.h
lib/ExecutionEngine/JIT/JITEmitter.cpp

index 42c95727e29efd06a87cb603ee740ae5c331a8ce..c820f63c29fb6758f410fa40b8fccac0ba10f264 100644 (file)
@@ -155,7 +155,8 @@ GenericValue ExecutionEngine::getConstantValue(const Constant *C) {
           const_cast<Function*>(dyn_cast<Function>(CPR->getValue())))
         Result = PTOGV(getPointerToFunctionOrStub(F));
       else 
-        Result = PTOGV(getPointerToGlobal(CPR->getValue()));
+        Result = PTOGV(getOrEmitGlobalVariable(
+                           cast<GlobalVariable>(CPR->getValue())));
 
     } else {
       assert(0 && "Unknown constant pointer type!");
@@ -374,7 +375,6 @@ void ExecutionEngine::emitGlobals() {
       // Allocate some memory for it!
       unsigned Size = TD.getTypeSize(Ty);
       addGlobalMapping(I, new char[Size]);
-      NumInitBytes += Size;
 
       DEBUG(std::cerr << "Global '" << I->getName() << "' -> "
                       << (void*)GlobalAddress[I] << "\n");
@@ -401,12 +401,15 @@ void ExecutionEngine::emitGlobals() {
 // EmitGlobalVariable - This method emits the specified global variable to the
 // address specified in GlobalAddresses, or allocates new memory if it's not
 // already in the map.
-void ExecutionEngine::EmitGlobalVariable(GlobalVariable *GV) {
+void ExecutionEngine::EmitGlobalVariable(const GlobalVariable *GV) {
   void *&GA = GlobalAddress[GV];
+  const Type *ElTy = GV->getType()->getElementType();
   if (GA == 0) {
     // If it's not already specified, allocate memory for the global.
-    GA = new char[getTargetData().getTypeSize(GV->getType()->getElementType())];
+    GA = new char[getTargetData().getTypeSize(ElTy)];
   }
+
   InitializeMemory(GV->getInitializer(), GA);
+  NumInitBytes += getTargetData().getTypeSize(ElTy);
   ++NumGlobals;
 }
index 09ac4262c02a039e44d952796c86a194ec929ee7..ab362a64ba11d316d82cf1c00756a540761c8ccb 100644 (file)
 //===----------------------------------------------------------------------===//
 
 #include "JIT.h"
+#include "llvm/DerivedTypes.h"
 #include "llvm/Function.h"
+#include "llvm/GlobalVariable.h"
 #include "llvm/ModuleProvider.h"
 #include "llvm/CodeGen/MachineCodeEmitter.h"
 #include "llvm/CodeGen/MachineFunction.h"
 #include "llvm/ExecutionEngine/GenericValue.h"
 #include "llvm/Target/TargetMachine.h"
 #include "llvm/Target/TargetJITInfo.h"
+#include "Support/DynamicLinker.h"
 using namespace llvm;
 
 JIT::JIT(ModuleProvider *MP, TargetMachine &tm, TargetJITInfo &tji)
@@ -39,8 +42,6 @@ JIT::JIT(ModuleProvider *MP, TargetMachine &tm, TargetJITInfo &tji)
               << "' doesn't support machine code emission!\n";
     abort();
   }
-
-  emitGlobals();
 }
 
 JIT::~JIT() {
@@ -81,22 +82,36 @@ void JIT::runJITOnFunction(Function *F) {
   isAlreadyCodeGenerating = true;
   PM.run(*F);
   isAlreadyCodeGenerating = false;
+
+  // If the function referred to a global variable that had not yet been
+  // emitted, it allocates memory for the global, but doesn't emit it yet.  Emit
+  // all of these globals now.
+  while (!PendingGlobals.empty()) {
+    const GlobalVariable *GV = PendingGlobals.back();
+    PendingGlobals.pop_back();
+    EmitGlobalVariable(GV);
+  }
 }
 
 /// getPointerToFunction - This method is used to get the address of the
 /// specified function, compiling it if neccesary.
 ///
 void *JIT::getPointerToFunction(Function *F) {
-  void *&Addr = GlobalAddress[F];   // Check if function already code gen'd
-  if (Addr) return Addr;
+  if (void *Addr = getPointerToGlobalIfAvailable(F))
+    return Addr;   // Check if function already code gen'd
 
   // Make sure we read in the function if it exists in this Module
   MP->materializeFunction(F);
 
-  if (F->isExternal())
-    return Addr = getPointerToNamedFunction(F->getName());
+  if (F->isExternal()) {
+    void *Addr = getPointerToNamedFunction(F->getName());
+    addGlobalMapping(F, Addr);
+    return Addr;
+  }
 
   runJITOnFunction(F);
+
+  void *Addr = getPointerToGlobalIfAvailable(F);
   assert(Addr && "Code generation didn't add function to GlobalAddress table!");
   return Addr;
 }
@@ -107,8 +122,8 @@ void *JIT::getPointerToFunction(Function *F) {
 //
 void *JIT::getPointerToFunctionOrStub(Function *F) {
   // If we have already code generated the function, just return the address.
-  std::map<const GlobalValue*, void *>::iterator I = GlobalAddress.find(F);
-  if (I != GlobalAddress.end()) return I->second;
+  if (void *Addr = getPointerToGlobalIfAvailable(F))
+    return Addr;
 
   // If the target supports "stubs" for functions, get a stub now.
   if (void *Ptr = TJI.getJITStubForFunction(F, *MCE))
@@ -118,6 +133,33 @@ void *JIT::getPointerToFunctionOrStub(Function *F) {
   return getPointerToFunction(F);
 }
 
+/// getOrEmitGlobalVariable - Return the address of the specified global
+/// variable, possibly emitting it to memory if needed.  This is used by the
+/// Emitter.
+void *JIT::getOrEmitGlobalVariable(const GlobalVariable *GV) {
+  void *Ptr = getPointerToGlobalIfAvailable(GV);
+  if (Ptr) return Ptr;
+
+  // If the global is external, just remember the address.
+  if (GV->isExternal()) {
+    Ptr = GetAddressOfSymbol(GV->getName().c_str());
+    if (Ptr == 0) {
+      std::cerr << "Could not resolve external global address: "
+                << GV->getName() << "\n";
+      abort();
+    }
+  } else {
+    // If the global hasn't been emitted to memory yet, allocate space.  We will
+    // actually initialize the global after current function has finished
+    // compilation.
+    Ptr =new char[getTargetData().getTypeSize(GV->getType()->getElementType())];
+    PendingGlobals.push_back(GV);
+  }
+  addGlobalMapping(GV, Ptr);
+  return Ptr;
+}
+
+
 /// recompileAndRelinkFunction - This method is used to force a function
 /// which has already been compiled, to be compiled again, possibly
 /// after it has been modified. Then the entry to the old copy is overwritten
@@ -125,16 +167,23 @@ void *JIT::getPointerToFunctionOrStub(Function *F) {
 /// just like JIT::getPointerToFunction().
 ///
 void *JIT::recompileAndRelinkFunction(Function *F) {
-  void *&Addr = GlobalAddress[F];   // Check if function already code gen'd
+  void *OldAddr = getPointerToGlobalIfAvailable(F);
 
-  // If it's not already compiled (this is kind of weird) there is no
-  // reason to patch it up.
-  if (!Addr) { return getPointerToFunction (F); }
+  // If it's not already compiled there is no reason to patch it up.
+  if (OldAddr == 0) { return getPointerToFunction(F); }
 
-  void *OldAddr = Addr;
-  Addr = 0;
+  // Delete the old function mapping.
+  addGlobalMapping(F, 0);
+
+  // Destroy the machine code for this function.  FIXME: this should be
+  // incorporated into the code generator!
   MachineFunction::destruct(F);
+
+  // Recodegen the function
   runJITOnFunction(F);
+
+  // Update state, forward the old function to the new function.
+  void *Addr = getPointerToGlobalIfAvailable(F);
   assert(Addr && "Code generation didn't add function to GlobalAddress table!");
   TJI.replaceMachineCodeForFunction(OldAddr, Addr);
   return Addr;
index adf4e46e7798c42da5f74a48b1754b767e8c3b5c..76d2b7a917048b4a5700f7b4f559c58b4356ba5c 100644 (file)
@@ -34,6 +34,11 @@ class JIT : public ExecutionEngine {
   FunctionPassManager PM;  // Passes to compile a function
   MachineCodeEmitter *MCE; // MCE object
 
+  /// PendingGlobals - Global variables which have had memory allocated for them
+  /// while a function was code generated, but which have not been initialized
+  /// yet.
+  std::vector<const GlobalVariable*> PendingGlobals;
+
   JIT(ModuleProvider *MP, TargetMachine &tm, TargetJITInfo &tji);
 public:
   ~JIT();
@@ -69,6 +74,11 @@ public:
   ///
   void *getPointerToFunction(Function *F);
 
+  /// getOrEmitGlobalVariable - Return the address of the specified global
+  /// variable, possibly emitting it to memory if needed.  This is used by the
+  /// Emitter.
+  void *getOrEmitGlobalVariable(const GlobalVariable *GV);
+
   /// getPointerToFunctionOrStub - If the specified function has been
   /// code-gen'd, return a pointer to the function.  If not, compile it, or use
   /// a stub to implement lazy compilation if available.
index 50b3610e518cf9a07ec72c539b29c0c59d21a8c7..8da50919fd3b2c50d9d4ba6737e288d97e799256 100644 (file)
@@ -248,7 +248,11 @@ void Emitter::emitWord(unsigned W) {
 uint64_t Emitter::getGlobalValueAddress(GlobalValue *V) {
   // Try looking up the function to see if it is already compiled, if not return
   // 0.
-  return (intptr_t)TheJIT->getPointerToGlobalIfAvailable(V);
+  if (isa<Function>(V))
+    return (intptr_t)TheJIT->getPointerToGlobalIfAvailable(V);
+  else {
+    return (intptr_t)TheJIT->getOrEmitGlobalVariable(cast<GlobalVariable>(V));
+  }
 }
 uint64_t Emitter::getGlobalValueAddress(const std::string &Name) {
   return (intptr_t)TheJIT->getPointerToNamedFunction(Name);