blob: b1a6cf3d7cf0f8e4f6d2c705ec97848293d2d027 [file]
/*
* 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