Browse Source

Move Array helper to separated compilation unit

cl-refactor
Paweł Bylica 10 years ago
parent
commit
d5d56657cf
  1. 233
      evmjit/libevmjit/Array.cpp
  2. 62
      evmjit/libevmjit/Array.h
  3. 204
      evmjit/libevmjit/Stack.cpp
  4. 46
      evmjit/libevmjit/Stack.h

233
evmjit/libevmjit/Array.cpp

@ -0,0 +1,233 @@
#include "Array.h"
#include "preprocessor/llvm_includes_start.h"
#include <llvm/IR/Function.h>
#include "preprocessor/llvm_includes_end.h"
#include "RuntimeManager.h"
#include "Runtime.h"
#include "Utils.h"
#include <set> // DEBUG only
namespace dev
{
namespace eth
{
namespace jit
{
static const auto c_reallocStep = 1;
static const auto c_reallocMultipier = 2;
llvm::Value* LazyFunction::call(llvm::IRBuilder<>& _builder, std::initializer_list<llvm::Value*> const& _args)
{
if (!m_func)
m_func = m_creator();
return _builder.CreateCall(m_func, {_args.begin(), _args.size()});
}
llvm::Function* Array::createArrayPushFunc()
{
llvm::Type* argTypes[] = {m_array->getType(), Type::Word};
auto func = llvm::Function::Create(llvm::FunctionType::get(Type::Void, argTypes, false), llvm::Function::PrivateLinkage, "array.push", getModule());
func->setDoesNotThrow();
func->setDoesNotCapture(1);
llvm::Type* reallocArgTypes[] = {Type::BytePtr, Type::Size};
auto reallocFunc = llvm::Function::Create(llvm::FunctionType::get(Type::BytePtr, reallocArgTypes, false), llvm::Function::ExternalLinkage, "ext_realloc", getModule());
reallocFunc->setDoesNotThrow();
reallocFunc->setDoesNotAlias(0);
reallocFunc->setDoesNotCapture(1);
auto arrayPtr = &func->getArgumentList().front();
arrayPtr->setName("arrayPtr");
auto value = arrayPtr->getNextNode();
value->setName("value");
InsertPointGuard guard{m_builder};
auto entryBB = llvm::BasicBlock::Create(m_builder.getContext(), "Entry", func);
auto reallocBB = llvm::BasicBlock::Create(m_builder.getContext(), "Realloc", func);
auto pushBB = llvm::BasicBlock::Create(m_builder.getContext(), "Push", func);
m_builder.SetInsertPoint(entryBB);
auto dataPtr = m_builder.CreateStructGEP(arrayPtr, 0, "dataPtr");
auto sizePtr = m_builder.CreateStructGEP(arrayPtr, 1, "sizePtr");
auto capPtr = m_builder.CreateStructGEP(arrayPtr, 2, "capPtr");
auto data = m_builder.CreateLoad(dataPtr, "data");
auto size = m_builder.CreateLoad(sizePtr, "size");
auto cap = m_builder.CreateLoad(capPtr, "cap");
auto reallocReq = m_builder.CreateICmpEQ(cap, size, "reallocReq");
m_builder.CreateCondBr(reallocReq, reallocBB, pushBB);
m_builder.SetInsertPoint(reallocBB);
auto newCap = m_builder.CreateNUWAdd(cap, m_builder.getInt64(c_reallocStep), "newCap");
//newCap = m_builder.CreateNUWMul(newCap, m_builder.getInt64(c_reallocMultipier));
auto reallocSize = m_builder.CreateShl(newCap, 5, "reallocSize"); // size in bytes: newCap * 32
auto bytes = m_builder.CreateBitCast(data, Type::BytePtr, "bytes");
auto newBytes = m_builder.CreateCall2(reallocFunc, bytes, reallocSize, "newBytes");
auto newData = m_builder.CreateBitCast(newBytes, Type::WordPtr, "newData");
m_builder.CreateStore(newData, dataPtr);
m_builder.CreateStore(newCap, capPtr);
m_builder.CreateBr(pushBB);
m_builder.SetInsertPoint(pushBB);
auto dataPhi = m_builder.CreatePHI(Type::WordPtr, 2, "dataPhi");
dataPhi->addIncoming(data, entryBB);
dataPhi->addIncoming(newData, reallocBB);
auto newElemPtr = m_builder.CreateGEP(dataPhi, size, "newElemPtr");
m_builder.CreateStore(value, newElemPtr);
auto newSize = m_builder.CreateNUWAdd(size, m_builder.getInt64(1), "newSize");
m_builder.CreateStore(newSize, sizePtr);
m_builder.CreateRetVoid();
return func;
}
llvm::Function* Array::createArraySetFunc()
{
llvm::Type* argTypes[] = {m_array->getType(), Type::Size, Type::Word};
auto func = llvm::Function::Create(llvm::FunctionType::get(Type::Void, argTypes, false), llvm::Function::PrivateLinkage, "array.set", getModule());
func->setDoesNotThrow();
func->setDoesNotCapture(1);
auto arrayPtr = &func->getArgumentList().front();
arrayPtr->setName("arrayPtr");
auto index = arrayPtr->getNextNode();
index->setName("index");
auto value = index->getNextNode();
value->setName("value");
InsertPointGuard guard{m_builder};
m_builder.SetInsertPoint(llvm::BasicBlock::Create(m_builder.getContext(), {}, func));
auto dataPtr = m_builder.CreateStructGEP(arrayPtr, 0, "dataPtr");
auto data = m_builder.CreateLoad(dataPtr, "data");
auto valuePtr = m_builder.CreateGEP(data, index, "valuePtr");
m_builder.CreateStore(value, valuePtr);
m_builder.CreateRetVoid();
return func;
}
llvm::Function* Array::createArrayGetFunc()
{
llvm::Type* argTypes[] = {m_array->getType(), Type::Size};
auto func = llvm::Function::Create(llvm::FunctionType::get(Type::Word, argTypes, false), llvm::Function::PrivateLinkage, "array.get", getModule());
func->setDoesNotThrow();
func->setDoesNotCapture(1);
auto arrayPtr = &func->getArgumentList().front();
arrayPtr->setName("arrayPtr");
auto index = arrayPtr->getNextNode();
index->setName("index");
InsertPointGuard guard{m_builder};
m_builder.SetInsertPoint(llvm::BasicBlock::Create(m_builder.getContext(), {}, func));
auto dataPtr = m_builder.CreateStructGEP(arrayPtr, 0, "dataPtr");
auto data = m_builder.CreateLoad(dataPtr, "data");
auto valuePtr = m_builder.CreateGEP(data, index, "valuePtr");
auto value = m_builder.CreateLoad(valuePtr, "value");
m_builder.CreateRet(value);
return func;
}
llvm::Function* Array::createFreeFunc()
{
auto func = llvm::Function::Create(llvm::FunctionType::get(Type::Void, m_array->getType(), false), llvm::Function::PrivateLinkage, "array.free", getModule());
func->setDoesNotThrow();
func->setDoesNotCapture(1);
auto freeFunc = llvm::Function::Create(llvm::FunctionType::get(Type::Void, Type::BytePtr, false), llvm::Function::ExternalLinkage, "ext_free", getModule());
freeFunc->setDoesNotThrow();
freeFunc->setDoesNotCapture(1);
auto arrayPtr = &func->getArgumentList().front();
arrayPtr->setName("arrayPtr");
InsertPointGuard guard{m_builder};
m_builder.SetInsertPoint(llvm::BasicBlock::Create(m_builder.getContext(), {}, func));
auto dataPtr = m_builder.CreateStructGEP(arrayPtr, 0, "dataPtr");
auto data = m_builder.CreateLoad(dataPtr, "data");
auto mem = m_builder.CreateBitCast(data, Type::BytePtr, "mem");
m_builder.CreateCall(freeFunc, mem);
m_builder.CreateRetVoid();
return func;
}
Array::Array(llvm::IRBuilder<>& _builder, char const* _name) :
CompilerHelper(_builder),
m_pushFunc([this](){ return createArrayPushFunc(); }),
m_setFunc([this](){ return createArraySetFunc(); }),
m_getFunc([this](){ return createArrayGetFunc(); }),
m_freeFunc([this](){ return createFreeFunc(); })
{
llvm::Type* elementTys[] = {Type::WordPtr, Type::Size, Type::Size};
static auto arrayTy = llvm::StructType::create(elementTys, "Array");
m_array = m_builder.CreateAlloca(arrayTy, nullptr, _name);
m_builder.CreateStore(llvm::ConstantAggregateZero::get(arrayTy), m_array);
}
void Array::pop(llvm::Value* _count)
{
auto sizePtr = m_builder.CreateStructGEP(m_array, 1, "sizePtr");
auto size = m_builder.CreateLoad(sizePtr, "size");
auto newSize = m_builder.CreateNUWSub(size, _count, "newSize");
m_builder.CreateStore(newSize, sizePtr);
}
llvm::Value* Array::size()
{
auto sizePtr = m_builder.CreateStructGEP(m_array, 1, "sizePtr");
return m_builder.CreateLoad(sizePtr, "array.size");
}
}
}
}
namespace
{
struct AllocatedMemoryWatchdog
{
std::set<void*> allocatedMemory;
~AllocatedMemoryWatchdog()
{
if (!allocatedMemory.empty())
DLOG(mem) << allocatedMemory.size() << " MEM LEAKS!\n";
}
};
AllocatedMemoryWatchdog watchdog;
}
extern "C"
{
using namespace dev::eth::jit;
EXPORT void* ext_realloc(void* _data, size_t _size)
{
//std::cerr << "REALLOC: " << _data << " [" << _size << "]" << std::endl;
auto newData = std::realloc(_data, _size);
if (_data != newData)
{
DLOG(mem) << "REALLOC: " << _data << " -> " << newData << " [" << _size << "]\n";
watchdog.allocatedMemory.erase(_data);
watchdog.allocatedMemory.insert(newData);
}
return newData;
}
EXPORT void ext_free(void* _data)
{
std::free(_data);
if (_data)
{
DLOG(mem) << "FREE : " << _data << "\n";
watchdog.allocatedMemory.erase(_data);
}
}
} // extern "C"

62
evmjit/libevmjit/Array.h

@ -0,0 +1,62 @@
#pragma once
#include <functional>
#include "CompilerHelper.h"
namespace dev
{
namespace eth
{
namespace jit
{
class LazyFunction
{
public:
using Creator = std::function<llvm::Function*()>;
LazyFunction(Creator _creator) :
m_creator(_creator)
{}
llvm::Value* call(llvm::IRBuilder<>& _builder, std::initializer_list<llvm::Value*> const& _args);
private:
llvm::Function* m_func = nullptr;
Creator m_creator;
};
class Array : public CompilerHelper
{
public:
Array(llvm::IRBuilder<>& _builder, char const* _name);
void push(llvm::Value* _value) { m_pushFunc.call(m_builder, {m_array, _value}); }
void set(llvm::Value* _index, llvm::Value* _value) { m_setFunc.call(m_builder, {m_array, _index, _value}); }
llvm::Value* get(llvm::Value* _index) { return m_getFunc.call(m_builder, {m_array, _index}); }
void pop(llvm::Value* _count);
llvm::Value* size();
void free() { m_freeFunc.call(m_builder, {m_array}); }
llvm::Value* getPointerTo() const { return m_array; }
private:
llvm::Value* m_array = nullptr;
LazyFunction m_pushFunc;
LazyFunction m_setFunc;
LazyFunction m_getFunc;
LazyFunction m_freeFunc;
llvm::Function* createArrayPushFunc();
llvm::Function* createArraySetFunc();
llvm::Function* createArrayGetFunc();
llvm::Function* createFreeFunc();
};
}
}
}

204
evmjit/libevmjit/Stack.cpp

@ -17,171 +17,6 @@ namespace eth
namespace jit
{
static const auto c_reallocStep = 1;
static const auto c_reallocMultipier = 2;
llvm::Value* LazyFunction::call(llvm::IRBuilder<>& _builder, std::initializer_list<llvm::Value*> const& _args)
{
if (!m_func)
m_func = m_creator();
return _builder.CreateCall(m_func, {_args.begin(), _args.size()});
}
llvm::Function* Array::createArrayPushFunc()
{
llvm::Type* argTypes[] = {m_array->getType(), Type::Word};
auto func = llvm::Function::Create(llvm::FunctionType::get(Type::Void, argTypes, false), llvm::Function::PrivateLinkage, "array.push", getModule());
func->setDoesNotThrow();
func->setDoesNotCapture(1);
llvm::Type* reallocArgTypes[] = {Type::BytePtr, Type::Size};
auto reallocFunc = llvm::Function::Create(llvm::FunctionType::get(Type::BytePtr, reallocArgTypes, false), llvm::Function::ExternalLinkage, "ext_realloc", getModule());
reallocFunc->setDoesNotThrow();
reallocFunc->setDoesNotAlias(0);
reallocFunc->setDoesNotCapture(1);
auto arrayPtr = &func->getArgumentList().front();
arrayPtr->setName("arrayPtr");
auto value = arrayPtr->getNextNode();
value->setName("value");
InsertPointGuard guard{m_builder};
auto entryBB = llvm::BasicBlock::Create(m_builder.getContext(), "Entry", func);
auto reallocBB = llvm::BasicBlock::Create(m_builder.getContext(), "Realloc", func);
auto pushBB = llvm::BasicBlock::Create(m_builder.getContext(), "Push", func);
m_builder.SetInsertPoint(entryBB);
auto dataPtr = m_builder.CreateStructGEP(arrayPtr, 0, "dataPtr");
auto sizePtr = m_builder.CreateStructGEP(arrayPtr, 1, "sizePtr");
auto capPtr = m_builder.CreateStructGEP(arrayPtr, 2, "capPtr");
auto data = m_builder.CreateLoad(dataPtr, "data");
auto size = m_builder.CreateLoad(sizePtr, "size");
auto cap = m_builder.CreateLoad(capPtr, "cap");
auto reallocReq = m_builder.CreateICmpEQ(cap, size, "reallocReq");
m_builder.CreateCondBr(reallocReq, reallocBB, pushBB);
m_builder.SetInsertPoint(reallocBB);
auto newCap = m_builder.CreateNUWAdd(cap, m_builder.getInt64(c_reallocStep), "newCap");
//newCap = m_builder.CreateNUWMul(newCap, m_builder.getInt64(c_reallocMultipier));
auto reallocSize = m_builder.CreateShl(newCap, 5, "reallocSize"); // size in bytes: newCap * 32
auto bytes = m_builder.CreateBitCast(data, Type::BytePtr, "bytes");
auto newBytes = m_builder.CreateCall2(reallocFunc, bytes, reallocSize, "newBytes");
auto newData = m_builder.CreateBitCast(newBytes, Type::WordPtr, "newData");
m_builder.CreateStore(newData, dataPtr);
m_builder.CreateStore(newCap, capPtr);
m_builder.CreateBr(pushBB);
m_builder.SetInsertPoint(pushBB);
auto dataPhi = m_builder.CreatePHI(Type::WordPtr, 2, "dataPhi");
dataPhi->addIncoming(data, entryBB);
dataPhi->addIncoming(newData, reallocBB);
auto newElemPtr = m_builder.CreateGEP(dataPhi, size, "newElemPtr");
m_builder.CreateStore(value, newElemPtr);
auto newSize = m_builder.CreateNUWAdd(size, m_builder.getInt64(1), "newSize");
m_builder.CreateStore(newSize, sizePtr);
m_builder.CreateRetVoid();
return func;
}
llvm::Function* Array::createArraySetFunc()
{
llvm::Type* argTypes[] = {m_array->getType(), Type::Size, Type::Word};
auto func = llvm::Function::Create(llvm::FunctionType::get(Type::Void, argTypes, false), llvm::Function::PrivateLinkage, "array.set", getModule());
func->setDoesNotThrow();
func->setDoesNotCapture(1);
auto arrayPtr = &func->getArgumentList().front();
arrayPtr->setName("arrayPtr");
auto index = arrayPtr->getNextNode();
index->setName("index");
auto value = index->getNextNode();
value->setName("value");
InsertPointGuard guard{m_builder};
m_builder.SetInsertPoint(llvm::BasicBlock::Create(m_builder.getContext(), {}, func));
auto dataPtr = m_builder.CreateStructGEP(arrayPtr, 0, "dataPtr");
auto data = m_builder.CreateLoad(dataPtr, "data");
auto valuePtr = m_builder.CreateGEP(data, index, "valuePtr");
m_builder.CreateStore(value, valuePtr);
m_builder.CreateRetVoid();
return func;
}
llvm::Function* Array::createArrayGetFunc()
{
llvm::Type* argTypes[] = {m_array->getType(), Type::Size};
auto func = llvm::Function::Create(llvm::FunctionType::get(Type::Word, argTypes, false), llvm::Function::PrivateLinkage, "array.get", getModule());
func->setDoesNotThrow();
func->setDoesNotCapture(1);
auto arrayPtr = &func->getArgumentList().front();
arrayPtr->setName("arrayPtr");
auto index = arrayPtr->getNextNode();
index->setName("index");
InsertPointGuard guard{m_builder};
m_builder.SetInsertPoint(llvm::BasicBlock::Create(m_builder.getContext(), {}, func));
auto dataPtr = m_builder.CreateStructGEP(arrayPtr, 0, "dataPtr");
auto data = m_builder.CreateLoad(dataPtr, "data");
auto valuePtr = m_builder.CreateGEP(data, index, "valuePtr");
auto value = m_builder.CreateLoad(valuePtr, "value");
m_builder.CreateRet(value);
return func;
}
llvm::Function* Array::createFreeFunc()
{
auto func = llvm::Function::Create(llvm::FunctionType::get(Type::Void, m_array->getType(), false), llvm::Function::PrivateLinkage, "array.free", getModule());
func->setDoesNotThrow();
func->setDoesNotCapture(1);
auto freeFunc = llvm::Function::Create(llvm::FunctionType::get(Type::Void, Type::BytePtr, false), llvm::Function::ExternalLinkage, "ext_free", getModule());
freeFunc->setDoesNotThrow();
freeFunc->setDoesNotCapture(1);
auto arrayPtr = &func->getArgumentList().front();
arrayPtr->setName("arrayPtr");
InsertPointGuard guard{m_builder};
m_builder.SetInsertPoint(llvm::BasicBlock::Create(m_builder.getContext(), {}, func));
auto dataPtr = m_builder.CreateStructGEP(arrayPtr, 0, "dataPtr");
auto data = m_builder.CreateLoad(dataPtr, "data");
auto mem = m_builder.CreateBitCast(data, Type::BytePtr, "mem");
m_builder.CreateCall(freeFunc, mem);
m_builder.CreateRetVoid();
return func;
}
Array::Array(llvm::IRBuilder<>& _builder, char const* _name) :
CompilerHelper(_builder),
m_pushFunc([this](){ return createArrayPushFunc(); }),
m_setFunc([this](){ return createArraySetFunc(); }),
m_getFunc([this](){ return createArrayGetFunc(); }),
m_freeFunc([this](){ return createFreeFunc(); })
{
llvm::Type* elementTys[] = {Type::WordPtr, Type::Size, Type::Size};
static auto arrayTy = llvm::StructType::create(elementTys, "Array");
m_array = m_builder.CreateAlloca(arrayTy, nullptr, _name);
m_builder.CreateStore(llvm::ConstantAggregateZero::get(arrayTy), m_array);
}
void Array::pop(llvm::Value* _count)
{
auto sizePtr = m_builder.CreateStructGEP(m_array, 1, "sizePtr");
auto size = m_builder.CreateLoad(sizePtr, "size");
auto newSize = m_builder.CreateNUWSub(size, _count, "newSize");
m_builder.CreateStore(newSize, sizePtr);
}
llvm::Value* Array::size()
{
auto sizePtr = m_builder.CreateStructGEP(m_array, 1, "sizePtr");
return m_builder.CreateLoad(sizePtr, "array.size");
}
Stack::Stack(llvm::IRBuilder<>& _builder, RuntimeManager& _runtimeManager):
CompilerHelper(_builder),
m_runtimeManager(_runtimeManager),
@ -344,22 +179,6 @@ void Stack::push(llvm::Value* _value)
}
}
namespace
{
struct AllocatedMemoryWatchdog
{
std::set<void*> allocatedMemory;
~AllocatedMemoryWatchdog()
{
if (!allocatedMemory.empty())
DLOG(mem) << allocatedMemory.size() << " MEM LEAKS!\n";
}
};
AllocatedMemoryWatchdog watchdog;
}
extern "C"
{
using namespace dev::eth::jit;
@ -386,28 +205,5 @@ extern "C"
}
}
EXPORT void* ext_realloc(void* _data, size_t _size)
{
//std::cerr << "REALLOC: " << _data << " [" << _size << "]" << std::endl;
auto newData = std::realloc(_data, _size);
if (_data != newData)
{
DLOG(mem) << "REALLOC: " << _data << " -> " << newData << " [" << _size << "]\n";
watchdog.allocatedMemory.erase(_data);
watchdog.allocatedMemory.insert(newData);
}
return newData;
}
EXPORT void ext_free(void* _data)
{
std::free(_data);
if (_data)
{
DLOG(mem) << "FREE : " << _data << "\n";
watchdog.allocatedMemory.erase(_data);
}
}
} // extern "C"

46
evmjit/libevmjit/Stack.h

@ -2,7 +2,7 @@
#include <functional>
#include "CompilerHelper.h"
#include "Array.h"
namespace dev
{
@ -12,50 +12,6 @@ namespace jit
{
class RuntimeManager;
class LazyFunction
{
public:
using Creator = std::function<llvm::Function*()>;
LazyFunction(Creator _creator) :
m_creator(_creator)
{}
llvm::Value* call(llvm::IRBuilder<>& _builder, std::initializer_list<llvm::Value*> const& _args);
private:
llvm::Function* m_func = nullptr;
Creator m_creator;
};
class Array : public CompilerHelper
{
public:
Array(llvm::IRBuilder<>& _builder, char const* _name);
void push(llvm::Value* _value) { m_pushFunc.call(m_builder, {m_array, _value}); }
void set(llvm::Value* _index, llvm::Value* _value) { m_setFunc.call(m_builder, {m_array, _index, _value}); }
llvm::Value* get(llvm::Value* _index) { return m_getFunc.call(m_builder, {m_array, _index}); }
void pop(llvm::Value* _count);
llvm::Value* size();
void free() { m_freeFunc.call(m_builder, {m_array}); }
llvm::Value* getPointerTo() const { return m_array; }
private:
llvm::Value* m_array = nullptr;
LazyFunction m_pushFunc;
LazyFunction m_setFunc;
LazyFunction m_getFunc;
LazyFunction m_freeFunc;
llvm::Function* createArrayPushFunc();
llvm::Function* createArraySetFunc();
llvm::Function* createArrayGetFunc();
llvm::Function* createFreeFunc();
};
class Stack : public CompilerHelper
{
public:

Loading…
Cancel
Save