| 108 | |
| 109 | private: |
| 110 | void printBlock(CFG::BasicBlock const& _block) |
| 111 | { |
| 112 | m_stream << "Block" << getBlockId(_block) << " [label=\"\\\n"; |
| 113 | |
| 114 | // Verify that the entries of this block exit into this block. |
| 115 | for (auto const& entry: _block.entries) |
| 116 | std::visit(util::GenericVisitor{ |
| 117 | [&](CFG::BasicBlock::Jump const& _jump) |
| 118 | { |
| 119 | soltestAssert(_jump.target == &_block, "Invalid control flow graph."); |
| 120 | }, |
| 121 | [&](CFG::BasicBlock::ConditionalJump const& _conditionalJump) |
| 122 | { |
| 123 | soltestAssert( |
| 124 | _conditionalJump.zero == &_block || _conditionalJump.nonZero == &_block, |
| 125 | "Invalid control flow graph." |
| 126 | ); |
| 127 | }, |
| 128 | [&](auto const&) |
| 129 | { |
| 130 | soltestAssert(false, "Invalid control flow graph."); |
| 131 | } |
| 132 | }, entry->exit); |
| 133 | |
| 134 | for (auto const& operation: _block.operations) |
| 135 | { |
| 136 | std::visit(util::GenericVisitor{ |
| 137 | [&](CFG::FunctionCall const& _call) { |
| 138 | m_stream << _call.function.get().name.str() << ": "; |
| 139 | }, |
| 140 | [&](CFG::BuiltinCall const& _call) { |
| 141 | m_stream << _call.builtin.get().name << ": "; |
| 142 | }, |
| 143 | [&](CFG::Assignment const& _assignment) { |
| 144 | m_stream << "Assignment("; |
| 145 | m_stream << joinHumanReadable(_assignment.variables | ranges::views::transform(variableSlotToString)); |
| 146 | m_stream << "): "; |
| 147 | } |
| 148 | }, operation.operation); |
| 149 | m_stream << stackToString(operation.input, m_dialect) << " => " << stackToString(operation.output, m_dialect) << "\\l\\\n"; |
| 150 | } |
| 151 | m_stream << "\"];\n"; |
| 152 | std::visit(util::GenericVisitor{ |
| 153 | [&](CFG::BasicBlock::MainExit const&) |
| 154 | { |
| 155 | m_stream << "Block" << getBlockId(_block) << "Exit [label=\"MainExit\"];\n"; |
| 156 | m_stream << "Block" << getBlockId(_block) << " -> Block" << getBlockId(_block) << "Exit;\n"; |
| 157 | }, |
| 158 | [&](CFG::BasicBlock::Jump const& _jump) |
| 159 | { |
| 160 | m_stream << "Block" << getBlockId(_block) << " -> Block" << getBlockId(_block) << "Exit [arrowhead=none];\n"; |
| 161 | m_stream << "Block" << getBlockId(_block) << "Exit [label=\""; |
| 162 | if (_jump.backwards) |
| 163 | m_stream << "Backwards"; |
| 164 | m_stream << "Jump\" shape=oval];\n"; |
| 165 | m_stream << "Block" << getBlockId(_block) << "Exit -> Block" << getBlockId(*_jump.target) << ";\n"; |
| 166 | }, |
| 167 | [&](CFG::BasicBlock::ConditionalJump const& _conditionalJump) |
nothing calls this directly
no test coverage detected