mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2025-02-05 14:34:55 +00:00
f4ccd11075
This compiles with no changes to clang/lld/lldb with MSVC and includes overloads to various functions which are used by those projects and llvm which have OwningPtr's as parameters. This should allow out of tree projects some time to move. There are also no changes to libs/Target, which should help out of tree targets have time to move, if necessary. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@203083 91177308-0d34-0410-b5e6-96231b3b80d8
303 lines
11 KiB
C++
303 lines
11 KiB
C++
//===- JITMemoryManagerTest.cpp - Unit tests for the JIT memory manager ---===//
|
|
//
|
|
// The LLVM Compiler Infrastructure
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "llvm/ExecutionEngine/JITMemoryManager.h"
|
|
#include "llvm/ADT/ArrayRef.h"
|
|
#include "llvm/IR/DerivedTypes.h"
|
|
#include "llvm/IR/Function.h"
|
|
#include "llvm/IR/GlobalValue.h"
|
|
#include "llvm/IR/LLVMContext.h"
|
|
#include "gtest/gtest.h"
|
|
|
|
using namespace llvm;
|
|
|
|
namespace {
|
|
|
|
Function *makeFakeFunction() {
|
|
std::vector<Type*> params;
|
|
FunctionType *FTy =
|
|
FunctionType::get(Type::getVoidTy(getGlobalContext()), params, false);
|
|
return Function::Create(FTy, GlobalValue::ExternalLinkage);
|
|
}
|
|
|
|
// Allocate three simple functions that fit in the initial slab. This exercises
|
|
// the code in the case that we don't have to allocate more memory to store the
|
|
// function bodies.
|
|
TEST(JITMemoryManagerTest, NoAllocations) {
|
|
std::unique_ptr<JITMemoryManager> MemMgr(
|
|
JITMemoryManager::CreateDefaultMemManager());
|
|
uintptr_t size;
|
|
std::string Error;
|
|
|
|
// Allocate the functions.
|
|
std::unique_ptr<Function> F1(makeFakeFunction());
|
|
size = 1024;
|
|
uint8_t *FunctionBody1 = MemMgr->startFunctionBody(F1.get(), size);
|
|
memset(FunctionBody1, 0xFF, 1024);
|
|
MemMgr->endFunctionBody(F1.get(), FunctionBody1, FunctionBody1 + 1024);
|
|
EXPECT_TRUE(MemMgr->CheckInvariants(Error)) << Error;
|
|
|
|
std::unique_ptr<Function> F2(makeFakeFunction());
|
|
size = 1024;
|
|
uint8_t *FunctionBody2 = MemMgr->startFunctionBody(F2.get(), size);
|
|
memset(FunctionBody2, 0xFF, 1024);
|
|
MemMgr->endFunctionBody(F2.get(), FunctionBody2, FunctionBody2 + 1024);
|
|
EXPECT_TRUE(MemMgr->CheckInvariants(Error)) << Error;
|
|
|
|
std::unique_ptr<Function> F3(makeFakeFunction());
|
|
size = 1024;
|
|
uint8_t *FunctionBody3 = MemMgr->startFunctionBody(F3.get(), size);
|
|
memset(FunctionBody3, 0xFF, 1024);
|
|
MemMgr->endFunctionBody(F3.get(), FunctionBody3, FunctionBody3 + 1024);
|
|
EXPECT_TRUE(MemMgr->CheckInvariants(Error)) << Error;
|
|
|
|
// Deallocate them out of order, in case that matters.
|
|
MemMgr->deallocateFunctionBody(FunctionBody2);
|
|
EXPECT_TRUE(MemMgr->CheckInvariants(Error)) << Error;
|
|
MemMgr->deallocateFunctionBody(FunctionBody1);
|
|
EXPECT_TRUE(MemMgr->CheckInvariants(Error)) << Error;
|
|
MemMgr->deallocateFunctionBody(FunctionBody3);
|
|
EXPECT_TRUE(MemMgr->CheckInvariants(Error)) << Error;
|
|
}
|
|
|
|
// Make three large functions that take up most of the space in the slab. Then
|
|
// try allocating three smaller functions that don't require additional slabs.
|
|
TEST(JITMemoryManagerTest, TestCodeAllocation) {
|
|
std::unique_ptr<JITMemoryManager> MemMgr(
|
|
JITMemoryManager::CreateDefaultMemManager());
|
|
uintptr_t size;
|
|
std::string Error;
|
|
|
|
// Big functions are a little less than the largest block size.
|
|
const uintptr_t smallFuncSize = 1024;
|
|
const uintptr_t bigFuncSize = (MemMgr->GetDefaultCodeSlabSize() -
|
|
smallFuncSize * 2);
|
|
|
|
// Allocate big functions
|
|
std::unique_ptr<Function> F1(makeFakeFunction());
|
|
size = bigFuncSize;
|
|
uint8_t *FunctionBody1 = MemMgr->startFunctionBody(F1.get(), size);
|
|
ASSERT_LE(bigFuncSize, size);
|
|
memset(FunctionBody1, 0xFF, bigFuncSize);
|
|
MemMgr->endFunctionBody(F1.get(), FunctionBody1, FunctionBody1 + bigFuncSize);
|
|
EXPECT_TRUE(MemMgr->CheckInvariants(Error)) << Error;
|
|
|
|
std::unique_ptr<Function> F2(makeFakeFunction());
|
|
size = bigFuncSize;
|
|
uint8_t *FunctionBody2 = MemMgr->startFunctionBody(F2.get(), size);
|
|
ASSERT_LE(bigFuncSize, size);
|
|
memset(FunctionBody2, 0xFF, bigFuncSize);
|
|
MemMgr->endFunctionBody(F2.get(), FunctionBody2, FunctionBody2 + bigFuncSize);
|
|
EXPECT_TRUE(MemMgr->CheckInvariants(Error)) << Error;
|
|
|
|
std::unique_ptr<Function> F3(makeFakeFunction());
|
|
size = bigFuncSize;
|
|
uint8_t *FunctionBody3 = MemMgr->startFunctionBody(F3.get(), size);
|
|
ASSERT_LE(bigFuncSize, size);
|
|
memset(FunctionBody3, 0xFF, bigFuncSize);
|
|
MemMgr->endFunctionBody(F3.get(), FunctionBody3, FunctionBody3 + bigFuncSize);
|
|
EXPECT_TRUE(MemMgr->CheckInvariants(Error)) << Error;
|
|
|
|
// Check that each large function took it's own slab.
|
|
EXPECT_EQ(3U, MemMgr->GetNumCodeSlabs());
|
|
|
|
// Allocate small functions
|
|
std::unique_ptr<Function> F4(makeFakeFunction());
|
|
size = smallFuncSize;
|
|
uint8_t *FunctionBody4 = MemMgr->startFunctionBody(F4.get(), size);
|
|
ASSERT_LE(smallFuncSize, size);
|
|
memset(FunctionBody4, 0xFF, smallFuncSize);
|
|
MemMgr->endFunctionBody(F4.get(), FunctionBody4,
|
|
FunctionBody4 + smallFuncSize);
|
|
EXPECT_TRUE(MemMgr->CheckInvariants(Error)) << Error;
|
|
|
|
std::unique_ptr<Function> F5(makeFakeFunction());
|
|
size = smallFuncSize;
|
|
uint8_t *FunctionBody5 = MemMgr->startFunctionBody(F5.get(), size);
|
|
ASSERT_LE(smallFuncSize, size);
|
|
memset(FunctionBody5, 0xFF, smallFuncSize);
|
|
MemMgr->endFunctionBody(F5.get(), FunctionBody5,
|
|
FunctionBody5 + smallFuncSize);
|
|
EXPECT_TRUE(MemMgr->CheckInvariants(Error)) << Error;
|
|
|
|
std::unique_ptr<Function> F6(makeFakeFunction());
|
|
size = smallFuncSize;
|
|
uint8_t *FunctionBody6 = MemMgr->startFunctionBody(F6.get(), size);
|
|
ASSERT_LE(smallFuncSize, size);
|
|
memset(FunctionBody6, 0xFF, smallFuncSize);
|
|
MemMgr->endFunctionBody(F6.get(), FunctionBody6,
|
|
FunctionBody6 + smallFuncSize);
|
|
EXPECT_TRUE(MemMgr->CheckInvariants(Error)) << Error;
|
|
|
|
// Check that the small functions didn't allocate any new slabs.
|
|
EXPECT_EQ(3U, MemMgr->GetNumCodeSlabs());
|
|
|
|
// Deallocate them out of order, in case that matters.
|
|
MemMgr->deallocateFunctionBody(FunctionBody2);
|
|
EXPECT_TRUE(MemMgr->CheckInvariants(Error)) << Error;
|
|
MemMgr->deallocateFunctionBody(FunctionBody1);
|
|
EXPECT_TRUE(MemMgr->CheckInvariants(Error)) << Error;
|
|
MemMgr->deallocateFunctionBody(FunctionBody4);
|
|
EXPECT_TRUE(MemMgr->CheckInvariants(Error)) << Error;
|
|
MemMgr->deallocateFunctionBody(FunctionBody3);
|
|
EXPECT_TRUE(MemMgr->CheckInvariants(Error)) << Error;
|
|
MemMgr->deallocateFunctionBody(FunctionBody5);
|
|
EXPECT_TRUE(MemMgr->CheckInvariants(Error)) << Error;
|
|
MemMgr->deallocateFunctionBody(FunctionBody6);
|
|
EXPECT_TRUE(MemMgr->CheckInvariants(Error)) << Error;
|
|
}
|
|
|
|
// Allocate five global ints of varying widths and alignment, and check their
|
|
// alignment and overlap.
|
|
TEST(JITMemoryManagerTest, TestSmallGlobalInts) {
|
|
std::unique_ptr<JITMemoryManager> MemMgr(
|
|
JITMemoryManager::CreateDefaultMemManager());
|
|
uint8_t *a = (uint8_t *)MemMgr->allocateGlobal(8, 0);
|
|
uint16_t *b = (uint16_t*)MemMgr->allocateGlobal(16, 2);
|
|
uint32_t *c = (uint32_t*)MemMgr->allocateGlobal(32, 4);
|
|
uint64_t *d = (uint64_t*)MemMgr->allocateGlobal(64, 8);
|
|
|
|
// Check the alignment.
|
|
EXPECT_EQ(0U, ((uintptr_t)b) & 0x1);
|
|
EXPECT_EQ(0U, ((uintptr_t)c) & 0x3);
|
|
EXPECT_EQ(0U, ((uintptr_t)d) & 0x7);
|
|
|
|
// Initialize them each one at a time and make sure they don't overlap.
|
|
*a = 0xff;
|
|
*b = 0U;
|
|
*c = 0U;
|
|
*d = 0U;
|
|
EXPECT_EQ(0xffU, *a);
|
|
EXPECT_EQ(0U, *b);
|
|
EXPECT_EQ(0U, *c);
|
|
EXPECT_EQ(0U, *d);
|
|
*a = 0U;
|
|
*b = 0xffffU;
|
|
EXPECT_EQ(0U, *a);
|
|
EXPECT_EQ(0xffffU, *b);
|
|
EXPECT_EQ(0U, *c);
|
|
EXPECT_EQ(0U, *d);
|
|
*b = 0U;
|
|
*c = 0xffffffffU;
|
|
EXPECT_EQ(0U, *a);
|
|
EXPECT_EQ(0U, *b);
|
|
EXPECT_EQ(0xffffffffU, *c);
|
|
EXPECT_EQ(0U, *d);
|
|
*c = 0U;
|
|
*d = 0xffffffffffffffffULL;
|
|
EXPECT_EQ(0U, *a);
|
|
EXPECT_EQ(0U, *b);
|
|
EXPECT_EQ(0U, *c);
|
|
EXPECT_EQ(0xffffffffffffffffULL, *d);
|
|
|
|
// Make sure we didn't allocate any extra slabs for this tiny amount of data.
|
|
EXPECT_EQ(1U, MemMgr->GetNumDataSlabs());
|
|
}
|
|
|
|
// Allocate a small global, a big global, and a third global, and make sure we
|
|
// only use two slabs for that.
|
|
TEST(JITMemoryManagerTest, TestLargeGlobalArray) {
|
|
std::unique_ptr<JITMemoryManager> MemMgr(
|
|
JITMemoryManager::CreateDefaultMemManager());
|
|
size_t Size = 4 * MemMgr->GetDefaultDataSlabSize();
|
|
uint64_t *a = (uint64_t*)MemMgr->allocateGlobal(64, 8);
|
|
uint8_t *g = MemMgr->allocateGlobal(Size, 8);
|
|
uint64_t *b = (uint64_t*)MemMgr->allocateGlobal(64, 8);
|
|
|
|
// Check the alignment.
|
|
EXPECT_EQ(0U, ((uintptr_t)a) & 0x7);
|
|
EXPECT_EQ(0U, ((uintptr_t)g) & 0x7);
|
|
EXPECT_EQ(0U, ((uintptr_t)b) & 0x7);
|
|
|
|
// Initialize them to make sure we don't segfault and make sure they don't
|
|
// overlap.
|
|
memset(a, 0x1, 8);
|
|
memset(g, 0x2, Size);
|
|
memset(b, 0x3, 8);
|
|
EXPECT_EQ(0x0101010101010101ULL, *a);
|
|
// Just check the edges.
|
|
EXPECT_EQ(0x02U, g[0]);
|
|
EXPECT_EQ(0x02U, g[Size - 1]);
|
|
EXPECT_EQ(0x0303030303030303ULL, *b);
|
|
|
|
// Check the number of slabs.
|
|
EXPECT_EQ(2U, MemMgr->GetNumDataSlabs());
|
|
}
|
|
|
|
// Allocate lots of medium globals so that we can test moving the bump allocator
|
|
// to a new slab.
|
|
TEST(JITMemoryManagerTest, TestManyGlobals) {
|
|
std::unique_ptr<JITMemoryManager> MemMgr(
|
|
JITMemoryManager::CreateDefaultMemManager());
|
|
size_t SlabSize = MemMgr->GetDefaultDataSlabSize();
|
|
size_t Size = 128;
|
|
int Iters = (SlabSize / Size) + 1;
|
|
|
|
// We should start with no slabs.
|
|
EXPECT_EQ(0U, MemMgr->GetNumDataSlabs());
|
|
|
|
// After allocating a bunch of globals, we should have two.
|
|
for (int I = 0; I < Iters; ++I)
|
|
MemMgr->allocateGlobal(Size, 8);
|
|
EXPECT_EQ(2U, MemMgr->GetNumDataSlabs());
|
|
|
|
// And after much more, we should have three.
|
|
for (int I = 0; I < Iters; ++I)
|
|
MemMgr->allocateGlobal(Size, 8);
|
|
EXPECT_EQ(3U, MemMgr->GetNumDataSlabs());
|
|
}
|
|
|
|
// Allocate lots of function stubs so that we can test moving the stub bump
|
|
// allocator to a new slab.
|
|
TEST(JITMemoryManagerTest, TestManyStubs) {
|
|
std::unique_ptr<JITMemoryManager> MemMgr(
|
|
JITMemoryManager::CreateDefaultMemManager());
|
|
size_t SlabSize = MemMgr->GetDefaultStubSlabSize();
|
|
size_t Size = 128;
|
|
int Iters = (SlabSize / Size) + 1;
|
|
|
|
// We should start with no slabs.
|
|
EXPECT_EQ(0U, MemMgr->GetNumDataSlabs());
|
|
|
|
// After allocating a bunch of stubs, we should have two.
|
|
for (int I = 0; I < Iters; ++I)
|
|
MemMgr->allocateStub(NULL, Size, 8);
|
|
EXPECT_EQ(2U, MemMgr->GetNumStubSlabs());
|
|
|
|
// And after much more, we should have three.
|
|
for (int I = 0; I < Iters; ++I)
|
|
MemMgr->allocateStub(NULL, Size, 8);
|
|
EXPECT_EQ(3U, MemMgr->GetNumStubSlabs());
|
|
}
|
|
|
|
// Check section allocation and alignment
|
|
TEST(JITMemoryManagerTest, AllocateSection) {
|
|
std::unique_ptr<JITMemoryManager> MemMgr(
|
|
JITMemoryManager::CreateDefaultMemManager());
|
|
uint8_t *code1 = MemMgr->allocateCodeSection(256, 0, 1, StringRef());
|
|
uint8_t *data1 = MemMgr->allocateDataSection(256, 16, 2, StringRef(), true);
|
|
uint8_t *code2 = MemMgr->allocateCodeSection(257, 32, 3, StringRef());
|
|
uint8_t *data2 = MemMgr->allocateDataSection(256, 64, 4, StringRef(), false);
|
|
uint8_t *code3 = MemMgr->allocateCodeSection(258, 64, 5, StringRef());
|
|
|
|
EXPECT_NE((uint8_t*)0, code1);
|
|
EXPECT_NE((uint8_t*)0, code2);
|
|
EXPECT_NE((uint8_t*)0, data1);
|
|
EXPECT_NE((uint8_t*)0, data2);
|
|
|
|
// Check alignment
|
|
EXPECT_EQ((uint64_t)code1 & 0xf, 0u);
|
|
EXPECT_EQ((uint64_t)code2 & 0x1f, 0u);
|
|
EXPECT_EQ((uint64_t)code3 & 0x3f, 0u);
|
|
EXPECT_EQ((uint64_t)data1 & 0xf, 0u);
|
|
EXPECT_EQ((uint64_t)data2 & 0x3f, 0u);
|
|
}
|
|
|
|
}
|