[llvm] [WebAssembly] Fix nondeterminism by using MapVector for pointer-keyed maps [NFC] (PR #205184)

Derek Schuff via llvm-commits llvm-commits at lists.llvm.org
Tue Jun 23 09:31:40 PDT 2026


https://github.com/dschuff updated https://github.com/llvm/llvm-project/pull/205184

>From 9bea55d106ef7ffc1902a9268b03c0f45031784b Mon Sep 17 00:00:00 2001
From: Derek Schuff <dschuff at chromium.org>
Date: Mon, 22 Jun 2026 19:53:10 +0000
Subject: [PATCH 1/4] [WebAssembly] Fix nondeterminism by using MapVector for
 pointer-keyed maps [NFC]

Several DenseMaps in the WebAssembly backend keyed by pointers were being
iterated over, potentially leading to nondeterministiccodegen (differing
try/delegate nesting, virtual register allocation, or PHI node insertion)
due to nondeterministsic pointer values.

This patch replaces these DenseMaps with MapVectors to guarantee
deterministic iteration order: - UnwindDestToTryRanges in
WebAssemblyCFGStackify.cpp - EHPadToUnwindDest in
WebAssemblyCFGStackify.cpp - EHPadToRethrows in
WebAssemblyLateEHPrepare.cpp - UnwindDestToNewPreds in
WebAssemblyLowerEmscriptenEHSjLj.cpp

Fixes: #204883

Assisted-by: Antigravity
---
 llvm/lib/Target/WebAssembly/WebAssemblyCFGStackify.cpp       | 5 +++--
 llvm/lib/Target/WebAssembly/WebAssemblyLateEHPrepare.cpp     | 3 ++-
 .../Target/WebAssembly/WebAssemblyLowerEmscriptenEHSjLj.cpp  | 3 ++-
 3 files changed, 7 insertions(+), 4 deletions(-)

diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyCFGStackify.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyCFGStackify.cpp
index 7d39e1074b026..f69c73b111891 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyCFGStackify.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyCFGStackify.cpp
@@ -29,6 +29,7 @@
 #include "WebAssemblySubtarget.h"
 #include "WebAssemblyTargetMachine.h"
 #include "WebAssemblyUtilities.h"
+#include "llvm/ADT/MapVector.h"
 #include "llvm/ADT/Statistic.h"
 #include "llvm/BinaryFormat/Wasm.h"
 #include "llvm/CodeGen/MachineDominators.h"
@@ -1837,7 +1838,7 @@ bool WebAssemblyCFGStackify::fixCallUnwindMismatches(MachineFunction &MF) {
   // multiple BBs.
   using TryRange = std::pair<MachineInstr *, MachineInstr *>;
   // In original CFG, <unwind destination BB, a vector of try/try_table ranges>
-  DenseMap<MachineBasicBlock *, SmallVector<TryRange, 4>> UnwindDestToTryRanges;
+  MapVector<MachineBasicBlock *, SmallVector<TryRange, 4>> UnwindDestToTryRanges;
 
   // Gather possibly throwing calls (i.e., previously invokes) whose current
   // unwind destination is not the same as the original CFG. (Case 1)
@@ -2203,7 +2204,7 @@ bool WebAssemblyCFGStackify::fixCatchUnwindMismatches(MachineFunction &MF) {
   SmallVector<const MachineBasicBlock *, 8> EHPadStack;
   // For EH pads that have catch unwind mismatches, a map of <EH pad, its
   // correct unwind destination>.
-  DenseMap<MachineBasicBlock *, MachineBasicBlock *> EHPadToUnwindDest;
+  MapVector<MachineBasicBlock *, MachineBasicBlock *> EHPadToUnwindDest;
 
   for (auto &MBB : reverse(MF)) {
     for (auto &MI : reverse(MBB)) {
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyLateEHPrepare.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyLateEHPrepare.cpp
index 548624e26d869..5e05aa1a1f6e9 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyLateEHPrepare.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyLateEHPrepare.cpp
@@ -15,6 +15,7 @@
 #include "WebAssemblySubtarget.h"
 #include "WebAssemblyTargetMachine.h"
 #include "WebAssemblyUtilities.h"
+#include "llvm/ADT/MapVector.h"
 #include "llvm/ADT/SmallPtrSet.h"
 #include "llvm/CodeGen/MachineFunctionPass.h"
 #include "llvm/CodeGen/MachineInstrBuilder.h"
@@ -297,7 +298,7 @@ bool WebAssemblyLateEHPrepare::replaceFuncletReturns(MachineFunction &MF) {
 bool WebAssemblyLateEHPrepare::addCatchRefsAndThrowRefs(MachineFunction &MF) {
   const auto &TII = *MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo();
   auto &MRI = MF.getRegInfo();
-  DenseMap<MachineBasicBlock *, SmallVector<MachineInstr *, 2>> EHPadToRethrows;
+  MapVector<MachineBasicBlock *, SmallVector<MachineInstr *, 2>> EHPadToRethrows;
 
   // Create a map of <EH pad, a vector of RETHROWs rethrowing its exception>
   for (auto &MBB : MF)
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenEHSjLj.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenEHSjLj.cpp
index 51b71ba646b42..dd75e226509e2 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenEHSjLj.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenEHSjLj.cpp
@@ -263,6 +263,7 @@
 
 #include "WebAssembly.h"
 #include "WebAssemblyTargetMachine.h"
+#include "llvm/ADT/MapVector.h"
 #include "llvm/ADT/StringExtras.h"
 #include "llvm/CodeGen/TargetPassConfig.h"
 #include "llvm/CodeGen/WasmEHInfo.h"
@@ -1745,7 +1746,7 @@ void WebAssemblyLowerEmscriptenEHSjLj::handleLongjmpableCallsForWasmSjLj(
     }
   }
 
-  SmallDenseMap<BasicBlock *, SmallSetVector<BasicBlock *, 4>, 4>
+  MapVector<BasicBlock *, SmallSetVector<BasicBlock *, 4>>
       UnwindDestToNewPreds;
   for (auto *CI : LongjmpableCalls) {
     // Even if the callee function has attribute 'nounwind', which is true for

>From e77a07a2db812d9ab63c7fbd5919974f538a291f Mon Sep 17 00:00:00 2001
From: Derek Schuff <dschuff at chromium.org>
Date: Mon, 22 Jun 2026 21:33:17 +0000
Subject: [PATCH 2/4] clang-format

---
 llvm/lib/Target/WebAssembly/WebAssemblyCFGStackify.cpp         | 3 ++-
 llvm/lib/Target/WebAssembly/WebAssemblyLateEHPrepare.cpp       | 3 ++-
 .../Target/WebAssembly/WebAssemblyLowerEmscriptenEHSjLj.cpp    | 3 +--
 3 files changed, 5 insertions(+), 4 deletions(-)

diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyCFGStackify.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyCFGStackify.cpp
index f69c73b111891..7e12b0861116e 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyCFGStackify.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyCFGStackify.cpp
@@ -1838,7 +1838,8 @@ bool WebAssemblyCFGStackify::fixCallUnwindMismatches(MachineFunction &MF) {
   // multiple BBs.
   using TryRange = std::pair<MachineInstr *, MachineInstr *>;
   // In original CFG, <unwind destination BB, a vector of try/try_table ranges>
-  MapVector<MachineBasicBlock *, SmallVector<TryRange, 4>> UnwindDestToTryRanges;
+  MapVector<MachineBasicBlock *, SmallVector<TryRange, 4>>
+      UnwindDestToTryRanges;
 
   // Gather possibly throwing calls (i.e., previously invokes) whose current
   // unwind destination is not the same as the original CFG. (Case 1)
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyLateEHPrepare.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyLateEHPrepare.cpp
index 5e05aa1a1f6e9..56f74dce630df 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyLateEHPrepare.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyLateEHPrepare.cpp
@@ -298,7 +298,8 @@ bool WebAssemblyLateEHPrepare::replaceFuncletReturns(MachineFunction &MF) {
 bool WebAssemblyLateEHPrepare::addCatchRefsAndThrowRefs(MachineFunction &MF) {
   const auto &TII = *MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo();
   auto &MRI = MF.getRegInfo();
-  MapVector<MachineBasicBlock *, SmallVector<MachineInstr *, 2>> EHPadToRethrows;
+  MapVector<MachineBasicBlock *, SmallVector<MachineInstr *, 2>>
+      EHPadToRethrows;
 
   // Create a map of <EH pad, a vector of RETHROWs rethrowing its exception>
   for (auto &MBB : MF)
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenEHSjLj.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenEHSjLj.cpp
index dd75e226509e2..e294ae7025af6 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenEHSjLj.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenEHSjLj.cpp
@@ -1746,8 +1746,7 @@ void WebAssemblyLowerEmscriptenEHSjLj::handleLongjmpableCallsForWasmSjLj(
     }
   }
 
-  MapVector<BasicBlock *, SmallSetVector<BasicBlock *, 4>>
-      UnwindDestToNewPreds;
+  MapVector<BasicBlock *, SmallSetVector<BasicBlock *, 4>> UnwindDestToNewPreds;
   for (auto *CI : LongjmpableCalls) {
     // Even if the callee function has attribute 'nounwind', which is true for
     // all C functions, it can longjmp, which means it can throw a Wasm

>From 7385b669ba0e79b7275db32da227b8842aade793 Mon Sep 17 00:00:00 2001
From: Derek Schuff <dschuff at chromium.org>
Date: Mon, 22 Jun 2026 21:54:12 +0000
Subject: [PATCH 3/4] use SmallMapVector

---
 .../lib/Target/WebAssembly/WebAssemblyLowerEmscriptenEHSjLj.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenEHSjLj.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenEHSjLj.cpp
index e294ae7025af6..9a2f658091946 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenEHSjLj.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenEHSjLj.cpp
@@ -1746,7 +1746,7 @@ void WebAssemblyLowerEmscriptenEHSjLj::handleLongjmpableCallsForWasmSjLj(
     }
   }
 
-  MapVector<BasicBlock *, SmallSetVector<BasicBlock *, 4>> UnwindDestToNewPreds;
+  SmallMapVector<BasicBlock *, SmallSetVector<BasicBlock *, 4>, 4> UnwindDestToNewPreds;
   for (auto *CI : LongjmpableCalls) {
     // Even if the callee function has attribute 'nounwind', which is true for
     // all C functions, it can longjmp, which means it can throw a Wasm

>From a3c491b9ce3e6a16a01b704078da6bb72decbde7 Mon Sep 17 00:00:00 2001
From: Derek Schuff <dschuff at chromium.org>
Date: Tue, 23 Jun 2026 16:31:25 +0000
Subject: [PATCH 4/4] format

---
 .../Target/WebAssembly/WebAssemblyLowerEmscriptenEHSjLj.cpp    | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenEHSjLj.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenEHSjLj.cpp
index 9a2f658091946..8c5917fab90a2 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenEHSjLj.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenEHSjLj.cpp
@@ -1746,7 +1746,8 @@ void WebAssemblyLowerEmscriptenEHSjLj::handleLongjmpableCallsForWasmSjLj(
     }
   }
 
-  SmallMapVector<BasicBlock *, SmallSetVector<BasicBlock *, 4>, 4> UnwindDestToNewPreds;
+  SmallMapVector<BasicBlock *, SmallSetVector<BasicBlock *, 4>, 4>
+      UnwindDestToNewPreds;
   for (auto *CI : LongjmpableCalls) {
     // Even if the callee function has attribute 'nounwind', which is true for
     // all C functions, it can longjmp, which means it can throw a Wasm



More information about the llvm-commits mailing list