@@ -47,22 +47,14 @@ using namespace solidity;
47
47
using namespace solidity ::yul;
48
48
using namespace std ;
49
49
50
- std::unique_ptr<CFG> ControlFlowGraphBuilder::build (
51
- AsmAnalysisInfo const & _analysisInfo,
52
- Dialect const & _dialect,
53
- Block const & _block
54
- )
50
+ namespace
51
+ {
52
+ // Removes edges to blocks that are not reachable.
53
+ void cleanUnreachable (CFG& _cfg)
55
54
{
56
- auto result = std::make_unique<CFG>();
57
- result->entry = &result->makeBlock ();
58
-
59
- ControlFlowGraphBuilder builder (*result, _analysisInfo, _dialect);
60
- builder.m_currentBlock = result->entry ;
61
- builder (_block);
62
-
63
55
// Determine which blocks are reachable from the entry.
64
- util::BreadthFirstSearch<CFG::BasicBlock*> reachabilityCheck{{result-> entry }};
65
- for (auto const & functionInfo: result-> functionInfo | ranges::views::values)
56
+ util::BreadthFirstSearch<CFG::BasicBlock*> reachabilityCheck{{_cfg. entry }};
57
+ for (auto const & functionInfo: _cfg. functionInfo | ranges::views::values)
66
58
reachabilityCheck.verticesToTraverse .emplace_back (functionInfo.entry );
67
59
68
60
reachabilityCheck.run ([&](CFG::BasicBlock* _node, auto && _addChild) {
@@ -85,6 +77,71 @@ std::unique_ptr<CFG> ControlFlowGraphBuilder::build(
85
77
cxx20::erase_if (node->entries , [&](CFG::BasicBlock* entry) -> bool {
86
78
return !reachabilityCheck.visited .count (entry);
87
79
});
80
+ }
81
+ // Sets the ``recursive`` member to ``true`` for all recursive function calls.
82
+ void markRecursiveCalls (CFG& _cfg)
83
+ {
84
+ map<CFG::BasicBlock*, vector<CFG::FunctionCall*>> callsPerBlock;
85
+ auto const & findCalls = [&](CFG::BasicBlock* _block)
86
+ {
87
+ if (auto * calls = util::valueOrNullptr (callsPerBlock, _block))
88
+ return *calls;
89
+ vector<CFG::FunctionCall*>& calls = callsPerBlock[_block];
90
+ util::BreadthFirstSearch<CFG::BasicBlock*>{{_block}}.run ([&](CFG::BasicBlock* _block, auto _addChild) {
91
+ for (auto & operation: _block->operations )
92
+ if (auto * functionCall = get_if<CFG::FunctionCall>(&operation.operation ))
93
+ calls.emplace_back (functionCall);
94
+ std::visit (util::GenericVisitor{
95
+ [&](CFG::BasicBlock::MainExit const &) {},
96
+ [&](CFG::BasicBlock::Jump const & _jump)
97
+ {
98
+ _addChild (_jump.target );
99
+ },
100
+ [&](CFG::BasicBlock::ConditionalJump const & _conditionalJump)
101
+ {
102
+ _addChild (_conditionalJump.zero );
103
+ _addChild (_conditionalJump.nonZero );
104
+ },
105
+ [&](CFG::BasicBlock::FunctionReturn const &) {},
106
+ [&](CFG::BasicBlock::Terminated const &) {},
107
+ }, _block->exit );
108
+ });
109
+ return calls;
110
+ };
111
+ for (auto & functionInfo: _cfg.functionInfo | ranges::views::values)
112
+ for (CFG::FunctionCall* call: findCalls (functionInfo.entry ))
113
+ {
114
+ util::BreadthFirstSearch<CFG::FunctionCall*> breadthFirstSearch{{call}};
115
+ breadthFirstSearch.run ([&](CFG::FunctionCall* _call, auto _addChild) {
116
+ auto & calledFunctionInfo = _cfg.functionInfo .at (&_call->function .get ());
117
+ if (&calledFunctionInfo == &functionInfo)
118
+ {
119
+ call->recursive = true ;
120
+ breadthFirstSearch.abort ();
121
+ return ;
122
+ }
123
+ for (CFG::FunctionCall* nestedCall: findCalls (_cfg.functionInfo .at (&_call->function .get ()).entry ))
124
+ _addChild (nestedCall);
125
+ });
126
+ }
127
+ }
128
+ }
129
+
130
+ std::unique_ptr<CFG> ControlFlowGraphBuilder::build (
131
+ AsmAnalysisInfo const & _analysisInfo,
132
+ Dialect const & _dialect,
133
+ Block const & _block
134
+ )
135
+ {
136
+ auto result = std::make_unique<CFG>();
137
+ result->entry = &result->makeBlock ();
138
+
139
+ ControlFlowGraphBuilder builder (*result, _analysisInfo, _dialect);
140
+ builder.m_currentBlock = result->entry ;
141
+ builder (_block);
142
+
143
+ cleanUnreachable (*result);
144
+ markRecursiveCalls (*result);
88
145
89
146
// TODO: It might be worthwhile to run some further simplifications on the graph itself here.
90
147
// E.g. if there is a jump to a node that has the jumping node as its only entry, the nodes can be fused, etc.
0 commit comments