Paweł Bylica
10 years ago
4 changed files with 296 additions and 249 deletions
@ -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"
|
|||
|
@ -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(); |
|||
}; |
|||
|
|||
} |
|||
} |
|||
} |
|||
|
|||
|
Loading…
Reference in new issue