Sets the ``recursive`` member to ``true`` for all recursive function calls.
| 101 | |
| 102 | /// Sets the ``recursive`` member to ``true`` for all recursive function calls. |
| 103 | void markRecursiveCalls(CFG& _cfg) |
| 104 | { |
| 105 | std::map<CFG::BasicBlock*, std::vector<CFG::FunctionCall*>> callsPerBlock; |
| 106 | auto const& findCalls = [&](CFG::BasicBlock* _block) |
| 107 | { |
| 108 | if (auto* calls = util::valueOrNullptr(callsPerBlock, _block)) |
| 109 | return *calls; |
| 110 | std::vector<CFG::FunctionCall*>& calls = callsPerBlock[_block]; |
| 111 | util::BreadthFirstSearch<CFG::BasicBlock*>{{_block}}.run([&](CFG::BasicBlock* _block, auto _addChild) { |
| 112 | for (auto& operation: _block->operations) |
| 113 | if (auto* functionCall = std::get_if<CFG::FunctionCall>(&operation.operation)) |
| 114 | calls.emplace_back(functionCall); |
| 115 | std::visit(util::GenericVisitor{ |
| 116 | [&](CFG::BasicBlock::MainExit const&) {}, |
| 117 | [&](CFG::BasicBlock::Jump const& _jump) |
| 118 | { |
| 119 | _addChild(_jump.target); |
| 120 | }, |
| 121 | [&](CFG::BasicBlock::ConditionalJump const& _conditionalJump) |
| 122 | { |
| 123 | _addChild(_conditionalJump.zero); |
| 124 | _addChild(_conditionalJump.nonZero); |
| 125 | }, |
| 126 | [&](CFG::BasicBlock::FunctionReturn const&) {}, |
| 127 | [&](CFG::BasicBlock::Terminated const&) {}, |
| 128 | }, _block->exit); |
| 129 | }); |
| 130 | return calls; |
| 131 | }; |
| 132 | for (auto& functionInfo: _cfg.functionInfo | ranges::views::values) |
| 133 | for (CFG::FunctionCall* call: findCalls(functionInfo.entry)) |
| 134 | { |
| 135 | util::BreadthFirstSearch<CFG::FunctionCall*> breadthFirstSearch{{call}}; |
| 136 | breadthFirstSearch.run([&](CFG::FunctionCall* _call, auto _addChild) { |
| 137 | auto& calledFunctionInfo = _cfg.functionInfo.at(&_call->function.get()); |
| 138 | if (&calledFunctionInfo == &functionInfo) |
| 139 | { |
| 140 | call->recursive = true; |
| 141 | breadthFirstSearch.abort(); |
| 142 | return; |
| 143 | } |
| 144 | for (CFG::FunctionCall* nestedCall: findCalls(_cfg.functionInfo.at(&_call->function.get()).entry)) |
| 145 | _addChild(nestedCall); |
| 146 | }); |
| 147 | } |
| 148 | } |
| 149 | |
| 150 | /// Marks each cut-vertex in the CFG, i.e. each block that begins a disconnected sub-graph of the CFG. |
| 151 | /// Entering such a block means that control flow will never return to a previously visited block. |