mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
CFG returns vector of blocks instead of assembly items.
This commit is contained in:
parent
85673ff00c
commit
bebe76828a
@ -318,7 +318,10 @@ Assembly& Assembly::optimise(bool _enable)
|
|||||||
copt << "Performing control flow analysis...";
|
copt << "Performing control flow analysis...";
|
||||||
{
|
{
|
||||||
ControlFlowGraph cfg(m_items);
|
ControlFlowGraph cfg(m_items);
|
||||||
AssemblyItems optItems = cfg.optimisedItems();
|
AssemblyItems optItems;
|
||||||
|
for (BasicBlock const& block: cfg.optimisedBlocks())
|
||||||
|
copy(m_items.begin() + block.begin, m_items.begin() + block.end,
|
||||||
|
back_inserter(optItems));
|
||||||
if (optItems.size() < m_items.size())
|
if (optItems.size() < m_items.size())
|
||||||
{
|
{
|
||||||
copt << "Old size: " << m_items.size() << ", new size: " << optItems.size();
|
copt << "Old size: " << m_items.size() << ", new size: " << optItems.size();
|
||||||
|
@ -38,10 +38,10 @@ BlockId::BlockId(u256 const& _id): m_id(_id)
|
|||||||
assertThrow( _id < initial().m_id, OptimizerException, "Tag number too large.");
|
assertThrow( _id < initial().m_id, OptimizerException, "Tag number too large.");
|
||||||
}
|
}
|
||||||
|
|
||||||
AssemblyItems ControlFlowGraph::optimisedItems()
|
BasicBlocks ControlFlowGraph::optimisedBlocks()
|
||||||
{
|
{
|
||||||
if (m_items.empty())
|
if (m_items.empty())
|
||||||
return m_items;
|
return BasicBlocks();
|
||||||
|
|
||||||
findLargestTag();
|
findLargestTag();
|
||||||
splitBlocks();
|
splitBlocks();
|
||||||
@ -216,17 +216,17 @@ void ControlFlowGraph::gatherKnowledge()
|
|||||||
{
|
{
|
||||||
// @todo actually we know that memory is filled with zeros at the beginning,
|
// @todo actually we know that memory is filled with zeros at the beginning,
|
||||||
// we could make use of that.
|
// we could make use of that.
|
||||||
shared_ptr<KnownState> emptyState = make_shared<KnownState>();
|
KnownStatePointer emptyState = make_shared<KnownState>();
|
||||||
ExpressionClasses& expr = emptyState->expressionClasses();
|
ExpressionClasses& expr = emptyState->expressionClasses();
|
||||||
bool unknownJumpEncountered = false;
|
bool unknownJumpEncountered = false;
|
||||||
|
|
||||||
vector<pair<BlockId, shared_ptr<KnownState>>> workQueue({make_pair(BlockId::initial(), emptyState->copy())});
|
vector<pair<BlockId, KnownStatePointer>> workQueue({make_pair(BlockId::initial(), emptyState->copy())});
|
||||||
while (!workQueue.empty())
|
while (!workQueue.empty())
|
||||||
{
|
{
|
||||||
//@todo we might have to do something like incrementing the sequence number for each JUMPDEST
|
//@todo we might have to do something like incrementing the sequence number for each JUMPDEST
|
||||||
assertThrow(!!workQueue.back().first, OptimizerException, "");
|
assertThrow(!!workQueue.back().first, OptimizerException, "");
|
||||||
BasicBlock& block = m_blocks.at(workQueue.back().first);
|
BasicBlock& block = m_blocks.at(workQueue.back().first);
|
||||||
shared_ptr<KnownState> state = workQueue.back().second;
|
KnownStatePointer state = workQueue.back().second;
|
||||||
workQueue.pop_back();
|
workQueue.pop_back();
|
||||||
if (block.startState)
|
if (block.startState)
|
||||||
{
|
{
|
||||||
@ -283,7 +283,7 @@ void ControlFlowGraph::gatherKnowledge()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
AssemblyItems ControlFlowGraph::rebuildCode()
|
BasicBlocks ControlFlowGraph::rebuildCode()
|
||||||
{
|
{
|
||||||
map<BlockId, unsigned> pushes;
|
map<BlockId, unsigned> pushes;
|
||||||
for (auto& idAndBlock: m_blocks)
|
for (auto& idAndBlock: m_blocks)
|
||||||
@ -294,7 +294,7 @@ AssemblyItems ControlFlowGraph::rebuildCode()
|
|||||||
for (auto it: m_blocks)
|
for (auto it: m_blocks)
|
||||||
blocksToAdd.insert(it.first);
|
blocksToAdd.insert(it.first);
|
||||||
set<BlockId> blocksAdded;
|
set<BlockId> blocksAdded;
|
||||||
AssemblyItems code;
|
BasicBlocks blocks;
|
||||||
|
|
||||||
for (
|
for (
|
||||||
BlockId blockId = BlockId::initial();
|
BlockId blockId = BlockId::initial();
|
||||||
@ -311,22 +311,18 @@ AssemblyItems ControlFlowGraph::rebuildCode()
|
|||||||
blocksToAdd.erase(blockId);
|
blocksToAdd.erase(blockId);
|
||||||
blocksAdded.insert(blockId);
|
blocksAdded.insert(blockId);
|
||||||
|
|
||||||
auto begin = m_items.begin() + block.begin;
|
if (block.begin == block.end)
|
||||||
auto end = m_items.begin() + block.end;
|
|
||||||
if (begin == end)
|
|
||||||
continue;
|
continue;
|
||||||
// If block starts with unused tag, skip it.
|
// If block starts with unused tag, skip it.
|
||||||
if (previousHandedOver && !pushes[blockId] && begin->type() == Tag)
|
if (previousHandedOver && !pushes[blockId] && m_items[block.begin].type() == Tag)
|
||||||
{
|
|
||||||
++begin;
|
|
||||||
++block.begin;
|
++block.begin;
|
||||||
}
|
if (block.begin < block.end)
|
||||||
|
blocks.push_back(block);
|
||||||
previousHandedOver = (block.endType == BasicBlock::EndType::HANDOVER);
|
previousHandedOver = (block.endType == BasicBlock::EndType::HANDOVER);
|
||||||
copy(begin, end, back_inserter(code));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return code;
|
return blocks;
|
||||||
}
|
}
|
||||||
|
|
||||||
BlockId ControlFlowGraph::expressionClassToBlockId(
|
BlockId ControlFlowGraph::expressionClassToBlockId(
|
||||||
|
@ -35,6 +35,7 @@ namespace eth
|
|||||||
{
|
{
|
||||||
|
|
||||||
class KnownState;
|
class KnownState;
|
||||||
|
using KnownStatePointer = std::shared_ptr<KnownState>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Identifier for a block, coincides with the tag number of an AssemblyItem but adds a special
|
* Identifier for a block, coincides with the tag number of an AssemblyItem but adds a special
|
||||||
@ -81,19 +82,22 @@ struct BasicBlock
|
|||||||
|
|
||||||
/// Knowledge about the state when this block is entered. Intersection of all possible ways
|
/// Knowledge about the state when this block is entered. Intersection of all possible ways
|
||||||
/// to enter this block.
|
/// to enter this block.
|
||||||
std::shared_ptr<KnownState> startState;
|
KnownStatePointer startState;
|
||||||
/// Knowledge about the state at the end of this block.
|
/// Knowledge about the state at the end of this block.
|
||||||
std::shared_ptr<KnownState> endState;
|
KnownStatePointer endState;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
using BasicBlocks = std::vector<BasicBlock>;
|
||||||
|
|
||||||
class ControlFlowGraph
|
class ControlFlowGraph
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
/// Initializes the control flow graph.
|
/// Initializes the control flow graph.
|
||||||
/// @a _items has to persist across the usage of this class.
|
/// @a _items has to persist across the usage of this class.
|
||||||
ControlFlowGraph(AssemblyItems const& _items): m_items(_items) {}
|
ControlFlowGraph(AssemblyItems const& _items): m_items(_items) {}
|
||||||
/// @returns the collection of optimised items, should be called only once.
|
/// @returns vector of basic blocks in the order they should be used in the final code.
|
||||||
AssemblyItems optimisedItems();
|
/// Should be called only once.
|
||||||
|
BasicBlocks optimisedBlocks();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void findLargestTag();
|
void findLargestTag();
|
||||||
@ -102,7 +106,7 @@ private:
|
|||||||
void removeUnusedBlocks();
|
void removeUnusedBlocks();
|
||||||
void gatherKnowledge();
|
void gatherKnowledge();
|
||||||
void setPrevLinks();
|
void setPrevLinks();
|
||||||
AssemblyItems rebuildCode();
|
BasicBlocks rebuildCode();
|
||||||
|
|
||||||
/// @returns the corresponding BlockId if _id is a pushed jump tag,
|
/// @returns the corresponding BlockId if _id is a pushed jump tag,
|
||||||
/// and an invalid BlockId otherwise.
|
/// and an invalid BlockId otherwise.
|
||||||
|
Loading…
Reference in New Issue
Block a user