| 233 | } |
| 234 | |
| 235 | std::unordered_map<uint32_t, uint32_t> BuildControlFlowGraph( |
| 236 | ControlFlowGraph& cfg) { |
| 237 | std::unordered_map<uint32_t, uint32_t> id_to_index; |
| 238 | |
| 239 | for (size_t index = 0; index < cfg.blocks.size(); ++index) { |
| 240 | SingleBlock& block = cfg.blocks[index]; |
| 241 | |
| 242 | // For future use, build the ID->index map |
| 243 | assert(static_cast<spv::Op>(block.instructions[0].get()->opcode) == |
| 244 | spv::Op::OpLabel); |
| 245 | const uint32_t id = block.instructions[0].get()->result_id; |
| 246 | |
| 247 | id_to_index[id] = static_cast<uint32_t>(index); |
| 248 | |
| 249 | // Look for a merge instruction first. The function of OpBranch depends on |
| 250 | // that. |
| 251 | if (block.instructions.size() >= 3) { |
| 252 | const spv_parsed_instruction_t* maybe_merge = |
| 253 | block.instructions[block.instructions.size() - 2].get(); |
| 254 | |
| 255 | switch (static_cast<spv::Op>(maybe_merge->opcode)) { |
| 256 | case spv::Op::OpLoopMerge: |
| 257 | block.successors.merge_block_id = GetOperand(maybe_merge, 0); |
| 258 | block.successors.continue_block_id = GetOperand(maybe_merge, 1); |
| 259 | break; |
| 260 | |
| 261 | case spv::Op::OpSelectionMerge: |
| 262 | block.successors.merge_block_id = GetOperand(maybe_merge, 0); |
| 263 | break; |
| 264 | |
| 265 | default: |
| 266 | break; |
| 267 | } |
| 268 | } |
| 269 | |
| 270 | // Then look at the last instruction; it must be a branch |
| 271 | assert(block.instructions.size() >= 2); |
| 272 | |
| 273 | const spv_parsed_instruction_t* branch = block.instructions.back().get(); |
| 274 | switch (static_cast<spv::Op>(branch->opcode)) { |
| 275 | case spv::Op::OpBranch: |
| 276 | if (block.successors.merge_block_id != 0) { |
| 277 | block.successors.body_block_id = GetOperand(branch, 0); |
| 278 | } else { |
| 279 | block.successors.next_block_id = GetOperand(branch, 0); |
| 280 | } |
| 281 | break; |
| 282 | |
| 283 | case spv::Op::OpBranchConditional: |
| 284 | block.successors.true_block_id = GetOperand(branch, 1); |
| 285 | block.successors.false_block_id = GetOperand(branch, 2); |
| 286 | break; |
| 287 | |
| 288 | case spv::Op::OpSwitch: |
| 289 | for (uint32_t case_index = 1; case_index < branch->num_operands; |
| 290 | case_index += 2) { |
| 291 | block.successors.case_block_ids.push_back( |
| 292 | GetOperand(branch, case_index)); |