[WebAssembly] Don't stackify multi-def instructions - #200429
Conversation
This commit updates the `WebAssemblyRegStackify.cpp` pass to specifically exclude attempting to stackify the first def of a multi-def instruction. As the previous comments indicate this is possible to do in some situations, but the current logic is incomplete and has led to miscompilations such as llvm#98323 and llvm#199910. One option would be to make the logic more robust, but in lieu of that in the meantime the change here is to completely disable stackification in these situations. This provides at least a "known working" base to build on later and fixes the known regressions around this. Closes llvm#98323 Closes llvm#199910
|
@llvm/pr-subscribers-backend-webassembly Author: Alex Crichton (alexcrichton) ChangesThis commit updates the Closes #98323 Patch is 40.70 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/200429.diff 6 Files Affected:
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyRegStackify.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyRegStackify.cpp
index 9015ceab87fb7..69f66858c20d1 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyRegStackify.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyRegStackify.cpp
@@ -355,38 +355,16 @@ static bool isSafeToMove(const MachineOperand *Def, const MachineOperand *Use,
assert(DefI->getParent() == Insert->getParent());
assert(UseI->getParent() == Insert->getParent());
- // The first def of a multivalue instruction can be stackified by moving,
- // since the later defs can always be placed into locals if necessary. Later
- // defs can only be stackified if all previous defs are already stackified
- // since ExplicitLocals will not know how to place a def in a local if a
- // subsequent def is stackified. But only one def can be stackified by moving
- // the instruction, so it must be the first one.
- //
- // TODO: This could be loosened to be the first *live* def, but care would
- // have to be taken to ensure the drops of the initial dead defs can be
- // placed. This would require checking that no previous defs are used in the
- // same instruction as subsequent defs.
- if (Def != DefI->defs().begin())
+ // For now avoid stackifying any multi-def instructions. While it's
+ // theoretically possible to do so for the first def in some cases this has
+ // historically led to bugs such as #199910 and #98323. For now this
+ // conservatively skips all multi-def instructions as a consequence. Note that
+ // multi-def instructions are expected to be not all that common so this in
+ // theory doesn't have a massive impact, but nevertheless this'd still be
+ // something to optimize better in the future.
+ if (DefI->getNumExplicitDefs() > 1)
return false;
- // If any subsequent def is used prior to the current value by the same
- // instruction in which the current value is used, we cannot
- // stackify. Stackifying in this case would require that def moving below the
- // current def in the stack, which cannot be achieved, even with locals.
- // Also ensure we don't sink the def past any other prior uses.
- for (const auto &SubsequentDef : drop_begin(DefI->defs())) {
- auto I = std::next(MachineBasicBlock::const_iterator(DefI));
- auto E = std::next(MachineBasicBlock::const_iterator(UseI));
- for (; I != E; ++I) {
- for (const auto &PriorUse : I->uses()) {
- if (&PriorUse == Use)
- break;
- if (PriorUse.isReg() && SubsequentDef.getReg() == PriorUse.getReg())
- return false;
- }
- }
- }
-
// If moving is a semantic nop, it is always allowed
const MachineBasicBlock *MBB = DefI->getParent();
auto NextI = std::next(MachineBasicBlock::const_iterator(DefI));
diff --git a/llvm/test/CodeGen/WebAssembly/multivalue-do-not-stackify.ll b/llvm/test/CodeGen/WebAssembly/multivalue-do-not-stackify.ll
new file mode 100644
index 0000000000000..53b36fb3bde0c
--- /dev/null
+++ b/llvm/test/CodeGen/WebAssembly/multivalue-do-not-stackify.ll
@@ -0,0 +1,33 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+
+; RUN: llc < %s -verify-machineinstrs -mattr=+multivalue -target-abi=experimental-mv -O2 | FileCheck %s
+
+target triple = "wasm32-unknown-unknown"
+
+; Regression test for #98323 where attempting to stackify the call to `@foo`
+; historically led to a miscompile.
+
+define i64 @test() {
+; CHECK-LABEL: test:
+; CHECK: .functype test () -> (i64)
+; CHECK-NEXT: .local i64, i64
+; CHECK-NEXT: # %bb.0: # %entry
+; CHECK-NEXT: call foo
+; CHECK-NEXT: local.set 1
+; CHECK-NEXT: local.set 0
+; CHECK-NEXT: i64.const 42
+; CHECK-NEXT: local.get 1
+; CHECK-NEXT: local.get 0
+; CHECK-NEXT: i64.eqz
+; CHECK-NEXT: i64.select
+; CHECK-NEXT: # fallthrough-return
+entry:
+ %pair = call { i64, i64 } @foo()
+ %v0 = extractvalue { i64, i64 } %pair, 0
+ %1 = icmp eq i64 %v0, 0
+ %v1 = extractvalue { i64, i64 } %pair, 1
+ %_0.sroa.0.0 = select i1 %1, i64 42, i64 %v1
+ ret i64 %_0.sroa.0.0
+}
+
+declare { i64, i64 } @foo()
diff --git a/llvm/test/CodeGen/WebAssembly/multivalue-stackify.ll b/llvm/test/CodeGen/WebAssembly/multivalue-stackify.ll
index 0b5a304589aa6..82a8ea739493b 100644
--- a/llvm/test/CodeGen/WebAssembly/multivalue-stackify.ll
+++ b/llvm/test/CodeGen/WebAssembly/multivalue-stackify.ll
@@ -47,9 +47,12 @@ define void @f3() {
define void @f12() {
; CHECK-LABEL: f12:
; CHECK: .functype f12 () -> ()
+; CHECK-NEXT: .local i32
; CHECK-NEXT: # %bb.0:
; CHECK-NEXT: call op_0_to_2
; CHECK-NEXT: drop
+; CHECK-NEXT: local.set 0
+; CHECK-NEXT: local.get 0
; CHECK-NEXT: call op_1_to_0
; CHECK-NEXT: # fallthrough-return
%t0 = call {i32, i32} @op_0_to_2()
@@ -82,7 +85,8 @@ define void @f14() {
; CHECK-NEXT: # %bb.0:
; CHECK-NEXT: call op_0_to_2
; CHECK-NEXT: drop
-; CHECK-NEXT: local.tee 0
+; CHECK-NEXT: local.set 0
+; CHECK-NEXT: local.get 0
; CHECK-NEXT: local.get 0
; CHECK-NEXT: call op_2_to_0
; CHECK-NEXT: # fallthrough-return
@@ -96,8 +100,13 @@ define void @f14() {
define void @f15() {
; CHECK-LABEL: f15:
; CHECK: .functype f15 () -> ()
+; CHECK-NEXT: .local i32, i32
; CHECK-NEXT: # %bb.0:
; CHECK-NEXT: call op_0_to_2
+; CHECK-NEXT: local.set 1
+; CHECK-NEXT: local.set 0
+; CHECK-NEXT: local.get 0
+; CHECK-NEXT: local.get 1
; CHECK-NEXT: call op_2_to_0
; CHECK-NEXT: # fallthrough-return
%t0 = call {i32, i32} @op_0_to_2()
@@ -148,10 +157,13 @@ define void @f17() {
define void @f25() {
; CHECK-LABEL: f25:
; CHECK: .functype f25 () -> ()
+; CHECK-NEXT: .local i32
; CHECK-NEXT: # %bb.0:
; CHECK-NEXT: call op_0_to_3
; CHECK-NEXT: drop
; CHECK-NEXT: drop
+; CHECK-NEXT: local.set 0
+; CHECK-NEXT: local.get 0
; CHECK-NEXT: call op_1_to_0
; CHECK-NEXT: # fallthrough-return
%t0 = call {i32, i32, i32} @op_0_to_3()
@@ -204,7 +216,8 @@ define void @f28() {
; CHECK-NEXT: call op_0_to_3
; CHECK-NEXT: drop
; CHECK-NEXT: drop
-; CHECK-NEXT: local.tee 0
+; CHECK-NEXT: local.set 0
+; CHECK-NEXT: local.get 0
; CHECK-NEXT: local.get 0
; CHECK-NEXT: call op_2_to_0
; CHECK-NEXT: # fallthrough-return
@@ -218,9 +231,14 @@ define void @f28() {
define void @f29() {
; CHECK-LABEL: f29:
; CHECK: .functype f29 () -> ()
+; CHECK-NEXT: .local i32, i32
; CHECK-NEXT: # %bb.0:
; CHECK-NEXT: call op_0_to_3
; CHECK-NEXT: drop
+; CHECK-NEXT: local.set 1
+; CHECK-NEXT: local.set 0
+; CHECK-NEXT: local.get 0
+; CHECK-NEXT: local.get 1
; CHECK-NEXT: call op_2_to_0
; CHECK-NEXT: # fallthrough-return
%t0 = call {i32, i32, i32} @op_0_to_3()
@@ -233,12 +251,14 @@ define void @f29() {
define void @f30() {
; CHECK-LABEL: f30:
; CHECK: .functype f30 () -> ()
-; CHECK-NEXT: .local i32
+; CHECK-NEXT: .local i32, i32
; CHECK-NEXT: # %bb.0:
; CHECK-NEXT: call op_0_to_3
-; CHECK-NEXT: local.set 0
+; CHECK-NEXT: local.set 1
; CHECK-NEXT: drop
+; CHECK-NEXT: local.set 0
; CHECK-NEXT: local.get 0
+; CHECK-NEXT: local.get 1
; CHECK-NEXT: call op_2_to_0
; CHECK-NEXT: # fallthrough-return
%t0 = call {i32, i32, i32} @op_0_to_3()
@@ -371,13 +391,15 @@ define void @f36() {
define void @f129() {
; CHECK-LABEL: f129:
; CHECK: .functype f129 () -> ()
-; CHECK-NEXT: .local i32
+; CHECK-NEXT: .local i32, i32
; CHECK-NEXT: # %bb.0:
; CHECK-NEXT: call op_0_to_2
+; CHECK-NEXT: local.set 1
; CHECK-NEXT: local.set 0
-; CHECK-NEXT: call op_1_to_0
; CHECK-NEXT: local.get 0
; CHECK-NEXT: call op_1_to_0
+; CHECK-NEXT: local.get 1
+; CHECK-NEXT: call op_1_to_0
; CHECK-NEXT: # fallthrough-return
%t0 = call {i32, i32} @op_0_to_2()
%t1 = extractvalue {i32, i32} %t0, 0
@@ -393,11 +415,12 @@ define void @f131() {
; CHECK-NEXT: .local i32, i32
; CHECK-NEXT: # %bb.0:
; CHECK-NEXT: call op_0_to_2
+; CHECK-NEXT: local.set 1
; CHECK-NEXT: local.set 0
-; CHECK-NEXT: local.tee 1
+; CHECK-NEXT: local.get 0
; CHECK-NEXT: call op_1_to_0
-; CHECK-NEXT: local.get 1
; CHECK-NEXT: local.get 0
+; CHECK-NEXT: local.get 1
; CHECK-NEXT: call op_2_to_0
; CHECK-NEXT: # fallthrough-return
%t0 = call {i32, i32} @op_0_to_2()
@@ -415,11 +438,12 @@ define void @f132() {
; CHECK-NEXT: .local i32, i32
; CHECK-NEXT: # %bb.0:
; CHECK-NEXT: call op_0_to_2
+; CHECK-NEXT: local.set 1
; CHECK-NEXT: local.set 0
-; CHECK-NEXT: local.tee 1
-; CHECK-NEXT: call op_1_to_0
; CHECK-NEXT: local.get 0
+; CHECK-NEXT: call op_1_to_0
; CHECK-NEXT: local.get 1
+; CHECK-NEXT: local.get 0
; CHECK-NEXT: call op_2_to_0
; CHECK-NEXT: # fallthrough-return
%t0 = call {i32, i32} @op_0_to_2()
@@ -434,13 +458,15 @@ define void @f132() {
define void @f133() {
; CHECK-LABEL: f133:
; CHECK: .functype f133 () -> ()
-; CHECK-NEXT: .local i32
+; CHECK-NEXT: .local i32, i32
; CHECK-NEXT: # %bb.0:
; CHECK-NEXT: call op_0_to_2
+; CHECK-NEXT: local.set 1
; CHECK-NEXT: local.set 0
-; CHECK-NEXT: call op_1_to_0
-; CHECK-NEXT: local.get 0
; CHECK-NEXT: local.get 0
+; CHECK-NEXT: call op_1_to_0
+; CHECK-NEXT: local.get 1
+; CHECK-NEXT: local.get 1
; CHECK-NEXT: call op_2_to_0
; CHECK-NEXT: # fallthrough-return
%t0 = call {i32, i32} @op_0_to_2()
@@ -548,11 +574,12 @@ define void @f155() {
; CHECK-NEXT: .local i32, i32
; CHECK-NEXT: # %bb.0:
; CHECK-NEXT: call op_0_to_2
+; CHECK-NEXT: local.set 1
; CHECK-NEXT: local.set 0
-; CHECK-NEXT: local.tee 1
-; CHECK-NEXT: local.get 1
-; CHECK-NEXT: call op_2_to_0
; CHECK-NEXT: local.get 0
+; CHECK-NEXT: local.get 0
+; CHECK-NEXT: call op_2_to_0
+; CHECK-NEXT: local.get 1
; CHECK-NEXT: call op_1_to_0
; CHECK-NEXT: # fallthrough-return
%t0 = call {i32, i32} @op_0_to_2()
@@ -570,13 +597,14 @@ define void @f159() {
; CHECK-NEXT: .local i32, i32
; CHECK-NEXT: # %bb.0:
; CHECK-NEXT: call op_0_to_2
+; CHECK-NEXT: local.set 1
; CHECK-NEXT: local.set 0
-; CHECK-NEXT: local.tee 1
-; CHECK-NEXT: local.get 1
-; CHECK-NEXT: call op_2_to_0
; CHECK-NEXT: local.get 0
; CHECK-NEXT: local.get 0
; CHECK-NEXT: call op_2_to_0
+; CHECK-NEXT: local.get 1
+; CHECK-NEXT: local.get 1
+; CHECK-NEXT: call op_2_to_0
; CHECK-NEXT: # fallthrough-return
%t0 = call {i32, i32} @op_0_to_2()
%t1 = extractvalue {i32, i32} %t0, 0
@@ -594,11 +622,12 @@ define void @f167() {
; CHECK-NEXT: .local i32, i32
; CHECK-NEXT: # %bb.0:
; CHECK-NEXT: call op_0_to_2
+; CHECK-NEXT: local.set 1
; CHECK-NEXT: local.set 0
-; CHECK-NEXT: local.tee 1
; CHECK-NEXT: local.get 0
-; CHECK-NEXT: call op_2_to_0
; CHECK-NEXT: local.get 1
+; CHECK-NEXT: call op_2_to_0
+; CHECK-NEXT: local.get 0
; CHECK-NEXT: call op_1_to_0
; CHECK-NEXT: # fallthrough-return
%t0 = call {i32, i32} @op_0_to_2()
@@ -613,13 +642,15 @@ define void @f167() {
define void @f168() {
; CHECK-LABEL: f168:
; CHECK: .functype f168 () -> ()
-; CHECK-NEXT: .local i32
+; CHECK-NEXT: .local i32, i32
; CHECK-NEXT: # %bb.0:
; CHECK-NEXT: call op_0_to_2
+; CHECK-NEXT: local.set 1
; CHECK-NEXT: local.set 0
; CHECK-NEXT: local.get 0
+; CHECK-NEXT: local.get 1
; CHECK-NEXT: call op_2_to_0
-; CHECK-NEXT: local.get 0
+; CHECK-NEXT: local.get 1
; CHECK-NEXT: call op_1_to_0
; CHECK-NEXT: # fallthrough-return
%t0 = call {i32, i32} @op_0_to_2()
@@ -637,12 +668,13 @@ define void @f171() {
; CHECK-NEXT: .local i32, i32
; CHECK-NEXT: # %bb.0:
; CHECK-NEXT: call op_0_to_2
+; CHECK-NEXT: local.set 1
; CHECK-NEXT: local.set 0
-; CHECK-NEXT: local.tee 1
; CHECK-NEXT: local.get 0
+; CHECK-NEXT: local.get 1
; CHECK-NEXT: call op_2_to_0
-; CHECK-NEXT: local.get 0
; CHECK-NEXT: local.get 1
+; CHECK-NEXT: local.get 0
; CHECK-NEXT: call op_2_to_0
; CHECK-NEXT: # fallthrough-return
%t0 = call {i32, i32} @op_0_to_2()
@@ -777,14 +809,16 @@ define void @f195() {
define void @f291() {
; CHECK-LABEL: f291:
; CHECK: .functype f291 () -> ()
-; CHECK-NEXT: .local i32
+; CHECK-NEXT: .local i32, i32
; CHECK-NEXT: # %bb.0:
; CHECK-NEXT: call op_0_to_3
; CHECK-NEXT: drop
+; CHECK-NEXT: local.set 1
; CHECK-NEXT: local.set 0
-; CHECK-NEXT: call op_1_to_0
; CHECK-NEXT: local.get 0
; CHECK-NEXT: call op_1_to_0
+; CHECK-NEXT: local.get 1
+; CHECK-NEXT: call op_1_to_0
; CHECK-NEXT: # fallthrough-return
%t0 = call {i32, i32, i32} @op_0_to_3()
%t1 = extractvalue {i32, i32, i32} %t0, 0
@@ -797,14 +831,16 @@ define void @f291() {
define void @f292() {
; CHECK-LABEL: f292:
; CHECK: .functype f292 () -> ()
-; CHECK-NEXT: .local i32
+; CHECK-NEXT: .local i32, i32
; CHECK-NEXT: # %bb.0:
; CHECK-NEXT: call op_0_to_3
-; CHECK-NEXT: local.set 0
+; CHECK-NEXT: local.set 1
; CHECK-NEXT: drop
-; CHECK-NEXT: call op_1_to_0
+; CHECK-NEXT: local.set 0
; CHECK-NEXT: local.get 0
; CHECK-NEXT: call op_1_to_0
+; CHECK-NEXT: local.get 1
+; CHECK-NEXT: call op_1_to_0
; CHECK-NEXT: # fallthrough-return
%t0 = call {i32, i32, i32} @op_0_to_3()
%t1 = extractvalue {i32, i32, i32} %t0, 0
@@ -821,11 +857,12 @@ define void @f294() {
; CHECK-NEXT: # %bb.0:
; CHECK-NEXT: call op_0_to_3
; CHECK-NEXT: drop
+; CHECK-NEXT: local.set 1
; CHECK-NEXT: local.set 0
-; CHECK-NEXT: local.tee 1
+; CHECK-NEXT: local.get 0
; CHECK-NEXT: call op_1_to_0
-; CHECK-NEXT: local.get 1
; CHECK-NEXT: local.get 0
+; CHECK-NEXT: local.get 1
; CHECK-NEXT: call op_2_to_0
; CHECK-NEXT: # fallthrough-return
%t0 = call {i32, i32, i32} @op_0_to_3()
@@ -843,12 +880,13 @@ define void @f295() {
; CHECK-NEXT: .local i32, i32
; CHECK-NEXT: # %bb.0:
; CHECK-NEXT: call op_0_to_3
-; CHECK-NEXT: local.set 0
+; CHECK-NEXT: local.set 1
; CHECK-NEXT: drop
-; CHECK-NEXT: local.tee 1
+; CHECK-NEXT: local.set 0
+; CHECK-NEXT: local.get 0
; CHECK-NEXT: call op_1_to_0
-; CHECK-NEXT: local.get 1
; CHECK-NEXT: local.get 0
+; CHECK-NEXT: local.get 1
; CHECK-NEXT: call op_2_to_0
; CHECK-NEXT: # fallthrough-return
%t0 = call {i32, i32, i32} @op_0_to_3()
@@ -867,11 +905,12 @@ define void @f296() {
; CHECK-NEXT: # %bb.0:
; CHECK-NEXT: call op_0_to_3
; CHECK-NEXT: drop
+; CHECK-NEXT: local.set 1
; CHECK-NEXT: local.set 0
-; CHECK-NEXT: local.tee 1
-; CHECK-NEXT: call op_1_to_0
; CHECK-NEXT: local.get 0
+; CHECK-NEXT: call op_1_to_0
; CHECK-NEXT: local.get 1
+; CHECK-NEXT: local.get 0
; CHECK-NEXT: call op_2_to_0
; CHECK-NEXT: # fallthrough-return
%t0 = call {i32, i32, i32} @op_0_to_3()
@@ -886,14 +925,16 @@ define void @f296() {
define void @f297() {
; CHECK-LABEL: f297:
; CHECK: .functype f297 () -> ()
-; CHECK-NEXT: .local i32
+; CHECK-NEXT: .local i32, i32
; CHECK-NEXT: # %bb.0:
; CHECK-NEXT: call op_0_to_3
; CHECK-NEXT: drop
+; CHECK-NEXT: local.set 1
; CHECK-NEXT: local.set 0
-; CHECK-NEXT: call op_1_to_0
-; CHECK-NEXT: local.get 0
; CHECK-NEXT: local.get 0
+; CHECK-NEXT: call op_1_to_0
+; CHECK-NEXT: local.get 1
+; CHECK-NEXT: local.get 1
; CHECK-NEXT: call op_2_to_0
; CHECK-NEXT: # fallthrough-return
%t0 = call {i32, i32, i32} @op_0_to_3()
@@ -908,14 +949,16 @@ define void @f297() {
define void @f298() {
; CHECK-LABEL: f298:
; CHECK: .functype f298 () -> ()
-; CHECK-NEXT: .local i32, i32
+; CHECK-NEXT: .local i32, i32, i32
; CHECK-NEXT: # %bb.0:
; CHECK-NEXT: call op_0_to_3
+; CHECK-NEXT: local.set 2
; CHECK-NEXT: local.set 1
; CHECK-NEXT: local.set 0
-; CHECK-NEXT: call op_1_to_0
; CHECK-NEXT: local.get 0
+; CHECK-NEXT: call op_1_to_0
; CHECK-NEXT: local.get 1
+; CHECK-NEXT: local.get 2
; CHECK-NEXT: call op_2_to_0
; CHECK-NEXT: # fallthrough-return
%t0 = call {i32, i32, i32} @op_0_to_3()
@@ -933,12 +976,13 @@ define void @f299() {
; CHECK-NEXT: .local i32, i32
; CHECK-NEXT: # %bb.0:
; CHECK-NEXT: call op_0_to_3
-; CHECK-NEXT: local.set 0
+; CHECK-NEXT: local.set 1
; CHECK-NEXT: drop
-; CHECK-NEXT: local.tee 1
-; CHECK-NEXT: call op_1_to_0
+; CHECK-NEXT: local.set 0
; CHECK-NEXT: local.get 0
+; CHECK-NEXT: call op_1_to_0
; CHECK-NEXT: local.get 1
+; CHECK-NEXT: local.get 0
; CHECK-NEXT: call op_2_to_0
; CHECK-NEXT: # fallthrough-return
%t0 = call {i32, i32, i32} @op_0_to_3()
@@ -953,14 +997,16 @@ define void @f299() {
define void @f300() {
; CHECK-LABEL: f300:
; CHECK: .functype f300 () -> ()
-; CHECK-NEXT: .local i32, i32
+; CHECK-NEXT: .local i32, i32, i32
; CHECK-NEXT: # %bb.0:
; CHECK-NEXT: call op_0_to_3
+; CHECK-NEXT: local.set 2
; CHECK-NEXT: local.set 1
; CHECK-NEXT: local.set 0
+; CHECK-NEXT: local.get 0
; CHECK-NEXT: call op_1_to_0
+; CHECK-NEXT: local.get 2
; CHECK-NEXT: local.get 1
-; CHECK-NEXT: local.get 0
; CHECK-NEXT: call op_2_to_0
; CHECK-NEXT: # fallthrough-return
%t0 = call {i32, i32, i32} @op_0_to_3()
@@ -975,14 +1021,16 @@ define void @f300() {
define void @f301() {
; CHECK-LABEL: f301:
; CHECK: .functype f301 () -> ()
-; CHECK-NEXT: .local i32
+; CHECK-NEXT: .local i32, i32
; CHECK-NEXT: # %bb.0:
; CHECK-NEXT: call op_0_to_3
-; CHECK-NEXT: local.set 0
+; CHECK-NEXT: local.set 1
; CHECK-NEXT: drop
-; CHECK-NEXT: call op_1_to_0
-; CHECK-NEXT: local.get 0
+; CHECK-NEXT: local.set 0
; CHECK-NEXT: local.get 0
+; CHECK-NEXT: call op_1_to_0
+; CHECK-NEXT: local.get 1
+; CHECK-NEXT: local.get 1
; CHECK-NEXT: call op_2_to_0
; CHECK-NEXT: # fallthrough-return
%t0 = call {i32, i32, i32} @op_0_to_3()
@@ -1473,11 +1521,12 @@ define void @f327() {
; CHECK-NEXT: # %bb.0:
; CHECK-NEXT: call op_0_to_3
; CHECK-NEXT: drop
+; CHECK-NEXT: local.set 1
; CHECK-NEXT: local.set 0
-; CHECK-NEXT: local.tee 1
-; CHECK-NEXT: local.get 1
-; CHECK-NEXT: call op_2_to_0
; CHECK-NEXT: local.get 0
+; CHECK-NEXT: local.get 0
+; CHECK-NEXT: call op_2_to_0
+; CHECK-NEXT: local.get 1
; CHECK-NEXT: call op_1_to_0
; CHECK-NEXT: # fallthrough-return
%t0 = call {i32, i32, i32} @op_0_to_3()
@@ -1495,12 +1544,13 @@ define void @f328() {
; CHECK-NEXT: .local i32, i32
; CHECK-NEXT: # %bb.0:
; CHECK-NEXT: call op_0_to_3
-; CHECK-NEXT: local.set 0
+; CHECK-NEXT: local.set 1
; CHECK-NEXT: drop
-; CHECK-NEXT: local.tee 1
-; CHECK-NEXT: local.get 1
-; CHECK-NEXT: call op_2_to_0
+; CHECK-NEXT: local.set 0
+; CHECK-NEXT: local.get 0
; CHECK-NEXT: local.get 0
+; CHECK-NEXT: call op_2_to_0
+; CHECK-NEXT: local.get 1
; CHECK-NEXT: call op_1_to_0
; CHECK-NEXT: # fallthrough-return
%t0 = call {i32, i32, i32} @op_0_to_3()
@@ -1519,13 +1569,14 @@ define void @f333() {
; CHECK-NEXT: # %bb.0:
; CHECK-NEXT: call op_0_to_3
; CHECK-NEXT: drop
+; CHECK-NEXT: local.set 1
; CHECK-NEXT: local.set 0
-; CHECK-NEXT: local.tee 1
-; CHECK-NEXT: local.get 1
-; CHECK-NEXT: call op_2_to_0
; CHECK-NEXT: local.get 0
; CHECK-NEXT: local.get 0
; CHECK-NEXT: call op_2_to_0
+; CHECK-NEXT: local.get 1
+; CHECK-NEXT: local.get 1
+; CHECK-NEXT: call op_2_to_0
; CHECK-NEXT: # fallthrough-return
%t0 = call {i32, i32, i32} @op_0_to_3()
%t1 = extractvalue {i32, i32, i32} %t0, 0
@@ -1543,13 +1594,14 @@ define void @f334() {
; CHECK-NEXT: .local i32, i32, i32
; CHECK-NEXT: # %bb.0:
; CHECK-NEXT: call op_0_to_3
+; CHECK-NEXT: local.set 2
; CHECK-NEXT: local.set 1
; CHECK-NEXT: local.set 0
-; CHECK-NEXT: local.tee 2
-; CHECK-NEXT: local.get 2
-; CHECK-NEXT: call op_2_to_0
; CHECK-NEXT: local.get 0
+; CHECK-NEXT: local.get 0
+; CHECK-NEXT: call op_2_to_0
; CHECK-NEXT: local.get 1
+; CHECK-NEXT: local.get 2
; CHECK-NEXT: call op_2_to_0
; CHECK-NEXT: # fallthrough-return
%t0 = call {i32, i32, i32} @op_0_to_3()
@@ -1568,13 +1620,14 @@ define void @f336() {
; CHECK-NEXT: .local i32, i32, i32...
[truncated]
|
|
@dschuff would you be able to merge this for me? |
|
I got it. |
|
Thanks! |
|
LLVM Buildbot has detected a new failure on builder Full details are available at: https://lab.llvm.org/buildbot/#/builders/228/builds/1332 Here is the relevant piece of the build log for the reference |
|
For future reference, CI treats all warnings as errors. There must be no warnings when compiling. Can you open a patch PR real quick, or would you prefer this reverted for now? |
|
Sorry about that! Posted a fix to #202464 and I don't think I saw this in development since it's a release-only unused variable (I was compiling with assertions on) |
Ah, yeah. I had the same problem once. It's a shame the normal CI doesn't catch that. I guess the CI is already expensive enough. But a compile dry-run to check for would-be warnings in release could be helpful. But I suppose, pretty rare to come across. Not worth burdening every PR. |
Fixes a mistake from llvm#200429.
This commit updates the `WebAssemblyRegStackify.cpp` pass to specifically exclude attempting to stackify the first def of a multi-def instruction. As the previous comments indicate this is possible to do in some situations, but the current logic is incomplete and has led to miscompilations such as llvm#98323 and llvm#199910. One option would be to make the logic more robust, but in lieu of that in the meantime the change here is to completely disable stackification in these situations. This provides at least a "known working" base to build on later and fixes the known regressions around this. Closes llvm#98323 Closes llvm#199910
Fixes a mistake from llvm#200429.
Backport: [WebAssembly] Don't stackify multi-def instructions (llvm#200429)
This commit updates the `WebAssemblyRegStackify.cpp` pass to specifically exclude attempting to stackify the first def of a multi-def instruction. As the previous comments indicate this is possible to do in some situations, but the current logic is incomplete and has led to miscompilations such as llvm#98323 and llvm#199910. One option would be to make the logic more robust, but in lieu of that in the meantime the change here is to completely disable stackification in these situations. This provides at least a "known working" base to build on later and fixes the known regressions around this. Closes llvm#98323 Closes llvm#199910 Backport to LLVM 21.1.2. Adapt the multivalue.ll REGS check to the older WebAssembly register-printer syntax. (cherry picked from commit b472674)
[WebAssembly] Don't stackify multi-def instructions (llvm#200429)
[WebAssembly] Don't stackify multi-def instructions (llvm#200429)
Adds the WebAssemblyRegStackify.cpp change from wasix-org/llvm-project a3d94d9 (backport of llvm/llvm-project#200429) to wasix-llvm.patch. The pass could stackify the first def of a multi-def instruction, which miscompiled overflow checks built on i64.mul_wide_s: the overflow flag came back set for products that fit, e.g. 3 * 7 reporting overflow while returning 21. Reachable from Rust via i64::overflowing_mul when built with -Ctarget-feature=+wide-arithmetic, and from C through __builtin_mul_overflow. Only the source hunk is taken; the commit's test-file updates are left out, matching the rest of this patch. Refs ECO-421, ECO-426. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit updates the
WebAssemblyRegStackify.cpppass to specifically exclude attempting to stackify the first def of a multi-def instruction. As the previous comments indicate this is possible to do in some situations, but the current logic is incomplete and has led to miscompilations such as #98323 and #199910. One option would be to make the logic more robust, but in lieu of that in the meantime the change here is to completely disable stackification in these situations. This provides at least a "known working" base to build on later and fixes the known regressions around this.Closes #98323
Closes #199910