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. 52
      evmcc/Stack.cpp
  5. 20
      evmcc/Stack.h

5
evmcc/BasicBlock.cpp

@ -6,8 +6,9 @@
namespace evmcc namespace evmcc
{ {
BasicBlock::BasicBlock(ProgramCounter _instIdx, llvm::Function* _mainFunc) BasicBlock::BasicBlock(ProgramCounter _beginInstIdx, llvm::Function* _mainFunc):
: m_llvmBB(llvm::BasicBlock::Create(_mainFunc->getContext(), {"Instr.", std::to_string(_instIdx)}, _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> #include <llvm/IR/BasicBlock.h>
namespace evmcc namespace evmcc
@ -9,14 +11,24 @@ using ProgramCounter = uint64_t;
class BasicBlock class BasicBlock
{ {
public: 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; BasicBlock(const BasicBlock&) = delete;
void operator=(const BasicBlock&) = delete; void operator=(const BasicBlock&) = delete;
operator llvm::BasicBlock*() { return m_llvmBB; } operator llvm::BasicBlock*() { return m_llvmBB; }
llvm::BasicBlock* llvm() { return m_llvmBB; }
State& getState() { return m_state; }
private: private:
ProgramCounter m_beginInstIdx;
llvm::BasicBlock* m_llvmBB; 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 "Compiler.h"
#include <llvm/IR/IRBuilder.h> #include <llvm/IR/IRBuilder.h>
#include <llvm/IR/CFG.h>
#include <libevmface/Instruction.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 memory = Memory(builder, module.get());
auto ext = Ext(builder, module.get()); auto ext = Ext(builder, module.get());
llvm::BasicBlock* currentBlock = entryBlock; BasicBlock* currentBlock = &basicBlocks.find(0)->second; // Any value, just to create branch for %entry to %Instr.0
BBStack stack(extStack); // Stack for current block BBStack stack(builder, extStack); // Stack for current block
for (auto pc = bytecode.cbegin(); pc != bytecode.cend(); ++pc) 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(); ProgramCounter currentPC = pc - bytecode.cbegin();
// Change basic block
auto blockIter = basicBlocks.find(currentPC); auto blockIter = basicBlocks.find(currentPC);
if (blockIter != basicBlocks.end()) if (blockIter != basicBlocks.end())
{ {
@ -201,8 +203,8 @@ std::unique_ptr<llvm::Module> Compiler::compile(const dev::bytes& bytecode)
builder.CreateBr(nextBlock); builder.CreateBr(nextBlock);
// Insert the next block into the main function. // Insert the next block into the main function.
builder.SetInsertPoint(nextBlock); builder.SetInsertPoint(nextBlock);
currentBlock = nextBlock; currentBlock = &nextBlock;
assert(stack.empty()); // Stack should be empty stack.setBasicBlock(*currentBlock);
} }
assert(currentBlock != nullptr); 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, // The target address is computed at compile time,
// just pop it without looking... // just pop it without looking...
stack.pop(); stack.pop();
stack.reset();
auto targetBlock = jumpTargets[currentPC]; auto targetBlock = jumpTargets[currentPC];
builder.CreateBr(targetBlock); builder.CreateBr(targetBlock);
@ -589,7 +590,6 @@ std::unique_ptr<llvm::Module> Compiler::compile(const dev::bytes& bytecode)
auto top = stack.pop(); auto top = stack.pop();
auto zero = ConstantInt::get(Types.word256, 0); auto zero = ConstantInt::get(Types.word256, 0);
auto cond = builder.CreateICmpNE(top, zero, "nonzero"); auto cond = builder.CreateICmpNE(top, zero, "nonzero");
stack.reset();
auto targetBlock = jumpTargets[currentPC]; auto targetBlock = jumpTargets[currentPC];
auto& followBlock = basicBlocks.find(currentPC + 1)->second; auto& followBlock = basicBlocks.find(currentPC + 1)->second;
builder.CreateCondBr(cond, targetBlock, followBlock); 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); ret = builder.CreateOr(ret, size);
builder.CreateRet(ret); builder.CreateRet(ret);
stack.clear();
currentBlock = nullptr; currentBlock = nullptr;
break; break;
} }
@ -770,7 +769,6 @@ std::unique_ptr<llvm::Module> Compiler::compile(const dev::bytes& bytecode)
case Instruction::STOP: case Instruction::STOP:
{ {
builder.CreateRet(builder.getInt64(0)); builder.CreateRet(builder.getInt64(0));
stack.clear();
currentBlock = nullptr; currentBlock = nullptr;
break; break;
} }
@ -790,6 +788,39 @@ std::unique_ptr<llvm::Module> Compiler::compile(const dev::bytes& bytecode)
builder.SetInsertPoint(finalBlock); builder.SetInsertPoint(finalBlock);
builder.CreateRet(builder.getInt64(0)); 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; return module;
} }

52
evmcc/Stack.cpp

@ -9,6 +9,7 @@
#include <llvm/IR/Function.h> #include <llvm/IR/Function.h>
#include "BasicBlock.h"
#include "Runtime.h" #include "Runtime.h"
#ifdef _MSC_VER #ifdef _MSC_VER
@ -20,52 +21,55 @@
namespace evmcc namespace evmcc
{ {
BBStack::BBStack(Stack& _extStack) BBStack::BBStack(llvm::IRBuilder<>& _builder, Stack& _extStack):
: m_extStack(_extStack) m_extStack(_extStack),
m_builder(_builder)
{} {}
void BBStack::push(llvm::Value* _value) void BBStack::push(llvm::Value* _value)
{ {
m_state.push_back(_value); m_block->getState().push_back(_value);
} }
llvm::Value* BBStack::pop() llvm::Value* BBStack::pop()
{ {
if (m_state.empty()) auto&& state = m_block->getState();
return m_extStack.pop(); 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(); auto top = state.back();
m_state.pop_back(); state.pop_back();
return top; 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) void BBStack::dup(size_t _index)
{ {
auto value = *(m_state.rbegin() + _index); auto&& state = m_block->getState();
m_state.push_back(value); auto value = *(state.rbegin() + _index);
state.push_back(value);
} }
void BBStack::swap(size_t _index) void BBStack::swap(size_t _index)
{ {
assert(_index != 0); 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) Stack::Stack(llvm::IRBuilder<>& _builder, llvm::Module* _module)

20
evmcc/Stack.h

@ -7,6 +7,7 @@
namespace evmcc namespace evmcc
{ {
class BasicBlock;
class Stack class Stack
{ {
@ -36,7 +37,7 @@ private:
class BBStack class BBStack
{ {
public: public:
BBStack(Stack& _extStack); BBStack(llvm::IRBuilder<>& _builder, Stack& _extStack);
void push(llvm::Value* _value); void push(llvm::Value* _value);
llvm::Value* pop(); llvm::Value* pop();
@ -44,23 +45,14 @@ public:
void swap(size_t _index); void swap(size_t _index);
/** /**
Resets stack on basic block change. Changes current basic block with a new one with empty state.
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.
*/ */
void reset(); void setBasicBlock(BasicBlock& _newBlock);
/**
Dumps values on stack.
*/
void clear();
/// Debug only
bool empty() const;
private: private:
std::vector<llvm::Value*> m_state; ///< Basic black state vector - current values and their positions
Stack& m_extStack; ///< External (global) stack Stack& m_extStack; ///< External (global) stack
BasicBlock* m_block = nullptr; ///< Current basic block
llvm::IRBuilder<>& m_builder;
}; };

Loading…
Cancel
Save