Browse Source

Change the way compiled program returns

cl-refactor
Paweł Bylica 10 years ago
parent
commit
7a89751433
  1. 19
      evmcc/Compiler.cpp
  2. 10
      evmcc/ExecutionEngine.cpp
  3. 64
      evmcc/Memory.cpp
  4. 9
      evmcc/Memory.h

19
evmcc/Compiler.cpp

@ -190,10 +190,7 @@ std::unique_ptr<llvm::Module> Compiler::compile(const dev::bytes& bytecode)
IRBuilder<> builder(context);
// Create main function
const auto i32Ty = builder.getInt32Ty();
//Type* retTypeElems[] = {i32Ty, i32Ty};
//auto retType = StructType::create(retTypeElems, "MemRef", true);
m_mainFunc = Function::Create(FunctionType::get(builder.getInt64Ty(), false), Function::ExternalLinkage, "main", module.get());
m_mainFunc = Function::Create(FunctionType::get(Type::MainReturn, false), Function::ExternalLinkage, "main", module.get());
// Create the basic blocks.
auto entryBlock = llvm::BasicBlock::Create(context, "entry", m_mainFunc);
@ -797,13 +794,9 @@ std::unique_ptr<llvm::Module> Compiler::compile(const dev::bytes& bytecode)
auto index = stack.pop();
auto size = stack.pop();
auto ret = builder.CreateTrunc(index, builder.getInt64Ty());
ret = builder.CreateShl(ret, 32);
size = builder.CreateTrunc(size, i32Ty);
size = builder.CreateZExt(size, builder.getInt64Ty());
ret = builder.CreateOr(ret, size);
memory.registerReturnData(index, size);
builder.CreateRet(ret);
builder.CreateRet(Constant::get(ReturnCode::Return));
break;
}
@ -815,7 +808,7 @@ std::unique_ptr<llvm::Module> Compiler::compile(const dev::bytes& bytecode)
}
case Instruction::STOP:
{
builder.CreateRet(builder.getInt64(0));
builder.CreateRet(Constant::get(ReturnCode::Stop));
break;
}
@ -847,11 +840,11 @@ std::unique_ptr<llvm::Module> Compiler::compile(const dev::bytes& bytecode)
// Note: Right now the codegen for special blocks depends only on createBasicBlock(),
// not on the codegen for 'regular' blocks. But it has to be done before linkBasicBlocks().
builder.SetInsertPoint(m_finalBlock->llvm());
builder.CreateRet(builder.getInt64(0));
builder.CreateRet(Constant::get(ReturnCode::Stop));
// TODO: throw an exception or something
builder.SetInsertPoint(m_badJumpBlock->llvm());
builder.CreateRet(builder.getInt64(0));
builder.CreateRet(Constant::get(ReturnCode::BadJumpDestination));
builder.SetInsertPoint(m_jumpTableBlock->llvm());
if (m_indirectJumpTargets.size() > 0)

10
evmcc/ExecutionEngine.cpp

@ -14,6 +14,8 @@
#include <llvm/Support/Host.h>
#include "Runtime.h"
#include "Memory.h"
#include "Type.h"
namespace evmcc
{
@ -97,13 +99,13 @@ int ExecutionEngine::run(std::unique_ptr<llvm::Module> _module)
auto result = exec->runFunction(entryFunc, {});
gas = static_cast<decltype(gas)>(Runtime::getGas());
if (auto intResult = result.IntVal.getZExtValue())
auto returnCode = static_cast<ReturnCode>(result.IntVal.getZExtValue());
if (returnCode == ReturnCode::Return)
{
auto index = intResult >> 32;
auto size = 0xFFFFFFFF & intResult;
auto&& returnData = Memory::getReturnData();
std::cout << "RETURN [ ";
for (dev::bytes::const_iterator it = Runtime::getMemory().cbegin() + index, end = it + size; it != end; ++it)
for (auto it = returnData.begin(), end = returnData.end(); it != end; ++it)
std::cout << std::hex << std::setw(2) << std::setfill('0') << (int)*it << " ";
std::cout << "]\n";

64
evmcc/Memory.cpp

@ -21,20 +21,8 @@ namespace evmcc
Memory::Memory(llvm::IRBuilder<>& _builder, llvm::Module* _module, GasMeter& _gasMeter):
m_builder(_builder)
{
auto voidTy = m_builder.getVoidTy();
auto i64Ty = m_builder.getInt64Ty();
auto memRequireTy = llvm::FunctionType::get(m_builder.getInt8PtrTy(), i64Ty, false);
m_memRequire = llvm::Function::Create(memRequireTy,
llvm::GlobalValue::LinkageTypes::ExternalLinkage,
"evmccrt_memory_require", _module);
auto memSizeTy = llvm::FunctionType::get(i64Ty, false);
m_memSize = llvm::Function::Create(memSizeTy,
llvm::GlobalValue::LinkageTypes::ExternalLinkage,
"evmccrt_memory_size", _module);
std::vector<llvm::Type*> argTypes = {i64Ty, i64Ty};
llvm::Type* argTypes[] = {i64Ty, i64Ty};
auto dumpTy = llvm::FunctionType::get(m_builder.getVoidTy(), llvm::ArrayRef<llvm::Type*>(argTypes), false);
m_memDump = llvm::Function::Create(dumpTy, llvm::GlobalValue::LinkageTypes::ExternalLinkage,
"evmccrt_memory_dump", _module);
@ -45,6 +33,12 @@ Memory::Memory(llvm::IRBuilder<>& _builder, llvm::Module* _module, GasMeter& _ga
m_size = new llvm::GlobalVariable(*_module, Type::i256, false, llvm::GlobalVariable::PrivateLinkage, m_builder.getIntN(256, 0), "mem.size");
m_size->setUnnamedAddr(true); // Address is not important
m_returnDataOffset = new llvm::GlobalVariable(*_module, Type::i256, false, llvm::GlobalVariable::ExternalLinkage, nullptr, "mem_returnDataOffset");
m_returnDataOffset->setUnnamedAddr(true); // Address is not important
m_returnDataSize = new llvm::GlobalVariable(*_module, Type::i256, false, llvm::GlobalVariable::ExternalLinkage, nullptr, "mem_returnDataSize");
m_returnDataSize->setUnnamedAddr(true); // Address is not important
m_resize = llvm::Function::Create(llvm::FunctionType::get(Type::BytePtr, Type::WordPtr, false), llvm::Function::ExternalLinkage, "mem_resize", _module);
m_loadWord = createFunc(false, Type::i256, _module, _gasMeter);
m_storeWord = createFunc(true, Type::i256, _module, _gasMeter);
@ -137,6 +131,12 @@ llvm::Value* Memory::getSize()
return m_builder.CreateLoad(m_size);
}
void Memory::registerReturnData(llvm::Value* _index, llvm::Value* _size)
{
m_builder.CreateStore(_index, m_returnDataOffset);
m_builder.CreateStore(_size, m_returnDataSize);
}
void Memory::dump(uint64_t _begin, uint64_t _end)
{
if (getenv("EVMCC_DEBUG_MEMORY") == nullptr)
@ -155,6 +155,9 @@ extern "C"
{
using namespace evmcc;
EXPORT i256 mem_returnDataOffset;
EXPORT i256 mem_returnDataSize;
EXPORT uint8_t* mem_resize(i256* _size)
{
auto size = _size->a; // Trunc to 64-bit
@ -163,37 +166,13 @@ EXPORT uint8_t* mem_resize(i256* _size)
return memory.data();
}
// Resizes memory to contain at least _index + 1 bytes and returns the base address.
EXPORT uint8_t* evmccrt_memory_require(uint64_t _index)
{
uint64_t requiredSize = (_index / 32 + 1) * 32;
auto&& memory = Runtime::getMemory();
if (memory.size() < requiredSize)
{
std::cerr << "MEMORY: current size: " << std::dec
<< memory.size() << " bytes, required size: "
<< requiredSize << " bytes"
<< std::endl;
memory.resize(requiredSize);
}
return memory.data();
}
EXPORT uint64_t evmccrt_memory_size()
{
return Runtime::getMemory().size() / 32;
}
EXPORT void evmccrt_memory_dump(uint64_t _begin, uint64_t _end)
{
if (_end == 0)
_end = Runtime::getMemory().size();
std::cerr << "MEMORY: active size: " << std::dec
<< evmccrt_memory_size() << " words\n";
<< Runtime::getMemory().size() / 32 << " words\n";
std::cerr << "MEMORY: dump from " << std::dec
<< _begin << " to " << _end << ":";
if (_end <= _begin)
@ -212,3 +191,12 @@ EXPORT void evmccrt_memory_dump(uint64_t _begin, uint64_t _end)
}
} // extern "C"
dev::bytesConstRef evmcc::Memory::getReturnData()
{
// TODO: Handle large indexes
auto offset = static_cast<size_t>(llvm2eth(mem_returnDataOffset));
auto size = static_cast<size_t>(llvm2eth(mem_returnDataSize));
auto& memory = Runtime::getMemory();
return {memory.data() + offset, size};
}

9
evmcc/Memory.h

@ -20,6 +20,9 @@ public:
void storeByte(llvm::Value* _addr, llvm::Value* _byte);
llvm::Value* getSize();
void registerReturnData(llvm::Value* _index, llvm::Value* _size);
static dev::bytesConstRef getReturnData();
void dump(uint64_t _begin, uint64_t _end = 0);
private:
@ -31,14 +34,16 @@ private:
llvm::GlobalVariable* m_data;
llvm::GlobalVariable* m_size;
/// @TODO: m_data and m_size could be used
llvm::GlobalVariable* m_returnDataOffset;
llvm::GlobalVariable* m_returnDataSize;
llvm::Function* m_loadWord;
llvm::Function* m_storeWord;
llvm::Function* m_storeByte;
llvm::Function* m_resize;
llvm::Function* m_memRequire;
llvm::Function* m_memDump;
llvm::Function* m_memSize;
};
}

Loading…
Cancel
Save