[llvm-commits] [llvm] r91943 - in /llvm/trunk: lib/ExecutionEngine/JIT/JITEmitter.cpp unittests/ExecutionEngine/JIT/JITTest.cpp unittests/ExecutionEngine/JIT/Makefile

Jeffrey Yasskin jyasskin at google.com
Tue Dec 22 15:47:23 PST 2009


Author: jyasskin
Date: Tue Dec 22 17:47:23 2009
New Revision: 91943

URL: http://llvm.org/viewvc/llvm-project?rev=91943&view=rev
Log:
Partially revert r91626.  Materializing extra functions to determine whether
they're available_externally broke VMKit, which was relying on the fact that
functions would only be materialized when they were first called.  We'll have
to wait for http://llvm.org/PR5737 to really fix this.

I also added a test for one of the F->isDeclaration() calls which wasn't
covered by anything else in the test suite.

Modified:
    llvm/trunk/lib/ExecutionEngine/JIT/JITEmitter.cpp
    llvm/trunk/unittests/ExecutionEngine/JIT/JITTest.cpp
    llvm/trunk/unittests/ExecutionEngine/JIT/Makefile

Modified: llvm/trunk/lib/ExecutionEngine/JIT/JITEmitter.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/ExecutionEngine/JIT/JITEmitter.cpp?rev=91943&r1=91942&r2=91943&view=diff

==============================================================================
--- llvm/trunk/lib/ExecutionEngine/JIT/JITEmitter.cpp (original)
+++ llvm/trunk/lib/ExecutionEngine/JIT/JITEmitter.cpp Tue Dec 22 17:47:23 2009
@@ -59,6 +59,12 @@
 static JIT *TheJIT = 0;
 
 
+// A declaration may stop being a declaration once it's fully read from bitcode.
+// This function returns true if F is fully read and is still a declaration.
+static bool isNonGhostDeclaration(const Function *F) {
+  return F->isDeclaration() && !F->hasNotBeenReadFromBitcode();
+}
+
 //===----------------------------------------------------------------------===//
 // JIT lazy compilation code.
 //
@@ -517,15 +523,9 @@
   void *Actual = TheJIT->isCompilingLazily()
     ? (void *)(intptr_t)LazyResolverFn : (void *)0;
 
-  // TODO: Delete this when PR5737 is fixed.
-  std::string ErrorMsg;
-  if (TheJIT->materializeFunction(F, &ErrorMsg)) {
-    llvm_report_error("Error reading function '" + F->getName()+
-                      "' from bitcode file: " + ErrorMsg);
-  }
   // If this is an external declaration, attempt to resolve the address now
   // to place in the stub.
-  if (F->isDeclaration() || F->hasAvailableExternallyLinkage()) {
+  if (isNonGhostDeclaration(F) || F->hasAvailableExternallyLinkage()) {
     Actual = TheJIT->getPointerToFunction(F);
 
     // If we resolved the symbol to a null address (eg. a weak external)
@@ -558,7 +558,7 @@
   // exist yet, add it to the JIT's work list so that we can fill in the stub
   // address later.
   if (!Actual && !TheJIT->isCompilingLazily())
-    if (!F->isDeclaration() && !F->hasAvailableExternallyLinkage())
+    if (!isNonGhostDeclaration(F) && !F->hasAvailableExternallyLinkage())
       TheJIT->addPendingFunction(F);
 
   return Stub;
@@ -761,16 +761,9 @@
     void *ResultPtr = TheJIT->getPointerToGlobalIfAvailable(F);
     if (ResultPtr) return ResultPtr;
 
-    // TODO: Delete this when PR5737 is fixed.
-    std::string ErrorMsg;
-    if (TheJIT->materializeFunction(F, &ErrorMsg)) {
-      llvm_report_error("Error reading function '" + F->getName()+
-                        "' from bitcode file: " + ErrorMsg);
-    }
-
     // If this is an external function pointer, we can force the JIT to
     // 'compile' it, which really just adds it to the map.
-    if (F->isDeclaration() || F->hasAvailableExternallyLinkage())
+    if (isNonGhostDeclaration(F) || F->hasAvailableExternallyLinkage())
       return TheJIT->getPointerToFunction(F);
   }
 

Modified: llvm/trunk/unittests/ExecutionEngine/JIT/JITTest.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/ExecutionEngine/JIT/JITTest.cpp?rev=91943&r1=91942&r2=91943&view=diff

==============================================================================
--- llvm/trunk/unittests/ExecutionEngine/JIT/JITTest.cpp (original)
+++ llvm/trunk/unittests/ExecutionEngine/JIT/JITTest.cpp Tue Dec 22 17:47:23 2009
@@ -12,6 +12,7 @@
 #include "llvm/ADT/SmallPtrSet.h"
 #include "llvm/Assembly/Parser.h"
 #include "llvm/BasicBlock.h"
+#include "llvm/Bitcode/ReaderWriter.h"
 #include "llvm/Constant.h"
 #include "llvm/Constants.h"
 #include "llvm/DerivedTypes.h"
@@ -24,6 +25,7 @@
 #include "llvm/Module.h"
 #include "llvm/ModuleProvider.h"
 #include "llvm/Support/IRBuilder.h"
+#include "llvm/Support/MemoryBuffer.h"
 #include "llvm/Support/SourceMgr.h"
 #include "llvm/Support/TypeBuilder.h"
 #include "llvm/Target/TargetSelect.h"
@@ -177,6 +179,17 @@
   }
 };
 
+bool LoadAssemblyInto(Module *M, const char *assembly) {
+  SMDiagnostic Error;
+  bool success =
+    NULL != ParseAssemblyString(assembly, M, Error, M->getContext());
+  std::string errMsg;
+  raw_string_ostream os(errMsg);
+  Error.Print("", os);
+  EXPECT_TRUE(success) << os.str();
+  return success;
+}
+
 class JITTest : public testing::Test {
  protected:
   virtual void SetUp() {
@@ -192,12 +205,7 @@
   }
 
   void LoadAssembly(const char *assembly) {
-    SMDiagnostic Error;
-    bool success = NULL != ParseAssemblyString(assembly, M, Error, Context);
-    std::string errMsg;
-    raw_string_ostream os(errMsg);
-    Error.Print("", os);
-    ASSERT_TRUE(success) << os.str();
+    LoadAssemblyInto(M, assembly);
   }
 
   LLVMContext Context;
@@ -619,6 +627,88 @@
                         << " not 7 from the IR version.";
 }
 
+// Converts the LLVM assembly to bitcode and returns it in a std::string.  An
+// empty string indicates an error.
+std::string AssembleToBitcode(LLVMContext &Context, const char *Assembly) {
+  Module TempModule("TempModule", Context);
+  if (!LoadAssemblyInto(&TempModule, Assembly)) {
+    return "";
+  }
+
+  std::string Result;
+  raw_string_ostream OS(Result);
+  WriteBitcodeToFile(&TempModule, OS);
+  OS.flush();
+  return Result;
+}
+
+// Returns a newly-created ExecutionEngine that reads the bitcode in 'Bitcode'
+// lazily.  The associated ModuleProvider (owned by the ExecutionEngine) is
+// returned in MP.  Both will be NULL on an error.  Bitcode must live at least
+// as long as the ExecutionEngine.
+ExecutionEngine *getJITFromBitcode(
+  LLVMContext &Context, const std::string &Bitcode, ModuleProvider *&MP) {
+  // c_str() is null-terminated like MemoryBuffer::getMemBuffer requires.
+  MemoryBuffer *BitcodeBuffer =
+    MemoryBuffer::getMemBuffer(Bitcode.c_str(),
+                               Bitcode.c_str() + Bitcode.size(),
+                               "Bitcode for test");
+  std::string errMsg;
+  MP = getBitcodeModuleProvider(BitcodeBuffer, Context, &errMsg);
+  if (MP == NULL) {
+    ADD_FAILURE() << errMsg;
+    delete BitcodeBuffer;
+    return NULL;
+  }
+  ExecutionEngine *TheJIT = EngineBuilder(MP)
+    .setEngineKind(EngineKind::JIT)
+    .setErrorStr(&errMsg)
+    .create();
+  if (TheJIT == NULL) {
+    ADD_FAILURE() << errMsg;
+    delete MP;
+    MP = NULL;
+    return NULL;
+  }
+  return TheJIT;
+}
+
+TEST(LazyLoadedJITTest, EagerCompiledRecursionThroughGhost) {
+  LLVMContext Context;
+  const std::string Bitcode =
+    AssembleToBitcode(Context,
+                      "define i32 @recur1(i32 %a) { "
+                      "  %zero = icmp eq i32 %a, 0 "
+                      "  br i1 %zero, label %done, label %notdone "
+                      "done: "
+                      "  ret i32 3 "
+                      "notdone: "
+                      "  %am1 = sub i32 %a, 1 "
+                      "  %result = call i32 @recur2(i32 %am1) "
+                      "  ret i32 %result "
+                      "} "
+                      " "
+                      "define i32 @recur2(i32 %b) { "
+                      "  %result = call i32 @recur1(i32 %b) "
+                      "  ret i32 %result "
+                      "} ");
+  ASSERT_FALSE(Bitcode.empty()) << "Assembling failed";
+  ModuleProvider *MP;
+  OwningPtr<ExecutionEngine> TheJIT(getJITFromBitcode(Context, Bitcode, MP));
+  ASSERT_TRUE(TheJIT.get()) << "Failed to create JIT.";
+  TheJIT->DisableLazyCompilation(true);
+
+  Module *M = MP->getModule();
+  Function *recur1IR = M->getFunction("recur1");
+  Function *recur2IR = M->getFunction("recur2");
+  EXPECT_TRUE(recur1IR->hasNotBeenReadFromBitcode());
+  EXPECT_TRUE(recur2IR->hasNotBeenReadFromBitcode());
+
+  int32_t (*recur1)(int32_t) = reinterpret_cast<int32_t(*)(int32_t)>(
+    (intptr_t)TheJIT->getPointerToFunction(recur1IR));
+  EXPECT_EQ(3, recur1(4));
+}
+
 // This code is copied from JITEventListenerTest, but it only runs once for all
 // the tests in this directory.  Everything seems fine, but that's strange
 // behavior.

Modified: llvm/trunk/unittests/ExecutionEngine/JIT/Makefile
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/ExecutionEngine/JIT/Makefile?rev=91943&r1=91942&r2=91943&view=diff

==============================================================================
--- llvm/trunk/unittests/ExecutionEngine/JIT/Makefile (original)
+++ llvm/trunk/unittests/ExecutionEngine/JIT/Makefile Tue Dec 22 17:47:23 2009
@@ -9,7 +9,7 @@
 
 LEVEL = ../../..
 TESTNAME = JIT
-LINK_COMPONENTS := asmparser core support jit native
+LINK_COMPONENTS := asmparser bitreader bitwriter core jit native support
 
 include $(LEVEL)/Makefile.config
 include $(LLVM_SRC_ROOT)/unittests/Makefile.unittest





More information about the llvm-commits mailing list