aboutsummaryrefslogtreecommitdiffstats
path: root/unittests/ExecutionEngine
diff options
context:
space:
mode:
authorJeffrey Yasskin <jyasskin@google.com>2009-07-08 21:59:57 +0000
committerJeffrey Yasskin <jyasskin@google.com>2009-07-08 21:59:57 +0000
commit489393d7b92107cc3de17d8dbe7dd11ab7395fdc (patch)
treec71a1374a4b25820422f596ca8e686c01514596a /unittests/ExecutionEngine
parente41dec60fa1ad6a46ec46c848ae1a8f2f7497e12 (diff)
downloadexternal_llvm-489393d7b92107cc3de17d8dbe7dd11ab7395fdc.zip
external_llvm-489393d7b92107cc3de17d8dbe7dd11ab7395fdc.tar.gz
external_llvm-489393d7b92107cc3de17d8dbe7dd11ab7395fdc.tar.bz2
Add an option to allocate JITed global data separately from code. By
default, this option is not enabled to support clients who rely on this behavior. Fixes http://llvm.org/PR4483 A patch to allocate additional memory for globals after we run out is forthcoming. Patch by Reid Kleckner! git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@75059 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'unittests/ExecutionEngine')
-rw-r--r--unittests/ExecutionEngine/JIT/JITTest.cpp126
1 files changed, 126 insertions, 0 deletions
diff --git a/unittests/ExecutionEngine/JIT/JITTest.cpp b/unittests/ExecutionEngine/JIT/JITTest.cpp
new file mode 100644
index 0000000..8f29918
--- /dev/null
+++ b/unittests/ExecutionEngine/JIT/JITTest.cpp
@@ -0,0 +1,126 @@
+//===- JITEmitter.cpp - Unit tests for the JIT code emitter ---------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "gtest/gtest.h"
+#include "llvm/ADT/OwningPtr.h"
+#include "llvm/BasicBlock.h"
+#include "llvm/Constant.h"
+#include "llvm/Constants.h"
+#include "llvm/DerivedTypes.h"
+#include "llvm/ExecutionEngine/JIT.h"
+#include "llvm/ExecutionEngine/JITMemoryManager.h"
+#include "llvm/Function.h"
+#include "llvm/GlobalValue.h"
+#include "llvm/GlobalVariable.h"
+#include "llvm/Module.h"
+#include "llvm/ModuleProvider.h"
+#include "llvm/Support/IRBuilder.h"
+#include "llvm/Target/TargetSelect.h"
+#include "llvm/Type.h"
+
+using namespace llvm;
+
+namespace {
+
+Function *makeReturnGlobal(std::string Name, GlobalVariable *G, Module *M) {
+ std::vector<const Type*> params;
+ const FunctionType *FTy = FunctionType::get(Type::VoidTy, params, false);
+ Function *F = Function::Create(FTy, GlobalValue::ExternalLinkage, Name, M);
+ BasicBlock *Entry = BasicBlock::Create("entry", F);
+ IRBuilder<> builder(Entry);
+ Value *Load = builder.CreateLoad(G);
+ const Type *GTy = G->getType()->getElementType();
+ Value *Add = builder.CreateAdd(Load, ConstantInt::get(GTy, 1LL));
+ builder.CreateStore(Add, G);
+ builder.CreateRet(Add);
+ return F;
+}
+
+// Regression test for a bug. The JIT used to allocate globals inside the same
+// memory block used for the function, and when the function code was freed,
+// the global was left in the same place. This test allocates a function
+// that uses and global, deallocates it, and then makes sure that the global
+// stays alive after that.
+TEST(JIT, GlobalInFunction) {
+ LLVMContext context;
+ Module *M = new Module("<main>", context);
+ ExistingModuleProvider *MP = new ExistingModuleProvider(M);
+
+ JITMemoryManager *MemMgr = JITMemoryManager::CreateDefaultMemManager();
+ // Tell the memory manager to poison freed memory so that accessing freed
+ // memory is more easily tested.
+ MemMgr->setPoisonMemory(true);
+ std::string Error;
+ OwningPtr<ExecutionEngine> JIT(ExecutionEngine::createJIT(
+ MP,
+ &Error,
+ MemMgr,
+ CodeGenOpt::Default,
+ false)); // This last argument enables the fix.
+ ASSERT_EQ(Error, "");
+
+ // Create a global variable.
+ const Type *GTy = Type::Int32Ty;
+ GlobalVariable *G = new GlobalVariable(
+ *M,
+ GTy,
+ false, // Not constant.
+ GlobalValue::InternalLinkage,
+ Constant::getNullValue(GTy),
+ "myglobal");
+
+ // Make a function that points to a global.
+ Function *F1 = makeReturnGlobal("F1", G, M);
+
+ // Get the pointer to the native code to force it to JIT the function and
+ // allocate space for the global.
+ void (*F1Ptr)();
+ // Hack to avoid ISO C++ warning about casting function pointers.
+ *(void**)(void*)&F1Ptr = JIT->getPointerToFunction(F1);
+
+ // Since F1 was codegen'd, a pointer to G should be available.
+ int32_t *GPtr = (int32_t*)JIT->getPointerToGlobalIfAvailable(G);
+ ASSERT_NE((int32_t*)NULL, GPtr);
+ EXPECT_EQ(0, *GPtr);
+
+ // F1() should increment G.
+ F1Ptr();
+ EXPECT_EQ(1, *GPtr);
+
+ // Make a second function identical to the first, referring to the same
+ // global.
+ Function *F2 = makeReturnGlobal("F2", G, M);
+ // Hack to avoid ISO C++ warning about casting function pointers.
+ void (*F2Ptr)();
+ *(void**)(void*)&F2Ptr = JIT->getPointerToFunction(F2);
+
+ // F2() should increment G.
+ F2Ptr();
+ EXPECT_EQ(2, *GPtr);
+
+ // Deallocate F1.
+ JIT->freeMachineCodeForFunction(F1);
+
+ // F2() should *still* increment G.
+ F2Ptr();
+ EXPECT_EQ(3, *GPtr);
+}
+
+// TODO(rnk): This seems to only run once for both tests, which is unexpected.
+// That works just fine, but we shouldn't duplicate the code.
+class JITEnvironment : public testing::Environment {
+ virtual void SetUp() {
+ // Required for ExecutionEngine::createJIT to create a JIT.
+ InitializeNativeTarget();
+ }
+};
+testing::Environment* const jit_env =
+ testing::AddGlobalTestEnvironment(new JITEnvironment);
+
+}