mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-21 20:26:41 +00:00
1) JUMP/I semantics updated. 2) Members of BasicBlock::LocalStack pulled out to BasicBlock
This commit is contained in:
parent
c91c5df4f6
commit
9a0f9d3e3c
3 changed files with 102 additions and 114 deletions
|
|
@ -26,38 +26,36 @@ BasicBlock::BasicBlock(ProgramCounter _beginInstIdx, ProgramCounter _endInstIdx,
|
|||
m_beginInstIdx(_beginInstIdx),
|
||||
m_endInstIdx(_endInstIdx),
|
||||
m_llvmBB(llvm::BasicBlock::Create(_mainFunc->getContext(), {NamePrefix, std::to_string(_beginInstIdx)}, _mainFunc)),
|
||||
m_stack(_builder, m_llvmBB)
|
||||
m_stack(*this),
|
||||
m_builder(_builder)
|
||||
{}
|
||||
|
||||
BasicBlock::BasicBlock(std::string _name, llvm::Function* _mainFunc, llvm::IRBuilder<>& _builder) :
|
||||
m_beginInstIdx(0),
|
||||
m_endInstIdx(0),
|
||||
m_llvmBB(llvm::BasicBlock::Create(_mainFunc->getContext(), _name, _mainFunc)),
|
||||
m_stack(_builder, m_llvmBB)
|
||||
m_stack(*this),
|
||||
m_builder(_builder)
|
||||
{}
|
||||
|
||||
BasicBlock::LocalStack::LocalStack(llvm::IRBuilder<>& _builder, llvm::BasicBlock* _llvmBB) :
|
||||
m_llvmBB(_llvmBB),
|
||||
m_builder(_builder),
|
||||
m_initialStack(),
|
||||
m_currentStack(),
|
||||
m_tosOffset(0)
|
||||
BasicBlock::LocalStack::LocalStack(BasicBlock& _owner) :
|
||||
m_bblock(_owner)
|
||||
{}
|
||||
|
||||
void BasicBlock::LocalStack::push(llvm::Value* _value)
|
||||
{
|
||||
m_currentStack.push_back(_value);
|
||||
m_tosOffset += 1;
|
||||
m_bblock.m_currentStack.push_back(_value);
|
||||
m_bblock.m_tosOffset += 1;
|
||||
}
|
||||
|
||||
llvm::Value* BasicBlock::LocalStack::pop()
|
||||
{
|
||||
auto result = get(0);
|
||||
|
||||
if (m_currentStack.size() > 0)
|
||||
m_currentStack.pop_back();
|
||||
if (m_bblock.m_currentStack.size() > 0)
|
||||
m_bblock.m_currentStack.pop_back();
|
||||
|
||||
m_tosOffset -= 1;
|
||||
m_bblock.m_tosOffset -= 1;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
@ -83,7 +81,56 @@ void BasicBlock::LocalStack::swap(size_t _index)
|
|||
set(0, val);
|
||||
}
|
||||
|
||||
void BasicBlock::LocalStack::synchronize(Stack& _evmStack)
|
||||
std::vector<llvm::Value*>::iterator BasicBlock::LocalStack::getItemIterator(size_t _index)
|
||||
{
|
||||
auto& currentStack = m_bblock.m_currentStack;
|
||||
if (_index < currentStack.size())
|
||||
return currentStack.end() - _index - 1;
|
||||
|
||||
// Need to map more elements from the EVM stack
|
||||
auto nNewItems = 1 + _index - currentStack.size();
|
||||
currentStack.insert(currentStack.begin(), nNewItems, nullptr);
|
||||
|
||||
return currentStack.end() - _index - 1;
|
||||
}
|
||||
|
||||
llvm::Value* BasicBlock::LocalStack::get(size_t _index)
|
||||
{
|
||||
auto& initialStack = m_bblock.m_initialStack;
|
||||
auto itemIter = getItemIterator(_index);
|
||||
|
||||
if (*itemIter == nullptr)
|
||||
{
|
||||
// Need to fetch a new item from the EVM stack
|
||||
assert(static_cast<int>(_index) >= m_bblock.m_tosOffset);
|
||||
size_t initialIdx = _index - m_bblock.m_tosOffset;
|
||||
if (initialIdx >= initialStack.size())
|
||||
{
|
||||
auto nNewItems = 1 + initialIdx - initialStack.size();
|
||||
initialStack.insert(initialStack.end(), nNewItems, nullptr);
|
||||
}
|
||||
|
||||
assert(initialStack[initialIdx] == nullptr);
|
||||
// Create a dummy value.
|
||||
std::string name = "get_" + boost::lexical_cast<std::string>(_index);
|
||||
initialStack[initialIdx] = m_bblock.m_builder.CreatePHI(Type::Word, 0, name);
|
||||
*itemIter = initialStack[initialIdx];
|
||||
}
|
||||
|
||||
return *itemIter;
|
||||
}
|
||||
|
||||
void BasicBlock::LocalStack::set(size_t _index, llvm::Value* _word)
|
||||
{
|
||||
auto itemIter = getItemIterator(_index);
|
||||
*itemIter = _word;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void BasicBlock::synchronizeLocalStack(Stack& _evmStack)
|
||||
{
|
||||
auto blockTerminator = m_llvmBB->getTerminator();
|
||||
assert(blockTerminator != nullptr);
|
||||
|
|
@ -141,51 +188,6 @@ void BasicBlock::LocalStack::synchronize(Stack& _evmStack)
|
|||
m_tosOffset = 0;
|
||||
}
|
||||
|
||||
std::vector<llvm::Value*>::iterator BasicBlock::LocalStack::getItemIterator(size_t _index)
|
||||
{
|
||||
if (_index < m_currentStack.size())
|
||||
return m_currentStack.end() - _index - 1;
|
||||
|
||||
// Need to map more elements from the EVM stack
|
||||
auto nNewItems = 1 + _index - m_currentStack.size();
|
||||
m_currentStack.insert(m_currentStack.begin(), nNewItems, nullptr);
|
||||
|
||||
return m_currentStack.end() - _index - 1;
|
||||
}
|
||||
|
||||
llvm::Value* BasicBlock::LocalStack::get(size_t _index)
|
||||
{
|
||||
auto itemIter = getItemIterator(_index);
|
||||
|
||||
if (*itemIter == nullptr)
|
||||
{
|
||||
// Need to fetch a new item from the EVM stack
|
||||
assert(static_cast<int>(_index) >= m_tosOffset);
|
||||
size_t initialIdx = _index - m_tosOffset;
|
||||
if (initialIdx >= m_initialStack.size())
|
||||
{
|
||||
auto nNewItems = 1 + initialIdx - m_initialStack.size();
|
||||
m_initialStack.insert(m_initialStack.end(), nNewItems, nullptr);
|
||||
}
|
||||
|
||||
assert(m_initialStack[initialIdx] == nullptr);
|
||||
// Create a dummy value.
|
||||
std::string name = "get_" + boost::lexical_cast<std::string>(_index);
|
||||
m_initialStack[initialIdx] = m_builder.CreatePHI(Type::Word, 0, name);
|
||||
*itemIter = m_initialStack[initialIdx];
|
||||
}
|
||||
|
||||
return *itemIter;
|
||||
}
|
||||
|
||||
void BasicBlock::LocalStack::set(size_t _index, llvm::Value* _word)
|
||||
{
|
||||
auto itemIter = getItemIterator(_index);
|
||||
*itemIter = _word;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void BasicBlock::linkLocalStacks(std::vector<BasicBlock*> basicBlocks, llvm::IRBuilder<>& _builder)
|
||||
{
|
||||
struct BBInfo
|
||||
|
|
@ -202,14 +204,14 @@ void BasicBlock::linkLocalStacks(std::vector<BasicBlock*> basicBlocks, llvm::IRB
|
|||
inputItems(0),
|
||||
outputItems(0)
|
||||
{
|
||||
auto& initialStack = bblock.localStack().m_initialStack;
|
||||
auto& initialStack = bblock.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;
|
||||
auto& exitStack = bblock.m_currentStack;
|
||||
for (auto it = exitStack.rbegin();
|
||||
it != exitStack.rend() && *it != nullptr;
|
||||
++it, ++outputItems);
|
||||
|
|
@ -281,7 +283,7 @@ void BasicBlock::linkLocalStacks(std::vector<BasicBlock*> basicBlocks, llvm::IRB
|
|||
auto& bblock = info.bblock;
|
||||
|
||||
llvm::BasicBlock::iterator fstNonPhi(bblock.llvm()->getFirstNonPHI());
|
||||
auto phiIter = bblock.localStack().m_initialStack.begin();
|
||||
auto phiIter = bblock.m_initialStack.begin();
|
||||
for (size_t index = 0; index < info.inputItems; ++index, ++phiIter)
|
||||
{
|
||||
assert(llvm::isa<llvm::PHINode>(*phiIter));
|
||||
|
|
@ -289,7 +291,7 @@ void BasicBlock::linkLocalStacks(std::vector<BasicBlock*> basicBlocks, llvm::IRB
|
|||
|
||||
for (auto predIt : info.predecessors)
|
||||
{
|
||||
auto& predExitStack = predIt->bblock.localStack().m_currentStack;
|
||||
auto& predExitStack = predIt->bblock.m_currentStack;
|
||||
auto value = *(predExitStack.end() - 1 - index);
|
||||
phi->addIncoming(value, predIt->bblock.llvm());
|
||||
}
|
||||
|
|
@ -305,10 +307,10 @@ void BasicBlock::linkLocalStacks(std::vector<BasicBlock*> basicBlocks, llvm::IRB
|
|||
|
||||
// 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;
|
||||
auto& initialStack = bblock.m_initialStack;
|
||||
initialStack.erase(initialStack.begin(), initialStack.begin() + info.inputItems);
|
||||
// Initial stack shrinks, so the size difference grows:
|
||||
bblock.localStack().m_tosOffset += info.inputItems;
|
||||
bblock.m_tosOffset += info.inputItems;
|
||||
}
|
||||
|
||||
// We must account for the items that were pushed directly to successor
|
||||
|
|
@ -319,9 +321,9 @@ void BasicBlock::linkLocalStacks(std::vector<BasicBlock*> basicBlocks, llvm::IRB
|
|||
auto& info = entry.second;
|
||||
auto& bblock = info.bblock;
|
||||
|
||||
auto& exitStack = bblock.localStack().m_currentStack;
|
||||
auto& exitStack = bblock.m_currentStack;
|
||||
exitStack.erase(exitStack.end() - info.outputItems, exitStack.end());
|
||||
bblock.localStack().m_tosOffset -= info.outputItems;
|
||||
bblock.m_tosOffset -= info.outputItems;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -335,7 +337,7 @@ 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_initialStack)
|
||||
{
|
||||
if (val == nullptr)
|
||||
out << " ?";
|
||||
|
|
@ -352,11 +354,11 @@ void BasicBlock::dump(std::ostream& _out, bool _dotOutput)
|
|||
out << *ins << (_dotOutput ? "\\l" : "\n");
|
||||
|
||||
if (! _dotOutput)
|
||||
out << "Current stack (offset = " << m_stack.m_tosOffset << "):\n";
|
||||
out << "Current stack (offset = " << m_tosOffset << "):\n";
|
||||
else
|
||||
out << "|";
|
||||
|
||||
for (auto val = m_stack.m_currentStack.rbegin(); val != m_stack.m_currentStack.rend(); ++val)
|
||||
for (auto val = m_currentStack.rbegin(); val != m_currentStack.rend(); ++val)
|
||||
{
|
||||
if (*val == nullptr)
|
||||
out << " ?";
|
||||
|
|
|
|||
|
|
@ -21,7 +21,6 @@ public:
|
|||
class LocalStack
|
||||
{
|
||||
public:
|
||||
|
||||
/// Pushes value on stack
|
||||
void push(llvm::Value* _value);
|
||||
|
||||
|
|
@ -35,12 +34,8 @@ public:
|
|||
/// @param _index Index of value to be swaped. Must be > 0.
|
||||
void swap(size_t _index);
|
||||
|
||||
/// Synchronize current local stack with the EVM stack.
|
||||
void synchronize(Stack& _evmStack);
|
||||
|
||||
private:
|
||||
|
||||
LocalStack(llvm::IRBuilder<>& _builder, llvm::BasicBlock* _llvmBB);
|
||||
LocalStack(BasicBlock& _owner);
|
||||
LocalStack(LocalStack const&) = delete;
|
||||
void operator=(LocalStack const&) = delete;
|
||||
friend BasicBlock;
|
||||
|
|
@ -54,34 +49,7 @@ public:
|
|||
std::vector<llvm::Value*>::iterator getItemIterator(size_t _index);
|
||||
|
||||
private:
|
||||
|
||||
llvm::BasicBlock* 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 current 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;
|
||||
|
||||
/**
|
||||
* How many items higher is the current stack than the initial one.
|
||||
* May be negative.
|
||||
*/
|
||||
int m_tosOffset;
|
||||
|
||||
BasicBlock& m_bblock;
|
||||
};
|
||||
|
||||
/// Basic block name prefix. The rest is beging instruction index.
|
||||
|
|
@ -105,6 +73,9 @@ public:
|
|||
/// to avoid excessive pushing/popping on the EVM stack.
|
||||
static void linkLocalStacks(std::vector<BasicBlock*> _basicBlocks, llvm::IRBuilder<>& _builder);
|
||||
|
||||
/// 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();
|
||||
|
|
@ -113,11 +84,31 @@ public:
|
|||
private:
|
||||
ProgramCounter const m_beginInstIdx;
|
||||
ProgramCounter const m_endInstIdx;
|
||||
|
||||
llvm::BasicBlock* const m_llvmBB;
|
||||
|
||||
/// Basic black state vector (stack) - current/end values and their positions on stack
|
||||
/// @internal Must be AFTER m_llvmBB
|
||||
LocalStack m_stack;
|
||||
|
||||
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 = {};
|
||||
|
||||
/// How many items higher is the current stack than the initial one.
|
||||
/// May be negative.
|
||||
int m_tosOffset = 0;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -81,12 +81,9 @@ void Compiler::createBasicBlocks(bytesConstRef _bytecode)
|
|||
|
||||
case Instruction::JUMPDEST:
|
||||
{
|
||||
// A basic block starts at the next instruction.
|
||||
if (currentPC + 1 < _bytecode.size())
|
||||
{
|
||||
splitPoints.insert(currentPC + 1);
|
||||
indirectJumpTargets.push_back(currentPC + 1);
|
||||
}
|
||||
// A basic block starts here.
|
||||
splitPoints.insert(currentPC);
|
||||
indirectJumpTargets.push_back(currentPC);
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -98,9 +95,7 @@ void Compiler::createBasicBlocks(bytesConstRef _bytecode)
|
|||
{
|
||||
// Create a basic block starting at the following instruction.
|
||||
if (curr + 1 < _bytecode.end())
|
||||
{
|
||||
splitPoints.insert(currentPC + 1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -234,9 +229,9 @@ std::unique_ptr<llvm::Module> Compiler::compile(bytesConstRef _bytecode)
|
|||
}
|
||||
|
||||
for (auto& entry : basicBlocks)
|
||||
entry.second.localStack().synchronize(stack);
|
||||
entry.second.synchronizeLocalStack(stack);
|
||||
if (m_jumpTableBlock)
|
||||
m_jumpTableBlock->localStack().synchronize(stack);
|
||||
m_jumpTableBlock->synchronizeLocalStack(stack);
|
||||
|
||||
dumpCFGifRequired("blocks-sync.dot");
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue