mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Attempt to split up the main algorithm a bit.
This commit is contained in:
parent
1fd4cf2254
commit
a756ec3e0e
@ -239,51 +239,60 @@ Stack StackLayoutGenerator::propagateStackThroughBlock(Stack _exitStack, CFG::Ba
|
|||||||
return stack;
|
return stack;
|
||||||
}
|
}
|
||||||
|
|
||||||
void StackLayoutGenerator::processEntryPoint(CFG::BasicBlock const& _entry)
|
list<pair<CFG::BasicBlock const*, CFG::BasicBlock const*>> StackLayoutGenerator::collectBackwardsJumps(CFG::BasicBlock const& _entry) const
|
||||||
{
|
{
|
||||||
std::list<CFG::BasicBlock const*> toVisit{&_entry};
|
list<pair<CFG::BasicBlock const*, CFG::BasicBlock const*>> backwardsJumps;
|
||||||
std::set<CFG::BasicBlock const*> visited;
|
util::BreadthFirstSearch<CFG::BasicBlock const*>{{&_entry}}.run([&](CFG::BasicBlock const* _block, auto _addChild) {
|
||||||
|
std::visit(util::GenericVisitor{
|
||||||
while (!toVisit.empty())
|
[&](CFG::BasicBlock::MainExit const&) {},
|
||||||
|
[&](CFG::BasicBlock::Jump const& _jump)
|
||||||
{
|
{
|
||||||
// TODO: calculate backwardsJumps only once.
|
if (_jump.backwards)
|
||||||
std::list<std::pair<CFG::BasicBlock const*, CFG::BasicBlock const*>> backwardsJumps;
|
backwardsJumps.emplace_back(_block, _jump.target);
|
||||||
while (!toVisit.empty())
|
_addChild(_jump.target);
|
||||||
|
},
|
||||||
|
[&](CFG::BasicBlock::ConditionalJump const& _conditionalJump)
|
||||||
{
|
{
|
||||||
CFG::BasicBlock const *block = *toVisit.begin();
|
_addChild(_conditionalJump.zero);
|
||||||
toVisit.pop_front();
|
_addChild(_conditionalJump.nonZero);
|
||||||
|
},
|
||||||
|
[&](CFG::BasicBlock::FunctionReturn const&) {},
|
||||||
|
[&](CFG::BasicBlock::Terminated const&) {},
|
||||||
|
}, _block->exit);
|
||||||
|
});
|
||||||
|
return backwardsJumps;
|
||||||
|
}
|
||||||
|
|
||||||
if (visited.count(block))
|
optional<Stack> StackLayoutGenerator::getExitLayoutOrStageDependencies(
|
||||||
continue;
|
CFG::BasicBlock const& _block,
|
||||||
|
set<CFG::BasicBlock const*> const& _blocksWithExitLayout,
|
||||||
if (std::optional<Stack> exitLayout = std::visit(util::GenericVisitor{
|
list<CFG::BasicBlock const*>& _toVisit
|
||||||
|
) const
|
||||||
|
{
|
||||||
|
return std::visit(util::GenericVisitor{
|
||||||
[&](CFG::BasicBlock::MainExit const&) -> std::optional<Stack>
|
[&](CFG::BasicBlock::MainExit const&) -> std::optional<Stack>
|
||||||
{
|
{
|
||||||
visited.emplace(block);
|
|
||||||
return Stack{};
|
return Stack{};
|
||||||
},
|
},
|
||||||
[&](CFG::BasicBlock::Jump const& _jump) -> std::optional<Stack>
|
[&](CFG::BasicBlock::Jump const& _jump) -> std::optional<Stack>
|
||||||
{
|
{
|
||||||
if (_jump.backwards)
|
if (_jump.backwards)
|
||||||
{
|
{
|
||||||
visited.emplace(block);
|
|
||||||
backwardsJumps.emplace_back(block, _jump.target);
|
|
||||||
if (auto* info = util::valueOrNullptr(m_layout.blockInfos, _jump.target))
|
if (auto* info = util::valueOrNullptr(m_layout.blockInfos, _jump.target))
|
||||||
return info->entryLayout;
|
return info->entryLayout;
|
||||||
return Stack{};
|
return Stack{};
|
||||||
}
|
}
|
||||||
if (visited.count(_jump.target))
|
if (_blocksWithExitLayout.count(_jump.target))
|
||||||
{
|
{
|
||||||
visited.emplace(block);
|
|
||||||
return m_layout.blockInfos.at(_jump.target).entryLayout;
|
return m_layout.blockInfos.at(_jump.target).entryLayout;
|
||||||
}
|
}
|
||||||
toVisit.emplace_front(_jump.target);
|
_toVisit.emplace_front(_jump.target);
|
||||||
return nullopt;
|
return nullopt;
|
||||||
},
|
},
|
||||||
[&](CFG::BasicBlock::ConditionalJump const& _conditionalJump) -> std::optional<Stack>
|
[&](CFG::BasicBlock::ConditionalJump const& _conditionalJump) -> std::optional<Stack>
|
||||||
{
|
{
|
||||||
bool zeroVisited = visited.count(_conditionalJump.zero);
|
bool zeroVisited = _blocksWithExitLayout.count(_conditionalJump.zero);
|
||||||
bool nonZeroVisited = visited.count(_conditionalJump.nonZero);
|
bool nonZeroVisited = _blocksWithExitLayout.count(_conditionalJump.nonZero);
|
||||||
if (zeroVisited && nonZeroVisited)
|
if (zeroVisited && nonZeroVisited)
|
||||||
{
|
{
|
||||||
Stack stack = combineStack(
|
Stack stack = combineStack(
|
||||||
@ -291,18 +300,16 @@ void StackLayoutGenerator::processEntryPoint(CFG::BasicBlock const& _entry)
|
|||||||
m_layout.blockInfos.at(_conditionalJump.nonZero).entryLayout
|
m_layout.blockInfos.at(_conditionalJump.nonZero).entryLayout
|
||||||
);
|
);
|
||||||
stack.emplace_back(_conditionalJump.condition);
|
stack.emplace_back(_conditionalJump.condition);
|
||||||
visited.emplace(block);
|
|
||||||
return stack;
|
return stack;
|
||||||
}
|
}
|
||||||
if (!zeroVisited)
|
if (!zeroVisited)
|
||||||
toVisit.emplace_front(_conditionalJump.zero);
|
_toVisit.emplace_front(_conditionalJump.zero);
|
||||||
if (!nonZeroVisited)
|
if (!nonZeroVisited)
|
||||||
toVisit.emplace_front(_conditionalJump.nonZero);
|
_toVisit.emplace_front(_conditionalJump.nonZero);
|
||||||
return nullopt;
|
return nullopt;
|
||||||
},
|
},
|
||||||
[&](CFG::BasicBlock::FunctionReturn const& _functionReturn) -> std::optional<Stack>
|
[&](CFG::BasicBlock::FunctionReturn const& _functionReturn) -> std::optional<Stack>
|
||||||
{
|
{
|
||||||
visited.emplace(block);
|
|
||||||
yulAssert(_functionReturn.info, "");
|
yulAssert(_functionReturn.info, "");
|
||||||
Stack stack = _functionReturn.info->returnVariables | ranges::views::transform([](auto const& _varSlot){
|
Stack stack = _functionReturn.info->returnVariables | ranges::views::transform([](auto const& _varSlot){
|
||||||
return StackSlot{_varSlot};
|
return StackSlot{_varSlot};
|
||||||
@ -312,11 +319,34 @@ void StackLayoutGenerator::processEntryPoint(CFG::BasicBlock const& _entry)
|
|||||||
},
|
},
|
||||||
[&](CFG::BasicBlock::Terminated const&) -> std::optional<Stack>
|
[&](CFG::BasicBlock::Terminated const&) -> std::optional<Stack>
|
||||||
{
|
{
|
||||||
visited.emplace(block);
|
|
||||||
return Stack{};
|
return Stack{};
|
||||||
},
|
},
|
||||||
}, block->exit))
|
}, _block.exit);
|
||||||
|
}
|
||||||
|
|
||||||
|
void StackLayoutGenerator::processEntryPoint(CFG::BasicBlock const& _entry)
|
||||||
{
|
{
|
||||||
|
list<CFG::BasicBlock const*> toVisit{&_entry};
|
||||||
|
set<CFG::BasicBlock const*> visited;
|
||||||
|
|
||||||
|
// TODO: check whether visiting only a subset of these in the outer iteration below is enough.
|
||||||
|
list<pair<CFG::BasicBlock const*, CFG::BasicBlock const*>> backwardsJumps = collectBackwardsJumps(_entry);
|
||||||
|
|
||||||
|
while (!toVisit.empty())
|
||||||
|
{
|
||||||
|
// First calculate stack layouts without walking backwards jumps, i.e. assuming the current preliminary
|
||||||
|
// entry layout of the backwards jump target as the initial exit layout of the backwards-jumping block.
|
||||||
|
while (!toVisit.empty())
|
||||||
|
{
|
||||||
|
CFG::BasicBlock const *block = *toVisit.begin();
|
||||||
|
toVisit.pop_front();
|
||||||
|
|
||||||
|
if (visited.count(block))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (std::optional<Stack> exitLayout = getExitLayoutOrStageDependencies(*block, visited, toVisit))
|
||||||
|
{
|
||||||
|
visited.emplace(block);
|
||||||
// We can skip the visit, if we have seen this precise exit layout already last time.
|
// We can skip the visit, if we have seen this precise exit layout already last time.
|
||||||
// Note: if the entire graph is revisited in the backwards jump check below, doing
|
// Note: if the entire graph is revisited in the backwards jump check below, doing
|
||||||
// this seems to break things; not sure why.
|
// this seems to break things; not sure why.
|
||||||
@ -336,6 +366,7 @@ void StackLayoutGenerator::processEntryPoint(CFG::BasicBlock const& _entry)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Determine which backwards jumps still require fixing and stage revisits of appropriate nodes.
|
||||||
for (auto [block, target]: backwardsJumps)
|
for (auto [block, target]: backwardsJumps)
|
||||||
if (ranges::any_of(
|
if (ranges::any_of(
|
||||||
m_layout.blockInfos[target].entryLayout,
|
m_layout.blockInfos[target].entryLayout,
|
||||||
|
@ -64,6 +64,14 @@ private:
|
|||||||
/// Iteratively reruns itself along backwards jumps until the layout is stabilized.
|
/// Iteratively reruns itself along backwards jumps until the layout is stabilized.
|
||||||
void processEntryPoint(CFG::BasicBlock const& _entry);
|
void processEntryPoint(CFG::BasicBlock const& _entry);
|
||||||
|
|
||||||
|
std::optional<Stack> getExitLayoutOrStageDependencies(
|
||||||
|
CFG::BasicBlock const& _block,
|
||||||
|
std::set<CFG::BasicBlock const*> const& _blocksWithExitLayouts,
|
||||||
|
std::list<CFG::BasicBlock const*>& _dependencyList
|
||||||
|
) const;
|
||||||
|
|
||||||
|
std::list<std::pair<CFG::BasicBlock const*, CFG::BasicBlock const*>> collectBackwardsJumps(CFG::BasicBlock const& _entry) const;
|
||||||
|
|
||||||
/// After the main algorithms, layouts at conditional jumps are merely compatible, i.e. the exit layout of the
|
/// After the main algorithms, layouts at conditional jumps are merely compatible, i.e. the exit layout of the
|
||||||
/// jumping block is a superset of the entry layout of the target block. This function modifies the entry layouts
|
/// jumping block is a superset of the entry layout of the target block. This function modifies the entry layouts
|
||||||
/// of conditional jump targets, s.t. the entry layout of target blocks match the exit layout of the jumping block
|
/// of conditional jump targets, s.t. the entry layout of target blocks match the exit layout of the jumping block
|
||||||
|
Loading…
Reference in New Issue
Block a user