From 1e926fe6bc5b82c53d23a0797dcf037e0c64052d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Mon, 27 Jul 2015 13:57:48 +0200 Subject: [PATCH] Move fields from BasicBlock to LocalStack. Remove dump() functions. --- evmjit/libevmjit/BasicBlock.cpp | 115 ++++++++------------------------ evmjit/libevmjit/BasicBlock.h | 55 ++++++--------- evmjit/libevmjit/Compiler.cpp | 82 ++--------------------- evmjit/libevmjit/Compiler.h | 9 --- 4 files changed, 57 insertions(+), 204 deletions(-) diff --git a/evmjit/libevmjit/BasicBlock.cpp b/evmjit/libevmjit/BasicBlock.cpp index 83ef3c7eb..f4f8b4645 100644 --- a/evmjit/libevmjit/BasicBlock.cpp +++ b/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(val)) - out << " " << val->getName(); - else if (llvm::isa(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(*val)) - out << " " << (*val)->getName(); - else if (llvm::isa(*val)) - out << **val; - else - out << " " << **val; - out << (_dotOutput ? "\\l" : "\n"); - } - - if (! _dotOutput) - out << " ...\n----------------------------------------\n"; -} - - - } } diff --git a/evmjit/libevmjit/BasicBlock.h b/evmjit/libevmjit/BasicBlock.h index 3111eb942..75b0efeab 100644 --- a/evmjit/libevmjit/BasicBlock.h +++ b/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(m_currentStack.size()) - static_cast(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 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 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(m_currentStack.size()) - static_cast(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 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 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; diff --git a/evmjit/libevmjit/Compiler.cpp b/evmjit/libevmjit/Compiler.cpp index 05d5a0fd1..58d8809d3 100644 --- a/evmjit/libevmjit/Compiler.cpp +++ b/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 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 blocks; - for (auto& pair : m_basicBlocks) - blocks.push_back(&pair.second); - if (m_jumpTableBlock) - blocks.push_back(m_jumpTableBlock.get()); - - // std::map 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(); -} } } diff --git a/evmjit/libevmjit/Compiler.h b/evmjit/libevmjit/Compiler.h index b9a9aae9b..a8cfa30e7 100644 --- a/evmjit/libevmjit/Compiler.h +++ b/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;