Browse Source

Use llvm::SwitchInstr as a jump dest map.

cl-refactor
Paweł Bylica 10 years ago
parent
commit
b44d4846f5
  1. 3
      evmjit/libevmjit/BasicBlock.cpp
  2. 6
      evmjit/libevmjit/BasicBlock.h
  3. 43
      evmjit/libevmjit/Compiler.cpp
  4. 5
      evmjit/libevmjit/Compiler.h

3
evmjit/libevmjit/BasicBlock.cpp

@ -27,8 +27,7 @@ BasicBlock::BasicBlock(instr_idx _firstInstrIdx, code_iterator _begin, code_iter
m_firstInstrIdx{_firstInstrIdx}, m_firstInstrIdx{_firstInstrIdx},
m_begin(_begin), m_begin(_begin),
m_end(_end), m_end(_end),
m_llvmBB(llvm::BasicBlock::Create(_mainFunc->getContext(), {isJumpDest ? jumpDestName : basicBlockName, std::to_string(_firstInstrIdx)}, _mainFunc)), m_llvmBB(llvm::BasicBlock::Create(_mainFunc->getContext(), {isJumpDest ? jumpDestName : basicBlockName, std::to_string(_firstInstrIdx)}, _mainFunc))
m_isJumpDest(isJumpDest)
{} {}
LocalStack::LocalStack(Stack& _globalStack): LocalStack::LocalStack(Stack& _globalStack):

6
evmjit/libevmjit/BasicBlock.h

@ -76,18 +76,12 @@ public:
code_iterator begin() const { return m_begin; } code_iterator begin() const { return m_begin; }
code_iterator end() const { return m_end; } code_iterator end() const { return m_end; }
bool isJumpDest() const { return m_isJumpDest; }
private: private:
instr_idx const m_firstInstrIdx = 0; ///< Code index of first instruction in the block 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 code_iterator const m_begin = {}; ///< Iterator pointing code beginning of the block
code_iterator const m_end = {}; ///< Iterator pointing code end of the block code_iterator const m_end = {}; ///< Iterator pointing code end of the block
llvm::BasicBlock* const m_llvmBB; llvm::BasicBlock* const m_llvmBB;
/// Is the basic block a valid jump destination.
/// JUMPDEST is the first instruction of the basic block.
bool const m_isJumpDest = false;
}; };
} }

43
evmjit/libevmjit/Compiler.cpp

@ -36,7 +36,7 @@ Compiler::Compiler(Options const& _options):
Type::init(m_builder.getContext()); Type::init(m_builder.getContext());
} }
void Compiler::createBasicBlocks(code_iterator _codeBegin, code_iterator _codeEnd) void Compiler::createBasicBlocks(code_iterator _codeBegin, code_iterator _codeEnd, llvm::SwitchInst& _jumpTable)
{ {
/// Helper function that skips push data and finds next iterator (can be the end) /// Helper function that skips push data and finds next iterator (can be the end)
auto skipPushDataAndGetNext = [](code_iterator _curr, code_iterator _end) auto skipPushDataAndGetNext = [](code_iterator _curr, code_iterator _end)
@ -86,8 +86,10 @@ void Compiler::createBasicBlocks(code_iterator _codeBegin, code_iterator _codeEn
if (isEnd) if (isEnd)
{ {
auto beginIdx = begin - _codeBegin; auto beginIdx = begin - _codeBegin;
m_basicBlocks.emplace(std::piecewise_construct, std::forward_as_tuple(beginIdx), auto r = m_basicBlocks.emplace(std::piecewise_construct, std::forward_as_tuple(beginIdx),
std::forward_as_tuple(beginIdx, begin, next, m_mainFunc, nextJumpDest)); std::forward_as_tuple(beginIdx, begin, next, m_mainFunc, nextJumpDest));
if (nextJumpDest)
_jumpTable.addCase(Constant::get(beginIdx), r.first->second.llvm());
nextJumpDest = false; nextJumpDest = false;
begin = next; begin = next;
} }
@ -97,27 +99,19 @@ void Compiler::createBasicBlocks(code_iterator _codeBegin, code_iterator _codeEn
void Compiler::fillJumpTable() void Compiler::fillJumpTable()
{ {
assert(m_jumpTableBB); assert(m_jumpTableBB);
if (llvm::pred_empty(m_jumpTableBB)) if (llvm::pred_empty(m_jumpTableBB))
{ {
m_jumpTableBB->eraseFromParent(); // remove if unused m_jumpTableBB->eraseFromParent(); // remove if unused
return; return;
} }
m_builder.SetInsertPoint(m_jumpTableBB); // TODO: Extend this function as `resolveJumps()` and fill gaps in branch instructions.
auto target = m_builder.CreatePHI(Type::Word, 16, "target"); auto target = llvm::cast<llvm::PHINode>(m_jumpTableBB->begin());
for (auto pred: llvm::predecessors(m_jumpTableBB)) for (auto pred: llvm::predecessors(m_jumpTableBB))
{ {
auto targetMd = llvm::cast<llvm::LocalAsMetadata>(pred->getTerminator()->getMetadata("target")->getOperand(0)); auto targetMd = llvm::cast<llvm::LocalAsMetadata>(pred->getTerminator()->getMetadata("target")->getOperand(0));
target->addIncoming(targetMd->getValue(), pred); target->addIncoming(targetMd->getValue(), pred);
} }
auto switchInst = m_builder.CreateSwitch(target, m_abortBB);
for (auto& p: m_basicBlocks)
{
if (p.second.isJumpDest())
switchInst->addCase(Constant::get(p.first), p.second.llvm());
}
} }
std::unique_ptr<llvm::Module> Compiler::compile(code_iterator _begin, code_iterator _end, std::string const& _id) std::unique_ptr<llvm::Module> Compiler::compile(code_iterator _begin, code_iterator _end, std::string const& _id)
@ -131,9 +125,17 @@ std::unique_ptr<llvm::Module> Compiler::compile(code_iterator _begin, code_itera
// Create entry basic block // Create entry basic block
auto entryBlock = llvm::BasicBlock::Create(m_builder.getContext(), {}, m_mainFunc); auto entryBlock = llvm::BasicBlock::Create(m_builder.getContext(), {}, m_mainFunc);
m_stopBB = llvm::BasicBlock::Create(m_mainFunc->getContext(), "Stop", m_mainFunc);
m_abortBB = llvm::BasicBlock::Create(m_mainFunc->getContext(), "Abort", m_mainFunc);
m_jumpTableBB = llvm::BasicBlock::Create(m_mainFunc->getContext(), "JumpTable", m_mainFunc);
m_builder.SetInsertPoint(m_jumpTableBB);
auto target = m_builder.CreatePHI(Type::Word, 16, "target");
auto& jumpTable = *m_builder.CreateSwitch(target, m_abortBB);
m_builder.SetInsertPoint(entryBlock); m_builder.SetInsertPoint(entryBlock);
createBasicBlocks(_begin, _end); createBasicBlocks(_begin, _end, jumpTable);
// Init runtime structures. // Init runtime structures.
RuntimeManager runtimeManager(m_builder, _begin, _end); RuntimeManager runtimeManager(m_builder, _begin, _end);
@ -158,10 +160,6 @@ std::unique_ptr<llvm::Module> Compiler::compile(code_iterator _begin, code_itera
auto normalFlow = m_builder.CreateICmpEQ(r, m_builder.getInt32(0)); auto normalFlow = m_builder.CreateICmpEQ(r, m_builder.getInt32(0));
runtimeManager.setJmpBuf(jmpBuf); runtimeManager.setJmpBuf(jmpBuf);
m_stopBB = llvm::BasicBlock::Create(m_mainFunc->getContext(), "Stop", m_mainFunc);
m_abortBB = llvm::BasicBlock::Create(m_mainFunc->getContext(), "Abort", m_mainFunc);
m_jumpTableBB = llvm::BasicBlock::Create(m_mainFunc->getContext(), "JumpTable", m_mainFunc);
auto firstBB = m_basicBlocks.empty() ? m_stopBB : m_basicBlocks.begin()->second.llvm(); auto firstBB = m_basicBlocks.empty() ? m_stopBB : m_basicBlocks.begin()->second.llvm();
m_builder.CreateCondBr(normalFlow, firstBB, m_abortBB, Type::expectTrue); m_builder.CreateCondBr(normalFlow, firstBB, m_abortBB, Type::expectTrue);
@ -171,7 +169,7 @@ std::unique_ptr<llvm::Module> Compiler::compile(code_iterator _begin, code_itera
auto iterCopy = basicBlockPairIt; auto iterCopy = basicBlockPairIt;
++iterCopy; ++iterCopy;
auto nextBasicBlock = (iterCopy != m_basicBlocks.end()) ? iterCopy->second.llvm() : nullptr; auto nextBasicBlock = (iterCopy != m_basicBlocks.end()) ? iterCopy->second.llvm() : nullptr;
compileBasicBlock(basicBlock, runtimeManager, arith, memory, ext, gasMeter, nextBasicBlock, stack); compileBasicBlock(basicBlock, runtimeManager, arith, memory, ext, gasMeter, nextBasicBlock, stack, jumpTable);
} }
// Code for special blocks: // Code for special blocks:
@ -188,7 +186,8 @@ std::unique_ptr<llvm::Module> Compiler::compile(code_iterator _begin, code_itera
void Compiler::compileBasicBlock(BasicBlock& _basicBlock, RuntimeManager& _runtimeManager, void Compiler::compileBasicBlock(BasicBlock& _basicBlock, RuntimeManager& _runtimeManager,
Arith256& _arith, Memory& _memory, Ext& _ext, GasMeter& _gasMeter, llvm::BasicBlock* _nextBasicBlock, Stack& _globalStack) Arith256& _arith, Memory& _memory, Ext& _ext, GasMeter& _gasMeter, llvm::BasicBlock* _nextBasicBlock, Stack& _globalStack,
llvm::SwitchInst& jumpTable)
{ {
if (!_nextBasicBlock) // this is the last block in the code if (!_nextBasicBlock) // this is the last block in the code
_nextBasicBlock = m_stopBB; _nextBasicBlock = m_stopBB;
@ -570,10 +569,8 @@ void Compiler::compileBasicBlock(BasicBlock& _basicBlock, RuntimeManager& _runti
if (auto constant = llvm::dyn_cast<llvm::ConstantInt>(target)) if (auto constant = llvm::dyn_cast<llvm::ConstantInt>(target))
{ {
// If target index is a constant do direct jump to the target block. // If target index is a constant do direct jump to the target block.
auto&& c = constant->getValue(); auto bb = jumpTable.findCaseValue(constant).getCaseSuccessor();
auto targetIdx = c.getActiveBits() <= 64 ? c.getZExtValue() : -1; jumpInst->setSuccessor(0, bb);
auto it = m_basicBlocks.find(targetIdx);
jumpInst->setSuccessor(0, (it != m_basicBlocks.end() && it->second.isJumpDest()) ? it->second.llvm() : m_abortBB);
} }
else else
{ {

5
evmjit/libevmjit/Compiler.h

@ -30,9 +30,10 @@ public:
private: private:
void createBasicBlocks(code_iterator _begin, code_iterator _end); void createBasicBlocks(code_iterator _begin, code_iterator _end, llvm::SwitchInst& _switchInst);
void compileBasicBlock(BasicBlock& _basicBlock, class RuntimeManager& _runtimeManager, class Arith256& _arith, class Memory& _memory, class Ext& _ext, class GasMeter& _gasMeter, llvm::BasicBlock* _nextBasicBlock, class Stack& _globalStack); void compileBasicBlock(BasicBlock& _basicBlock, class RuntimeManager& _runtimeManager, class Arith256& _arith, class Memory& _memory, class Ext& _ext, class GasMeter& _gasMeter,
llvm::BasicBlock* _nextBasicBlock, class Stack& _globalStack, llvm::SwitchInst& _jumpTable);
void fillJumpTable(); void fillJumpTable();

Loading…
Cancel
Save