From 4016344d34745221f36f37cf763e057da1dc53b6 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Tue, 22 Sep 2026 16:36:53 -0700 Subject: [PATCH 1/6] work --- src/cfg/rpo.h | 80 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) create mode 100644 src/cfg/rpo.h diff --git a/src/cfg/rpo.h b/src/cfg/rpo.h new file mode 100644 index 00000000000..753cc8fa5c5 --- /dev/null +++ b/src/cfg/rpo.h @@ -0,0 +1,80 @@ +/* + * 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 rpo_h +#define rpo_h + +#include + +#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 +struct RPOQueue : public std::priority_queue, std::greater> { + 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; + } + } + + void push(CFG::BasicBlock* block) { + // Push if ont already in the queue. + if (!block->contents.inQueue) { + block->contents.inQueue = true; + work.push(block->contents.index); + } + } + + CFG::BasicBlock* pop() { + // Pop the smallest element (next in RPO), which is at the top. + auto* block = cfg.basicBlocks[work.top()].get(); + work.pop(); + block->contents.inQueue = false; + return block; + } +}; + +} // namespace wasm + +#endif // rpo_h + +// TODO: use in moar passes From 14a127dcbeb5ff384aff444b231db2e00867299c Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Tue, 22 Sep 2026 16:37:07 -0700 Subject: [PATCH 2/6] format --- src/cfg/rpo.h | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/src/cfg/rpo.h b/src/cfg/rpo.h index 753cc8fa5c5..098f88d8d34 100644 --- a/src/cfg/rpo.h +++ b/src/cfg/rpo.h @@ -28,14 +28,14 @@ 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. +// 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: // @@ -43,9 +43,10 @@ namespace wasm { // Index index; // basic block index // template -struct RPOQueue : public std::priority_queue, std::greater> { +struct RPOQueue + : public std::priority_queue, std::greater> { CFG& cfg; - + RPOQueue(CFG& cfg) : cfg(cfg) { // Initialize the block indexes and queue booleans. auto& basicBlocks = cfg.basicBlocks; From 145b445692cad604c8b372a72e711a31cb6ce73b Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Tue, 22 Sep 2026 16:44:21 -0700 Subject: [PATCH 3/6] yolo --- src/cfg/rpo.h | 15 ++++++++++----- src/passes/ConstraintAnalysis.cpp | 7 ++++++- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/src/cfg/rpo.h b/src/cfg/rpo.h index 098f88d8d34..baa7e59f03b 100644 --- a/src/cfg/rpo.h +++ b/src/cfg/rpo.h @@ -43,8 +43,7 @@ namespace wasm { // Index index; // basic block index // template -struct RPOQueue - : public std::priority_queue, std::greater> { +struct RPOQueue { CFG& cfg; RPOQueue(CFG& cfg) : cfg(cfg) { @@ -57,21 +56,27 @@ struct RPOQueue } } + std::priority_queue, std::greater> queue; + void push(CFG::BasicBlock* block) { // Push if ont already in the queue. if (!block->contents.inQueue) { block->contents.inQueue = true; - work.push(block->contents.index); + queue.push(block->contents.index); } } CFG::BasicBlock* pop() { // Pop the smallest element (next in RPO), which is at the top. - auto* block = cfg.basicBlocks[work.top()].get(); - work.pop(); + auto* block = cfg.basicBlocks[queue.top()].get(); + queue.pop(); block->contents.inQueue = false; return block; } + + bool empty() const { + return queue.empty(); + } }; } // namespace wasm diff --git a/src/passes/ConstraintAnalysis.cpp b/src/passes/ConstraintAnalysis.cpp index 9e275665e9e..091e46b3657 100644 --- a/src/passes/ConstraintAnalysis.cpp +++ b/src/passes/ConstraintAnalysis.cpp @@ -69,6 +69,7 @@ #include #include "cfg/cfg-traversal.h" +#include "cfg/rpo.h" #include "ir/constraint.h" #include "ir/drop.h" #include "ir/eh-utils.h" @@ -96,6 +97,10 @@ namespace { // Information in a basic block. struct Info { + // For RPOQueue + bool inQueue; + Index index; + // All relevant operations: local gets and sets and uses of them. std::vector actions; @@ -337,7 +342,7 @@ struct ConstraintAnalysis } // Starting from the entry, keep going while we find something new. - UniqueDeferredQueue work; + RPOQueue work(*this); work.push(entry); while (!work.empty()) { From 182f8b34d8e67af02c2db63008c40797c881afce Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Tue, 22 Sep 2026 16:44:27 -0700 Subject: [PATCH 4/6] yolo --- src/cfg/rpo.h | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/cfg/rpo.h b/src/cfg/rpo.h index baa7e59f03b..54efa71f33d 100644 --- a/src/cfg/rpo.h +++ b/src/cfg/rpo.h @@ -42,8 +42,7 @@ namespace wasm { // bool inQueue; // whether already in the queue // Index index; // basic block index // -template -struct RPOQueue { +template struct RPOQueue { CFG& cfg; RPOQueue(CFG& cfg) : cfg(cfg) { @@ -74,9 +73,7 @@ struct RPOQueue { return block; } - bool empty() const { - return queue.empty(); - } + bool empty() const { return queue.empty(); } }; } // namespace wasm From 086afa5b77d6e91cf5b15e3a82970d81240d80ff Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Wed, 23 Sep 2026 10:54:57 -0700 Subject: [PATCH 5/6] typo --- src/cfg/rpo.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cfg/rpo.h b/src/cfg/rpo.h index 54efa71f33d..809c5d39685 100644 --- a/src/cfg/rpo.h +++ b/src/cfg/rpo.h @@ -58,7 +58,7 @@ template struct RPOQueue { std::priority_queue, std::greater> queue; void push(CFG::BasicBlock* block) { - // Push if ont already in the queue. + // Push if not already in the queue. if (!block->contents.inQueue) { block->contents.inQueue = true; queue.push(block->contents.index); From e780f9d974e4627d2ce1316c6aeecbd38c134e3f Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Wed, 23 Sep 2026 17:04:38 -0700 Subject: [PATCH 6/6] feedback --- src/cfg/rpo.h | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/cfg/rpo.h b/src/cfg/rpo.h index 809c5d39685..f99f5543ac3 100644 --- a/src/cfg/rpo.h +++ b/src/cfg/rpo.h @@ -18,8 +18,8 @@ // Utilities for reverse-postorder queue management. // -#ifndef rpo_h -#define rpo_h +#ifndef cfg_rpo_h +#define cfg_rpo_h #include @@ -78,6 +78,5 @@ template struct RPOQueue { } // namespace wasm -#endif // rpo_h +#endif // cfg_rpo_h -// TODO: use in moar passes