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

Conflicts:
	evmcc/Compiler.cpp
This commit is contained in:
artur-zawlocki 2014-09-30 23:02:27 +02:00
commit 15b945219a
14 changed files with 490 additions and 51 deletions

View file

@ -3,8 +3,11 @@
#include <llvm/IR/IRBuilder.h>
#include <libevmface/Instruction.h>
#include "Memory.h"
#include "Stack.h"
#include "Ext.h"
namespace evmcc
{
@ -18,6 +21,7 @@ struct
llvm::Type* word256arr;
llvm::Type* size;
llvm::Type* Void;
llvm::Type* WordLowPrecision;
} Types;
Compiler::Compiler()
@ -30,6 +34,9 @@ Compiler::Compiler()
Types.word256arr = llvm::ArrayType::get(Types.word256, 100);
Types.size = llvm::Type::getInt64Ty(context);
Types.Void = llvm::Type::getVoidTy(context);
// TODO: Use 64-bit for now. In 128-bit compiler-rt library functions are required
Types.WordLowPrecision = llvm::Type::getIntNTy(context, 64);
}
@ -38,41 +45,212 @@ std::unique_ptr<llvm::Module> Compiler::compile(const dev::bytes& bytecode)
using namespace llvm;
auto& context = getGlobalContext();
auto module = std::make_unique<Module>("main", context);
IRBuilder<> builder(context);
// Create main function
FunctionType* funcType = FunctionType::get(llvm::Type::getInt32Ty(context), false);
Function* mainFunc = Function::Create(funcType, Function::ExternalLinkage, "main", module.get());
auto mainFuncType = FunctionType::get(llvm::Type::getInt32Ty(context), false);
auto mainFunc = Function::Create(mainFuncType, Function::ExternalLinkage, "main", module.get());
BasicBlock* entryBlock = BasicBlock::Create(context, "entry", mainFunc);
auto entryBlock = BasicBlock::Create(context, "entry", mainFunc);
builder.SetInsertPoint(entryBlock);
// Init stack and memory
auto stack = Stack(builder, module.get());
auto memory = Memory(builder, module.get());
uint64_t words[] = { 1, 2, 3, 4 };
auto val = llvm::APInt(256, 4, words);
auto c = ConstantInt::get(Types.word256, val);
auto ext = Ext(builder);
stack.push(c);
stack.push(ConstantInt::get(Types.word256, 0x1122334455667788));
for (auto pc = bytecode.cbegin(); pc != bytecode.cend(); ++pc)
{
using dev::eth::Instruction;
auto top = stack.top();
stack.push(top); // dup
stack.pop();
auto inst = static_cast<Instruction>(*pc);
switch (inst)
{
auto index = ConstantInt::get(Types.word256, 123);
memory.storeWord(index, c);
case Instruction::ADD:
{
auto lhs = stack.pop();
auto rhs = stack.pop();
auto result = builder.CreateAdd(lhs, rhs);
stack.push(result);
break;
}
memory.dump(123, 123+32);
case Instruction::SUB:
{
auto lhs = stack.pop();
auto rhs = stack.pop();
auto result = builder.CreateSub(lhs, rhs);
stack.push(result);
break;
}
auto index2 = ConstantInt::get(Types.word256, 123 + 16);
auto byte = memory.loadByte(index2);
auto result = builder.CreateZExt(byte, builder.getInt32Ty());
builder.CreateRet(result); // should return 3
case Instruction::MUL:
{
auto lhs256 = stack.pop();
auto rhs256 = stack.pop();
auto lhs128 = builder.CreateTrunc(lhs256, Types.WordLowPrecision);
auto rhs128 = builder.CreateTrunc(rhs256, Types.WordLowPrecision);
auto res128 = builder.CreateMul(lhs128, rhs128);
auto res256 = builder.CreateZExt(res128, Types.word256);
stack.push(res256);
break;
}
case Instruction::DIV:
{
auto lhs256 = stack.pop();
auto rhs256 = stack.pop();
auto lhs128 = builder.CreateTrunc(lhs256, Types.WordLowPrecision);
auto rhs128 = builder.CreateTrunc(rhs256, Types.WordLowPrecision);
auto res128 = builder.CreateUDiv(lhs128, rhs128);
auto res256 = builder.CreateZExt(res128, Types.word256);
stack.push(res256);
break;
}
case Instruction::SDIV:
{
auto lhs256 = stack.pop();
auto rhs256 = stack.pop();
auto lhs128 = builder.CreateTrunc(lhs256, Types.WordLowPrecision);
auto rhs128 = builder.CreateTrunc(rhs256, Types.WordLowPrecision);
auto res128 = builder.CreateSDiv(lhs128, rhs128);
auto res256 = builder.CreateSExt(res128, Types.word256);
stack.push(res256);
break;
}
case Instruction::MOD:
{
auto lhs256 = stack.pop();
auto rhs256 = stack.pop();
auto lhs128 = builder.CreateTrunc(lhs256, Types.WordLowPrecision);
auto rhs128 = builder.CreateTrunc(rhs256, Types.WordLowPrecision);
auto res128 = builder.CreateURem(lhs128, rhs128);
auto res256 = builder.CreateZExt(res128, Types.word256);
stack.push(res256);
break;
}
case Instruction::SMOD:
{
auto lhs256 = stack.pop();
auto rhs256 = stack.pop();
auto lhs128 = builder.CreateTrunc(lhs256, Types.WordLowPrecision);
auto rhs128 = builder.CreateTrunc(rhs256, Types.WordLowPrecision);
auto res128 = builder.CreateSRem(lhs128, rhs128);
auto res256 = builder.CreateSExt(res128, Types.word256);
stack.push(res256);
break;
}
case Instruction::POP:
{
stack.pop();
break;
}
case Instruction::PUSH1:
case Instruction::PUSH2:
case Instruction::PUSH3:
case Instruction::PUSH4:
case Instruction::PUSH5:
case Instruction::PUSH6:
case Instruction::PUSH7:
case Instruction::PUSH8:
case Instruction::PUSH9:
case Instruction::PUSH10:
case Instruction::PUSH11:
case Instruction::PUSH12:
case Instruction::PUSH13:
case Instruction::PUSH14:
case Instruction::PUSH15:
case Instruction::PUSH16:
case Instruction::PUSH17:
case Instruction::PUSH18:
case Instruction::PUSH19:
case Instruction::PUSH20:
case Instruction::PUSH21:
case Instruction::PUSH22:
case Instruction::PUSH23:
case Instruction::PUSH24:
case Instruction::PUSH25:
case Instruction::PUSH26:
case Instruction::PUSH27:
case Instruction::PUSH28:
case Instruction::PUSH29:
case Instruction::PUSH30:
case Instruction::PUSH31:
case Instruction::PUSH32:
{
auto numBytes = static_cast<size_t>(inst) - static_cast<size_t>(Instruction::PUSH1) + 1;
auto value = llvm::APInt(256, 0);
for (decltype(numBytes) i = 0; i < numBytes; ++i) // TODO: Use pc as iterator
{
++pc;
value <<= 8;
value |= *pc;
}
auto c = builder.getInt(value);
stack.push(c);
break;
}
case Instruction::DUP1:
case Instruction::DUP2:
case Instruction::DUP3:
case Instruction::DUP4:
case Instruction::DUP5:
case Instruction::DUP6:
case Instruction::DUP7:
case Instruction::DUP8:
case Instruction::DUP9:
case Instruction::DUP10:
case Instruction::DUP11:
case Instruction::DUP12:
case Instruction::DUP13:
case Instruction::DUP14:
case Instruction::DUP15:
case Instruction::DUP16:
{
auto index = static_cast<uint32_t>(inst) - static_cast<uint32_t>(Instruction::DUP1);
auto value = stack.get(index);
stack.push(value);
break;
}
case Instruction::SWAP1:
case Instruction::SWAP2:
case Instruction::SWAP3:
case Instruction::SWAP4:
case Instruction::SWAP5:
case Instruction::SWAP6:
case Instruction::SWAP7:
case Instruction::SWAP8:
case Instruction::SWAP9:
case Instruction::SWAP10:
case Instruction::SWAP11:
case Instruction::SWAP12:
case Instruction::SWAP13:
case Instruction::SWAP14:
case Instruction::SWAP15:
case Instruction::SWAP16:
{
auto index = static_cast<uint32_t>(inst) - static_cast<uint32_t>(Instruction::SWAP1) + 1;
auto loValue = stack.get(index);
auto hiValue = stack.get(0);
stack.set(index, hiValue);
stack.set(0, loValue);
break;
}
}
}
builder.CreateRet(ConstantInt::get(Type::getInt32Ty(context), 0));
return module;
}

View file

@ -13,6 +13,8 @@
#include <llvm/Support/PrettyStackTrace.h>
#include <llvm/Support/Host.h>
#include "Ext.h"
namespace evmcc
{
@ -66,6 +68,9 @@ int ExecutionEngine::run(std::unique_ptr<llvm::Module> _module)
_module.release(); // Successfully created llvm::ExecutionEngine takes ownership of the module
exec->finalizeObject();
auto ext = std::make_unique<dev::eth::ExtVMFace>();
Ext::init(std::move(ext));
auto entryFunc = module->getFunction("main");
if (!entryFunc)
{

52
evmcc/Ext.cpp Normal file
View file

@ -0,0 +1,52 @@
#include "Ext.h"
#include <llvm/IR/Function.h>
#include <llvm/IR/TypeBuilder.h>
#ifdef _MSC_VER
#define EXPORT __declspec(dllexport)
#else
#define EXPORT
#endif
using namespace llvm;
using llvm::types::i;
using Linkage = llvm::GlobalValue::LinkageTypes;
namespace evmcc
{
std::unique_ptr<dev::eth::ExtVMFace> g_ext;
void Ext::init(std::unique_ptr<dev::eth::ExtVMFace> _ext)
{
g_ext = std::move(_ext);
}
Ext::Ext(llvm::IRBuilder<>& _builder)
: m_builder(_builder)
{
auto module = m_builder.GetInsertBlock()->getParent()->getParent();
auto&& ctx = _builder.getContext();
Function::Create(TypeBuilder<void(i<256>*, i<256>*), true>::get(ctx), Linkage::ExternalLinkage, "ext_store", module);
Function::Create(TypeBuilder<void(i<256>*, i<256>*), true>::get(ctx), Linkage::ExternalLinkage, "ext_setStore", module);
}
extern "C"
{
EXPORT void ext_store(void* _index, void* _value)
{
}
EXPORT void ext_setStore(void* _index, void* _value)
{
}
}
}

22
evmcc/Ext.h Normal file
View file

@ -0,0 +1,22 @@
#include <llvm/IR/IRBuilder.h>
#include <libevm/ExtVMFace.h>
namespace evmcc
{
class Ext
{
public:
Ext(llvm::IRBuilder<>& _builder);
static void init(std::unique_ptr<dev::eth::ExtVMFace> _ext);
private:
llvm::IRBuilder<>& m_builder;
};
}

View file

@ -47,12 +47,17 @@ Stack::Stack(llvm::IRBuilder<>& _builder, llvm::Module* _module)
m_stackPush = llvm::Function::Create(funcType,
llvm::GlobalValue::LinkageTypes::ExternalLinkage, "evmccrt_stack_push", _module);
m_stackTop = llvm::Function::Create(funcType,
llvm::GlobalValue::LinkageTypes::ExternalLinkage, "evmccrt_stack_top", _module);
m_stackPop = llvm::Function::Create(funcType,
llvm::GlobalValue::LinkageTypes::ExternalLinkage, "evmccrt_stack_pop", _module);
llvm::Type* getArgsTypes[] = {stackPtrTy, m_builder.getInt32Ty(), i256PtrTy};
auto getFuncType = llvm::FunctionType::get(voidTy, getArgsTypes, false);
m_stackGet = llvm::Function::Create(getFuncType,
llvm::GlobalValue::LinkageTypes::ExternalLinkage, "evmccrt_stack_get", _module);
m_stackSet = llvm::Function::Create(getFuncType,
llvm::GlobalValue::LinkageTypes::ExternalLinkage, "evmccrt_stack_set", _module);
m_args[0] = m_builder.CreateCall(stackCreate, "stack.ptr");
m_args[1] = m_builder.CreateAlloca(i256Ty, nullptr, "stack.val");
}
@ -65,13 +70,6 @@ void Stack::push(llvm::Value* _value)
}
llvm::Value* Stack::top()
{
m_builder.CreateCall(m_stackTop, m_args);
return m_builder.CreateLoad(m_args[1]);
}
llvm::Value* Stack::pop()
{
m_builder.CreateCall(m_stackPop, m_args);
@ -79,18 +77,41 @@ llvm::Value* Stack::pop()
}
void debugStack(const char* op, const i256& word)
llvm::Value* Stack::get(uint32_t _index)
{
std::cerr << "STACK " << std::setw(4) << std::setfill(' ') << op << ": "
<< std::dec << word.a
<< " HEX: " << std::hex << std::setfill('0');
if (word.b || word.c || word.d)
llvm::Value* args[] = {m_args[0], m_builder.getInt32(_index), m_args[1]};
m_builder.CreateCall(m_stackGet, args);
return m_builder.CreateLoad(m_args[1]);
}
void Stack::set(uint32_t _index, llvm::Value* _value)
{
m_builder.CreateStore(_value, m_args[1]); // copy value to memory
llvm::Value* args[] = {m_args[0], m_builder.getInt32(_index), m_args[1]};
m_builder.CreateCall(m_stackSet, args);
}
llvm::Value* Stack::top()
{
return get(0);
}
void debugStack(const char* _op, const i256& _word, uint32_t _index = 0)
{
std::cerr << "STACK " << std::setw(4) << std::setfill(' ') << _op
<< " [" << std::setw(2) << std::setfill('0') << _index << "] "
<< std::dec << _word.a
<< " HEX: " << std::hex;
if (_word.b || _word.c || _word.d)
{
std::cerr << std::setw(16) << word.d << " "
<< std::setw(16) << word.c << " "
<< std::setw(16) << word.b << " ";
std::cerr << std::setw(16) << _word.d << " "
<< std::setw(16) << _word.c << " "
<< std::setw(16) << _word.b << " ";
}
std::cerr << std::setw(16) << word.a << "\n";
std::cerr << std::setw(16) << _word.a << "\n";
}
}
@ -114,16 +135,6 @@ EXPORT void evmccrt_stack_push(void* _stack, void* _pWord)
stack->push_back(*word);
}
EXPORT void evmccrt_stack_top(void* _stack, void* _pWord)
{
auto stack = static_cast<StackImpl*>(_stack);
assert(!stack->empty());
auto word = &stack->back();
debugStack("top", *word);
auto outWord = static_cast<i256*>(_pWord);
*outWord = *word;
}
EXPORT void evmccrt_stack_pop(void* _stack, void* _pWord)
{
auto stack = static_cast<StackImpl*>(_stack);
@ -135,4 +146,23 @@ EXPORT void evmccrt_stack_pop(void* _stack, void* _pWord)
*outWord = *word;
}
EXPORT void evmccrt_stack_get(void* _stack, uint32_t _index, void* _pWord)
{
auto stack = static_cast<StackImpl*>(_stack);
assert(_index < stack->size());
auto word = stack->rbegin() + _index;
debugStack("get", *word, _index);
auto outWord = static_cast<i256*>(_pWord);
*outWord = *word;
}
EXPORT void evmccrt_stack_set(void* _stack, uint32_t _index, void* _pWord)
{
auto stack = static_cast<StackImpl*>(_stack);
auto word = static_cast<i256*>(_pWord);
assert(_index < stack->size());
*(stack->rbegin() + _index) = *word;
debugStack("set", *word, _index);
}
} // extern "C"

View file

@ -12,15 +12,18 @@ public:
Stack(llvm::IRBuilder<>& _builder, llvm::Module* _module);
void push(llvm::Value* _value);
llvm::Value* top();
llvm::Value* pop();
llvm::Value* top();
llvm::Value* get(uint32_t _index);
void set(uint32_t _index, llvm::Value* _value);
private:
llvm::IRBuilder<>& m_builder;
llvm::Value* m_args[2];
llvm::Function* m_stackPush;
llvm::Function* m_stackTop;
llvm::Function* m_stackPop;
llvm::Function* m_stackGet;
llvm::Function* m_stackSet;
};
}

View file

@ -0,0 +1 @@
60016001900160070260050160029004600490066021900560150160030260059007600303

1
evmcc/bytecode/fib1.evm Normal file
View file

@ -0,0 +1 @@
60016001818101818101818101818101818101818101818101818101818101818101818101818101818101818101818101818101818101

View file

@ -0,0 +1 @@
60656107d26204a0c763026921f4640bc5588eb165372d0f1dca6e661ba1d901961c71670c55f7bc23038e3868056bc75e2d630fffff69021e19e0c9bab24000016a085d1c6e8050f0ea1c71bd6b0688be36543f3c36e638e37a6c03d41f73d55d0d482ae55555376dc76810d0fe03c91964d31c71c6f46e615dd0360c07d931663b14e38e38b16f2da3f99955a3adcf27ebb1caaaaaaa6e7014ccba6a8bb1ed35bd86bf065c71c71c2b7109491c5d4781b79c9009de6bfb8e38e38de8720414a0f6fdec81304d4c563e740bffffffffa573118427b3b4a05bc8a8a4de8459868000000000017406eb15e7331e727940d4ac54b7cdca1c71c71c71bd750567a91c9fefc96ebaa626a22f98c5e638e38e38e37a76032abd16c5b68006e15d5aa307e383f4e55555555555377701a6427bdc4f0d58eab5f48a3ec67f64e21c71c71c71c6f478080dd0a0c9b9ff2c2a0c740b06853a0a980ee38e38e38e38b17903c679cb5e8f2f9cb3b5d6652b0e7334f746faaaaaaaaaaaaa6e7a01b873815917ebb2bf3b890a1af495d6235bae3c71c71c71c71c2b7b07ae4cca96e1a55dfa49c85ad3c3e60e426b92fb8e38e38e38e38de87c036018bf074e292bcc7d6c8bea0f9699443046178bffffffffffffffa57d0e7d34c64a9c85d4460dbbca87196b61618a4bd2168000000000000000017e05b901f48a5b994d6572502bc4ea43140486666416aa1c71c71c71c71c71bd7f047889870c178fc477414ea231d70467a388fffe31b4e638e38e38e38e38e37a

View file

@ -0,0 +1 @@
65372d0f1dca6e661925338e3e5c2b808280848184505050505050506104576108ae81819290

View file

@ -0,0 +1,29 @@
(asm
1
1
SWAP1
ADD ;; 2
7
MUL ;; 14
5
ADD ;; 19
2
SWAP1
DIV ;; 9
4
SWAP1
MOD ;; 1
33
SWAP1
SDIV;; 0
21
ADD ;; 21
3
MUL ;; 63
5
SWAP1
SMOD;; 3
3
SUB ;; 0
)

57
evmcc/lll/fib1.lll Normal file
View file

@ -0,0 +1,57 @@
;; Fibbonacci unrolled
(asm
1
1
DUP2
DUP2
ADD
DUP2
DUP2
ADD
DUP2
DUP2
ADD
DUP2
DUP2
ADD
DUP2
DUP2
ADD
DUP2
DUP2
ADD
DUP2
DUP2
ADD
DUP2
DUP2
ADD
DUP2
DUP2
ADD
DUP2
DUP2
ADD
DUP2
DUP2
ADD
DUP2
DUP2
ADD
DUP2
DUP2
ADD
DUP2
DUP2
ADD
DUP2
DUP2
ADD
DUP2
DUP2
ADD
DUP2
DUP2
ADD
)

35
evmcc/lll/push_test.lll Normal file
View file

@ -0,0 +1,35 @@
(asm
101 ;; PUSH1
2002 ;; PUSH2
303303 ;; PUSH3
40444404 ;; PUSH4
50555555505 ;; PUSH5
60666666666606
7777777777777777
888888888888888888
99999999999999999999
10000000000000000000001
10111111111111111111111101
2022222222222222222222222202
303333333333333333333333333303
4044444444444444444444444444444404
505555555555555555555555555555555505
60666666666666666666666666666666666606
7077777777777777777777777777777777777707
808888888888888888888888888888888888888808
90999999999999999999999999999999999999999909
100000000000000000000000000000000000000000000001
10111111111111111111111111111111111111111111111101
2022222222222222222222222222222222222222222222222202
303333333333333333333333333333333333333333333333333303
40444444444444444444444444444444444444444444444444444404
50555555555555555555555555555555555555555555555555555555505
6066666666666666666666666666666666666666666666666666666666606
707777777777777777777777777777777777777777777777777777777777707
808888888888888888888888888888888888888888888888888888888888888808
90999999999999999999999999999999999999999999999999999999999999999909
100000000000000000000000000000000000000000000000000000000000000000000001
10111111111111111111111111111111111111111111111111111111111111111111111101
2022222222222222222222222222222222222222222222222222222222222222222222222202 ;; PUSH32
)

24
evmcc/lll/stack_test.lll Normal file
View file

@ -0,0 +1,24 @@
(asm
60666666666606
7077777777777707
DUP1
DUP3
DUP1
DUP5
DUP2
DUP5
POP
POP
POP
POP
POP
POP
POP
1111
2222
DUP2
DUP2
SWAP3
SWAP1
)