Browse Source

Move fields from BasicBlock to LocalStack. Remove dump() functions.

cl-refactor
Paweł Bylica 10 years ago
parent
commit
1e926fe6bc
  1. 115
      evmjit/libevmjit/BasicBlock.cpp
  2. 55
      evmjit/libevmjit/BasicBlock.h
  3. 82
      evmjit/libevmjit/Compiler.cpp
  4. 9
      evmjit/libevmjit/Compiler.h

115
evmjit/libevmjit/BasicBlock.cpp

@ -23,42 +23,39 @@ namespace jit
static const char* jumpDestName = "JmpDst.";
static const char* basicBlockName = "Instr.";
BasicBlock::BasicBlock(instr_idx _firstInstrIdx, code_iterator _begin, code_iterator _end, llvm::Function* _mainFunc, llvm::IRBuilder<>& _builder, bool isJumpDest) :
BasicBlock::BasicBlock(instr_idx _firstInstrIdx, code_iterator _begin, code_iterator _end, llvm::Function* _mainFunc, bool isJumpDest):
m_firstInstrIdx{_firstInstrIdx},
m_begin(_begin),
m_end(_end),
m_llvmBB(llvm::BasicBlock::Create(_mainFunc->getContext(), {isJumpDest ? jumpDestName : basicBlockName, std::to_string(_firstInstrIdx)}, _mainFunc)),
m_builder(_builder),
m_isJumpDest(isJumpDest)
{}
BasicBlock::BasicBlock(std::string _name, llvm::Function* _mainFunc, llvm::IRBuilder<>& _builder, bool isJumpDest) :
BasicBlock::BasicBlock(std::string _name, llvm::Function* _mainFunc, bool isJumpDest):
m_llvmBB(llvm::BasicBlock::Create(_mainFunc->getContext(), _name, _mainFunc)),
m_builder(_builder),
m_isJumpDest(isJumpDest)
{}
LocalStack::LocalStack(BasicBlock& _owner, Stack& _globalStack) :
m_bblock(_owner),
LocalStack::LocalStack(Stack& _globalStack):
m_global(_globalStack)
{}
void LocalStack::push(llvm::Value* _value)
{
assert(_value->getType() == Type::Word);
m_bblock.m_currentStack.push_back(_value);
m_maxSize = std::max(m_maxSize, m_bblock.m_currentStack.size());
m_currentStack.push_back(_value);
m_maxSize = std::max(m_maxSize, m_currentStack.size()); // FIXME: This is wrong too. + add min size;
}
llvm::Value* LocalStack::pop()
{
auto item = get(0);
assert(!m_bblock.m_currentStack.empty() || !m_bblock.m_initialStack.empty());
assert(!m_currentStack.empty() || !m_initialStack.empty());
if (m_bblock.m_currentStack.size() > 0)
m_bblock.m_currentStack.pop_back();
if (m_currentStack.size() > 0)
m_currentStack.pop_back();
else
++m_bblock.m_globalPops;
++m_globalPops;
return item;
}
@ -87,15 +84,13 @@ void LocalStack::swap(size_t _index)
llvm::Value* LocalStack::get(size_t _index)
{
auto& currentStack = m_bblock.m_currentStack;
if (_index < currentStack.size())
return *(currentStack.rbegin() + _index); // count from back
if (_index < m_currentStack.size())
return *(m_currentStack.rbegin() + _index); // count from back
auto& initialStack = m_bblock.m_initialStack;
auto idx = _index - currentStack.size() + m_bblock.m_globalPops;
if (idx >= initialStack.size())
initialStack.resize(idx + 1);
auto& item = initialStack[idx];
auto idx = _index - m_currentStack.size() + m_globalPops;
if (idx >= m_initialStack.size())
m_initialStack.resize(idx + 1);
auto& item = m_initialStack[idx];
if (!item)
item = m_global.get(idx);
@ -105,104 +100,50 @@ llvm::Value* LocalStack::get(size_t _index)
void LocalStack::set(size_t _index, llvm::Value* _word)
{
auto& currentStack = m_bblock.m_currentStack;
if (_index < currentStack.size())
if (_index < m_currentStack.size())
{
*(currentStack.rbegin() + _index) = _word;
*(m_currentStack.rbegin() + _index) = _word;
return;
}
auto& initialStack = m_bblock.m_initialStack;
auto idx = _index - currentStack.size() + m_bblock.m_globalPops;
assert(idx < initialStack.size());
initialStack[idx] = _word;
auto idx = _index - m_currentStack.size() + m_globalPops;
assert(idx < m_initialStack.size());
m_initialStack[idx] = _word;
}
void BasicBlock::synchronizeLocalStack(Stack& _evmStack)
void LocalStack::finalize(llvm::IRBuilder<>& _builder, llvm::BasicBlock& _bb)
{
auto blockTerminator = m_llvmBB->getTerminator();
auto blockTerminator = _bb.getTerminator();
assert(blockTerminator);
if (blockTerminator->getOpcode() != llvm::Instruction::Ret)
{
// Not needed in case of ret instruction. Ret invalidates the stack.
m_builder.SetInsertPoint(blockTerminator);
_builder.SetInsertPoint(blockTerminator);
// Update items fetched from global stack ignoring the poped ones
assert(m_globalPops <= m_initialStack.size()); // pop() always does get()
for (auto i = m_globalPops; i < m_initialStack.size(); ++i)
{
if (m_initialStack[i])
_evmStack.set(i, m_initialStack[i]);
m_global.set(i, m_initialStack[i]);
}
// Add new items
for (auto& item: m_currentStack)
{
if (m_globalPops) // Override poped global items
_evmStack.set(--m_globalPops, item); // using pops counter as the index
if (m_globalPops) // Override poped global items
m_global.set(--m_globalPops, item); // using pops counter as the index
else
_evmStack.push(item);
m_global.push(item);
}
// Pop not overriden items
if (m_globalPops)
_evmStack.pop(m_globalPops);
m_global.pop(m_globalPops);
}
}
void BasicBlock::dump()
{
dump(std::cerr, false);
}
void BasicBlock::dump(std::ostream& _out, bool _dotOutput)
{
llvm::raw_os_ostream out(_out);
out << (_dotOutput ? "" : "Initial stack:\n");
for (auto val : m_initialStack)
{
if (val == nullptr)
out << " ?";
else if (llvm::isa<llvm::ExtractValueInst>(val))
out << " " << val->getName();
else if (llvm::isa<llvm::Instruction>(val))
out << *val;
else
out << " " << *val;
out << (_dotOutput ? "\\l" : "\n");
}
out << (_dotOutput ? "| " : "Instructions:\n");
for (auto ins = m_llvmBB->begin(); ins != m_llvmBB->end(); ++ins)
out << *ins << (_dotOutput ? "\\l" : "\n");
if (! _dotOutput)
out << "Current stack:\n";
else
out << "|";
for (auto val = m_currentStack.rbegin(); val != m_currentStack.rend(); ++val)
{
if (*val == nullptr)
out << " ?";
else if (llvm::isa<llvm::ExtractValueInst>(*val))
out << " " << (*val)->getName();
else if (llvm::isa<llvm::Instruction>(*val))
out << **val;
else
out << " " << **val;
out << (_dotOutput ? "\\l" : "\n");
}
if (! _dotOutput)
out << " ...\n----------------------------------------\n";
}
}
}

55
evmjit/libevmjit/BasicBlock.h

@ -19,7 +19,7 @@ class BasicBlock;
class LocalStack
{
public:
LocalStack(BasicBlock& _owner, Stack& _globalStack);
explicit LocalStack(Stack& _globalStack);
LocalStack(LocalStack const&) = delete;
void operator=(LocalStack const&) = delete;
@ -36,8 +36,13 @@ public:
/// @param _index Index of value to be swaped. Must be > 0.
void swap(size_t _index);
ssize_t getDiff() const { return static_cast<ssize_t>(m_currentStack.size()) - static_cast<ssize_t>(m_globalPops); }
size_t getMaxSize() const { return m_maxSize; }
/// TODO: comment
/// TODO: It must be the same builder as in global stack.
void finalize(llvm::IRBuilder<>& _builder, llvm::BasicBlock& _bb);
private:
/// Gets _index'th value from top (counting from 0)
llvm::Value* get(size_t _index);
@ -45,8 +50,20 @@ private:
/// Sets _index'th value from top (counting from 0)
void set(size_t _index, llvm::Value* _value);
private:
BasicBlock& m_bblock;
/// This stack contains LLVM values that correspond to items found at
/// the EVM stack when the current basic block starts executing.
/// Location 0 corresponds to the top of the EVM stack, location 1 is
/// the item below the top and so on. The stack grows as the code
/// accesses more items on the EVM stack but once a value is put on
/// the stack, it will never be replaced.
std::vector<llvm::Value*> m_initialStack;
/// This stack tracks the contents of the EVM stack as the basic block
/// executes. It may grow on both sides, as the code pushes items on
/// top of the stack or changes existing items.
std::vector<llvm::Value*> m_currentStack;
size_t m_globalPops = 0; ///< Number of items poped from global stack. In other words: global - local stack overlap.
Stack& m_global;
size_t m_maxSize = 0; ///< Max size reached by the stack.
};
@ -54,8 +71,8 @@ private:
class BasicBlock
{
public:
explicit BasicBlock(instr_idx _firstInstrIdx, code_iterator _begin, code_iterator _end, llvm::Function* _mainFunc, llvm::IRBuilder<>& _builder, bool isJumpDest);
explicit BasicBlock(std::string _name, llvm::Function* _mainFunc, llvm::IRBuilder<>& _builder, bool isJumpDest);
explicit BasicBlock(instr_idx _firstInstrIdx, code_iterator _begin, code_iterator _end, llvm::Function* _mainFunc, bool isJumpDest);
explicit BasicBlock(std::string _name, llvm::Function* _mainFunc, bool isJumpDest);
BasicBlock(const BasicBlock&) = delete;
BasicBlock& operator=(const BasicBlock&) = delete;
@ -71,16 +88,6 @@ public:
llvm::Value* getJumpTarget() const { return m_jumpTarget; }
void setJumpTarget(llvm::Value* _jumpTarget) { m_jumpTarget = _jumpTarget; }
ssize_t getDiff() const { return static_cast<ssize_t>(m_currentStack.size()) - static_cast<ssize_t>(m_globalPops); }
/// Synchronize current local stack with the EVM stack.
void synchronizeLocalStack(Stack& _evmStack);
/// Prints local stack and block instructions to stderr.
/// Useful for calling in a debugger session.
void dump();
void dump(std::ostream& os, bool _dotOutput = false);
private:
instr_idx const m_firstInstrIdx = 0; ///< Code index of first instruction in the block
code_iterator const m_begin = {}; ///< Iterator pointing code beginning of the block
@ -88,24 +95,6 @@ private:
llvm::BasicBlock* const m_llvmBB;
llvm::IRBuilder<>& m_builder;
/// This stack contains LLVM values that correspond to items found at
/// the EVM stack when the current basic block starts executing.
/// Location 0 corresponds to the top of the EVM stack, location 1 is
/// the item below the top and so on. The stack grows as the code
/// accesses more items on the EVM stack but once a value is put on
/// the stack, it will never be replaced.
std::vector<llvm::Value*> m_initialStack;
/// This stack tracks the contents of the EVM stack as the basic block
/// executes. It may grow on both sides, as the code pushes items on
/// top of the stack or changes existing items.
std::vector<llvm::Value*> m_currentStack;
friend class LocalStack;
size_t m_globalPops = 0; ///< Number of items poped from global stack. In other words: global - local stack overlap.
/// Is the basic block a valid jump destination.
/// JUMPDEST is the first instruction of the basic block.
bool const m_isJumpDest = false;

82
evmjit/libevmjit/Compiler.cpp

@ -87,7 +87,7 @@ void Compiler::createBasicBlocks(code_iterator _codeBegin, code_iterator _codeEn
{
auto beginIdx = begin - _codeBegin;
m_basicBlocks.emplace(std::piecewise_construct, std::forward_as_tuple(beginIdx),
std::forward_as_tuple(beginIdx, begin, next, m_mainFunc, m_builder, nextJumpDest));
std::forward_as_tuple(beginIdx, begin, next, m_mainFunc, nextJumpDest));
nextJumpDest = false;
begin = next;
}
@ -98,12 +98,12 @@ llvm::BasicBlock* Compiler::getJumpTableBlock()
{
if (!m_jumpTableBlock)
{
m_jumpTableBlock.reset(new BasicBlock("JumpTable", m_mainFunc, m_builder, true));
m_jumpTableBlock.reset(new BasicBlock("JumpTable", m_mainFunc, true));
InsertPointGuard g{m_builder};
m_builder.SetInsertPoint(m_jumpTableBlock->llvm());
auto dest = m_builder.CreatePHI(Type::Word, 8, "target");
auto switchInstr = m_builder.CreateSwitch(dest, m_abortBB);
for (auto&& p : m_basicBlocks)
for (auto&& p : m_basicBlocks) // FIXME: It mast be done at the end
{
if (p.second.isJumpDest())
switchInstr->addCase(Constant::get(p.first), p.second.llvm());
@ -196,15 +196,6 @@ std::unique_ptr<llvm::Module> Compiler::compile(code_iterator _begin, code_itera
}
}
dumpCFGifRequired("blocks-init.dot");
for (auto& entry : m_basicBlocks)
entry.second.synchronizeLocalStack(stack);
if (m_jumpTableBlock)
m_jumpTableBlock->synchronizeLocalStack(stack);
dumpCFGifRequired("blocks-sync.dot");
return module;
}
@ -216,7 +207,7 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, RuntimeManager& _runti
_nextBasicBlock = m_stopBB;
m_builder.SetInsertPoint(_basicBlock.llvm());
LocalStack stack{_basicBlock, _globalStack};
LocalStack stack{_globalStack};
for (auto it = _basicBlock.begin(); it != _basicBlock.end(); ++it)
{
@ -842,12 +833,13 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, RuntimeManager& _runti
if (!_basicBlock.llvm()->getTerminator())
m_builder.CreateBr(_nextBasicBlock);
stack.finalize(m_builder, *_basicBlock.llvm()); // TODO: Use references
m_builder.SetInsertPoint(_basicBlock.llvm()->getFirstNonPHI());
_runtimeManager.checkStackLimit(stack.getMaxSize(), _basicBlock.getDiff());
_runtimeManager.checkStackLimit(stack.getMaxSize(), stack.getDiff());
}
void Compiler::removeDeadBlocks()
{
// Remove dead basic blocks
@ -877,66 +869,6 @@ void Compiler::removeDeadBlocks()
}
}
void Compiler::dumpCFGifRequired(std::string const& _dotfilePath)
{
if (! m_options.dumpCFG)
return;
// TODO: handle i/o failures
std::ofstream ofs(_dotfilePath);
dumpCFGtoStream(ofs);
ofs.close();
}
void Compiler::dumpCFGtoStream(std::ostream& _out)
{
_out << "digraph BB {\n"
<< " node [shape=record, fontname=Courier, fontsize=10];\n"
<< " entry [share=record, label=\"entry block\"];\n";
std::vector<BasicBlock*> blocks;
for (auto& pair : m_basicBlocks)
blocks.push_back(&pair.second);
if (m_jumpTableBlock)
blocks.push_back(m_jumpTableBlock.get());
// std::map<BasicBlock*,int> phiNodesPerBlock;
// Output nodes
for (auto bb : blocks)
{
std::string blockName = bb->llvm()->getName();
std::ostringstream oss;
bb->dump(oss, true);
_out << " \"" << blockName << "\" [shape=record, label=\" { " << blockName << "|" << oss.str() << "} \"];\n";
}
// Output edges
for (auto bb : blocks)
{
std::string blockName = bb->llvm()->getName();
auto end = llvm::pred_end(bb->llvm());
for (llvm::pred_iterator it = llvm::pred_begin(bb->llvm()); it != end; ++it)
{
_out << " \"" << (*it)->getName().str() << "\" -> \"" << blockName << "\" ["
<< ((m_jumpTableBlock.get() && *it == m_jumpTableBlock.get()->llvm()) ? "style = dashed, " : "")
<< "];\n";
}
}
_out << "}\n";
}
void Compiler::dump()
{
for (auto& entry : m_basicBlocks)
entry.second.dump();
if (m_jumpTableBlock != nullptr)
m_jumpTableBlock->dump();
}
}
}

9
evmjit/libevmjit/Compiler.h

@ -38,15 +38,6 @@ private:
void removeDeadBlocks();
/// Dumps basic block graph in graphviz format to a file, if option dumpCFG is enabled.
void dumpCFGifRequired(std::string const& _dotfilePath);
/// Dumps basic block graph in graphviz format to a stream.
void dumpCFGtoStream(std::ostream& _out);
/// Dumps all basic blocks to stderr. Useful in a debugging session.
void dump();
/// Compiler options
Options const& m_options;

Loading…
Cancel
Save