@ -53,13 +53,16 @@ void LocalStack::push(llvm::Value* _value)
llvm : : Value * LocalStack : : pop ( )
llvm : : Value * LocalStack : : pop ( )
{
{
auto result = get ( 0 ) ;
auto item = get ( 0 ) ;
assert ( ! m_bblock . m_currentStack . empty ( ) | | ! m_bblock . m_initialStack . empty ( ) ) ;
if ( m_bblock . m_currentStack . size ( ) > 0 )
if ( m_bblock . m_currentStack . size ( ) > 0 )
m_bblock . m_currentStack . pop_back ( ) ;
m_bblock . m_currentStack . pop_back ( ) ;
else
+ + m_bblock . m_globalPops ;
m_bblock . m_tosOffset - = 1 ;
m_bblock . m_tosOffset - = 1 ;
return result ;
return item ;
}
}
/**
/**
@ -84,109 +87,71 @@ void LocalStack::swap(size_t _index)
set ( 0 , val ) ;
set ( 0 , val ) ;
}
}
std : : vector < llvm : : Value * > : : iterator LocalStack : : getItemIterator ( size_t _index )
llvm : : Value * LocalStack : : get ( size_t _index )
{
{
auto & currentStack = m_bblock . m_currentStack ;
auto & currentStack = m_bblock . m_currentStack ;
if ( _index < currentStack . size ( ) )
if ( _index < currentStack . size ( ) )
return currentStack . end ( ) - _index - 1 ;
return * ( currentStack . rb egi n( ) + _index ) ; // count from back
// 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 * LocalStack : : get ( size_t _index )
{
auto & initialStack = m_bblock . m_initialStack ;
auto & initialStack = m_bblock . m_initialStack ;
auto itemIter = getItemIterator ( _index ) ;
auto idx = _index - currentStack . size ( ) + m_bblock . m_globalPops ;
if ( idx > = initialStack . size ( ) )
initialStack . resize ( idx + 1 ) ;
auto & item = initialStack [ idx ] ;
if ( * itemIter = = nullptr )
if ( ! item )
{
item = m_global . get ( idx ) ;
// 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 ) ;
return item ;
// Create a dummy value.
std : : string name = " get_ " + std : : to_string ( _index ) ;
initialStack [ initialIdx ] = m_bblock . m_builder . CreatePHI ( Type : : Word , 0 , std : : move ( name ) ) ;
* itemIter = initialStack [ initialIdx ] ;
}
return * itemIter ;
}
}
void LocalStack : : set ( size_t _index , llvm : : Value * _word )
void LocalStack : : set ( size_t _index , llvm : : Value * _word )
{
{
auto itemIter = getItemIterator ( _index ) ;
auto & currentStack = m_bblock . m_currentStack ;
* itemIter = _word ;
if ( _index < currentStack . size ( ) )
}
{
* ( 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 ;
}
void BasicBlock : : synchronizeLocalStack ( Stack & _evmStack )
void BasicBlock : : synchronizeLocalStack ( Stack & _evmStack )
{
{
auto blockTerminator = m_llvmBB - > getTerminator ( ) ;
auto blockTerminator = m_llvmBB - > getTerminator ( ) ;
assert ( blockTerminator ! = nullptr ) ;
assert ( blockTerminator ) ;
if ( blockTerminator - > getOpcode ( ) ! = llvm : : Instruction : : Ret )
if ( blockTerminator - > getOpcode ( ) ! = llvm : : Instruction : : Ret )
{
{
// Not needed in case of ret instruction. Ret also invalidates the stack.
// Not needed in case of ret instruction. Ret invalidates the stack.
m_builder . SetInsertPoint ( blockTerminator ) ;
m_builder . SetInsertPoint ( blockTerminator ) ;
auto currIter = m_currentStack . begin ( ) ;
// Update items fetched from global stack ignoring the poped ones
auto endIter = m_currentStack . end ( ) ;
assert ( m_globalPops < = m_initialStack . size ( ) ) ; // pop() always does get()
for ( auto i = m_globalPops ; i < m_initialStack . size ( ) ; + + i )
// Update (emit set()) changed values
for ( int idx = ( int ) m_currentStack . size ( ) - 1 - m_tosOffset ;
currIter < endIter & & idx > = 0 ;
+ + currIter , - - idx )
{
{
assert ( static_cast < size_t > ( idx ) < m_initialStack . size ( ) ) ;
if ( m_initialStack [ i ] )
if ( * currIter ! = m_initialStack [ idx ] ) // value needs update
_evmStack . set ( i , m_initialStack [ i ] ) ;
_evmStack . set ( static_cast < size_t > ( idx ) , * currIter ) ;
}
}
// Pop values
// Add new items
if ( m_tosOffset < 0 )
for ( auto & item : m_currentStack )
_evmStack . pop ( static_cast < size_t > ( - m_tosOffset ) ) ;
// Push new values
for ( ; currIter < endIter ; + + currIter )
{
{
assert ( * currIter ! = nullptr ) ;
if ( m_globalPops ) // Override poped global items
_evmStack . push ( * currIter ) ;
_evmStack . set ( - - m_globalPops , item ) ; // using pops counter as the index
else
_evmStack . push ( item ) ;
}
}
}
// Emit get() for all (used) values from the initial stack
// Pop not overriden items
for ( size_t idx = 0 ; idx < m_initialStack . size ( ) ; + + idx )
if ( m_globalPops )
{
_evmStack . pop ( m_globalPops ) ;
auto val = m_initialStack [ idx ] ;
if ( val = = nullptr )
continue ;
llvm : : PHINode * phi = llvm : : cast < llvm : : PHINode > ( val ) ;
// Insert call to get() just before the PHI node and replace
// the uses of PHI with the uses of this new instruction.
m_builder . SetInsertPoint ( phi ) ;
auto newVal = _evmStack . get ( idx ) ; // OPT: Value may be never user but we need to check stack heigth
// It is probably a good idea to keep heigth as a local variable accesible by LLVM directly
phi - > replaceAllUsesWith ( newVal ) ;
phi - > eraseFromParent ( ) ;
}
}
// Reset the stack
m_initialStack . erase ( m_initialStack . begin ( ) , m_initialStack . end ( ) ) ;
m_currentStack . erase ( m_currentStack . begin ( ) , m_currentStack . end ( ) ) ;
m_tosOffset = 0 ;
m_tosOffset = 0 ;
}
}
@ -211,8 +176,6 @@ void BasicBlock::linkLocalStacks(std::vector<BasicBlock*> basicBlocks, llvm::IRB
it ! = initialStack . end ( ) & & * it ! = nullptr ;
it ! = initialStack . end ( ) & & * it ! = nullptr ;
+ + it , + + inputItems ) ;
+ + it , + + inputItems ) ;
//if (bblock.localStack().m_tosOffset > 0)
// outputItems = bblock.localStack().m_tosOffset;
auto & exitStack = bblock . m_currentStack ;
auto & exitStack = bblock . m_currentStack ;
for ( auto it = exitStack . rbegin ( ) ;
for ( auto it = exitStack . rbegin ( ) ;
it ! = exitStack . rend ( ) & & * it ! = nullptr ;
it ! = exitStack . rend ( ) & & * it ! = nullptr ;