Browse Source

Using Array as a second memory

cl-refactor
Paweł Bylica 10 years ago
parent
commit
fa86522565
  1. 85
      evmjit/libevmjit/Array.cpp
  2. 21
      evmjit/libevmjit/Array.h
  3. 5
      evmjit/libevmjit/ExecutionEngine.cpp
  4. 29
      evmjit/libevmjit/Memory.cpp
  5. 1
      evmjit/libevmjit/Runtime.h

85
evmjit/libevmjit/Array.cpp

@ -1,6 +1,7 @@
#include "Array.h"
#include "preprocessor/llvm_includes_start.h"
#include <llvm/IR/Module.h>
#include <llvm/IR/Function.h>
#include "preprocessor/llvm_includes_end.h"
@ -20,12 +21,12 @@ 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)
llvm::Value* LazyFunction::call(llvm::IRBuilder<>& _builder, std::initializer_list<llvm::Value*> const& _args, llvm::Twine const& _name)
{
if (!m_func)
m_func = m_creator();
return _builder.CreateCall(m_func, {_args.begin(), _args.size()});
return _builder.CreateCall(m_func, {_args.begin(), _args.size()}, _name);
}
llvm::Function* Array::createArrayPushFunc()
@ -35,12 +36,6 @@ llvm::Function* Array::createArrayPushFunc()
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();
@ -66,7 +61,7 @@ llvm::Function* Array::createArrayPushFunc()
//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 newBytes = m_reallocFunc.call(m_builder, {bytes, reallocSize}, "newBytes");
auto newData = m_builder.CreateBitCast(newBytes, Type::WordPtr, "newData");
m_builder.CreateStore(newData, dataPtr);
m_builder.CreateStore(newCap, capPtr);
@ -131,6 +126,28 @@ llvm::Function* Array::createArrayGetFunc()
return func;
}
llvm::Function* Array::createGetPtrFunc()
{
llvm::Type* argTypes[] = {m_array->getType(), Type::Size};
auto func = llvm::Function::Create(llvm::FunctionType::get(Type::WordPtr, argTypes, false), llvm::Function::PrivateLinkage, "array.getPtr", 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.CreateBitCast(arrayPtr, Type::BytePtr->getPointerTo(), "dataPtr");
auto data = m_builder.CreateLoad(dataPtr, "data");
auto bytePtr = m_builder.CreateGEP(data, index, "bytePtr");
auto wordPtr = m_builder.CreateBitCast(bytePtr, Type::WordPtr, "wordPtr");
m_builder.CreateRet(wordPtr);
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());
@ -154,6 +171,49 @@ llvm::Function* Array::createFreeFunc()
return func;
}
llvm::Function* Array::getReallocFunc()
{
if (auto func = getModule()->getFunction("ext_realloc"))
return func;
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);
return reallocFunc;
}
llvm::Function* Array::createExtendFunc()
{
llvm::Type* argTypes[] = {m_array->getType(), Type::Size};
auto func = llvm::Function::Create(llvm::FunctionType::get(Type::Void, argTypes, false), llvm::Function::PrivateLinkage, "array.extend", getModule());
func->setDoesNotThrow();
func->setDoesNotCapture(1);
auto arrayPtr = &func->getArgumentList().front();
arrayPtr->setName("arrayPtr");
auto newSize = arrayPtr->getNextNode();
newSize->setName("newSize");
InsertPointGuard guard{m_builder};
m_builder.SetInsertPoint(llvm::BasicBlock::Create(m_builder.getContext(), {}, func));
auto dataPtr = m_builder.CreateBitCast(arrayPtr, Type::BytePtr->getPointerTo(), "dataPtr");// TODO: Use byte* in Array
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 extSize = m_builder.CreateNUWSub(newSize, size, "extSize");
auto newData = m_reallocFunc.call(m_builder, {data, newSize}, "newData"); // TODO: Check realloc result for null
auto extPtr = m_builder.CreateGEP(newData, size, "extPtr");
m_builder.CreateMemSet(extPtr, m_builder.getInt8(0), extSize, 16);
m_builder.CreateStore(newData, dataPtr);
m_builder.CreateStore(newSize, sizePtr);
m_builder.CreateStore(newSize, capPtr);
m_builder.CreateRetVoid();
return func;
}
llvm::Type* Array::getType()
{
llvm::Type* elementTys[] = {Type::WordPtr, Type::Size, Type::Size};
@ -196,6 +256,13 @@ llvm::Value* Array::size()
return m_builder.CreateLoad(sizePtr, "array.size");
}
void Array::extend(llvm::Value* _arrayPtr, llvm::Value* _size)
{
assert(_arrayPtr->getType() == m_array->getType());
assert(_size->getType() == Type::Size);
m_extendFunc.call(m_builder, {_arrayPtr, _size});
}
}
}
}

21
evmjit/libevmjit/Array.h

@ -20,7 +20,7 @@ public:
m_creator(_creator)
{}
llvm::Value* call(llvm::IRBuilder<>& _builder, std::initializer_list<llvm::Value*> const& _args);
llvm::Value* call(llvm::IRBuilder<>& _builder, std::initializer_list<llvm::Value*> const& _args, llvm::Twine const& _name = {});
private:
llvm::Function* m_func = nullptr;
@ -40,6 +40,9 @@ public:
llvm::Value* size();
void free() { m_freeFunc.call(m_builder, {m_array}); }
void extend(llvm::Value* _arrayPtr, llvm::Value* _size);
llvm::Value* getPtr(llvm::Value* _arrayPtr, llvm::Value* _index) { return m_getPtrFunc.call(m_builder, {_arrayPtr, _index}); }
llvm::Value* getPointerTo() const { return m_array; }
static llvm::Type* getType();
@ -47,15 +50,21 @@ public:
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* createGetPtrFunc();
llvm::Function* createFreeFunc();
llvm::Function* createExtendFunc();
llvm::Function* getReallocFunc();
LazyFunction m_pushFunc = {[this](){ return createArrayPushFunc(); }}; // TODO: If works on MSVC, remove form initialization list
LazyFunction m_setFunc;
LazyFunction m_getPtrFunc = {[this](){ return createGetPtrFunc(); }};
LazyFunction m_getFunc;
LazyFunction m_freeFunc;
LazyFunction m_extendFunc = {[this](){ return createExtendFunc(); }};
LazyFunction m_reallocFunc = {[this](){ return getReallocFunc(); }};
};
}

5
evmjit/libevmjit/ExecutionEngine.cpp

@ -160,6 +160,11 @@ ReturnCode ExecutionEngine::run(RuntimeData* _data, Env* _env)
if (g_stats)
statsCollector.stats.push_back(std::move(listener));
if (runtime.m_memData)
{
std::cerr << "MEM: " << (size_t) runtime.m_memData << " [" << runtime.m_memSize << ", " << runtime.m_memCap << "}\n";
}
return returnCode;
}

29
evmjit/libevmjit/Memory.cpp

@ -87,6 +87,8 @@ llvm::Function* Memory::getRequireFunc()
auto newData = m_builder.CreateCall2(resize, rt, sizePtr, "newData");
auto dataPtr = m_builder.CreateStructGEP(rtPtr, 2);
m_builder.CreateStore(newData, dataPtr);
auto extendSize = m_builder.CreateTrunc(sizeRequired, Type::Size, "extendSize");
m_memory.extend(mem, extendSize);
m_builder.CreateBr(returnBB);
// BB "Return"
@ -100,8 +102,8 @@ llvm::Function* Memory::createFunc(bool _isStore, llvm::Type* _valueType)
{
auto isWord = _valueType == Type::Word;
llvm::Type* storeArgs[] = {Type::RuntimePtr, Type::Word, _valueType};
llvm::Type* loadArgs[] = {Type::RuntimePtr, Type::Word};
llvm::Type* storeArgs[] = {Type::RuntimePtr, Type::Word, _valueType, Array::getType()->getPointerTo()};
llvm::Type* loadArgs[] = {Type::RuntimePtr, Type::Word, Array::getType()->getPointerTo()};
auto name = _isStore ? isWord ? "mstore" : "mstore8" : "mload";
auto funcType = _isStore ? llvm::FunctionType::get(Type::Void, storeArgs, false) : llvm::FunctionType::get(Type::Word, loadArgs, false);
auto func = llvm::Function::Create(funcType, llvm::Function::PrivateLinkage, name, getModule());
@ -119,15 +121,24 @@ llvm::Function* Memory::createFunc(bool _isStore, llvm::Type* _valueType)
ptr = m_builder.CreateBitCast(ptr, Type::WordPtr, "wordPtr");
if (_isStore)
{
llvm::Value* value = index->getNextNode();
value->setName("value");
if (isWord)
value = Endianness::toBE(m_builder, value);
auto valueArg = index->getNextNode();
valueArg->setName("value");
auto mem = valueArg->getNextNode();
mem->setName("mem");
auto value = isWord ? Endianness::toBE(m_builder, valueArg) : valueArg;
m_builder.CreateStore(value, ptr);
auto memPtr = m_memory.getPtr(mem, m_builder.CreateTrunc(index, Type::Size));
auto valuePtr = m_builder.CreateBitCast(memPtr, _valueType->getPointerTo(), "valuePtr");
m_builder.CreateStore(value, valuePtr);
m_builder.CreateRetVoid();
}
else
{
auto mem = index->getNextNode();
mem->setName("mem");
auto memPtr = m_memory.getPtr(mem, m_builder.CreateTrunc(index, Type::Size));
llvm::Value* ret = m_builder.CreateLoad(ptr);
ret = Endianness::toNative(m_builder, ret);
m_builder.CreateRet(ret);
@ -164,20 +175,20 @@ llvm::Function* Memory::getStoreByteFunc()
llvm::Value* Memory::loadWord(llvm::Value* _addr)
{
require(_addr, Constant::get(Type::Word->getPrimitiveSizeInBits() / 8));
return createCall(getLoadWordFunc(), {getRuntimeManager().getRuntimePtr(), _addr});
return createCall(getLoadWordFunc(), {getRuntimeManager().getRuntimePtr(), _addr, getRuntimeManager().getMem()});
}
void Memory::storeWord(llvm::Value* _addr, llvm::Value* _word)
{
require(_addr, Constant::get(Type::Word->getPrimitiveSizeInBits() / 8));
createCall(getStoreWordFunc(), {getRuntimeManager().getRuntimePtr(), _addr, _word});
createCall(getStoreWordFunc(), {getRuntimeManager().getRuntimePtr(), _addr, _word, getRuntimeManager().getMem()});
}
void Memory::storeByte(llvm::Value* _addr, llvm::Value* _word)
{
require(_addr, Constant::get(Type::Byte->getPrimitiveSizeInBits() / 8));
auto byte = m_builder.CreateTrunc(_word, Type::Byte, "byte");
createCall(getStoreByteFunc(), {getRuntimeManager().getRuntimePtr(), _addr, byte});
createCall(getStoreByteFunc(), {getRuntimeManager().getRuntimePtr(), _addr, byte, getRuntimeManager().getMem()});
}
llvm::Value* Memory::getData()

1
evmjit/libevmjit/Runtime.h

@ -27,6 +27,7 @@ private:
Env& m_env; ///< Pointer to environment proxy. Expected by compiled contract.
byte* m_memoryData = nullptr;
i256 m_memorySize;
public:
byte* m_memData = nullptr;
uint64_t m_memSize = 0;
uint64_t m_memCap = 0;

Loading…
Cancel
Save