|
|
@ -7,6 +7,8 @@ |
|
|
|
#include "RuntimeManager.h" |
|
|
|
#include "Runtime.h" |
|
|
|
|
|
|
|
#include <iostream> |
|
|
|
|
|
|
|
namespace dev |
|
|
|
{ |
|
|
|
namespace eth |
|
|
@ -14,9 +16,151 @@ 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, "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; |
|
|
|
} |
|
|
|
|
|
|
|
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(); }) |
|
|
|
{ |
|
|
|
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) |
|
|
|
m_runtimeManager(_runtimeManager), |
|
|
|
m_stack(_builder, "stack") |
|
|
|
{} |
|
|
|
|
|
|
|
llvm::Function* Stack::getPushFunc() |
|
|
@ -53,7 +197,7 @@ llvm::Function* Stack::getSetFunc() |
|
|
|
llvm::Type* argTypes[] = {Type::RuntimePtr, Type::Size, Type::Word}; |
|
|
|
func = llvm::Function::Create(llvm::FunctionType::get(Type::Void, argTypes, false), llvm::Function::ExternalLinkage, "stack.set", getModule()); |
|
|
|
llvm::Type* extArgTypes[] = {Type::RuntimePtr, Type::Size, Type::WordPtr}; |
|
|
|
auto extPushFunc = llvm::Function::Create(llvm::FunctionType::get(Type::Void, extArgTypes, false), llvm::Function::ExternalLinkage, "stack_set", getModule()); |
|
|
|
auto extSetFunc = llvm::Function::Create(llvm::FunctionType::get(Type::Void, extArgTypes, false), llvm::Function::ExternalLinkage, "stack_set", getModule()); |
|
|
|
|
|
|
|
auto rt = &func->getArgumentList().front(); |
|
|
|
rt->setName("rt"); |
|
|
@ -67,7 +211,7 @@ llvm::Function* Stack::getSetFunc() |
|
|
|
m_builder.SetInsertPoint(entryBB); |
|
|
|
auto a = m_builder.CreateAlloca(Type::Word); |
|
|
|
m_builder.CreateStore(value, a); |
|
|
|
createCall(extPushFunc, {rt, index, a}); |
|
|
|
createCall(extSetFunc, {rt, index, a}); |
|
|
|
m_builder.CreateRetVoid(); |
|
|
|
} |
|
|
|
return func; |
|
|
@ -114,16 +258,14 @@ llvm::Function* Stack::getGetFunc() |
|
|
|
auto& func = m_get; |
|
|
|
if (!func) |
|
|
|
{ |
|
|
|
llvm::Type* argTypes[] = {Type::RuntimePtr, Type::Size, Type::BytePtr}; |
|
|
|
func = llvm::Function::Create(llvm::FunctionType::get(Type::WordPtr, argTypes, false), llvm::Function::ExternalLinkage, "stack.get", getModule()); |
|
|
|
llvm::Type* extArgTypes[] = {Type::RuntimePtr, Type::Size}; |
|
|
|
auto extGetFunc = llvm::Function::Create(llvm::FunctionType::get(Type::WordPtr, extArgTypes, false), llvm::Function::ExternalLinkage, "stack_get", getModule()); |
|
|
|
llvm::Type* argTypes[] = {Type::Size, Type::Size, Type::BytePtr}; |
|
|
|
func = llvm::Function::Create(llvm::FunctionType::get(Type::Void, argTypes, false), llvm::Function::ExternalLinkage, "stack.require", getModule()); |
|
|
|
|
|
|
|
auto rt = &func->getArgumentList().front(); |
|
|
|
rt->setName("rt"); |
|
|
|
auto index = rt->getNextNode(); |
|
|
|
auto index = &func->getArgumentList().front(); |
|
|
|
index->setName("index"); |
|
|
|
auto jmpBuf = index->getNextNode(); |
|
|
|
auto size = index->getNextNode(); |
|
|
|
size->setName("size"); |
|
|
|
auto jmpBuf = size->getNextNode(); |
|
|
|
jmpBuf->setName("jmpBuf"); |
|
|
|
|
|
|
|
InsertPointGuard guard{m_builder}; |
|
|
@ -132,39 +274,45 @@ llvm::Function* Stack::getGetFunc() |
|
|
|
auto returnBB = llvm::BasicBlock::Create(m_builder.getContext(), "Return", func); |
|
|
|
|
|
|
|
m_builder.SetInsertPoint(entryBB); |
|
|
|
auto valuePtr = createCall(extGetFunc, {rt, index}); |
|
|
|
auto ok = m_builder.CreateICmpNE(valuePtr, llvm::ConstantPointerNull::get(Type::WordPtr)); |
|
|
|
m_builder.CreateCondBr(ok, returnBB, underflowBB); //TODO: Add branch weight
|
|
|
|
auto underflow = m_builder.CreateICmpUGE(index, size, "underflow"); |
|
|
|
m_builder.CreateCondBr(underflow, underflowBB, returnBB); |
|
|
|
|
|
|
|
m_builder.SetInsertPoint(underflowBB); |
|
|
|
m_runtimeManager.abort(jmpBuf); |
|
|
|
m_builder.CreateUnreachable(); |
|
|
|
|
|
|
|
m_builder.SetInsertPoint(returnBB); |
|
|
|
m_builder.CreateRet(valuePtr); |
|
|
|
m_builder.CreateRetVoid(); |
|
|
|
} |
|
|
|
return func; |
|
|
|
} |
|
|
|
|
|
|
|
llvm::Value* Stack::get(size_t _index) |
|
|
|
{ |
|
|
|
auto valuePtr = createCall(getGetFunc(), {m_runtimeManager.getRuntimePtr(), m_builder.getInt64(_index), m_runtimeManager.getJmpBuf()}); |
|
|
|
return m_builder.CreateLoad(valuePtr); |
|
|
|
createCall(getGetFunc(), {m_builder.getInt64(_index), m_stack.size(), m_runtimeManager.getJmpBuf()}); |
|
|
|
auto value = m_stack.get(m_builder.CreateSub(m_stack.size(), m_builder.getInt64(_index + 1))); |
|
|
|
//return m_builder.CreateLoad(valuePtr);
|
|
|
|
return value; |
|
|
|
} |
|
|
|
|
|
|
|
void Stack::set(size_t _index, llvm::Value* _value) |
|
|
|
{ |
|
|
|
createCall(getSetFunc(), {m_runtimeManager.getRuntimePtr(), m_builder.getInt64(_index), _value}); |
|
|
|
m_stack.set(m_builder.CreateSub(m_stack.size(), m_builder.getInt64(_index + 1)), _value); |
|
|
|
//createCall(getSetFunc(), {m_runtimeManager.getRuntimePtr(), m_builder.getInt64(_index), _value});
|
|
|
|
} |
|
|
|
|
|
|
|
void Stack::pop(size_t _count) |
|
|
|
{ |
|
|
|
createCall(getPopFunc(), {m_runtimeManager.getRuntimePtr(), m_builder.getInt64(_count), m_runtimeManager.getJmpBuf()}); |
|
|
|
// FIXME: Pop does not check for stack underflow but looks like not needed
|
|
|
|
// We should place stack.require() check and begining of every BB
|
|
|
|
m_stack.pop(m_builder.getInt64(_count)); |
|
|
|
//createCall(getPopFunc(), {m_runtimeManager.getRuntimePtr(), m_builder.getInt64(_count), m_runtimeManager.getJmpBuf()});
|
|
|
|
} |
|
|
|
|
|
|
|
void Stack::push(llvm::Value* _value) |
|
|
|
{ |
|
|
|
createCall(getPushFunc(), {m_runtimeManager.getRuntimePtr(), _value}); |
|
|
|
m_stack.push(_value); |
|
|
|
//createCall(getPushFunc(), {m_runtimeManager.getRuntimePtr(), _value});
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
@ -175,38 +323,6 @@ extern "C" |
|
|
|
{ |
|
|
|
using namespace dev::eth::jit; |
|
|
|
|
|
|
|
EXPORT bool stack_pop(Runtime* _rt, uint64_t _count) |
|
|
|
{ |
|
|
|
auto& stack = _rt->getStack(); |
|
|
|
if (stack.size() < _count) |
|
|
|
return false; |
|
|
|
|
|
|
|
stack.erase(stack.end() - _count, stack.end()); |
|
|
|
return true; |
|
|
|
} |
|
|
|
|
|
|
|
EXPORT void stack_push(Runtime* _rt, i256 const* _word) |
|
|
|
{ |
|
|
|
auto& stack = _rt->getStack(); |
|
|
|
stack.push_back(*_word); |
|
|
|
} |
|
|
|
|
|
|
|
EXPORT i256* stack_get(Runtime* _rt, uint64_t _index) |
|
|
|
{ |
|
|
|
auto& stack = _rt->getStack(); |
|
|
|
return _index < stack.size() ? &*(stack.rbegin() + _index) : nullptr; |
|
|
|
} |
|
|
|
|
|
|
|
EXPORT void stack_set(Runtime* _rt, uint64_t _index, i256 const* _word) |
|
|
|
{ |
|
|
|
auto& stack = _rt->getStack(); |
|
|
|
assert(_index < stack.size()); |
|
|
|
if (_index >= stack.size()) |
|
|
|
return; |
|
|
|
|
|
|
|
*(stack.rbegin() + _index) = *_word; |
|
|
|
} |
|
|
|
|
|
|
|
EXPORT void ext_calldataload(RuntimeData* _rtData, i256* _index, byte* o_value) |
|
|
|
{ |
|
|
|
// It asumes all indexes are less than 2^64
|
|
|
@ -229,5 +345,13 @@ extern "C" |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
EXPORT void* ext_realloc(void* _data, size_t _size) |
|
|
|
{ |
|
|
|
//std::cerr << "REALLOC: " << _data << " [" << _size << "]" << std::endl;
|
|
|
|
auto newData = std::realloc(_data, _size); |
|
|
|
//std::cerr << "REALLOC: " << _data << " -> " << newData << " [" << _size << "]" << std::endl;
|
|
|
|
return newData; |
|
|
|
} |
|
|
|
|
|
|
|
} // extern "C"
|
|
|
|
|
|
|
|