| /* |
| * Copyright 2026 WebAssembly Community Group participants |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| // |
| // Utilities for reverse-postorder queue management. |
| // |
| |
| #ifndef cfg_rpo_h |
| #define cfg_rpo_h |
| |
| #include <queue> |
| |
| #include "wasm.h" |
| |
| namespace wasm { |
| |
| // |
| // Given a CFG in reverse postorder (e.g. from cfg-traversal), implement a |
| // priority queue working in reverse postorder. BasicBlock indexes indicate the |
| // block's position in RPO, and by processing the ones with lower indexes first, |
| // we can ensure that we fully process loops and diamonds before proceeding |
| // onward to flow data elsewhere in the CFG. This avoids the wasted work problem |
| // where we have, say, an If, and process one arm, then look at the rest of a |
| // massive function, then process the other If arm, and the entire massive |
| // function must be recomputed. |
| // |
| // The BasicBlock of the CFG must contain two fields: |
| // |
| // bool inQueue; // whether already in the queue |
| // Index index; // basic block index |
| // |
| template<typename CFG, typename Compare = std::greater<Index>> struct RPOQueue { |
| CFG& cfg; |
| |
| RPOQueue(CFG& cfg) : cfg(cfg) { |
| // Initialize the block indexes and queue booleans. |
| auto& basicBlocks = cfg.basicBlocks; |
| for (Index i = 0; i < basicBlocks.size(); ++i) { |
| auto& contents = basicBlocks[i]->contents; |
| contents.inQueue = false; |
| contents.index = i; |
| } |
| } |
| |
| std::priority_queue<Index, std::vector<Index>, Compare> queue; |
| |
| void push(typename CFG::BasicBlock* block) { |
| // Push if not already in the queue. |
| if (!block->contents.inQueue) { |
| block->contents.inQueue = true; |
| queue.push(block->contents.index); |
| } |
| } |
| |
| typename CFG::BasicBlock* pop() { |
| // Pop the top element. |
| auto* block = cfg.basicBlocks[queue.top()].get(); |
| queue.pop(); |
| block->contents.inQueue = false; |
| return block; |
| } |
| |
| bool empty() const { return queue.empty(); } |
| }; |
| |
| // A queue that works in postorder (the reverse of RPO), which is useful when |
| // flowing information backwards through the CFG (such as in liveness analysis). |
| // By processing blocks with higher RPO indexes first, we process successors |
| // before predecessors, and fully process loops and diamonds before flowing data |
| // backwards to earlier blocks in the CFG. |
| template<typename CFG> using POQueue = RPOQueue<CFG, std::less<Index>>; |
| |
| } // namespace wasm |
| |
| #endif // cfg_rpo_h |
| |