mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-19 19:30:44 +00:00
Merge branch 'develop-evmcc' of https://github.com/imapp-pl/ethereum into develop-evmcc
This commit is contained in:
commit
954300fce1
12 changed files with 257 additions and 14 deletions
|
|
@ -39,6 +39,119 @@ Compiler::Compiler()
|
||||||
Types.WordLowPrecision = llvm::Type::getIntNTy(context, 64);
|
Types.WordLowPrecision = llvm::Type::getIntNTy(context, 64);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
llvm::BasicBlock* Compiler::getOrCreateBasicBlockAtPC(ProgramCounter pc)
|
||||||
|
{
|
||||||
|
llvm::BasicBlock* block = nullptr;
|
||||||
|
auto blockIter = basicBlocks.find(pc);
|
||||||
|
if (blockIter == basicBlocks.cend())
|
||||||
|
{
|
||||||
|
// Create a basic block at targetPC.
|
||||||
|
std::ostringstream oss;
|
||||||
|
oss << "instr." << pc;
|
||||||
|
block = llvm::BasicBlock::Create(llvm::getGlobalContext(), oss.str());
|
||||||
|
basicBlocks[pc] = block;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
block = blockIter->second;
|
||||||
|
}
|
||||||
|
return block;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Compiler::createBasicBlocks(const dev::bytes& bytecode)
|
||||||
|
{
|
||||||
|
getOrCreateBasicBlockAtPC(0);
|
||||||
|
|
||||||
|
for (auto curr = bytecode.cbegin(); curr != bytecode.cend(); ++curr)
|
||||||
|
{
|
||||||
|
using dev::eth::Instruction;
|
||||||
|
|
||||||
|
auto inst = static_cast<Instruction>(*curr);
|
||||||
|
switch (inst)
|
||||||
|
{
|
||||||
|
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 next = curr + numBytes + 1;
|
||||||
|
if (next == bytecode.cend())
|
||||||
|
break;
|
||||||
|
|
||||||
|
auto nextInst = static_cast<Instruction>(*next);
|
||||||
|
|
||||||
|
if (nextInst == Instruction::JUMP || nextInst == Instruction::JUMPI)
|
||||||
|
{
|
||||||
|
// Compute target PC of the jump.
|
||||||
|
dev::u256 val = 0;
|
||||||
|
for (auto iter = curr + 1; iter < next; ++iter)
|
||||||
|
{
|
||||||
|
val <<= 8;
|
||||||
|
val |= *iter;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a block for the JUMP target.
|
||||||
|
ProgramCounter targetPC = val.convert_to<ProgramCounter>();
|
||||||
|
auto targetBlock = getOrCreateBasicBlockAtPC(targetPC);
|
||||||
|
|
||||||
|
ProgramCounter jumpPC = (next - bytecode.cbegin());
|
||||||
|
jumpTargets[jumpPC] = targetBlock;
|
||||||
|
|
||||||
|
// Create a block following the JUMP.
|
||||||
|
if (next + 1 < bytecode.cend())
|
||||||
|
{
|
||||||
|
ProgramCounter nextPC = (next + 1 - bytecode.cbegin());
|
||||||
|
getOrCreateBasicBlockAtPC(nextPC);
|
||||||
|
}
|
||||||
|
|
||||||
|
curr += 1; // skip over JUMP
|
||||||
|
}
|
||||||
|
|
||||||
|
curr += numBytes;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case Instruction::JUMP:
|
||||||
|
case Instruction::JUMPI:
|
||||||
|
{
|
||||||
|
std::cerr << "JUMP/JUMPI at " << (curr - bytecode.cbegin()) << " not preceded by PUSH\n";
|
||||||
|
std::exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
std::unique_ptr<llvm::Module> Compiler::compile(const dev::bytes& bytecode)
|
std::unique_ptr<llvm::Module> Compiler::compile(const dev::bytes& bytecode)
|
||||||
{
|
{
|
||||||
|
|
@ -55,21 +168,42 @@ std::unique_ptr<llvm::Module> Compiler::compile(const dev::bytes& bytecode)
|
||||||
auto mainFuncType = FunctionType::get(builder.getInt64Ty(), false);
|
auto mainFuncType = FunctionType::get(builder.getInt64Ty(), false);
|
||||||
auto mainFunc = Function::Create(mainFuncType, Function::ExternalLinkage, "main", module.get());
|
auto mainFunc = Function::Create(mainFuncType, Function::ExternalLinkage, "main", module.get());
|
||||||
|
|
||||||
|
// Create the basic blocks.
|
||||||
auto entryBlock = BasicBlock::Create(context, "entry", mainFunc);
|
auto entryBlock = BasicBlock::Create(context, "entry", mainFunc);
|
||||||
builder.SetInsertPoint(entryBlock);
|
builder.SetInsertPoint(entryBlock);
|
||||||
|
createBasicBlocks(bytecode);
|
||||||
|
|
||||||
// Init stack and memory
|
// Init runtime structures.
|
||||||
auto stack = Stack(builder, module.get());
|
auto stack = Stack(builder, module.get());
|
||||||
auto memory = Memory(builder);
|
auto memory = Memory(builder, module.get());
|
||||||
|
auto ext = Ext(builder, module.get());
|
||||||
auto ext = Ext(builder);
|
|
||||||
|
|
||||||
auto userRet = false;
|
auto userRet = false;
|
||||||
auto finished = false;
|
auto finished = false;
|
||||||
for (auto pc = bytecode.cbegin(); pc != bytecode.cend() && !finished; ++pc)
|
|
||||||
|
BasicBlock* currentBlock = entryBlock;
|
||||||
|
|
||||||
|
for (auto pc = bytecode.cbegin(); pc != bytecode.cend(); ++pc)
|
||||||
{
|
{
|
||||||
using dev::eth::Instruction;
|
using dev::eth::Instruction;
|
||||||
|
|
||||||
|
ProgramCounter currentPC = pc - bytecode.cbegin();
|
||||||
|
|
||||||
|
auto blockIter = basicBlocks.find(currentPC);
|
||||||
|
if (blockIter != basicBlocks.end())
|
||||||
|
{
|
||||||
|
auto nextBlock = blockIter->second;
|
||||||
|
// Terminate the current block by jumping to the next one.
|
||||||
|
if (currentBlock != nullptr)
|
||||||
|
builder.CreateBr(nextBlock);
|
||||||
|
// Insert the next block into the main function.
|
||||||
|
mainFunc->getBasicBlockList().push_back(nextBlock);
|
||||||
|
builder.SetInsertPoint(nextBlock);
|
||||||
|
currentBlock = nextBlock;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(currentBlock != nullptr);
|
||||||
|
|
||||||
auto inst = static_cast<Instruction>(*pc);
|
auto inst = static_cast<Instruction>(*pc);
|
||||||
switch (inst)
|
switch (inst)
|
||||||
{
|
{
|
||||||
|
|
@ -152,6 +286,16 @@ std::unique_ptr<llvm::Module> Compiler::compile(const dev::bytes& bytecode)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case Instruction::NOT:
|
||||||
|
{
|
||||||
|
auto top = stack.pop();
|
||||||
|
auto zero = ConstantInt::get(Types.word256, 0);
|
||||||
|
auto iszero = builder.CreateICmpEQ(top, zero, "iszero");
|
||||||
|
auto result = builder.CreateZExt(iszero, Types.word256);
|
||||||
|
stack.push(result);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case Instruction::POP:
|
case Instruction::POP:
|
||||||
{
|
{
|
||||||
stack.pop();
|
stack.pop();
|
||||||
|
|
@ -299,6 +443,38 @@ std::unique_ptr<llvm::Module> Compiler::compile(const dev::bytes& bytecode)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case Instruction::JUMP:
|
||||||
|
{
|
||||||
|
// The target address is computed at compile time,
|
||||||
|
// just pop it without looking...
|
||||||
|
stack.pop();
|
||||||
|
|
||||||
|
auto targetBlock = jumpTargets[currentPC];
|
||||||
|
builder.CreateBr(targetBlock);
|
||||||
|
|
||||||
|
currentBlock = nullptr;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case Instruction::JUMPI:
|
||||||
|
{
|
||||||
|
assert(pc + 1 < bytecode.cend());
|
||||||
|
|
||||||
|
// The target address is computed at compile time,
|
||||||
|
// just pop it without looking...
|
||||||
|
stack.pop();
|
||||||
|
|
||||||
|
auto top = stack.pop();
|
||||||
|
auto zero = ConstantInt::get(Types.word256, 0);
|
||||||
|
auto cond = builder.CreateICmpNE(top, zero, "nonzero");
|
||||||
|
auto targetBlock = jumpTargets[currentPC];
|
||||||
|
auto followBlock = basicBlocks[currentPC + 1];
|
||||||
|
builder.CreateCondBr(cond, targetBlock, followBlock);
|
||||||
|
|
||||||
|
currentBlock = nullptr;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case Instruction::ADDRESS:
|
case Instruction::ADDRESS:
|
||||||
{
|
{
|
||||||
auto value = ext.address();
|
auto value = ext.address();
|
||||||
|
|
@ -396,6 +572,20 @@ std::unique_ptr<llvm::Module> Compiler::compile(const dev::bytes& bytecode)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Generate final basic block (may be jumped to).
|
||||||
|
auto finalPC = bytecode.size();
|
||||||
|
auto it = basicBlocks.find(finalPC);
|
||||||
|
if (it != basicBlocks.end())
|
||||||
|
{
|
||||||
|
auto finalBlock = it->second;
|
||||||
|
|
||||||
|
if (currentBlock != nullptr)
|
||||||
|
builder.CreateBr(finalBlock);
|
||||||
|
|
||||||
|
mainFunc->getBasicBlockList().push_back(finalBlock);
|
||||||
|
builder.SetInsertPoint(finalBlock);
|
||||||
|
}
|
||||||
|
|
||||||
if (!userRet)
|
if (!userRet)
|
||||||
builder.CreateRet(builder.getInt64(0));
|
builder.CreateRet(builder.getInt64(0));
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -12,10 +12,26 @@ class Compiler
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
using ProgramCounter = uint64_t;
|
||||||
|
|
||||||
Compiler();
|
Compiler();
|
||||||
|
|
||||||
std::unique_ptr<llvm::Module> compile(const dev::bytes& bytecode);
|
std::unique_ptr<llvm::Module> compile(const dev::bytes& bytecode);
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
llvm::BasicBlock* getOrCreateBasicBlockAtPC(ProgramCounter pc);
|
||||||
|
void createBasicBlocks(const dev::bytes& bytecode);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Maps a program counter pc to a basic block which starts at pc (if any).
|
||||||
|
*/
|
||||||
|
std::map<ProgramCounter, llvm::BasicBlock*> basicBlocks;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Maps a pc at which there is a JUMP or JUMPI to the target block of the jump.
|
||||||
|
*/
|
||||||
|
std::map<ProgramCounter, llvm::BasicBlock*> jumpTargets;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -45,10 +45,9 @@ struct ExtData
|
||||||
const byte* calldata;
|
const byte* calldata;
|
||||||
};
|
};
|
||||||
|
|
||||||
Ext::Ext(llvm::IRBuilder<>& _builder)
|
Ext::Ext(llvm::IRBuilder<>& _builder, llvm::Module* module)
|
||||||
: m_builder(_builder)
|
: m_builder(_builder)
|
||||||
{
|
{
|
||||||
auto module = m_builder.GetInsertBlock()->getParent()->getParent();
|
|
||||||
auto&& ctx = _builder.getContext();
|
auto&& ctx = _builder.getContext();
|
||||||
|
|
||||||
auto i256Ty = m_builder.getIntNTy(256);
|
auto i256Ty = m_builder.getIntNTy(256);
|
||||||
|
|
@ -171,4 +170,4 @@ EXPORT void ext_balance(h256* _address, i256* _value)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ namespace evmcc
|
||||||
class Ext
|
class Ext
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Ext(llvm::IRBuilder<>& _builder);
|
Ext(llvm::IRBuilder<>& _builder, llvm::Module* module);
|
||||||
static void init(std::unique_ptr<dev::eth::ExtVMFace> _ext);
|
static void init(std::unique_ptr<dev::eth::ExtVMFace> _ext);
|
||||||
|
|
||||||
llvm::Value* store(llvm::Value* _index);
|
llvm::Value* store(llvm::Value* _index);
|
||||||
|
|
@ -48,4 +48,4 @@ private:
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -26,13 +26,11 @@ using MemoryImpl = dev::bytes;
|
||||||
static MemoryImpl* evmccrt_memory;
|
static MemoryImpl* evmccrt_memory;
|
||||||
|
|
||||||
|
|
||||||
Memory::Memory(llvm::IRBuilder<>& _builder)
|
Memory::Memory(llvm::IRBuilder<>& _builder, llvm::Module* module)
|
||||||
: m_builder(_builder)
|
: m_builder(_builder)
|
||||||
{
|
{
|
||||||
auto voidTy = m_builder.getVoidTy();
|
auto voidTy = m_builder.getVoidTy();
|
||||||
auto i64Ty = m_builder.getInt64Ty();
|
auto i64Ty = m_builder.getInt64Ty();
|
||||||
auto module = _builder.GetInsertBlock()->getParent()->getParent();
|
|
||||||
|
|
||||||
|
|
||||||
auto memRequireTy = llvm::FunctionType::get(m_builder.getInt8PtrTy(), i64Ty, false);
|
auto memRequireTy = llvm::FunctionType::get(m_builder.getInt8PtrTy(), i64Ty, false);
|
||||||
m_memRequire = llvm::Function::Create(memRequireTy,
|
m_memRequire = llvm::Function::Create(memRequireTy,
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ namespace evmcc
|
||||||
class Memory
|
class Memory
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Memory(llvm::IRBuilder<>& _builder);
|
Memory(llvm::IRBuilder<>& _builder, llvm::Module* module);
|
||||||
|
|
||||||
static const dev::bytes& init();
|
static const dev::bytes& init();
|
||||||
|
|
||||||
|
|
|
||||||
1
evmcc/bytecode/if1.evm
Normal file
1
evmcc/bytecode/if1.evm
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
600160805460006080530b6016596003608054601b586002608054
|
||||||
1
evmcc/bytecode/when1.evm
Normal file
1
evmcc/bytecode/when1.evm
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
60010f600b59600d608054
|
||||||
21
evmcc/lll/if1.asm
Normal file
21
evmcc/lll/if1.asm
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
.code:
|
||||||
|
PUSH 1
|
||||||
|
PUSH 128
|
||||||
|
MSTORE
|
||||||
|
PUSH 0
|
||||||
|
PUSH 128
|
||||||
|
MLOAD
|
||||||
|
GT
|
||||||
|
PUSH [tag0]
|
||||||
|
JUMPI
|
||||||
|
PUSH 3
|
||||||
|
PUSH 128
|
||||||
|
MSTORE
|
||||||
|
PUSH [tag1]
|
||||||
|
JUMP
|
||||||
|
tag0:
|
||||||
|
PUSH 2
|
||||||
|
PUSH 128
|
||||||
|
MSTORE
|
||||||
|
tag1:
|
||||||
|
|
||||||
5
evmcc/lll/if1.lll
Normal file
5
evmcc/lll/if1.lll
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
{
|
||||||
|
[i] 1
|
||||||
|
|
||||||
|
( if (> @i 0) [i] 2 [i] 3 )
|
||||||
|
}
|
||||||
10
evmcc/lll/when1.asm
Normal file
10
evmcc/lll/when1.asm
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
.code:
|
||||||
|
PUSH 1
|
||||||
|
NOT
|
||||||
|
PUSH [tag0]
|
||||||
|
JUMPI
|
||||||
|
PUSH 13
|
||||||
|
PUSH 128
|
||||||
|
MSTORE
|
||||||
|
tag0:
|
||||||
|
|
||||||
2
evmcc/lll/when1.lll
Normal file
2
evmcc/lll/when1.lll
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
(when (> 1 0) [i] 13)
|
||||||
|
|
||||||
Loading…
Reference in a new issue