Browse Source

Merge branch 'develop-evmcc' of github.com:imapp-pl/ethereum into develop-evmcc

Conflicts:
	evmcc/test/jump/loop1.evm
	evmcc/test/jump/loop1.lll
	evmcc/test/jump/loop2.evm
	evmcc/test/jump/loop2.lll
cl-refactor
artur-zawlocki 10 years ago
parent
commit
07131e4e18
  1. 57
      evmcc/Compiler.cpp
  2. 10
      evmcc/ExecutionEngine.cpp
  3. 6
      evmcc/GasMeter.cpp
  4. 75
      evmcc/Memory.cpp
  5. 9
      evmcc/Memory.h
  6. 12
      evmcc/Type.cpp
  7. 21
      evmcc/Type.h
  8. 1
      evmcc/bytecode/return2.evm
  9. 6
      evmcc/lll/return2.lll
  10. 2
      evmcc/test/jump/loop1.evm
  11. 4
      evmcc/test/jump/loop1.lll
  12. 2
      evmcc/test/jump/loop2.evm
  13. 6
      evmcc/test/jump/loop2.lll

57
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);
@ -423,12 +420,12 @@ std::unique_ptr<llvm::Module> Compiler::compile(const dev::bytes& bytecode)
// TODO: Shifting by 0 gives wrong results as of this bug http://llvm.org/bugs/show_bug.cgi?id=16439
auto shbits = builder.CreateShl(byteNum, builder.getIntN(256, 3));
auto shbits = builder.CreateShl(byteNum, Constant::get(3));
value = builder.CreateShl(value, shbits);
value = builder.CreateLShr(value, builder.getIntN(256, 31 * 8));
value = builder.CreateLShr(value, Constant::get(31 * 8));
auto byteNumValid = builder.CreateICmpULT(byteNum, builder.getIntN(256, 32));
value = builder.CreateSelect(byteNumValid, value, builder.getIntN(256, 0));
auto byteNumValid = builder.CreateICmpULT(byteNum, Constant::get(32));
value = builder.CreateSelect(byteNumValid, value, Constant::get(0));
stack.push(value);
break;
@ -684,7 +681,7 @@ std::unique_ptr<llvm::Module> Compiler::compile(const dev::bytes& bytecode)
case Instruction::PC:
{
auto value = builder.getIntN(256, currentPC);
auto value = Constant::get(currentPC);
stack.push(value);
break;
}
@ -756,7 +753,7 @@ std::unique_ptr<llvm::Module> Compiler::compile(const dev::bytes& bytecode)
case Instruction::CODESIZE:
{
auto value = builder.getIntN(256, bytecode.size());
auto value = Constant::get(bytecode.size());
stack.push(value);
break;
}
@ -834,13 +831,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;
}
@ -852,7 +845,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;
}
@ -884,11 +877,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)
@ -919,17 +912,22 @@ std::unique_ptr<llvm::Module> Compiler::compile(const dev::bytes& bytecode)
void Compiler::linkBasicBlocks()
{
/// Helper function that finds basic block given LLVM basic block pointer
auto findBasicBlock = [this](llvm::BasicBlock* _llbb) -> BasicBlock&
auto findBasicBlock = [this](llvm::BasicBlock* _llbb) -> BasicBlock*
{
// TODO: Fix for finding jumpTableBlock
if (_llbb == this->m_jumpTableBlock->llvm())
return *this->m_jumpTableBlock;
return this->m_jumpTableBlock.get();
for (auto&& bb : this->basicBlocks)
if (_llbb == bb.second.llvm())
return &bb.second;
return nullptr;
// Name is used to get basic block index (index of first instruction)
// TODO: If basicBlocs are still a map - multikey map can be used
auto&& idxStr = _llbb->getName().substr(sizeof(BasicBlock::NamePrefix) - 2);
auto idx = std::stoul(idxStr);
return basicBlocks.find(idx)->second;
//auto&& idxStr = _llbb->getName().substr(sizeof(BasicBlock::NamePrefix) - 2);
//auto idx = std::stoul(idxStr);
//return basicBlocks.find(idx)->second;
};
auto completePhiNodes = [findBasicBlock](llvm::BasicBlock* _llbb) -> void
@ -942,9 +940,14 @@ void Compiler::linkBasicBlocks()
for (auto predIt = llvm::pred_begin(_llbb); predIt != llvm::pred_end(_llbb); ++predIt)
{
// TODO: In case entry block is reached - report error
auto& predBB = findBasicBlock(*predIt);
auto value = predBB.getStack().get(valueIdx);
phi->addIncoming(value, predBB);
auto predBB = findBasicBlock(*predIt);
if (!predBB)
{
std::cerr << "Stack too small in " << _llbb->getName().str() << std::endl;
std::exit(1);
}
auto value = predBB->getStack().get(valueIdx);
phi->addIncoming(value, predBB->llvm());
}
}
};

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(); // TODO: It might be better to place is in Runtime interface
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";

6
evmcc/GasMeter.cpp

@ -45,7 +45,7 @@ uint64_t getStepCost(dev::eth::Instruction inst) // TODO: Add this function to F
return static_cast<uint64_t>(c_createGas);
default: // Assumes instruction code is valid
return static_cast<uint64_t>(c_stepGas);;
return static_cast<uint64_t>(c_stepGas);
}
}
@ -113,7 +113,7 @@ void GasMeter::commitCostBlock()
if (m_checkCall)
{
if (m_blockCost > 0) // If any cost
m_checkCall->setArgOperand(0, m_builder.getIntN(256, m_blockCost)); // Update block cost in gas check call
m_checkCall->setArgOperand(0, Constant::get(m_blockCost)); // Update block cost in gas check call
else
m_checkCall->eraseFromParent(); // Remove the gas check call
@ -126,7 +126,7 @@ void GasMeter::commitCostBlock()
void GasMeter::checkMemory(llvm::Value* _additionalMemoryInWords, llvm::IRBuilder<>& _builder)
{
// Memory uses other builder, but that can be changes later
auto cost = _builder.CreateMul(_additionalMemoryInWords, _builder.getIntN(256, static_cast<uint64_t>(c_memoryGas)), "memcost");
auto cost = _builder.CreateMul(_additionalMemoryInWords, Constant::get(static_cast<uint64_t>(c_memoryGas)), "memcost");
_builder.CreateCall(m_gasCheckFunc, cost);
}

75
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);
@ -42,9 +30,15 @@ Memory::Memory(llvm::IRBuilder<>& _builder, llvm::Module* _module, GasMeter& _ga
m_data = new llvm::GlobalVariable(*_module, Type::BytePtr, false, llvm::GlobalVariable::PrivateLinkage, llvm::UndefValue::get(Type::BytePtr), "mem.data");
m_data->setUnnamedAddr(true); // Address is not important
m_size = new llvm::GlobalVariable(*_module, Type::i256, false, llvm::GlobalVariable::PrivateLinkage, m_builder.getIntN(256, 0), "mem.size");
m_size = new llvm::GlobalVariable(*_module, Type::i256, false, llvm::GlobalVariable::PrivateLinkage, Constant::get(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);
@ -69,7 +63,7 @@ llvm::Function* Memory::createFunc(bool _isStore, llvm::Type* _valueType, llvm::
llvm::Value* index = func->arg_begin();
index->setName("index");
auto valueSize = _valueType->getPrimitiveSizeInBits() / 8;
auto sizeRequired = builder.CreateAdd(index, builder.getIntN(256, valueSize), "sizeRequired");
auto sizeRequired = builder.CreateAdd(index, Constant::get(valueSize), "sizeRequired");
auto size = builder.CreateLoad(m_size, "size");
auto resizeNeeded = builder.CreateICmpULE(size, sizeRequired, "resizeNeeded");
builder.CreateCondBr(resizeNeeded, resizeBB, accessBB); // OPT branch weights?
@ -77,8 +71,8 @@ llvm::Function* Memory::createFunc(bool _isStore, llvm::Type* _valueType, llvm::
// BB "resize"
builder.SetInsertPoint(resizeBB);
// Check gas first
auto wordsRequired = builder.CreateUDiv(builder.CreateAdd(sizeRequired, builder.getIntN(256, 31)), builder.getIntN(256, 32), "wordsRequired");
auto words = builder.CreateUDiv(builder.CreateAdd(size, builder.getIntN(256, 31)), builder.getIntN(256, 32), "words");
auto wordsRequired = builder.CreateUDiv(builder.CreateAdd(sizeRequired, Constant::get(31)), Constant::get(32), "wordsRequired");
auto words = builder.CreateUDiv(builder.CreateAdd(size, Constant::get(31)), Constant::get(32), "words");
auto newWords = builder.CreateSub(wordsRequired, words, "addtionalWords");
_gasMeter.checkMemory(newWords, builder);
// Resize
@ -137,6 +131,15 @@ llvm::Value* Memory::getSize()
return m_builder.CreateLoad(m_size);
}
void Memory::registerReturnData(llvm::Value* _index, llvm::Value* _size)
{
auto lastWord = m_builder.CreateAdd(_index, m_builder.CreateSub(_size, Constant::get(32)), "lastWord");
loadWord(lastWord); // Make sure that memory is allocated and count gas
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 +158,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 +169,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 +194,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;
};
}

12
evmcc/Type.cpp

@ -12,6 +12,7 @@ llvm::IntegerType* Type::lowPrecision;
llvm::IntegerType* Type::Byte;
llvm::PointerType* Type::BytePtr;
llvm::Type* Type::Void;
llvm::Type* Type::MainReturn;
void Type::init(llvm::LLVMContext& _context)
{
@ -21,6 +22,17 @@ void Type::init(llvm::LLVMContext& _context)
Byte = llvm::Type::getInt8Ty(_context);
BytePtr = Byte->getPointerTo();
Void = llvm::Type::getVoidTy(_context);
MainReturn = llvm::Type::getInt32Ty(_context);
}
llvm::Constant* Constant::get(uint64_t _n)
{
return llvm::ConstantInt::get(Type::i256, _n);
}
llvm::Constant* Constant::get(ReturnCode _returnCode)
{
return llvm::ConstantInt::get(Type::MainReturn, static_cast<uint64_t>(_returnCode));
}
}

21
evmcc/Type.h

@ -2,6 +2,7 @@
#pragma once
#include <llvm/IR/Type.h>
#include <llvm/IR/Constants.h>
namespace evmcc
{
@ -20,7 +21,27 @@ struct Type
static llvm::Type* Void;
/// Main function return type
static llvm::Type* MainReturn;
static void init(llvm::LLVMContext& _context);
};
enum class ReturnCode
{
Stop = 0,
Return = 1,
Suicide = 2,
BadJumpDestination = 101,
};
struct Constant
{
/// Returns word-size constant
static llvm::Constant* get(uint64_t _n);
static llvm::Constant* get(ReturnCode _returnCode);
};
}

1
evmcc/bytecode/return2.evm

@ -0,0 +1 @@
6001620f4240f2

6
evmcc/lll/return2.lll

@ -0,0 +1,6 @@
(asm
1
1000000
RETURN ;; return 1 byte from index 1M
)

2
evmcc/test/jump/loop1.evm

@ -1 +1 @@
600a600181038060025960005460015460025460035400
600a600181038060025960005460015460025400

4
evmcc/test/jump/loop1.lll

@ -18,8 +18,8 @@ MSTORE
MSTORE
2
MSTORE
3
MSTORE
;;3
;;MSTORE
STOP
)

2
evmcc/test/jump/loop2.evm

@ -1 +1 @@
600a80600190038060025960005460015460025460035400
600a80600190038060025960005460015460025400

6
evmcc/test/jump/loop2.lll

@ -5,7 +5,7 @@
;; 2
DUP1
1
1
SWAP1
SUB
DUP1
@ -19,8 +19,8 @@ MSTORE
MSTORE
2
MSTORE
3
MSTORE
;;3
;;MSTORE
STOP
)

Loading…
Cancel
Save