diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyRegStackify.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyRegStackify.cpp index bc91c6424b63e..7f2eb7d9b7fd8 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyRegStackify.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyRegStackify.cpp @@ -339,38 +339,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 ; 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: local.get 0 +; CHECK-NEXT: local.get 0 ; CHECK-NEXT: call op_2_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() @@ -1593,14 +1646,15 @@ define void @f337() { ; 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: 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 @@ -1619,11 +1673,12 @@ define void @f338() { ; 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_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, i32} @op_0_to_3() @@ -1638,14 +1693,16 @@ define void @f338() { define void @f339() { ; CHECK-LABEL: f339: ; CHECK: .functype f339 () -> () -; 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: 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, i32} @op_0_to_3() @@ -1660,12 +1717,16 @@ define void @f339() { define void @f340() { ; CHECK-LABEL: f340: ; CHECK: .functype f340 () -> () -; CHECK-NEXT: .local 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_2_to_0 ; CHECK-NEXT: local.get 0 +; CHECK-NEXT: local.get 1 +; CHECK-NEXT: call op_2_to_0 +; CHECK-NEXT: local.get 2 ; CHECK-NEXT: call op_1_to_0 ; CHECK-NEXT: # fallthrough-return %t0 = call {i32, i32, i32} @op_0_to_3() @@ -1683,13 +1744,14 @@ define void @f343() { ; 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 0 +; CHECK-NEXT: local.get 1 ; CHECK-NEXT: call op_2_to_0 +; CHECK-NEXT: local.get 0 ; CHECK-NEXT: local.get 2 -; 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() @@ -1709,12 +1771,13 @@ define void @f344() { ; 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: 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, i32} @op_0_to_3() @@ -1730,15 +1793,17 @@ define void @f344() { define void @f346() { ; CHECK-LABEL: f346: ; CHECK: .functype f346 () -> () -; 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: local.get 1 ; CHECK-NEXT: call op_2_to_0 -; CHECK-NEXT: local.get 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() @@ -1757,13 +1822,14 @@ define void @f347() { ; 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 0 -; CHECK-NEXT: call op_2_to_0 ; CHECK-NEXT: local.get 1 +; CHECK-NEXT: call op_2_to_0 ; CHECK-NEXT: local.get 2 +; 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() @@ -1779,15 +1845,17 @@ define void @f347() { define void @f348() { ; CHECK-LABEL: f348: ; CHECK: .functype f348 () -> () -; 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: local.get 1 ; CHECK-NEXT: call op_2_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() @@ -1803,13 +1871,17 @@ define void @f348() { define void @f349() { ; CHECK-LABEL: f349: ; CHECK: .functype f349 () -> () -; CHECK-NEXT: .local 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_2_to_0 -; CHECK-NEXT: local.get 0 ; CHECK-NEXT: local.get 0 +; CHECK-NEXT: local.get 1 +; CHECK-NEXT: call op_2_to_0 +; CHECK-NEXT: local.get 2 +; 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() @@ -1828,12 +1900,13 @@ define void @f350() { ; 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_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, i32} @op_0_to_3() @@ -1848,14 +1921,16 @@ define void @f350() { define void @f351() { ; CHECK-LABEL: f351: ; CHECK: .functype f351 () -> () -; 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 1 -; CHECK-NEXT: call op_2_to_0 ; CHECK-NEXT: local.get 0 +; CHECK-NEXT: local.get 2 +; 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() @@ -1870,14 +1945,16 @@ define void @f351() { define void @f352() { ; CHECK-LABEL: f352: ; CHECK: .functype f352 () -> () -; 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: local.get 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() @@ -1895,13 +1972,14 @@ define void @f354() { ; 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 1 -; CHECK-NEXT: call op_2_to_0 +; CHECK-NEXT: local.get 0 ; CHECK-NEXT: local.get 2 +; CHECK-NEXT: call op_2_to_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() @@ -1920,14 +1998,15 @@ define void @f356() { ; 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 1 -; CHECK-NEXT: call op_2_to_0 ; CHECK-NEXT: local.get 0 ; CHECK-NEXT: local.get 2 ; CHECK-NEXT: call op_2_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() %t1 = extractvalue {i32, i32, i32} %t0, 0 @@ -1942,15 +2021,17 @@ define void @f356() { define void @f357() { ; CHECK-LABEL: f357: ; CHECK: .functype f357 () -> () -; 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 1 -; CHECK-NEXT: call op_2_to_0 -; CHECK-NEXT: local.get 0 ; CHECK-NEXT: local.get 0 +; CHECK-NEXT: local.get 2 +; 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() @@ -1966,15 +2047,17 @@ define void @f357() { define void @f358() { ; CHECK-LABEL: f358: ; CHECK: .functype f358 () -> () -; 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 1 -; CHECK-NEXT: call op_2_to_0 ; CHECK-NEXT: local.get 0 +; CHECK-NEXT: local.get 2 +; 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() @@ -1993,13 +2076,14 @@ define void @f359() { ; 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: 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, i32} @op_0_to_3() @@ -2015,15 +2099,17 @@ define void @f359() { define void @f360() { ; CHECK-LABEL: f360: ; CHECK: .functype f360 () -> () -; 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 1 +; CHECK-NEXT: local.get 0 +; CHECK-NEXT: local.get 2 ; CHECK-NEXT: call op_2_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() diff --git a/llvm/test/CodeGen/WebAssembly/multivalue.ll b/llvm/test/CodeGen/WebAssembly/multivalue.ll index 5001db7e57a1e..46c75f5506ce7 100644 --- a/llvm/test/CodeGen/WebAssembly/multivalue.ll +++ b/llvm/test/CodeGen/WebAssembly/multivalue.ll @@ -48,9 +48,14 @@ define void @pair_call() { ; CHECK-LABEL: pair_call_return: ; CHECK-NEXT: .functype pair_call_return () -> (i32, i64) +; CHECK-NEXT: .local i32, i64 ; CHECK-NEXT: call pair_const{{$}} +; CHECK-NEXT: local.set 1 +; CHECK-NEXT: local.set 0 +; CHECK-NEXT: local.get 0 +; CHECK-NEXT: local.get 1 ; CHECK-NEXT: end_function{{$}} -; REGS: call $push{{[0-9]+}}=, $push{{[0-9]+}}=, pair_const{{$}} +; REGS: call $0=, $1=, pair_const{{$}} define %pair @pair_call_return() { %p = call %pair @pair_const() ret %pair %p @@ -58,11 +63,16 @@ define %pair @pair_call_return() { ; CHECK-LABEL: pair_call_indirect: ; CHECK-NEXT: .functype pair_call_indirect (i32) -> (i32, i64) +; CHECK-NEXT: .local i64 ; CHECK-NEXT: local.get 0{{$}} ; CHECK-NEXT: call_indirect () -> (i32, i64){{$}} +; CHECK-NEXT: local.set 1 +; CHECK-NEXT: local.set 0 +; CHECK-NEXT: local.get 0 +; CHECK-NEXT: local.get 1 ; REF: call_indirect __indirect_function_table, () -> (i32, i64){{$}} ; CHECK-NEXT: end_function{{$}} -; REGS: call_indirect $push{{[0-9]+}}=, $push{{[0-9]+}}=, $0{{$}} +; REGS: call_indirect ${{[0-9]+}}=, ${{[0-9]+}}=, $0{{$}} define %pair @pair_call_indirect(ptr %f) { %p = call %pair %f() ret %pair %p @@ -80,10 +90,13 @@ define %pair @pair_tail_call() { ; CHECK-LABEL: pair_call_return_first: ; CHECK-NEXT: .functype pair_call_return_first () -> (i32) +; CHECK-NEXT: .local i32 ; CHECK-NEXT: call pair_const{{$}} ; CHECK-NEXT: drop{{$}} +; CHECK-NEXT: local.set 0 +; CHECK-NEXT: local.get 0 ; CHECK-NEXT: end_function{{$}} -; REGS: call $push{{[0-9]+}}=, $drop=, pair_const{{$}} +; REGS: call $0=, $drop=, pair_const{{$}} define i32 @pair_call_return_first() { %p = call %pair @pair_const() %v = extractvalue %pair %p, 0 @@ -107,11 +120,14 @@ define i64 @pair_call_return_second() { ; CHECK-LABEL: pair_call_use_first: ; CHECK-NEXT: .functype pair_call_use_first () -> () +; CHECK-NEXT: .local i32 ; CHECK-NEXT: call pair_const{{$}} ; CHECK-NEXT: drop{{$}} +; CHECK-NEXT: local.set 0 +; CHECK-NEXT: local.get 0 ; CHECK-NEXT: call use_i32{{$}} ; CHECK-NEXT: end_function{{$}} -; REGS: call $push{{[0-9]+}}=, $drop=, pair_const{{$}} +; REGS: call $0=, $drop=, pair_const{{$}} define void @pair_call_use_first() { %p = call %pair @pair_const() %v = extractvalue %pair %p, 0 @@ -138,13 +154,15 @@ define void @pair_call_use_second() { ; CHECK-LABEL: pair_call_use_first_return_second: ; CHECK-NEXT: .functype pair_call_use_first_return_second () -> (i64) -; CHECK-NEXT: .local i64{{$}} +; CHECK-NEXT: .local i32, i64{{$}} ; CHECK-NEXT: call pair_const{{$}} +; CHECK-NEXT: local.set 1{{$}} ; CHECK-NEXT: local.set 0{{$}} -; CHECK-NEXT: call use_i32{{$}} ; CHECK-NEXT: local.get 0{{$}} +; CHECK-NEXT: call use_i32{{$}} +; CHECK-NEXT: local.get 1{{$}} ; CHECK-NEXT: end_function{{$}} -; REGS: call $push{{[0-9]+}}=, $0=, pair_const{{$}} +; REGS: call $0=, $1=, pair_const{{$}} define i64 @pair_call_use_first_return_second() { %p = call %pair @pair_const() %v = extractvalue %pair %p, 0 @@ -177,8 +195,12 @@ define i32 @pair_call_use_second_return_first() { ; CHECK-NEXT: local.get 0 ; CHECK-NEXT: local.get 1 ; CHECK-NEXT: call pair_ident{{$}} +; CHECK-NEXT: local.set 1 +; CHECK-NEXT: local.set 0 +; CHECK-NEXT: local.get 0 +; CHECK-NEXT: local.get 1 ; CHECK-NEXT: end_function{{$}} -; REGS: call $push{{[0-9]+}}=, $push{{[0-9]+}}=, pair_ident, $0, $1{{$}} +; REGS: call $0=, $1=, pair_ident, $0, $1{{$}} define %pair @pair_pass_through(%pair %p) { %r = call %pair @pair_ident(%pair %p) ret %pair %r diff --git a/llvm/test/CodeGen/WebAssembly/multivalue_libcall.ll b/llvm/test/CodeGen/WebAssembly/multivalue_libcall.ll index c1343d32f80e5..5f2ba7ee52a12 100644 --- a/llvm/test/CodeGen/WebAssembly/multivalue_libcall.ll +++ b/llvm/test/CodeGen/WebAssembly/multivalue_libcall.ll @@ -15,6 +15,10 @@ define i128 @multivalue_sdiv(i128 %a, i128 %b) { ; MULTIVALUE-NEXT: local.get 2 ; MULTIVALUE-NEXT: local.get 3 ; MULTIVALUE-NEXT: call __divti3 +; MULTIVALUE-NEXT: local.set 2 +; MULTIVALUE-NEXT: local.set 3 +; MULTIVALUE-NEXT: local.get 3 +; MULTIVALUE-NEXT: local.get 2 ; MULTIVALUE-NEXT: # fallthrough-return ; ; NO_MULTIVALUE-LABEL: multivalue_sdiv: @@ -59,6 +63,10 @@ define fp128 @multivalue_fsub(fp128 %a, fp128 %b) { ; MULTIVALUE-NEXT: local.get 2 ; MULTIVALUE-NEXT: local.get 3 ; MULTIVALUE-NEXT: call __subtf3 +; MULTIVALUE-NEXT: local.set 2 +; MULTIVALUE-NEXT: local.set 3 +; MULTIVALUE-NEXT: local.get 3 +; MULTIVALUE-NEXT: local.get 2 ; MULTIVALUE-NEXT: # fallthrough-return ; ; NO_MULTIVALUE-LABEL: multivalue_fsub: @@ -102,6 +110,10 @@ define i128 @multivalue_lshr(i128 %a, i128 %b) { ; MULTIVALUE-NEXT: local.get 0 ; MULTIVALUE-NEXT: i32.wrap_i64 ; MULTIVALUE-NEXT: call __ashlti3 +; MULTIVALUE-NEXT: local.set 3 +; MULTIVALUE-NEXT: local.set 0 +; MULTIVALUE-NEXT: local.get 0 +; MULTIVALUE-NEXT: local.get 3 ; MULTIVALUE-NEXT: # fallthrough-return ; ; NO_MULTIVALUE-LABEL: multivalue_lshr: diff --git a/llvm/test/CodeGen/WebAssembly/wide-arithmetic.ll b/llvm/test/CodeGen/WebAssembly/wide-arithmetic.ll index 71974b012a2b6..724ae46ebca10 100644 --- a/llvm/test/CodeGen/WebAssembly/wide-arithmetic.ll +++ b/llvm/test/CodeGen/WebAssembly/wide-arithmetic.ll @@ -1,5 +1,5 @@ ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5 -; RUN: llc -mattr=+wide-arithmetic < %s | FileCheck %s +; RUN: llc -mattr=+wide-arithmetic < %s -O2 | FileCheck %s target triple = "wasm32-unknown-unknown" @@ -50,16 +50,18 @@ define i128 @sub_i128(i128 %a, i128 %b) { define i128 @mul_i128(i128 %a, i128 %b) { ; CHECK-LABEL: mul_i128: ; CHECK: .functype mul_i128 (i32, i64, i64, i64, i64) -> () -; CHECK-NEXT: .local i64 +; CHECK-NEXT: .local i64, i64 ; CHECK-NEXT: # %bb.0: -; CHECK-NEXT: local.get 0 ; CHECK-NEXT: local.get 1 ; CHECK-NEXT: local.get 3 ; CHECK-NEXT: i64.mul_wide_u +; CHECK-NEXT: local.set 6 ; CHECK-NEXT: local.set 5 -; CHECK-NEXT: i64.store 0 ; CHECK-NEXT: local.get 0 ; CHECK-NEXT: local.get 5 +; CHECK-NEXT: i64.store 0 +; CHECK-NEXT: local.get 0 +; CHECK-NEXT: local.get 6 ; CHECK-NEXT: local.get 1 ; CHECK-NEXT: local.get 4 ; CHECK-NEXT: i64.mul @@ -192,22 +194,26 @@ define { i64, i64 } @add_wide3_u_via_intrinsics(i64 %a, i64 %b, i64 %c) { ; CHECK-LABEL: add_wide3_u_via_intrinsics: ; CHECK: .functype add_wide3_u_via_intrinsics (i32, i64, i64, i64) -> () ; CHECK-NEXT: # %bb.0: -; CHECK-NEXT: local.get 0 ; CHECK-NEXT: local.get 1 ; CHECK-NEXT: i64.const 0 ; CHECK-NEXT: local.get 2 ; CHECK-NEXT: i64.const 0 ; CHECK-NEXT: i64.add128 +; CHECK-NEXT: local.set 1 ; CHECK-NEXT: local.set 2 +; CHECK-NEXT: local.get 2 ; CHECK-NEXT: i64.const 0 ; CHECK-NEXT: local.get 3 ; CHECK-NEXT: i64.const 0 ; CHECK-NEXT: i64.add128 -; CHECK-NEXT: local.set 1 -; CHECK-NEXT: i64.store 0 +; CHECK-NEXT: local.set 3 +; CHECK-NEXT: local.set 2 ; CHECK-NEXT: local.get 0 ; CHECK-NEXT: local.get 2 +; CHECK-NEXT: i64.store 0 +; CHECK-NEXT: local.get 0 ; CHECK-NEXT: local.get 1 +; CHECK-NEXT: local.get 3 ; CHECK-NEXT: i64.add ; CHECK-NEXT: i64.store 8 ; CHECK-NEXT: # fallthrough-return @@ -239,6 +245,10 @@ define { i64, i64 } @add_wide3_u_via_i128(i64 %a, i64 %b, i64 %c) { ; CHECK-NEXT: local.get 2 ; CHECK-NEXT: i64.const 0 ; CHECK-NEXT: i64.add128 +; CHECK-NEXT: local.set 1 +; CHECK-NEXT: local.set 2 +; CHECK-NEXT: local.get 2 +; CHECK-NEXT: local.get 1 ; CHECK-NEXT: local.get 3 ; CHECK-NEXT: i64.const 0 ; CHECK-NEXT: i64.add128 @@ -264,3 +274,26 @@ define { i64, i64 } @add_wide3_u_via_i128(i64 %a, i64 %b, i64 %c) { %ret1 = insertvalue { i64, i64 } %ret0, i64 %carry, 1 ret { i64, i64 } %ret1 } + +define i1 @smul64_with_overflow(i64 %a, i64 %b) { +; CHECK-LABEL: smul64_with_overflow: +; CHECK: .functype smul64_with_overflow (i64, i64) -> (i32) +; CHECK-NEXT: # %bb.0: # %entry +; CHECK-NEXT: local.get 0 +; CHECK-NEXT: local.get 1 +; CHECK-NEXT: i64.mul_wide_s +; CHECK-NEXT: local.set 0 +; CHECK-NEXT: local.set 1 +; CHECK-NEXT: local.get 0 +; CHECK-NEXT: local.get 1 +; CHECK-NEXT: i64.const 63 +; CHECK-NEXT: i64.shr_s +; CHECK-NEXT: i64.ne +; CHECK-NEXT: # fallthrough-return +entry: + %res = call { i64, i1 } @llvm.smul.with.overflow.i64(i64 %a, i64 %b) + %ov = extractvalue { i64, i1 } %res, 1 + ret i1 %ov +} + +declare { i64, i1 } @llvm.smul.with.overflow.i64(i64, i64)