mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-21 20:26:41 +00:00
Merge branch 'develop-evmcc' of https://github.com/imapp-pl/ethereum into develop-evmcc
This commit is contained in:
commit
097b7ae1eb
8 changed files with 288 additions and 224 deletions
|
|
@ -1 +1 @@
|
||||||
600160026001600a590090600160115900016000546001601ff2
|
600560026001600c59505000906001601559505000036000546001601ff2
|
||||||
|
|
|
||||||
|
|
@ -1,20 +1,26 @@
|
||||||
(asm
|
(asm
|
||||||
1 ;; 0
|
5 ;; 0
|
||||||
2 ;; 2
|
2 ;; 2
|
||||||
1 ;; 4
|
1 ;; 4
|
||||||
10 ;; 6
|
12 ;; 6
|
||||||
JUMPI ;; 8
|
JUMPI ;; 8
|
||||||
STOP ;; 9
|
|
||||||
|
POP ;; 9
|
||||||
|
POP ;; 10
|
||||||
|
STOP ;; 11
|
||||||
|
|
||||||
;; stack = 2,1
|
;; stack = 2,1
|
||||||
SWAP1 ;; 10
|
SWAP1 ;; 12
|
||||||
1 ;; 11
|
1 ;; 13
|
||||||
17 ;; 13
|
21 ;; 15
|
||||||
JUMPI ;; 15
|
JUMPI ;; 17
|
||||||
STOP ;; 16
|
|
||||||
|
POP ;; 18
|
||||||
|
POP ;; 19
|
||||||
|
STOP ;; 20
|
||||||
|
|
||||||
;; stack = 1,2
|
;; stack = 1,2
|
||||||
ADD ;; 17
|
SUB ;; 21
|
||||||
0
|
0
|
||||||
MSTORE
|
MSTORE
|
||||||
1
|
1
|
||||||
|
|
|
||||||
|
|
@ -1 +1 @@
|
||||||
600160026001600a59009090600160125900016000546001601ff2
|
600260056001600c5950500090906001601659505000036000546001601ff2
|
||||||
|
|
|
||||||
|
|
@ -1,21 +1,27 @@
|
||||||
(asm
|
(asm
|
||||||
1 ;; 0
|
2 ;; 0
|
||||||
2 ;; 2
|
5 ;; 2
|
||||||
1 ;; 4
|
1 ;; 4
|
||||||
10 ;; 6
|
12 ;; 6
|
||||||
JUMPI ;; 8
|
JUMPI ;; 8
|
||||||
STOP ;; 9
|
|
||||||
|
POP ;; 9
|
||||||
|
POP ;; 10
|
||||||
|
STOP ;; 11
|
||||||
|
|
||||||
;; stack = 2,1
|
;; stack = 2,1
|
||||||
SWAP1 ;; 10
|
SWAP1 ;; 12
|
||||||
SWAP1 ;; 11
|
SWAP1 ;; 13
|
||||||
1 ;; 12
|
1 ;; 14
|
||||||
18 ;; 14
|
22 ;; 16
|
||||||
JUMPI ;; 16
|
JUMPI ;; 18
|
||||||
STOP ;; 17
|
|
||||||
|
POP ;; 19
|
||||||
|
POP ;; 20
|
||||||
|
STOP ;; 21
|
||||||
|
|
||||||
;; stack = 2,1
|
;; stack = 2,1
|
||||||
ADD ;; 18
|
SUB ;; 22
|
||||||
0
|
0
|
||||||
MSTORE
|
MSTORE
|
||||||
1
|
1
|
||||||
|
|
|
||||||
|
|
@ -5,9 +5,11 @@
|
||||||
|
|
||||||
#include <boost/lexical_cast.hpp>
|
#include <boost/lexical_cast.hpp>
|
||||||
|
|
||||||
|
#include <llvm/IR/CFG.h>
|
||||||
#include <llvm/IR/Function.h>
|
#include <llvm/IR/Function.h>
|
||||||
#include <llvm/IR/Instructions.h>
|
#include <llvm/IR/Instructions.h>
|
||||||
#include <llvm/IR/IRBuilder.h>
|
#include <llvm/IR/IRBuilder.h>
|
||||||
|
#include <llvm/Support/raw_os_ostream.h>
|
||||||
|
|
||||||
#include "Type.h"
|
#include "Type.h"
|
||||||
|
|
||||||
|
|
@ -24,17 +26,18 @@ BasicBlock::BasicBlock(ProgramCounter _beginInstIdx, ProgramCounter _endInstIdx,
|
||||||
m_beginInstIdx(_beginInstIdx),
|
m_beginInstIdx(_beginInstIdx),
|
||||||
m_endInstIdx(_endInstIdx),
|
m_endInstIdx(_endInstIdx),
|
||||||
m_llvmBB(llvm::BasicBlock::Create(_mainFunc->getContext(), {NamePrefix, std::to_string(_beginInstIdx)}, _mainFunc)),
|
m_llvmBB(llvm::BasicBlock::Create(_mainFunc->getContext(), {NamePrefix, std::to_string(_beginInstIdx)}, _mainFunc)),
|
||||||
m_stack(_builder)
|
m_stack(_builder, m_llvmBB)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
BasicBlock::BasicBlock(std::string _name, llvm::Function* _mainFunc, llvm::IRBuilder<>& _builder) :
|
BasicBlock::BasicBlock(std::string _name, llvm::Function* _mainFunc, llvm::IRBuilder<>& _builder) :
|
||||||
m_beginInstIdx(0),
|
m_beginInstIdx(0),
|
||||||
m_endInstIdx(0),
|
m_endInstIdx(0),
|
||||||
m_llvmBB(llvm::BasicBlock::Create(_mainFunc->getContext(), _name, _mainFunc)),
|
m_llvmBB(llvm::BasicBlock::Create(_mainFunc->getContext(), _name, _mainFunc)),
|
||||||
m_stack(_builder)
|
m_stack(_builder, m_llvmBB)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
BasicBlock::LocalStack::LocalStack(llvm::IRBuilder<>& _builder) :
|
BasicBlock::LocalStack::LocalStack(llvm::IRBuilder<>& _builder, llvm::BasicBlock* _llvmBB) :
|
||||||
|
m_llvmBB(_llvmBB),
|
||||||
m_builder(_builder),
|
m_builder(_builder),
|
||||||
m_initialStack(),
|
m_initialStack(),
|
||||||
m_currentStack(),
|
m_currentStack(),
|
||||||
|
|
@ -82,7 +85,7 @@ void BasicBlock::LocalStack::swap(size_t _index)
|
||||||
|
|
||||||
void BasicBlock::LocalStack::synchronize(Stack& _evmStack)
|
void BasicBlock::LocalStack::synchronize(Stack& _evmStack)
|
||||||
{
|
{
|
||||||
auto blockTerminator = m_builder.GetInsertBlock()->getTerminator();
|
auto blockTerminator = m_llvmBB->getTerminator();
|
||||||
assert(blockTerminator != nullptr);
|
assert(blockTerminator != nullptr);
|
||||||
m_builder.SetInsertPoint(blockTerminator);
|
m_builder.SetInsertPoint(blockTerminator);
|
||||||
|
|
||||||
|
|
@ -182,44 +185,190 @@ void BasicBlock::LocalStack::set(size_t _index, llvm::Value* _word)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void BasicBlock::linkLocalStacks(std::vector<BasicBlock*> basicBlocks, llvm::IRBuilder<>& _builder)
|
||||||
|
{
|
||||||
|
struct BBInfo
|
||||||
|
{
|
||||||
|
BasicBlock& bblock;
|
||||||
|
std::vector<BBInfo*> predecessors;
|
||||||
|
size_t inputItems;
|
||||||
|
size_t outputItems;
|
||||||
|
std::vector<llvm::PHINode*> phisToRewrite;
|
||||||
|
|
||||||
|
BBInfo(BasicBlock& _bblock) :
|
||||||
|
bblock(_bblock),
|
||||||
|
predecessors(),
|
||||||
|
inputItems(0),
|
||||||
|
outputItems(0)
|
||||||
|
{
|
||||||
|
auto& initialStack = bblock.localStack().m_initialStack;
|
||||||
|
for (auto it = initialStack.begin();
|
||||||
|
it != initialStack.end() && *it != nullptr;
|
||||||
|
++it, ++inputItems);
|
||||||
|
|
||||||
|
//if (bblock.localStack().m_tosOffset > 0)
|
||||||
|
// outputItems = bblock.localStack().m_tosOffset;
|
||||||
|
auto& exitStack = bblock.localStack().m_currentStack;
|
||||||
|
for (auto it = exitStack.rbegin();
|
||||||
|
it != exitStack.rend() && *it != nullptr;
|
||||||
|
++it, ++outputItems);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
std::map<llvm::BasicBlock*, BBInfo> cfg;
|
||||||
|
|
||||||
|
// Create nodes in cfg
|
||||||
|
for (auto bb : basicBlocks)
|
||||||
|
cfg.emplace(bb->llvm(), *bb);
|
||||||
|
|
||||||
|
// Create edges in cfg: for each bb info fill the list
|
||||||
|
// of predecessor infos.
|
||||||
|
for (auto& pair : cfg)
|
||||||
|
{
|
||||||
|
auto bb = pair.first;
|
||||||
|
auto& info = pair.second;
|
||||||
|
|
||||||
|
for (auto predIt = llvm::pred_begin(bb); predIt != llvm::pred_end(bb); ++predIt)
|
||||||
|
{
|
||||||
|
auto predInfoEntry = cfg.find(*predIt);
|
||||||
|
if (predInfoEntry != cfg.end())
|
||||||
|
info.predecessors.push_back(&predInfoEntry->second);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Iteratively compute inputs and outputs of each block, until reaching fixpoint.
|
||||||
|
bool valuesChanged = true;
|
||||||
|
while (valuesChanged)
|
||||||
|
{
|
||||||
|
if (getenv("EVMCC_DEBUG_BLOCKS"))
|
||||||
|
{
|
||||||
|
for (auto& pair: cfg)
|
||||||
|
std::cerr << pair.second.bblock.llvm()->getName().str()
|
||||||
|
<< ": in " << pair.second.inputItems
|
||||||
|
<< ", out " << pair.second.outputItems
|
||||||
|
<< "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
valuesChanged = false;
|
||||||
|
for (auto& pair : cfg)
|
||||||
|
{
|
||||||
|
auto& info = pair.second;
|
||||||
|
|
||||||
|
if (info.predecessors.empty())
|
||||||
|
info.inputItems = 0; // no consequences for other blocks, so leave valuesChanged false
|
||||||
|
|
||||||
|
for (auto predInfo : info.predecessors)
|
||||||
|
{
|
||||||
|
if (predInfo->outputItems < info.inputItems)
|
||||||
|
{
|
||||||
|
info.inputItems = predInfo->outputItems;
|
||||||
|
valuesChanged = true;
|
||||||
|
}
|
||||||
|
else if (predInfo->outputItems > info.inputItems)
|
||||||
|
{
|
||||||
|
predInfo->outputItems = info.inputItems;
|
||||||
|
valuesChanged = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Propagate values between blocks.
|
||||||
|
for (auto& entry : cfg)
|
||||||
|
{
|
||||||
|
auto& info = entry.second;
|
||||||
|
auto& bblock = info.bblock;
|
||||||
|
|
||||||
|
llvm::BasicBlock::iterator fstNonPhi(bblock.llvm()->getFirstNonPHI());
|
||||||
|
auto phiIter = bblock.localStack().m_initialStack.begin();
|
||||||
|
for (size_t index = 0; index < info.inputItems; ++index, ++phiIter)
|
||||||
|
{
|
||||||
|
assert(llvm::isa<llvm::PHINode>(*phiIter));
|
||||||
|
auto phi = llvm::cast<llvm::PHINode>(*phiIter);
|
||||||
|
|
||||||
|
for (auto predIt : info.predecessors)
|
||||||
|
{
|
||||||
|
auto& predExitStack = predIt->bblock.localStack().m_currentStack;
|
||||||
|
auto value = *(predExitStack.end() - 1 - index);
|
||||||
|
phi->addIncoming(value, predIt->bblock.llvm());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Move phi to the front
|
||||||
|
if (llvm::BasicBlock::iterator(phi) != bblock.llvm()->begin())
|
||||||
|
{
|
||||||
|
phi->removeFromParent();
|
||||||
|
_builder.SetInsertPoint(bblock.llvm(), bblock.llvm()->begin());
|
||||||
|
_builder.Insert(phi);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// The items pulled directly from predecessors block must be removed
|
||||||
|
// from the list of items that has to be popped from the initial stack.
|
||||||
|
auto& initialStack = bblock.localStack().m_initialStack;
|
||||||
|
initialStack.erase(initialStack.begin(), initialStack.begin() + info.inputItems);
|
||||||
|
// Initial stack shrinks, so the size difference grows:
|
||||||
|
bblock.localStack().m_tosOffset += info.inputItems;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We must account for the items that were pushed directly to successor
|
||||||
|
// blocks and thus should not be on the list of items to be pushed onto
|
||||||
|
// to EVM stack
|
||||||
|
for (auto& entry : cfg)
|
||||||
|
{
|
||||||
|
auto& info = entry.second;
|
||||||
|
auto& bblock = info.bblock;
|
||||||
|
|
||||||
|
auto& exitStack = bblock.localStack().m_currentStack;
|
||||||
|
exitStack.erase(exitStack.end() - info.outputItems, exitStack.end());
|
||||||
|
bblock.localStack().m_tosOffset -= info.outputItems;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void BasicBlock::dump()
|
void BasicBlock::dump()
|
||||||
{
|
{
|
||||||
std::cerr << "Initial stack:\n";
|
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_stack.m_initialStack)
|
for (auto val : m_stack.m_initialStack)
|
||||||
{
|
{
|
||||||
if (val == nullptr)
|
if (val == nullptr)
|
||||||
std::cerr << " ?\n";
|
out << " ?";
|
||||||
else if (llvm::isa<llvm::Instruction>(val))
|
else if (llvm::isa<llvm::Instruction>(val))
|
||||||
val->dump();
|
out << *val;
|
||||||
else
|
else
|
||||||
{
|
out << " " << *val;
|
||||||
std::cerr << " ";
|
|
||||||
val->dump();
|
out << (_dotOutput ? "\\l" : "\n");
|
||||||
}
|
|
||||||
}
|
}
|
||||||
std::cerr << " ...\n";
|
|
||||||
|
|
||||||
std::cerr << "Instructions:\n";
|
out << (_dotOutput ? "| " : "Instructions:\n");
|
||||||
for (auto ins = m_llvmBB->begin(); ins != m_llvmBB->end(); ++ins)
|
for (auto ins = m_llvmBB->begin(); ins != m_llvmBB->end(); ++ins)
|
||||||
ins->dump();
|
out << *ins << (_dotOutput ? "\\l" : "\n");
|
||||||
|
|
||||||
std::cerr << "Current stack (offset = "
|
if (! _dotOutput)
|
||||||
<< m_stack.m_tosOffset << "):\n";
|
out << "Current stack (offset = " << m_stack.m_tosOffset << "):\n";
|
||||||
|
else
|
||||||
|
out << "|";
|
||||||
|
|
||||||
for (auto val = m_stack.m_currentStack.rbegin(); val != m_stack.m_currentStack.rend(); ++val)
|
for (auto val = m_stack.m_currentStack.rbegin(); val != m_stack.m_currentStack.rend(); ++val)
|
||||||
{
|
{
|
||||||
if (*val == nullptr)
|
if (*val == nullptr)
|
||||||
std::cerr << " ?\n";
|
out << " ?";
|
||||||
else if (llvm::isa<llvm::Instruction>(*val))
|
else if (llvm::isa<llvm::Instruction>(*val))
|
||||||
(*val)->dump();
|
out << **val;
|
||||||
else
|
else
|
||||||
{
|
out << " " << **val;
|
||||||
std::cerr << " ";
|
out << (_dotOutput ? "\\l" : "\n");
|
||||||
(*val)->dump();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
std::cerr << " ...\n----------------------------------------\n";
|
|
||||||
|
if (! _dotOutput)
|
||||||
|
out << " ...\n----------------------------------------\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,7 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
LocalStack(llvm::IRBuilder<>& _builder);
|
LocalStack(llvm::IRBuilder<>& _builder, llvm::BasicBlock* _llvmBB);
|
||||||
LocalStack(LocalStack const&) = delete;
|
LocalStack(LocalStack const&) = delete;
|
||||||
void operator=(LocalStack const&) = delete;
|
void operator=(LocalStack const&) = delete;
|
||||||
friend BasicBlock;
|
friend BasicBlock;
|
||||||
|
|
@ -55,6 +55,8 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
llvm::BasicBlock* m_llvmBB;
|
||||||
|
|
||||||
llvm::IRBuilder<>& m_builder;
|
llvm::IRBuilder<>& m_builder;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -99,9 +101,14 @@ public:
|
||||||
|
|
||||||
LocalStack& localStack() { return m_stack; }
|
LocalStack& localStack() { return m_stack; }
|
||||||
|
|
||||||
|
/// Optimization: propagates values between local stacks in basic blocks
|
||||||
|
/// to avoid excessive pushing/popping on the EVM stack.
|
||||||
|
static void linkLocalStacks(std::vector<BasicBlock*> _basicBlocks, llvm::IRBuilder<>& _builder);
|
||||||
|
|
||||||
/// Prints local stack and block instructions to stderr.
|
/// Prints local stack and block instructions to stderr.
|
||||||
/// Useful for calling in a debugger session.
|
/// Useful for calling in a debugger session.
|
||||||
void dump();
|
void dump();
|
||||||
|
void dump(std::ostream& os, bool _dotOutput = false);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ProgramCounter const m_beginInstIdx;
|
ProgramCounter const m_beginInstIdx;
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,13 @@
|
||||||
|
|
||||||
#include "Compiler.h"
|
#include "Compiler.h"
|
||||||
|
|
||||||
|
#include <fstream>
|
||||||
|
|
||||||
#include <boost/dynamic_bitset.hpp>
|
#include <boost/dynamic_bitset.hpp>
|
||||||
|
|
||||||
#include <llvm/IR/Module.h>
|
|
||||||
#include <llvm/IR/CFG.h>
|
|
||||||
#include <llvm/ADT/PostOrderIterator.h>
|
#include <llvm/ADT/PostOrderIterator.h>
|
||||||
|
#include <llvm/IR/CFG.h>
|
||||||
|
#include <llvm/IR/Module.h>
|
||||||
#include <llvm/IR/IntrinsicInst.h>
|
#include <llvm/IR/IntrinsicInst.h>
|
||||||
|
|
||||||
#include <libevmface/Instruction.h>
|
#include <libevmface/Instruction.h>
|
||||||
|
|
@ -190,9 +192,6 @@ std::unique_ptr<llvm::Module> Compiler::compile(bytesConstRef bytecode)
|
||||||
++iterCopy;
|
++iterCopy;
|
||||||
auto nextBasicBlock = (iterCopy != basicBlocks.end()) ? iterCopy->second.llvm() : nullptr;
|
auto nextBasicBlock = (iterCopy != basicBlocks.end()) ? iterCopy->second.llvm() : nullptr;
|
||||||
compileBasicBlock(basicBlock, bytecode, memory, ext, gasMeter, nextBasicBlock);
|
compileBasicBlock(basicBlock, bytecode, memory, ext, gasMeter, nextBasicBlock);
|
||||||
if (getenv("EVMCC_DEBUG_BLOCKS"))
|
|
||||||
basicBlock.dump();
|
|
||||||
basicBlock.localStack().synchronize(stack);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Code for special blocks:
|
// Code for special blocks:
|
||||||
|
|
@ -208,9 +207,7 @@ std::unique_ptr<llvm::Module> Compiler::compile(bytesConstRef bytecode)
|
||||||
m_builder.SetInsertPoint(m_jumpTableBlock->llvm());
|
m_builder.SetInsertPoint(m_jumpTableBlock->llvm());
|
||||||
if (m_indirectJumpTargets.size() > 0)
|
if (m_indirectJumpTargets.size() > 0)
|
||||||
{
|
{
|
||||||
// auto& stack = m_jumpTableBlock->getStack();
|
auto dest = m_jumpTableBlock->localStack().pop();
|
||||||
|
|
||||||
auto dest = m_jumpTableBlock->localStack().pop(); //m_jumpTableBlock->localGet(0); // stack.pop();
|
|
||||||
auto switchInstr = m_builder.CreateSwitch(dest, m_badJumpBlock->llvm(),
|
auto switchInstr = m_builder.CreateSwitch(dest, m_badJumpBlock->llvm(),
|
||||||
m_indirectJumpTargets.size());
|
m_indirectJumpTargets.size());
|
||||||
for (auto it = m_indirectJumpTargets.cbegin(); it != m_indirectJumpTargets.cend(); ++it)
|
for (auto it = m_indirectJumpTargets.cbegin(); it != m_indirectJumpTargets.cend(); ++it)
|
||||||
|
|
@ -225,8 +222,51 @@ std::unique_ptr<llvm::Module> Compiler::compile(bytesConstRef bytecode)
|
||||||
m_builder.CreateBr(m_badJumpBlock->llvm());
|
m_builder.CreateBr(m_badJumpBlock->llvm());
|
||||||
}
|
}
|
||||||
|
|
||||||
m_jumpTableBlock->localStack().synchronize(stack);
|
removeDeadBlocks();
|
||||||
linkBasicBlocks();
|
|
||||||
|
if (getenv("EVMCC_DEBUG_BLOCKS"))
|
||||||
|
{
|
||||||
|
std::ofstream ofs("blocks-init.dot");
|
||||||
|
dumpBasicBlockGraph(ofs);
|
||||||
|
ofs.close();
|
||||||
|
std::cerr << "\n\nAfter dead block elimination \n\n";
|
||||||
|
dump();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (getenv("EVMCC_OPTIMIZE_STACK"))
|
||||||
|
{
|
||||||
|
std::vector<BasicBlock*> blockList;
|
||||||
|
for (auto& entry : basicBlocks)
|
||||||
|
blockList.push_back(&entry.second);
|
||||||
|
|
||||||
|
if (m_jumpTableBlock != nullptr)
|
||||||
|
blockList.push_back(m_jumpTableBlock.get());
|
||||||
|
|
||||||
|
BasicBlock::linkLocalStacks(blockList, m_builder);
|
||||||
|
|
||||||
|
if (getenv("EVMCC_DEBUG_BLOCKS"))
|
||||||
|
{
|
||||||
|
std::ofstream ofs("blocks-opt.dot");
|
||||||
|
dumpBasicBlockGraph(ofs);
|
||||||
|
ofs.close();
|
||||||
|
std::cerr << "\n\nAfter stack optimization \n\n";
|
||||||
|
dump();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto& entry : basicBlocks)
|
||||||
|
entry.second.localStack().synchronize(stack);
|
||||||
|
if (m_jumpTableBlock != nullptr)
|
||||||
|
m_jumpTableBlock->localStack().synchronize(stack);
|
||||||
|
|
||||||
|
if (getenv("EVMCC_DEBUG_BLOCKS"))
|
||||||
|
{
|
||||||
|
std::ofstream ofs("blocks-sync.dot");
|
||||||
|
dumpBasicBlockGraph(ofs);
|
||||||
|
ofs.close();
|
||||||
|
std::cerr << "\n\nAfter stack synchronization \n\n";
|
||||||
|
dump();
|
||||||
|
}
|
||||||
|
|
||||||
return module;
|
return module;
|
||||||
}
|
}
|
||||||
|
|
@ -879,7 +919,8 @@ void Compiler::compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Compiler::linkBasicBlocks() // Stack& stack)
|
|
||||||
|
void Compiler::removeDeadBlocks()
|
||||||
{
|
{
|
||||||
// Remove dead basic blocks
|
// Remove dead basic blocks
|
||||||
auto sthErased = false;
|
auto sthErased = false;
|
||||||
|
|
@ -907,187 +948,33 @@ void Compiler::linkBasicBlocks() // Stack& stack)
|
||||||
m_jumpTableBlock->llvm()->eraseFromParent();
|
m_jumpTableBlock->llvm()->eraseFromParent();
|
||||||
m_jumpTableBlock.reset();
|
m_jumpTableBlock.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
struct BBInfo
|
|
||||||
{
|
|
||||||
BasicBlock& bblock;
|
|
||||||
std::vector<BBInfo*> predecessors;
|
|
||||||
size_t inputItems;
|
|
||||||
size_t outputItems;
|
|
||||||
std::vector<llvm::PHINode*> phisToRewrite;
|
|
||||||
|
|
||||||
BBInfo(BasicBlock& _bblock)
|
|
||||||
: bblock(_bblock),
|
|
||||||
predecessors(),
|
|
||||||
inputItems(_bblock.getStack().initialSize()),
|
|
||||||
outputItems(_bblock.getStack().size())
|
|
||||||
{}
|
|
||||||
};
|
|
||||||
|
|
||||||
std::map<llvm::BasicBlock*, BBInfo> cfg;
|
|
||||||
|
|
||||||
// Create nodes in cfg
|
|
||||||
for (auto& pair : this->basicBlocks)
|
|
||||||
{
|
|
||||||
auto& bb = pair.second;
|
|
||||||
cfg.emplace(bb.llvm(), bb);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Insert jump table block into cfg
|
|
||||||
if (m_jumpTableBlock)
|
|
||||||
cfg.emplace(m_jumpTableBlock->llvm(), *m_jumpTableBlock);
|
|
||||||
|
|
||||||
auto& entryBlock = m_mainFunc->getEntryBlock();
|
|
||||||
|
|
||||||
// Create edges in cfg
|
|
||||||
for (auto& pair : cfg)
|
|
||||||
{
|
|
||||||
auto bbPtr = pair.first;
|
|
||||||
auto& bbInfo = pair.second;
|
|
||||||
|
|
||||||
for (auto predIt = llvm::pred_begin(bbPtr); predIt != llvm::pred_end(bbPtr); ++predIt)
|
|
||||||
{
|
|
||||||
if (*predIt != &entryBlock)
|
|
||||||
{
|
|
||||||
auto predInfoEntry = cfg.find(*predIt);
|
|
||||||
assert(predInfoEntry != cfg.end());
|
|
||||||
bbInfo.predecessors.push_back(&predInfoEntry->second);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Iteratively compute inputs and outputs of each block, until reaching fixpoint.
|
|
||||||
bool valuesChanged = true;
|
|
||||||
while (valuesChanged)
|
|
||||||
{
|
|
||||||
valuesChanged = false;
|
|
||||||
for (auto& pair : cfg)
|
|
||||||
{
|
|
||||||
auto& bbInfo = pair.second;
|
|
||||||
|
|
||||||
if (bbInfo.predecessors.empty())
|
|
||||||
bbInfo.inputItems = 0; // no consequences for other blocks, so leave valuesChanged false
|
|
||||||
|
|
||||||
for (auto predInfo : bbInfo.predecessors)
|
|
||||||
{
|
|
||||||
if (predInfo->outputItems < bbInfo.inputItems)
|
|
||||||
{
|
|
||||||
bbInfo.inputItems = predInfo->outputItems;
|
|
||||||
valuesChanged = true;
|
|
||||||
}
|
|
||||||
else if (predInfo->outputItems > bbInfo.inputItems)
|
|
||||||
{
|
|
||||||
predInfo->outputItems = bbInfo.inputItems;
|
|
||||||
valuesChanged = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// std::map<llvm::Instruction*, llvm::Value*> phiReplacements;
|
|
||||||
// std::vector<llvm::Instruction*> phiNodesToRewrite;
|
|
||||||
|
|
||||||
// Propagate values between blocks.
|
|
||||||
for (auto& pair : cfg)
|
|
||||||
{
|
|
||||||
auto llbb = pair.first;
|
|
||||||
auto& bbInfo = pair.second;
|
|
||||||
auto& bblock = bbInfo.bblock;
|
|
||||||
|
|
||||||
// Complete phi nodes for the top bbInfo.inputItems placeholder values
|
|
||||||
auto instrIter = llbb->begin();
|
|
||||||
for (size_t valueIdx = 0; valueIdx < bbInfo.inputItems; ++instrIter, ++valueIdx)
|
|
||||||
{
|
|
||||||
auto phi = llvm::cast<llvm::PHINode>(instrIter);
|
|
||||||
for (auto predIt : bbInfo.predecessors)
|
|
||||||
{
|
|
||||||
assert(valueIdx < predIt->bblock.getStack().size());
|
|
||||||
auto value = predIt->bblock.getStack().get(valueIdx);
|
|
||||||
phi->addIncoming(value, predIt->bblock.llvm());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Turn the remaining phi nodes into stack.pop's.
|
|
||||||
// m_builder.SetInsertPoint(llbb, llvm::BasicBlock::iterator(llbb->getFirstNonPHI()));
|
|
||||||
for (; llvm::isa<llvm::PHINode>(*instrIter); ++instrIter)
|
|
||||||
{
|
|
||||||
auto phi = llvm::cast<llvm::PHINode>(instrIter);
|
|
||||||
// auto value = stack.popWord();
|
|
||||||
// Don't delete the phi node yet. It may still be stored in a local stack of some block.
|
|
||||||
// phiReplacements[phi] = value;
|
|
||||||
bbInfo.phisToRewrite.push_back(phi);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Emit stack push's at the end of the block, just before the terminator;
|
|
||||||
m_builder.SetInsertPoint(llbb, -- llbb->end());
|
|
||||||
auto localStackSize = bblock.getStack().size();
|
|
||||||
assert(localStackSize >= bbInfo.outputItems);
|
|
||||||
for (size_t i = 0; i < localStackSize - bbInfo.outputItems; ++i)
|
|
||||||
stack.pushWord(bblock.getStack().get(localStackSize - 1 - i));
|
|
||||||
}
|
|
||||||
|
|
||||||
for (auto& entry : cfg)
|
|
||||||
{
|
|
||||||
// Where was the last stack.pop() inserted
|
|
||||||
auto lastPopIt = entry.first->begin();
|
|
||||||
|
|
||||||
for (auto phi : entry.second.phisToRewrite)
|
|
||||||
{
|
|
||||||
// Insert stack.pop() before the first use of phi,
|
|
||||||
// then replace all uses of phi with the popped val.
|
|
||||||
|
|
||||||
if (phi->use_begin() == phi->use_end())
|
|
||||||
{
|
|
||||||
// For a phi with no uses, insert pop just after the previous one
|
|
||||||
}
|
|
||||||
std::cout << "*** PHI node " << phi->getName().str() << " has no uses!\n";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
assert(llvm::isa<llvm::Instruction>(phi->use_begin()->getUser()));
|
|
||||||
|
|
||||||
m_builder.SetInsertPoint(*phi->use_begin());
|
|
||||||
auto popVal = stack.popWord();
|
|
||||||
phi->replaceAllUsesWith(popVal);
|
|
||||||
phi->eraseFromParent();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Compiler::dumpBasicBlockGraph(std::ostream& out)
|
void Compiler::dumpBasicBlockGraph(std::ostream& out)
|
||||||
{
|
{
|
||||||
out << "digraph BB {\n"
|
out << "digraph BB {\n"
|
||||||
<< " node [shape=record];\n"
|
<< " node [shape=record, fontname=Courier, fontsize=10];\n"
|
||||||
<< " entry [share=record, label=\"entry block\"];\n";
|
<< " entry [share=record, label=\"entry block\"];\n";
|
||||||
/*
|
|
||||||
std::vector<BasicBlock*> blocks;
|
std::vector<BasicBlock*> blocks;
|
||||||
for (auto& pair : this->basicBlocks)
|
for (auto& pair : basicBlocks)
|
||||||
blocks.push_back(&pair.second);
|
blocks.push_back(&pair.second);
|
||||||
if (m_jumpTableBlock)
|
if (m_jumpTableBlock)
|
||||||
blocks.push_back(m_jumpTableBlock.get());
|
blocks.push_back(m_jumpTableBlock.get());
|
||||||
if (m_badJumpBlock)
|
if (m_badJumpBlock)
|
||||||
blocks.push_back(m_badJumpBlock.get());
|
blocks.push_back(m_badJumpBlock.get());
|
||||||
|
|
||||||
std::map<BasicBlock*,int> phiNodesPerBlock;
|
// std::map<BasicBlock*,int> phiNodesPerBlock;
|
||||||
|
|
||||||
// Output nodes
|
// Output nodes
|
||||||
for (auto bb : blocks)
|
for (auto bb : blocks)
|
||||||
{
|
{
|
||||||
std::string blockName = bb->llvm()->getName();
|
std::string blockName = bb->llvm()->getName();
|
||||||
|
|
||||||
int numOfPhiNodes = 0;
|
std::ostringstream oss;
|
||||||
auto firstNonPhiPtr = bb->llvm()->getFirstNonPHI();
|
bb->dump(oss, true);
|
||||||
for (auto instrIter = bb->llvm()->begin(); &*instrIter != firstNonPhiPtr; ++instrIter, ++numOfPhiNodes);
|
|
||||||
phiNodesPerBlock[bb] = numOfPhiNodes;
|
|
||||||
|
|
||||||
auto initStackSize = bb->getStack().initialSize();
|
out << " \"" << blockName << "\" [shape=record, label=\" { " << blockName << "|" << oss.str() << "} \"];\n";
|
||||||
auto endStackSize = bb->getStack().size();
|
|
||||||
|
|
||||||
out << " \"" << blockName << "\" [shape=record, label=\""
|
|
||||||
<< initStackSize << "|" << blockName << "|" << endStackSize
|
|
||||||
<< "\"];\n";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Output edges
|
// Output edges
|
||||||
|
|
@ -1100,14 +987,21 @@ void Compiler::dumpBasicBlockGraph(std::ostream& out)
|
||||||
{
|
{
|
||||||
out << " \"" << (*it)->getName().str() << "\" -> \"" << blockName << "\" ["
|
out << " \"" << (*it)->getName().str() << "\" -> \"" << blockName << "\" ["
|
||||||
<< ((m_jumpTableBlock.get() && *it == m_jumpTableBlock.get()->llvm()) ? "style = dashed, " : "")
|
<< ((m_jumpTableBlock.get() && *it == m_jumpTableBlock.get()->llvm()) ? "style = dashed, " : "")
|
||||||
<< "label = \""
|
//<< "label = \""
|
||||||
<< phiNodesPerBlock[bb]
|
//<< phiNodesPerBlock[bb]
|
||||||
<< "\"];\n";
|
<< "];\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
out << "}\n";
|
out << "}\n";
|
||||||
*/
|
}
|
||||||
|
|
||||||
|
void Compiler::dump()
|
||||||
|
{
|
||||||
|
for (auto& entry : basicBlocks)
|
||||||
|
entry.second.dump();
|
||||||
|
if (m_jumpTableBlock != nullptr)
|
||||||
|
m_jumpTableBlock->dump();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -33,8 +33,10 @@ private:
|
||||||
|
|
||||||
void compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, class Memory& memory, class Ext& ext, class GasMeter& gasMeter, llvm::BasicBlock* nextBasicBlock);
|
void compileBasicBlock(BasicBlock& basicBlock, bytesConstRef bytecode, class Memory& memory, class Ext& ext, class GasMeter& gasMeter, llvm::BasicBlock* nextBasicBlock);
|
||||||
|
|
||||||
void linkBasicBlocks(); //class Stack& stack);
|
void removeDeadBlocks();
|
||||||
|
|
||||||
|
/// Dump all basic blocks to stderr. Useful in a debugging session.
|
||||||
|
void dump();
|
||||||
|
|
||||||
llvm::IRBuilder<> m_builder;
|
llvm::IRBuilder<> m_builder;
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue