mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-21 12:16:44 +00:00
parent
0961908efa
commit
e52d421955
5 changed files with 89 additions and 49 deletions
|
|
@ -6,8 +6,9 @@
|
|||
namespace evmcc
|
||||
{
|
||||
|
||||
BasicBlock::BasicBlock(ProgramCounter _instIdx, llvm::Function* _mainFunc)
|
||||
: m_llvmBB(llvm::BasicBlock::Create(_mainFunc->getContext(), {"Instr.", std::to_string(_instIdx)}, _mainFunc))
|
||||
BasicBlock::BasicBlock(ProgramCounter _beginInstIdx, llvm::Function* _mainFunc):
|
||||
m_beginInstIdx(_beginInstIdx),
|
||||
m_llvmBB(llvm::BasicBlock::Create(_mainFunc->getContext(), {"Instr.", std::to_string(_beginInstIdx)}, _mainFunc))
|
||||
{}
|
||||
|
||||
}
|
||||
|
|
@ -1,4 +1,6 @@
|
|||
|
||||
#include <vector>
|
||||
|
||||
#include <llvm/IR/BasicBlock.h>
|
||||
|
||||
namespace evmcc
|
||||
|
|
@ -9,14 +11,24 @@ using ProgramCounter = uint64_t;
|
|||
class BasicBlock
|
||||
{
|
||||
public:
|
||||
explicit BasicBlock(ProgramCounter _instIdx, llvm::Function* _mainFunc);
|
||||
using State = std::vector<llvm::Value*>;
|
||||
|
||||
explicit BasicBlock(ProgramCounter _beginInstIdx, llvm::Function* _mainFunc);
|
||||
|
||||
BasicBlock(const BasicBlock&) = delete;
|
||||
void operator=(const BasicBlock&) = delete;
|
||||
|
||||
operator llvm::BasicBlock*() { return m_llvmBB; }
|
||||
llvm::BasicBlock* llvm() { return m_llvmBB; }
|
||||
|
||||
State& getState() { return m_state; }
|
||||
|
||||
private:
|
||||
ProgramCounter m_beginInstIdx;
|
||||
llvm::BasicBlock* m_llvmBB;
|
||||
|
||||
/// Basic black state vector - current/end values and their positions
|
||||
State m_state;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
@ -2,6 +2,7 @@
|
|||
#include "Compiler.h"
|
||||
|
||||
#include <llvm/IR/IRBuilder.h>
|
||||
#include <llvm/IR/CFG.h>
|
||||
|
||||
#include <libevmface/Instruction.h>
|
||||
|
||||
|
|
@ -183,8 +184,8 @@ std::unique_ptr<llvm::Module> Compiler::compile(const dev::bytes& bytecode)
|
|||
auto memory = Memory(builder, module.get());
|
||||
auto ext = Ext(builder, module.get());
|
||||
|
||||
llvm::BasicBlock* currentBlock = entryBlock;
|
||||
BBStack stack(extStack); // Stack for current block
|
||||
BasicBlock* currentBlock = &basicBlocks.find(0)->second; // Any value, just to create branch for %entry to %Instr.0
|
||||
BBStack stack(builder, extStack); // Stack for current block
|
||||
|
||||
for (auto pc = bytecode.cbegin(); pc != bytecode.cend(); ++pc)
|
||||
{
|
||||
|
|
@ -192,6 +193,7 @@ std::unique_ptr<llvm::Module> Compiler::compile(const dev::bytes& bytecode)
|
|||
|
||||
ProgramCounter currentPC = pc - bytecode.cbegin();
|
||||
|
||||
// Change basic block
|
||||
auto blockIter = basicBlocks.find(currentPC);
|
||||
if (blockIter != basicBlocks.end())
|
||||
{
|
||||
|
|
@ -201,8 +203,8 @@ std::unique_ptr<llvm::Module> Compiler::compile(const dev::bytes& bytecode)
|
|||
builder.CreateBr(nextBlock);
|
||||
// Insert the next block into the main function.
|
||||
builder.SetInsertPoint(nextBlock);
|
||||
currentBlock = nextBlock;
|
||||
assert(stack.empty()); // Stack should be empty
|
||||
currentBlock = &nextBlock;
|
||||
stack.setBasicBlock(*currentBlock);
|
||||
}
|
||||
|
||||
assert(currentBlock != nullptr);
|
||||
|
|
@ -569,7 +571,6 @@ std::unique_ptr<llvm::Module> Compiler::compile(const dev::bytes& bytecode)
|
|||
// The target address is computed at compile time,
|
||||
// just pop it without looking...
|
||||
stack.pop();
|
||||
stack.reset();
|
||||
|
||||
auto targetBlock = jumpTargets[currentPC];
|
||||
builder.CreateBr(targetBlock);
|
||||
|
|
@ -589,7 +590,6 @@ std::unique_ptr<llvm::Module> Compiler::compile(const dev::bytes& bytecode)
|
|||
auto top = stack.pop();
|
||||
auto zero = ConstantInt::get(Types.word256, 0);
|
||||
auto cond = builder.CreateICmpNE(top, zero, "nonzero");
|
||||
stack.reset();
|
||||
auto targetBlock = jumpTargets[currentPC];
|
||||
auto& followBlock = basicBlocks.find(currentPC + 1)->second;
|
||||
builder.CreateCondBr(cond, targetBlock, followBlock);
|
||||
|
|
@ -756,7 +756,6 @@ std::unique_ptr<llvm::Module> Compiler::compile(const dev::bytes& bytecode)
|
|||
ret = builder.CreateOr(ret, size);
|
||||
|
||||
builder.CreateRet(ret);
|
||||
stack.clear();
|
||||
currentBlock = nullptr;
|
||||
break;
|
||||
}
|
||||
|
|
@ -770,7 +769,6 @@ std::unique_ptr<llvm::Module> Compiler::compile(const dev::bytes& bytecode)
|
|||
case Instruction::STOP:
|
||||
{
|
||||
builder.CreateRet(builder.getInt64(0));
|
||||
stack.clear();
|
||||
currentBlock = nullptr;
|
||||
break;
|
||||
}
|
||||
|
|
@ -790,6 +788,39 @@ std::unique_ptr<llvm::Module> Compiler::compile(const dev::bytes& bytecode)
|
|||
builder.SetInsertPoint(finalBlock);
|
||||
builder.CreateRet(builder.getInt64(0));
|
||||
|
||||
auto findBB = [this](llvm::BasicBlock* _llvmBB)
|
||||
{
|
||||
for (auto&& bb : basicBlocks)
|
||||
{
|
||||
if (bb.second.llvm() == _llvmBB)
|
||||
return &bb.second;
|
||||
}
|
||||
return (BasicBlock*)nullptr;
|
||||
};
|
||||
|
||||
// Link basic blocks
|
||||
for (auto&& p : basicBlocks)
|
||||
{
|
||||
BasicBlock& bb = p.second;
|
||||
llvm::BasicBlock* llvmBB = bb.llvm();
|
||||
|
||||
size_t i = 0;
|
||||
for (auto& inst : *llvmBB)
|
||||
{
|
||||
if (auto phi = llvm::dyn_cast<llvm::PHINode>(&inst))
|
||||
{
|
||||
for (auto preIt = llvm::pred_begin(llvmBB); preIt != llvm::pred_end(llvmBB); ++preIt)
|
||||
{
|
||||
llvm::BasicBlock* preBB = *preIt;
|
||||
auto pbb = findBB(preBB);
|
||||
assert(i < pbb->getState().size()); // TODO: Report error
|
||||
phi->addIncoming(*(pbb->getState().rbegin() + i), preBB);
|
||||
}
|
||||
++i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return module;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
|
||||
#include <llvm/IR/Function.h>
|
||||
|
||||
#include "BasicBlock.h"
|
||||
#include "Runtime.h"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
|
|
@ -20,52 +21,55 @@
|
|||
namespace evmcc
|
||||
{
|
||||
|
||||
BBStack::BBStack(Stack& _extStack)
|
||||
: m_extStack(_extStack)
|
||||
BBStack::BBStack(llvm::IRBuilder<>& _builder, Stack& _extStack):
|
||||
m_extStack(_extStack),
|
||||
m_builder(_builder)
|
||||
{}
|
||||
|
||||
void BBStack::push(llvm::Value* _value)
|
||||
{
|
||||
m_state.push_back(_value);
|
||||
m_block->getState().push_back(_value);
|
||||
}
|
||||
|
||||
llvm::Value* BBStack::pop()
|
||||
{
|
||||
if (m_state.empty())
|
||||
return m_extStack.pop();
|
||||
auto&& state = m_block->getState();
|
||||
if (state.empty())
|
||||
{
|
||||
// Create PHI node
|
||||
auto first = m_block->llvm()->getFirstNonPHI();
|
||||
auto llvmBB = m_block->llvm();
|
||||
if (llvmBB->getInstList().empty())
|
||||
return llvm::PHINode::Create(m_builder.getIntNTy(256), 0, {}, m_block->llvm());
|
||||
return llvm::PHINode::Create(m_builder.getIntNTy(256), 0, {}, llvmBB->getFirstNonPHI());
|
||||
}
|
||||
|
||||
auto top = m_state.back();
|
||||
m_state.pop_back();
|
||||
auto top = state.back();
|
||||
state.pop_back();
|
||||
return top;
|
||||
}
|
||||
|
||||
void BBStack::reset()
|
||||
void BBStack::setBasicBlock(BasicBlock& _newBlock)
|
||||
{
|
||||
for (auto&& value : m_state)
|
||||
m_extStack.push(value);
|
||||
m_state.clear();
|
||||
}
|
||||
|
||||
void BBStack::clear()
|
||||
{
|
||||
m_state.clear();
|
||||
}
|
||||
|
||||
bool BBStack::empty() const
|
||||
{
|
||||
return m_state.empty();
|
||||
// Current block keeps end state
|
||||
// Just update pointer to current block
|
||||
// New block should have empty state
|
||||
assert(_newBlock.getState().empty());
|
||||
m_block = &_newBlock;
|
||||
}
|
||||
|
||||
void BBStack::dup(size_t _index)
|
||||
{
|
||||
auto value = *(m_state.rbegin() + _index);
|
||||
m_state.push_back(value);
|
||||
auto&& state = m_block->getState();
|
||||
auto value = *(state.rbegin() + _index);
|
||||
state.push_back(value);
|
||||
}
|
||||
|
||||
void BBStack::swap(size_t _index)
|
||||
{
|
||||
assert(_index != 0);
|
||||
std::swap(*m_state.rbegin(), *(m_state.rbegin() + _index));
|
||||
auto&& state = m_block->getState();
|
||||
std::swap(*state.rbegin(), *(state.rbegin() + _index));
|
||||
}
|
||||
|
||||
Stack::Stack(llvm::IRBuilder<>& _builder, llvm::Module* _module)
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
namespace evmcc
|
||||
{
|
||||
class BasicBlock;
|
||||
|
||||
class Stack
|
||||
{
|
||||
|
|
@ -36,7 +37,7 @@ private:
|
|||
class BBStack
|
||||
{
|
||||
public:
|
||||
BBStack(Stack& _extStack);
|
||||
BBStack(llvm::IRBuilder<>& _builder, Stack& _extStack);
|
||||
|
||||
void push(llvm::Value* _value);
|
||||
llvm::Value* pop();
|
||||
|
|
@ -44,23 +45,14 @@ public:
|
|||
void swap(size_t _index);
|
||||
|
||||
/**
|
||||
Resets stack on basic block change.
|
||||
Values left on local stack are pushed on external stack.
|
||||
Local stack is empty after this operation and compilation of new basic block can be started.
|
||||
Changes current basic block with a new one with empty state.
|
||||
*/
|
||||
void reset();
|
||||
|
||||
/**
|
||||
Dumps values on stack.
|
||||
*/
|
||||
void clear();
|
||||
|
||||
/// Debug only
|
||||
bool empty() const;
|
||||
void setBasicBlock(BasicBlock& _newBlock);
|
||||
|
||||
private:
|
||||
std::vector<llvm::Value*> m_state; ///< Basic black state vector - current values and their positions
|
||||
Stack& m_extStack; ///< External (global) stack
|
||||
BasicBlock* m_block = nullptr; ///< Current basic block
|
||||
llvm::IRBuilder<>& m_builder;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue