Browse Source

Link basic blocks with phi functions

[#80113672]
cl-refactor
Paweł Bylica 10 years ago
parent
commit
e52d421955
  1. 5
      evmcc/BasicBlock.cpp
  2. 14
      evmcc/BasicBlock.h
  3. 47
      evmcc/Compiler.cpp
  4. 50
      evmcc/Stack.cpp
  5. 20
      evmcc/Stack.h

5
evmcc/BasicBlock.cpp

@ -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))
{}
}

14
evmcc/BasicBlock.h

@ -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;
};
}

47
evmcc/Compiler.cpp

@ -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;
}

50
evmcc/Stack.cpp

@ -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 top = m_state.back();
m_state.pop_back();
return top;
}
void BBStack::reset()
auto&& state = m_block->getState();
if (state.empty())
{
for (auto&& value : m_state)
m_extStack.push(value);
m_state.clear();
// 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());
}
void BBStack::clear()
{
m_state.clear();
auto top = state.back();
state.pop_back();
return top;
}
bool BBStack::empty() const
void BBStack::setBasicBlock(BasicBlock& _newBlock)
{
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)

20
evmcc/Stack.h

@ -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…
Cancel
Save