llvm-6502/unittests/ExecutionEngine/JIT/JITTest.cpp
Owen Anderson 0a5372ed3e Begin the painful process of tearing apart the rat'ss nest that is Constants.cpp and ConstantFold.cpp.
This involves temporarily hard wiring some parts to use the global context.  This isn't ideal, but it's
the only way I could figure out to make this process vaguely incremental.


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@75445 91177308-0d34-0410-b5e6-96231b3b80d8
2009-07-13 04:09:18 +00:00

128 lines
4.1 KiB
C++

//===- 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(G->getType()->getElementType(),
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,
context.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);
}