Given the control flow graph, calculates and returns the reverse post-order ordering of the blocks. The blocks are then disassembled in that order for readability.
| 408 | // ordering of the blocks. The blocks are then disassembled in that order for |
| 409 | // readability. |
| 410 | std::vector<uint32_t> OrderBlocks( |
| 411 | ControlFlowGraph& cfg, |
| 412 | const std::unordered_map<uint32_t, uint32_t>& id_to_index) { |
| 413 | std::vector<uint32_t> post_order; |
| 414 | |
| 415 | // Nest level of a function's first block is 0. |
| 416 | cfg.blocks[0].nest_level = 0; |
| 417 | cfg.blocks[0].nest_level_assigned = true; |
| 418 | |
| 419 | // Stack of block indices as they are visited. |
| 420 | std::stack<StackEntry> dfs_stack; |
| 421 | dfs_stack.push({0, false}); |
| 422 | |
| 423 | std::set<uint32_t> visited; |
| 424 | |
| 425 | while (!dfs_stack.empty()) { |
| 426 | const uint32_t block_index = dfs_stack.top().block_index; |
| 427 | const bool post_visit = dfs_stack.top().post_visit; |
| 428 | dfs_stack.pop(); |
| 429 | |
| 430 | // If this is the second time the block is visited, that's the post-order |
| 431 | // visit. |
| 432 | if (post_visit) { |
| 433 | post_order.push_back(block_index); |
| 434 | continue; |
| 435 | } |
| 436 | |
| 437 | // If already visited, another path got to it first (like a case |
| 438 | // fallthrough), avoid reprocessing it. |
| 439 | if (visited.count(block_index) > 0) { |
| 440 | continue; |
| 441 | } |
| 442 | visited.insert(block_index); |
| 443 | |
| 444 | // Push it back in the stack for post-order visit |
| 445 | dfs_stack.push({block_index, true}); |
| 446 | |
| 447 | SingleBlock& block = cfg.blocks[block_index]; |
| 448 | |
| 449 | // Assign nest levels of successors right away. The successors are either |
| 450 | // nested under this block, or are back or forward edges to blocks outside |
| 451 | // this nesting level (no farther than the merge block), whose nesting |
| 452 | // levels are already assigned before this block is visited. |
| 453 | NestSuccessors(cfg, block, id_to_index); |
| 454 | block.reachable = true; |
| 455 | |
| 456 | // The post-order visit yields the order in which the blocks are naturally |
| 457 | // ordered _backwards_. So blocks to be ordered last should be visited |
| 458 | // first. In other words, they should be pushed to the DFS stack last. |
| 459 | VisitSuccesor(&dfs_stack, id_to_index, block.successors.true_block_id); |
| 460 | VisitSuccesor(&dfs_stack, id_to_index, block.successors.false_block_id); |
| 461 | VisitSuccesor(&dfs_stack, id_to_index, block.successors.body_block_id); |
| 462 | VisitSuccesor(&dfs_stack, id_to_index, block.successors.next_block_id); |
| 463 | for (uint32_t case_block_id : block.successors.case_block_ids) { |
| 464 | VisitSuccesor(&dfs_stack, id_to_index, case_block_id); |
| 465 | } |
| 466 | VisitSuccesor(&dfs_stack, id_to_index, block.successors.continue_block_id); |
| 467 | VisitSuccesor(&dfs_stack, id_to_index, block.successors.merge_block_id); |
no test coverage detected