Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 10 additions & 7 deletions src/cfg/liveness-traversal.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@

#include "cfg-traversal.h"
#include "ir/utils.h"
#include "rpo.h"
#include "support/sorted_vector.h"
#include "support/sparse_square_matrix.h"
#include "wasm-builder.h"
Expand Down Expand Up @@ -82,6 +83,10 @@ struct LivenessAction {

// information about liveness in a basic block
struct Liveness {
// For POQueue
bool inQueue;
Index index;

SetOfLocals start, end; // live locals at the start and end
std::vector<LivenessAction> actions; // actions occurring in this block

Expand Down Expand Up @@ -220,23 +225,21 @@ struct LivenessWalker : public CFGWalker<SubType, VisitorType, Liveness> {

void flowLiveness() {
// keep working while stuff is flowing
std::unordered_set<BasicBlock*> queue;
POQueue<LivenessWalker<SubType, VisitorType>> queue(*this);
for (auto& curr : CFGWalker<SubType, VisitorType, Liveness>::basicBlocks) {
if (!liveBlocks.contains(curr.get())) {
continue; // ignore dead blocks
}
queue.insert(curr.get());
queue.push(curr.get());
// do the first scan through the block, starting with nothing live at the
// end, and updating the liveness at the start
scanLivenessThroughActions(curr->contents.actions, curr->contents.start);
}
// at every point in time, we assume we already noted interferences between
// things already known alive at the end, and scanned back through the block
// using that
while (queue.size() > 0) {
auto iter = queue.begin();
auto* curr = *iter;
queue.erase(iter);
while (!queue.empty()) {
auto* curr = queue.pop();
SetOfLocals live;
if (!mergeStartsAndCheckChange(curr->out, curr->contents.end, live)) {
continue;
Expand All @@ -252,7 +255,7 @@ struct LivenessWalker : public CFGWalker<SubType, VisitorType, Liveness> {
assert(curr->contents.start.size() < live.size());
curr->contents.start = live;
for (auto* in : curr->in) {
queue.insert(in);
queue.push(in);
}
}
}
Expand Down
17 changes: 12 additions & 5 deletions src/cfg/rpo.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ namespace wasm {
// bool inQueue; // whether already in the queue
// Index index; // basic block index
//
template<typename CFG> struct RPOQueue {
template<typename CFG, typename Compare = std::greater<Index>> struct RPOQueue {
CFG& cfg;

RPOQueue(CFG& cfg) : cfg(cfg) {
Expand All @@ -55,18 +55,18 @@ template<typename CFG> struct RPOQueue {
}
}

std::priority_queue<Index, std::vector<Index>, std::greater<Index>> queue;
std::priority_queue<Index, std::vector<Index>, Compare> queue;

void push(CFG::BasicBlock* block) {
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);
}
}

CFG::BasicBlock* pop() {
// Pop the smallest element (next in RPO), which is at the top.
typename CFG::BasicBlock* pop() {
// Pop the top element.
auto* block = cfg.basicBlocks[queue.top()].get();
queue.pop();
block->contents.inQueue = false;
Expand All @@ -76,6 +76,13 @@ template<typename CFG> struct RPOQueue {
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>>;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can't not read this as "program-order queue," which is exactly wrong 😢

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could write this out as PostOrderQueue, though ReversePostOrderQueue is clunky...

Another option is RRPOQueue 😉

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, it's ok as-is. I'll just have to deal with it.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, landing for now, but I'm happy to rename later to PostOrderQueue if you find this annoying.


} // namespace wasm

#endif // cfg_rpo_h
Expand Down
Loading