[llvm] [WebAssembly][GlobalISel] CallLowering `lowerReturn` (PR #190247)
Demetrius Kanios via llvm-commits
llvm-commits at lists.llvm.org
Thu Apr 2 12:56:32 PDT 2026
https://github.com/QuantumSegfault created https://github.com/llvm/llvm-project/pull/190247
Implements `WebAssemblyCallLowering::lowerReturn`
Split from #157161
>From a8ceee1897194e51fa07a89df992a1b36bd19994 Mon Sep 17 00:00:00 2001
From: Demetrius Kanios <demetrius at kanios.net>
Date: Thu, 2 Apr 2026 12:53:15 -0700
Subject: [PATCH] Implement `WebAssemblyCallLowering::lowerReturn`
---
.../GISel/WebAssemblyCallLowering.cpp | 164 +++++++++--
.../GlobalISel/irtranslator/ret-aggregates.ll | 265 ++++++++++++++++++
.../GlobalISel/irtranslator/ret-basics.ll | 153 ++++++++++
.../GlobalISel/irtranslator/ret-simd.ll | 90 ++++++
4 files changed, 647 insertions(+), 25 deletions(-)
create mode 100644 llvm/test/CodeGen/WebAssembly/GlobalISel/irtranslator/ret-aggregates.ll
create mode 100644 llvm/test/CodeGen/WebAssembly/GlobalISel/irtranslator/ret-basics.ll
create mode 100644 llvm/test/CodeGen/WebAssembly/GlobalISel/irtranslator/ret-simd.ll
diff --git a/llvm/lib/Target/WebAssembly/GISel/WebAssemblyCallLowering.cpp b/llvm/lib/Target/WebAssembly/GISel/WebAssemblyCallLowering.cpp
index 9450749a4f6ab..3009c2334273d 100644
--- a/llvm/lib/Target/WebAssembly/GISel/WebAssemblyCallLowering.cpp
+++ b/llvm/lib/Target/WebAssembly/GISel/WebAssemblyCallLowering.cpp
@@ -23,11 +23,13 @@
#include "llvm/CodeGen/Analysis.h"
#include "llvm/CodeGen/FunctionLoweringInfo.h"
#include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h"
+#include "llvm/CodeGen/LowLevelTypeUtils.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/RegisterBankInfo.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/DebugLoc.h"
#include "llvm/IR/Value.h"
+#include "llvm/Support/ErrorHandling.h"
#define DEBUG_TYPE "wasm-call-lowering"
@@ -48,6 +50,32 @@ static bool callingConvSupported(CallingConv::ID CallConv) {
CallConv == CallingConv::Swift;
}
+static unsigned extendOpFromFlags(ISD::ArgFlagsTy Flags) {
+ if (Flags.isSExt())
+ return TargetOpcode::G_SEXT;
+ if (Flags.isZExt())
+ return TargetOpcode::G_ZEXT;
+ return TargetOpcode::G_ANYEXT;
+}
+
+static LLT getLLTForWasmMVT(MVT Ty, const DataLayout &DL) {
+ if (Ty == MVT::externref) {
+ return LLT::pointer(
+ WebAssembly::WasmAddressSpace::WASM_ADDRESS_SPACE_EXTERNREF,
+ DL.getPointerSizeInBits(
+ WebAssembly::WasmAddressSpace::WASM_ADDRESS_SPACE_EXTERNREF));
+ }
+
+ if (Ty == MVT::funcref) {
+ return LLT::pointer(
+ WebAssembly::WasmAddressSpace::WASM_ADDRESS_SPACE_FUNCREF,
+ DL.getPointerSizeInBits(
+ WebAssembly::WasmAddressSpace::WASM_ADDRESS_SPACE_FUNCREF));
+ }
+
+ return llvm::getLLTForMVT(Ty);
+}
+
WebAssemblyCallLowering::WebAssemblyCallLowering(
const WebAssemblyTargetLowering &TLI)
: CallLowering(&TLI) {}
@@ -65,13 +93,117 @@ bool WebAssemblyCallLowering::lowerReturn(MachineIRBuilder &MIRBuilder,
ArrayRef<Register> VRegs,
FunctionLoweringInfo &FLI,
Register SwiftErrorVReg) const {
- if (!Val)
- return true; // allow only void returns for now
+ MachineFunction &MF = MIRBuilder.getMF();
+ const WebAssemblySubtarget &Subtarget =
+ MF.getSubtarget<WebAssemblySubtarget>();
+ const RegisterBankInfo &RBI = *Subtarget.getRegBankInfo();
+ const Function &F = MF.getFunction();
+ MachineRegisterInfo &MRI = MF.getRegInfo();
+ const WebAssemblyTargetLowering &TLI = *getTLI<WebAssemblyTargetLowering>();
+ const DataLayout &DL = F.getDataLayout();
- return false;
+ MachineInstrBuilder MIB = MIRBuilder.buildInstrNoInsert(WebAssembly::RETURN);
+
+ assert(((Val && !VRegs.empty()) || (!Val && VRegs.empty())) &&
+ "Return value without a vreg or vice versa");
+
+ if (Val) {
+ LLVMContext &Ctx = Val->getType()->getContext();
+
+ if (!FLI.CanLowerReturn) {
+ insertSRetStores(MIRBuilder, Val->getType(), VRegs, FLI.DemoteRegister);
+ } else {
+ SmallVector<EVT, 4> SplitEVTs;
+ ComputeValueVTs(TLI, DL, Val->getType(), SplitEVTs);
+ assert(VRegs.size() == SplitEVTs.size() &&
+ "For each split Type there should be exactly one VReg.");
+
+ SmallVector<ArgInfo, 8> SplitRets;
+ CallingConv::ID CallConv = F.getCallingConv();
+
+ unsigned RetIdx = 0;
+ for (EVT SplitEVT : SplitEVTs) {
+ Register CurVReg = VRegs[RetIdx];
+ ArgInfo CurRetInfo = ArgInfo{CurVReg, SplitEVT.getTypeForEVT(Ctx), 0};
+ setArgFlags(CurRetInfo, AttributeList::ReturnIndex, DL, F);
+
+ splitToValueTypes(CurRetInfo, SplitRets, DL, CallConv);
+ ++RetIdx;
+ }
+
+ for (ArgInfo &Ret : SplitRets) {
+ const EVT OrigVT = TLI.getValueType(DL, Ret.Ty);
+ const MVT NewVT =
+ TLI.getRegisterTypeForCallingConv(Ctx, CallConv, OrigVT);
+ const LLT OrigLLT =
+ getLLTForType(*OrigVT.getTypeForEVT(F.getContext()), DL);
+ const LLT NewLLT = getLLTForWasmMVT(NewVT, DL);
+
+ const TargetRegisterClass &NewRegClass = *TLI.getRegClassFor(NewVT);
+
+ // If we need to split the type over multiple regs, check it's a
+ // scenario we currently support.
+ const unsigned NumParts =
+ TLI.getNumRegistersForCallingConv(Ctx, CallConv, OrigVT);
+
+ const ISD::ArgFlagsTy OrigFlags = Ret.Flags[0];
+ Ret.Flags.clear();
+
+ for (unsigned Part = 0; Part < NumParts; ++Part) {
+ ISD::ArgFlagsTy Flags = OrigFlags;
+
+ if (Part == 0) {
+ Flags.setSplit();
+ } else {
+ Flags.setOrigAlign(Align(1));
+ if (Part == NumParts - 1)
+ Flags.setSplitEnd();
+ }
+
+ Ret.Flags.push_back(Flags);
+ }
+
+ Ret.OrigRegs.assign(Ret.Regs.begin(), Ret.Regs.end());
+ if (NumParts != 1 || OrigLLT != NewLLT) {
+ // If we can't directly assign the register, we need one or more
+ // intermediate values.
+ Ret.Regs.resize(NumParts);
+
+ // For each split register, create and assign a vreg that will store
+ // the incoming component of the larger value. These will later be
+ // merged to form the final vreg.
+ for (unsigned Part = 0; Part < NumParts; ++Part) {
+ Register NewOutReg = MRI.createGenericVirtualRegister(NewLLT);
+
+ if (!RBI.constrainGenericRegister(NewOutReg, NewRegClass, MRI))
+ reportFatalInternalError(
+ "Couldn't constrain brand-new register?");
+
+ MIB.addUse(NewOutReg);
+
+ Ret.Regs[Part] = NewOutReg;
+ }
+
+ buildCopyToRegs(MIRBuilder, Ret.Regs, Ret.OrigRegs[0], OrigLLT,
+ NewLLT, extendOpFromFlags(Ret.Flags[0]));
+ } else {
+ MIB.addUse(Ret.Regs[0]);
+ }
+ }
+ }
+ }
+
+ if (SwiftErrorVReg) {
+ reportFatalInternalError(
+ "Wasm does not `supportSwiftError`, yet SwiftErrorVReg is "
+ "improperly valid.");
+ }
+
+ MIRBuilder.insertInstr(MIB);
+ return true;
}
-static unsigned getWASMArgumentOpcode(MVT ArgType) {
+static unsigned getWasmArgumentOpcode(MVT ArgType) {
switch (ArgType.SimpleTy) {
case MVT::i32:
return WebAssembly::ARGUMENT_i32;
@@ -106,25 +238,7 @@ static unsigned getWASMArgumentOpcode(MVT ArgType) {
default:
break;
}
- llvm_unreachable("Found unexpected type for WASM argument");
-}
-
-static LLT getLLTForWasmMVT(MVT Ty, const DataLayout &DL) {
- if (Ty == MVT::externref) {
- return LLT::pointer(
- WebAssembly::WasmAddressSpace::WASM_ADDRESS_SPACE_EXTERNREF,
- DL.getPointerSizeInBits(
- WebAssembly::WasmAddressSpace::WASM_ADDRESS_SPACE_EXTERNREF));
- }
-
- if (Ty == MVT::funcref) {
- return LLT::pointer(
- WebAssembly::WasmAddressSpace::WASM_ADDRESS_SPACE_FUNCREF,
- DL.getPointerSizeInBits(
- WebAssembly::WasmAddressSpace::WASM_ADDRESS_SPACE_FUNCREF));
- }
-
- return llvm::getLLTForMVT(Ty);
+ llvm_unreachable("Found unexpected type for Wasm argument");
}
bool WebAssemblyCallLowering::lowerFormalArguments(
@@ -221,7 +335,7 @@ bool WebAssemblyCallLowering::lowerFormalArguments(
for (unsigned Part = 0; Part < NumParts; ++Part) {
MachineInstrBuilder ArgInst =
- MIRBuilder.buildInstr(getWASMArgumentOpcode(NewVT))
+ MIRBuilder.buildInstr(getWasmArgumentOpcode(NewVT))
.addDef(Arg.Regs[Part])
.addImm(FinalArgIdx);
@@ -262,7 +376,7 @@ bool WebAssemblyCallLowering::lowerFormalArguments(
MFI->setVarargBufferVreg(VarargVreg);
MachineInstrBuilder ArgInst =
- MIRBuilder.buildInstr(getWASMArgumentOpcode(PtrVT))
+ MIRBuilder.buildInstr(getWasmArgumentOpcode(PtrVT))
.addDef(VarargVreg)
.addImm(FinalArgIdx);
diff --git a/llvm/test/CodeGen/WebAssembly/GlobalISel/irtranslator/ret-aggregates.ll b/llvm/test/CodeGen/WebAssembly/GlobalISel/irtranslator/ret-aggregates.ll
new file mode 100644
index 0000000000000..02c72cf9f157d
--- /dev/null
+++ b/llvm/test/CodeGen/WebAssembly/GlobalISel/irtranslator/ret-aggregates.ll
@@ -0,0 +1,265 @@
+; NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py UTC_ARGS: --version 6
+; RUN: llc -mtriple=wasm32 -mattr=-simd128 -global-isel -stop-after=irtranslator -verify-machineinstrs < %s | FileCheck %s -check-prefixes=WASM32-NOMULTIVAL
+; RUN: llc -mtriple=wasm64 -mattr=-simd128 -global-isel -stop-after=irtranslator -verify-machineinstrs < %s | FileCheck %s -check-prefixes=WASM64-NOMULTIVAL
+; RUN: llc -mtriple=wasm32 -mattr=-simd128,+multivalue -target-abi=experimental-mv -global-isel -stop-after=irtranslator -verify-machineinstrs < %s | FileCheck %s -check-prefixes=MULTIVAL,WASM32-MULTIVAL
+; RUN: llc -mtriple=wasm64 -mattr=-simd128,+multivalue -target-abi=experimental-mv -global-isel -stop-after=irtranslator -verify-machineinstrs < %s | FileCheck %s -check-prefixes=MULTIVAL,WASM64-MULTIVAL
+
+define i128 @test_ret_i128() {
+ ; WASM32-NOMULTIVAL-LABEL: name: test_ret_i128
+ ; WASM32-NOMULTIVAL: bb.1 (%ir-block.0):
+ ; WASM32-NOMULTIVAL-NEXT: liveins: $arguments
+ ; WASM32-NOMULTIVAL-NEXT: {{ $}}
+ ; WASM32-NOMULTIVAL-NEXT: [[ARGUMENT_i32_:%[0-9]+]]:i32(p0) = ARGUMENT_i32 0, implicit $arguments
+ ; WASM32-NOMULTIVAL-NEXT: [[C:%[0-9]+]]:_(s128) = G_CONSTANT i128 0
+ ; WASM32-NOMULTIVAL-NEXT: G_STORE [[C]](s128), [[ARGUMENT_i32_]](p0) :: (store (s128))
+ ; WASM32-NOMULTIVAL-NEXT: RETURN implicit-def $arguments
+ ;
+ ; WASM64-NOMULTIVAL-LABEL: name: test_ret_i128
+ ; WASM64-NOMULTIVAL: bb.1 (%ir-block.0):
+ ; WASM64-NOMULTIVAL-NEXT: liveins: $arguments
+ ; WASM64-NOMULTIVAL-NEXT: {{ $}}
+ ; WASM64-NOMULTIVAL-NEXT: [[ARGUMENT_i64_:%[0-9]+]]:i64(p0) = ARGUMENT_i64 0, implicit $arguments
+ ; WASM64-NOMULTIVAL-NEXT: [[C:%[0-9]+]]:_(s128) = G_CONSTANT i128 0
+ ; WASM64-NOMULTIVAL-NEXT: G_STORE [[C]](s128), [[ARGUMENT_i64_]](p0) :: (store (s128))
+ ; WASM64-NOMULTIVAL-NEXT: RETURN implicit-def $arguments
+ ;
+ ; MULTIVAL-LABEL: name: test_ret_i128
+ ; MULTIVAL: bb.1 (%ir-block.0):
+ ; MULTIVAL-NEXT: liveins: $arguments
+ ; MULTIVAL-NEXT: {{ $}}
+ ; MULTIVAL-NEXT: [[C:%[0-9]+]]:_(s128) = G_CONSTANT i128 0
+ ; MULTIVAL-NEXT: [[UV:%[0-9]+]]:i64(s64), [[UV1:%[0-9]+]]:i64(s64) = G_UNMERGE_VALUES [[C]](s128)
+ ; MULTIVAL-NEXT: RETURN [[UV]](s64), [[UV1]](s64), implicit-def $arguments
+ ret i128 0
+}
+
+define fp128 @test_ret_f128() {
+ ; WASM32-NOMULTIVAL-LABEL: name: test_ret_f128
+ ; WASM32-NOMULTIVAL: bb.1 (%ir-block.0):
+ ; WASM32-NOMULTIVAL-NEXT: liveins: $arguments
+ ; WASM32-NOMULTIVAL-NEXT: {{ $}}
+ ; WASM32-NOMULTIVAL-NEXT: [[ARGUMENT_i32_:%[0-9]+]]:i32(p0) = ARGUMENT_i32 0, implicit $arguments
+ ; WASM32-NOMULTIVAL-NEXT: [[C:%[0-9]+]]:_(s128) = G_FCONSTANT fp128 0xL00000000000000000000000000000000
+ ; WASM32-NOMULTIVAL-NEXT: G_STORE [[C]](s128), [[ARGUMENT_i32_]](p0) :: (store (s128))
+ ; WASM32-NOMULTIVAL-NEXT: RETURN implicit-def $arguments
+ ;
+ ; WASM64-NOMULTIVAL-LABEL: name: test_ret_f128
+ ; WASM64-NOMULTIVAL: bb.1 (%ir-block.0):
+ ; WASM64-NOMULTIVAL-NEXT: liveins: $arguments
+ ; WASM64-NOMULTIVAL-NEXT: {{ $}}
+ ; WASM64-NOMULTIVAL-NEXT: [[ARGUMENT_i64_:%[0-9]+]]:i64(p0) = ARGUMENT_i64 0, implicit $arguments
+ ; WASM64-NOMULTIVAL-NEXT: [[C:%[0-9]+]]:_(s128) = G_FCONSTANT fp128 0xL00000000000000000000000000000000
+ ; WASM64-NOMULTIVAL-NEXT: G_STORE [[C]](s128), [[ARGUMENT_i64_]](p0) :: (store (s128))
+ ; WASM64-NOMULTIVAL-NEXT: RETURN implicit-def $arguments
+ ;
+ ; MULTIVAL-LABEL: name: test_ret_f128
+ ; MULTIVAL: bb.1 (%ir-block.0):
+ ; MULTIVAL-NEXT: liveins: $arguments
+ ; MULTIVAL-NEXT: {{ $}}
+ ; MULTIVAL-NEXT: [[C:%[0-9]+]]:_(s128) = G_FCONSTANT fp128 0xL00000000000000000000000000000000
+ ; MULTIVAL-NEXT: [[UV:%[0-9]+]]:i64(s64), [[UV1:%[0-9]+]]:i64(s64) = G_UNMERGE_VALUES [[C]](s128)
+ ; MULTIVAL-NEXT: RETURN [[UV]](s64), [[UV1]](s64), implicit-def $arguments
+ ret fp128 zeroinitializer
+}
+
+define <4 x i32> @test_ret_v4i32() {
+ ; WASM32-NOMULTIVAL-LABEL: name: test_ret_v4i32
+ ; WASM32-NOMULTIVAL: bb.1 (%ir-block.0):
+ ; WASM32-NOMULTIVAL-NEXT: liveins: $arguments
+ ; WASM32-NOMULTIVAL-NEXT: {{ $}}
+ ; WASM32-NOMULTIVAL-NEXT: [[ARGUMENT_i32_:%[0-9]+]]:i32(p0) = ARGUMENT_i32 0, implicit $arguments
+ ; WASM32-NOMULTIVAL-NEXT: [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 0
+ ; WASM32-NOMULTIVAL-NEXT: [[BUILD_VECTOR:%[0-9]+]]:_(<4 x s32>) = G_BUILD_VECTOR [[C]](s32), [[C]](s32), [[C]](s32), [[C]](s32)
+ ; WASM32-NOMULTIVAL-NEXT: G_STORE [[BUILD_VECTOR]](<4 x s32>), [[ARGUMENT_i32_]](p0) :: (store (<4 x s32>))
+ ; WASM32-NOMULTIVAL-NEXT: RETURN implicit-def $arguments
+ ;
+ ; WASM64-NOMULTIVAL-LABEL: name: test_ret_v4i32
+ ; WASM64-NOMULTIVAL: bb.1 (%ir-block.0):
+ ; WASM64-NOMULTIVAL-NEXT: liveins: $arguments
+ ; WASM64-NOMULTIVAL-NEXT: {{ $}}
+ ; WASM64-NOMULTIVAL-NEXT: [[ARGUMENT_i64_:%[0-9]+]]:i64(p0) = ARGUMENT_i64 0, implicit $arguments
+ ; WASM64-NOMULTIVAL-NEXT: [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 0
+ ; WASM64-NOMULTIVAL-NEXT: [[BUILD_VECTOR:%[0-9]+]]:_(<4 x s32>) = G_BUILD_VECTOR [[C]](s32), [[C]](s32), [[C]](s32), [[C]](s32)
+ ; WASM64-NOMULTIVAL-NEXT: G_STORE [[BUILD_VECTOR]](<4 x s32>), [[ARGUMENT_i64_]](p0) :: (store (<4 x s32>))
+ ; WASM64-NOMULTIVAL-NEXT: RETURN implicit-def $arguments
+ ;
+ ; MULTIVAL-LABEL: name: test_ret_v4i32
+ ; MULTIVAL: bb.1 (%ir-block.0):
+ ; MULTIVAL-NEXT: liveins: $arguments
+ ; MULTIVAL-NEXT: {{ $}}
+ ; MULTIVAL-NEXT: [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 0
+ ; MULTIVAL-NEXT: [[BUILD_VECTOR:%[0-9]+]]:_(<4 x s32>) = G_BUILD_VECTOR [[C]](s32), [[C]](s32), [[C]](s32), [[C]](s32)
+ ; MULTIVAL-NEXT: [[UV:%[0-9]+]]:i32(s32), [[UV1:%[0-9]+]]:i32(s32), [[UV2:%[0-9]+]]:i32(s32), [[UV3:%[0-9]+]]:i32(s32) = G_UNMERGE_VALUES [[BUILD_VECTOR]](<4 x s32>)
+ ; MULTIVAL-NEXT: RETURN [[UV]](s32), [[UV1]](s32), [[UV2]](s32), [[UV3]](s32), implicit-def $arguments
+ ret <4 x i32> zeroinitializer
+}
+
+define [5 x i16] @test_array_arg() {
+ ; WASM32-NOMULTIVAL-LABEL: name: test_array_arg
+ ; WASM32-NOMULTIVAL: bb.1 (%ir-block.0):
+ ; WASM32-NOMULTIVAL-NEXT: liveins: $arguments
+ ; WASM32-NOMULTIVAL-NEXT: {{ $}}
+ ; WASM32-NOMULTIVAL-NEXT: [[ARGUMENT_i32_:%[0-9]+]]:i32(p0) = ARGUMENT_i32 0, implicit $arguments
+ ; WASM32-NOMULTIVAL-NEXT: [[C:%[0-9]+]]:_(s16) = G_CONSTANT i16 0
+ ; WASM32-NOMULTIVAL-NEXT: G_STORE [[C]](s16), [[ARGUMENT_i32_]](p0) :: (store (s16))
+ ; WASM32-NOMULTIVAL-NEXT: [[C1:%[0-9]+]]:_(s32) = G_CONSTANT i32 2
+ ; WASM32-NOMULTIVAL-NEXT: [[PTR_ADD:%[0-9]+]]:_(p0) = nuw inbounds G_PTR_ADD [[ARGUMENT_i32_]], [[C1]](s32)
+ ; WASM32-NOMULTIVAL-NEXT: G_STORE [[C]](s16), [[PTR_ADD]](p0) :: (store (s16))
+ ; WASM32-NOMULTIVAL-NEXT: [[C2:%[0-9]+]]:_(s32) = G_CONSTANT i32 4
+ ; WASM32-NOMULTIVAL-NEXT: [[PTR_ADD1:%[0-9]+]]:_(p0) = nuw inbounds G_PTR_ADD [[ARGUMENT_i32_]], [[C2]](s32)
+ ; WASM32-NOMULTIVAL-NEXT: G_STORE [[C]](s16), [[PTR_ADD1]](p0) :: (store (s16))
+ ; WASM32-NOMULTIVAL-NEXT: [[C3:%[0-9]+]]:_(s32) = G_CONSTANT i32 6
+ ; WASM32-NOMULTIVAL-NEXT: [[PTR_ADD2:%[0-9]+]]:_(p0) = nuw inbounds G_PTR_ADD [[ARGUMENT_i32_]], [[C3]](s32)
+ ; WASM32-NOMULTIVAL-NEXT: G_STORE [[C]](s16), [[PTR_ADD2]](p0) :: (store (s16))
+ ; WASM32-NOMULTIVAL-NEXT: [[C4:%[0-9]+]]:_(s32) = G_CONSTANT i32 8
+ ; WASM32-NOMULTIVAL-NEXT: [[PTR_ADD3:%[0-9]+]]:_(p0) = nuw inbounds G_PTR_ADD [[ARGUMENT_i32_]], [[C4]](s32)
+ ; WASM32-NOMULTIVAL-NEXT: G_STORE [[C]](s16), [[PTR_ADD3]](p0) :: (store (s16))
+ ; WASM32-NOMULTIVAL-NEXT: RETURN implicit-def $arguments
+ ;
+ ; WASM64-NOMULTIVAL-LABEL: name: test_array_arg
+ ; WASM64-NOMULTIVAL: bb.1 (%ir-block.0):
+ ; WASM64-NOMULTIVAL-NEXT: liveins: $arguments
+ ; WASM64-NOMULTIVAL-NEXT: {{ $}}
+ ; WASM64-NOMULTIVAL-NEXT: [[ARGUMENT_i64_:%[0-9]+]]:i64(p0) = ARGUMENT_i64 0, implicit $arguments
+ ; WASM64-NOMULTIVAL-NEXT: [[C:%[0-9]+]]:_(s16) = G_CONSTANT i16 0
+ ; WASM64-NOMULTIVAL-NEXT: G_STORE [[C]](s16), [[ARGUMENT_i64_]](p0) :: (store (s16))
+ ; WASM64-NOMULTIVAL-NEXT: [[C1:%[0-9]+]]:_(s64) = G_CONSTANT i64 2
+ ; WASM64-NOMULTIVAL-NEXT: [[PTR_ADD:%[0-9]+]]:_(p0) = nuw inbounds G_PTR_ADD [[ARGUMENT_i64_]], [[C1]](s64)
+ ; WASM64-NOMULTIVAL-NEXT: G_STORE [[C]](s16), [[PTR_ADD]](p0) :: (store (s16))
+ ; WASM64-NOMULTIVAL-NEXT: [[C2:%[0-9]+]]:_(s64) = G_CONSTANT i64 4
+ ; WASM64-NOMULTIVAL-NEXT: [[PTR_ADD1:%[0-9]+]]:_(p0) = nuw inbounds G_PTR_ADD [[ARGUMENT_i64_]], [[C2]](s64)
+ ; WASM64-NOMULTIVAL-NEXT: G_STORE [[C]](s16), [[PTR_ADD1]](p0) :: (store (s16))
+ ; WASM64-NOMULTIVAL-NEXT: [[C3:%[0-9]+]]:_(s64) = G_CONSTANT i64 6
+ ; WASM64-NOMULTIVAL-NEXT: [[PTR_ADD2:%[0-9]+]]:_(p0) = nuw inbounds G_PTR_ADD [[ARGUMENT_i64_]], [[C3]](s64)
+ ; WASM64-NOMULTIVAL-NEXT: G_STORE [[C]](s16), [[PTR_ADD2]](p0) :: (store (s16))
+ ; WASM64-NOMULTIVAL-NEXT: [[C4:%[0-9]+]]:_(s64) = G_CONSTANT i64 8
+ ; WASM64-NOMULTIVAL-NEXT: [[PTR_ADD3:%[0-9]+]]:_(p0) = nuw inbounds G_PTR_ADD [[ARGUMENT_i64_]], [[C4]](s64)
+ ; WASM64-NOMULTIVAL-NEXT: G_STORE [[C]](s16), [[PTR_ADD3]](p0) :: (store (s16))
+ ; WASM64-NOMULTIVAL-NEXT: RETURN implicit-def $arguments
+ ;
+ ; MULTIVAL-LABEL: name: test_array_arg
+ ; MULTIVAL: bb.1 (%ir-block.0):
+ ; MULTIVAL-NEXT: liveins: $arguments
+ ; MULTIVAL-NEXT: {{ $}}
+ ; MULTIVAL-NEXT: [[C:%[0-9]+]]:_(s16) = G_CONSTANT i16 0
+ ; MULTIVAL-NEXT: [[ANYEXT:%[0-9]+]]:i32(s32) = G_ANYEXT [[C]](s16)
+ ; MULTIVAL-NEXT: [[ANYEXT1:%[0-9]+]]:i32(s32) = G_ANYEXT [[C]](s16)
+ ; MULTIVAL-NEXT: [[ANYEXT2:%[0-9]+]]:i32(s32) = G_ANYEXT [[C]](s16)
+ ; MULTIVAL-NEXT: [[ANYEXT3:%[0-9]+]]:i32(s32) = G_ANYEXT [[C]](s16)
+ ; MULTIVAL-NEXT: [[ANYEXT4:%[0-9]+]]:i32(s32) = G_ANYEXT [[C]](s16)
+ ; MULTIVAL-NEXT: RETURN [[ANYEXT]](s32), [[ANYEXT1]](s32), [[ANYEXT2]](s32), [[ANYEXT3]](s32), [[ANYEXT4]](s32), implicit-def $arguments
+ ret [5 x i16] zeroinitializer
+}
+
+%StructTy = type { i8, i16, i32, i64, ptr, float, double, i128 }
+
+define %StructTy @test_ret_struct() {
+ ; WASM32-NOMULTIVAL-LABEL: name: test_ret_struct
+ ; WASM32-NOMULTIVAL: bb.1 (%ir-block.0):
+ ; WASM32-NOMULTIVAL-NEXT: liveins: $arguments
+ ; WASM32-NOMULTIVAL-NEXT: {{ $}}
+ ; WASM32-NOMULTIVAL-NEXT: [[ARGUMENT_i32_:%[0-9]+]]:i32(p0) = ARGUMENT_i32 0, implicit $arguments
+ ; WASM32-NOMULTIVAL-NEXT: [[C:%[0-9]+]]:_(s8) = G_CONSTANT i8 0
+ ; WASM32-NOMULTIVAL-NEXT: [[C1:%[0-9]+]]:_(s16) = G_CONSTANT i16 0
+ ; WASM32-NOMULTIVAL-NEXT: [[C2:%[0-9]+]]:_(s32) = G_CONSTANT i32 0
+ ; WASM32-NOMULTIVAL-NEXT: [[C3:%[0-9]+]]:_(s64) = G_CONSTANT i64 0
+ ; WASM32-NOMULTIVAL-NEXT: [[C4:%[0-9]+]]:_(p0) = G_CONSTANT i32 0
+ ; WASM32-NOMULTIVAL-NEXT: [[C5:%[0-9]+]]:_(s32) = G_FCONSTANT float 0.000000e+00
+ ; WASM32-NOMULTIVAL-NEXT: [[C6:%[0-9]+]]:_(s64) = G_FCONSTANT double 0.000000e+00
+ ; WASM32-NOMULTIVAL-NEXT: [[C7:%[0-9]+]]:_(s128) = G_CONSTANT i128 0
+ ; WASM32-NOMULTIVAL-NEXT: G_STORE [[C]](s8), [[ARGUMENT_i32_]](p0) :: (store (s8), align 16)
+ ; WASM32-NOMULTIVAL-NEXT: [[C8:%[0-9]+]]:_(s32) = G_CONSTANT i32 2
+ ; WASM32-NOMULTIVAL-NEXT: [[PTR_ADD:%[0-9]+]]:_(p0) = nuw inbounds G_PTR_ADD [[ARGUMENT_i32_]], [[C8]](s32)
+ ; WASM32-NOMULTIVAL-NEXT: G_STORE [[C1]](s16), [[PTR_ADD]](p0) :: (store (s16))
+ ; WASM32-NOMULTIVAL-NEXT: [[C9:%[0-9]+]]:_(s32) = G_CONSTANT i32 4
+ ; WASM32-NOMULTIVAL-NEXT: [[PTR_ADD1:%[0-9]+]]:_(p0) = nuw inbounds G_PTR_ADD [[ARGUMENT_i32_]], [[C9]](s32)
+ ; WASM32-NOMULTIVAL-NEXT: G_STORE [[C2]](s32), [[PTR_ADD1]](p0) :: (store (s32))
+ ; WASM32-NOMULTIVAL-NEXT: [[C10:%[0-9]+]]:_(s32) = G_CONSTANT i32 8
+ ; WASM32-NOMULTIVAL-NEXT: [[PTR_ADD2:%[0-9]+]]:_(p0) = nuw inbounds G_PTR_ADD [[ARGUMENT_i32_]], [[C10]](s32)
+ ; WASM32-NOMULTIVAL-NEXT: G_STORE [[C3]](s64), [[PTR_ADD2]](p0) :: (store (s64))
+ ; WASM32-NOMULTIVAL-NEXT: [[C11:%[0-9]+]]:_(s32) = G_CONSTANT i32 16
+ ; WASM32-NOMULTIVAL-NEXT: [[PTR_ADD3:%[0-9]+]]:_(p0) = nuw inbounds G_PTR_ADD [[ARGUMENT_i32_]], [[C11]](s32)
+ ; WASM32-NOMULTIVAL-NEXT: G_STORE [[C4]](p0), [[PTR_ADD3]](p0) :: (store (p0), align 16)
+ ; WASM32-NOMULTIVAL-NEXT: [[C12:%[0-9]+]]:_(s32) = G_CONSTANT i32 20
+ ; WASM32-NOMULTIVAL-NEXT: [[PTR_ADD4:%[0-9]+]]:_(p0) = nuw inbounds G_PTR_ADD [[ARGUMENT_i32_]], [[C12]](s32)
+ ; WASM32-NOMULTIVAL-NEXT: G_STORE [[C5]](s32), [[PTR_ADD4]](p0) :: (store (s32))
+ ; WASM32-NOMULTIVAL-NEXT: [[C13:%[0-9]+]]:_(s32) = G_CONSTANT i32 24
+ ; WASM32-NOMULTIVAL-NEXT: [[PTR_ADD5:%[0-9]+]]:_(p0) = nuw inbounds G_PTR_ADD [[ARGUMENT_i32_]], [[C13]](s32)
+ ; WASM32-NOMULTIVAL-NEXT: G_STORE [[C6]](s64), [[PTR_ADD5]](p0) :: (store (s64))
+ ; WASM32-NOMULTIVAL-NEXT: [[C14:%[0-9]+]]:_(s32) = G_CONSTANT i32 32
+ ; WASM32-NOMULTIVAL-NEXT: [[PTR_ADD6:%[0-9]+]]:_(p0) = nuw inbounds G_PTR_ADD [[ARGUMENT_i32_]], [[C14]](s32)
+ ; WASM32-NOMULTIVAL-NEXT: G_STORE [[C7]](s128), [[PTR_ADD6]](p0) :: (store (s128))
+ ; WASM32-NOMULTIVAL-NEXT: RETURN implicit-def $arguments
+ ;
+ ; WASM64-NOMULTIVAL-LABEL: name: test_ret_struct
+ ; WASM64-NOMULTIVAL: bb.1 (%ir-block.0):
+ ; WASM64-NOMULTIVAL-NEXT: liveins: $arguments
+ ; WASM64-NOMULTIVAL-NEXT: {{ $}}
+ ; WASM64-NOMULTIVAL-NEXT: [[ARGUMENT_i64_:%[0-9]+]]:i64(p0) = ARGUMENT_i64 0, implicit $arguments
+ ; WASM64-NOMULTIVAL-NEXT: [[C:%[0-9]+]]:_(s8) = G_CONSTANT i8 0
+ ; WASM64-NOMULTIVAL-NEXT: [[C1:%[0-9]+]]:_(s16) = G_CONSTANT i16 0
+ ; WASM64-NOMULTIVAL-NEXT: [[C2:%[0-9]+]]:_(s32) = G_CONSTANT i32 0
+ ; WASM64-NOMULTIVAL-NEXT: [[C3:%[0-9]+]]:_(s64) = G_CONSTANT i64 0
+ ; WASM64-NOMULTIVAL-NEXT: [[C4:%[0-9]+]]:_(p0) = G_CONSTANT i64 0
+ ; WASM64-NOMULTIVAL-NEXT: [[C5:%[0-9]+]]:_(s32) = G_FCONSTANT float 0.000000e+00
+ ; WASM64-NOMULTIVAL-NEXT: [[C6:%[0-9]+]]:_(s64) = G_FCONSTANT double 0.000000e+00
+ ; WASM64-NOMULTIVAL-NEXT: [[C7:%[0-9]+]]:_(s128) = G_CONSTANT i128 0
+ ; WASM64-NOMULTIVAL-NEXT: G_STORE [[C]](s8), [[ARGUMENT_i64_]](p0) :: (store (s8), align 16)
+ ; WASM64-NOMULTIVAL-NEXT: [[C8:%[0-9]+]]:_(s64) = G_CONSTANT i64 2
+ ; WASM64-NOMULTIVAL-NEXT: [[PTR_ADD:%[0-9]+]]:_(p0) = nuw inbounds G_PTR_ADD [[ARGUMENT_i64_]], [[C8]](s64)
+ ; WASM64-NOMULTIVAL-NEXT: G_STORE [[C1]](s16), [[PTR_ADD]](p0) :: (store (s16))
+ ; WASM64-NOMULTIVAL-NEXT: [[C9:%[0-9]+]]:_(s64) = G_CONSTANT i64 4
+ ; WASM64-NOMULTIVAL-NEXT: [[PTR_ADD1:%[0-9]+]]:_(p0) = nuw inbounds G_PTR_ADD [[ARGUMENT_i64_]], [[C9]](s64)
+ ; WASM64-NOMULTIVAL-NEXT: G_STORE [[C2]](s32), [[PTR_ADD1]](p0) :: (store (s32))
+ ; WASM64-NOMULTIVAL-NEXT: [[C10:%[0-9]+]]:_(s64) = G_CONSTANT i64 8
+ ; WASM64-NOMULTIVAL-NEXT: [[PTR_ADD2:%[0-9]+]]:_(p0) = nuw inbounds G_PTR_ADD [[ARGUMENT_i64_]], [[C10]](s64)
+ ; WASM64-NOMULTIVAL-NEXT: G_STORE [[C3]](s64), [[PTR_ADD2]](p0) :: (store (s64))
+ ; WASM64-NOMULTIVAL-NEXT: [[C11:%[0-9]+]]:_(s64) = G_CONSTANT i64 16
+ ; WASM64-NOMULTIVAL-NEXT: [[PTR_ADD3:%[0-9]+]]:_(p0) = nuw inbounds G_PTR_ADD [[ARGUMENT_i64_]], [[C11]](s64)
+ ; WASM64-NOMULTIVAL-NEXT: G_STORE [[C4]](p0), [[PTR_ADD3]](p0) :: (store (p0), align 16)
+ ; WASM64-NOMULTIVAL-NEXT: [[C12:%[0-9]+]]:_(s64) = G_CONSTANT i64 24
+ ; WASM64-NOMULTIVAL-NEXT: [[PTR_ADD4:%[0-9]+]]:_(p0) = nuw inbounds G_PTR_ADD [[ARGUMENT_i64_]], [[C12]](s64)
+ ; WASM64-NOMULTIVAL-NEXT: G_STORE [[C5]](s32), [[PTR_ADD4]](p0) :: (store (s32), align 8)
+ ; WASM64-NOMULTIVAL-NEXT: [[C13:%[0-9]+]]:_(s64) = G_CONSTANT i64 32
+ ; WASM64-NOMULTIVAL-NEXT: [[PTR_ADD5:%[0-9]+]]:_(p0) = nuw inbounds G_PTR_ADD [[ARGUMENT_i64_]], [[C13]](s64)
+ ; WASM64-NOMULTIVAL-NEXT: G_STORE [[C6]](s64), [[PTR_ADD5]](p0) :: (store (s64), align 16)
+ ; WASM64-NOMULTIVAL-NEXT: [[C14:%[0-9]+]]:_(s64) = G_CONSTANT i64 48
+ ; WASM64-NOMULTIVAL-NEXT: [[PTR_ADD6:%[0-9]+]]:_(p0) = nuw inbounds G_PTR_ADD [[ARGUMENT_i64_]], [[C14]](s64)
+ ; WASM64-NOMULTIVAL-NEXT: G_STORE [[C7]](s128), [[PTR_ADD6]](p0) :: (store (s128))
+ ; WASM64-NOMULTIVAL-NEXT: RETURN implicit-def $arguments
+ ;
+ ; WASM32-MULTIVAL-LABEL: name: test_ret_struct
+ ; WASM32-MULTIVAL: bb.1 (%ir-block.0):
+ ; WASM32-MULTIVAL-NEXT: liveins: $arguments
+ ; WASM32-MULTIVAL-NEXT: {{ $}}
+ ; WASM32-MULTIVAL-NEXT: [[C:%[0-9]+]]:_(s8) = G_CONSTANT i8 0
+ ; WASM32-MULTIVAL-NEXT: [[C1:%[0-9]+]]:_(s16) = G_CONSTANT i16 0
+ ; WASM32-MULTIVAL-NEXT: [[C2:%[0-9]+]]:_(s32) = G_CONSTANT i32 0
+ ; WASM32-MULTIVAL-NEXT: [[C3:%[0-9]+]]:_(s64) = G_CONSTANT i64 0
+ ; WASM32-MULTIVAL-NEXT: [[C4:%[0-9]+]]:_(p0) = G_CONSTANT i32 0
+ ; WASM32-MULTIVAL-NEXT: [[C5:%[0-9]+]]:_(s32) = G_FCONSTANT float 0.000000e+00
+ ; WASM32-MULTIVAL-NEXT: [[C6:%[0-9]+]]:_(s64) = G_FCONSTANT double 0.000000e+00
+ ; WASM32-MULTIVAL-NEXT: [[C7:%[0-9]+]]:_(s128) = G_CONSTANT i128 0
+ ; WASM32-MULTIVAL-NEXT: [[ANYEXT:%[0-9]+]]:i32(s32) = G_ANYEXT [[C]](s8)
+ ; WASM32-MULTIVAL-NEXT: [[ANYEXT1:%[0-9]+]]:i32(s32) = G_ANYEXT [[C1]](s16)
+ ; WASM32-MULTIVAL-NEXT: [[UV:%[0-9]+]]:i64(s64), [[UV1:%[0-9]+]]:i64(s64) = G_UNMERGE_VALUES [[C7]](s128)
+ ; WASM32-MULTIVAL-NEXT: RETURN [[ANYEXT]](s32), [[ANYEXT1]](s32), [[C2]](s32), [[C3]](s64), [[C4]](p0), [[C5]](s32), [[C6]](s64), [[UV]](s64), [[UV1]](s64), implicit-def $arguments
+ ;
+ ; WASM64-MULTIVAL-LABEL: name: test_ret_struct
+ ; WASM64-MULTIVAL: bb.1 (%ir-block.0):
+ ; WASM64-MULTIVAL-NEXT: liveins: $arguments
+ ; WASM64-MULTIVAL-NEXT: {{ $}}
+ ; WASM64-MULTIVAL-NEXT: [[C:%[0-9]+]]:_(s8) = G_CONSTANT i8 0
+ ; WASM64-MULTIVAL-NEXT: [[C1:%[0-9]+]]:_(s16) = G_CONSTANT i16 0
+ ; WASM64-MULTIVAL-NEXT: [[C2:%[0-9]+]]:_(s32) = G_CONSTANT i32 0
+ ; WASM64-MULTIVAL-NEXT: [[C3:%[0-9]+]]:_(s64) = G_CONSTANT i64 0
+ ; WASM64-MULTIVAL-NEXT: [[C4:%[0-9]+]]:_(p0) = G_CONSTANT i64 0
+ ; WASM64-MULTIVAL-NEXT: [[C5:%[0-9]+]]:_(s32) = G_FCONSTANT float 0.000000e+00
+ ; WASM64-MULTIVAL-NEXT: [[C6:%[0-9]+]]:_(s64) = G_FCONSTANT double 0.000000e+00
+ ; WASM64-MULTIVAL-NEXT: [[C7:%[0-9]+]]:_(s128) = G_CONSTANT i128 0
+ ; WASM64-MULTIVAL-NEXT: [[ANYEXT:%[0-9]+]]:i32(s32) = G_ANYEXT [[C]](s8)
+ ; WASM64-MULTIVAL-NEXT: [[ANYEXT1:%[0-9]+]]:i32(s32) = G_ANYEXT [[C1]](s16)
+ ; WASM64-MULTIVAL-NEXT: [[UV:%[0-9]+]]:i64(s64), [[UV1:%[0-9]+]]:i64(s64) = G_UNMERGE_VALUES [[C7]](s128)
+ ; WASM64-MULTIVAL-NEXT: RETURN [[ANYEXT]](s32), [[ANYEXT1]](s32), [[C2]](s32), [[C3]](s64), [[C4]](p0), [[C5]](s32), [[C6]](s64), [[UV]](s64), [[UV1]](s64), implicit-def $arguments
+ ret %StructTy zeroinitializer
+}
diff --git a/llvm/test/CodeGen/WebAssembly/GlobalISel/irtranslator/ret-basics.ll b/llvm/test/CodeGen/WebAssembly/GlobalISel/irtranslator/ret-basics.ll
new file mode 100644
index 0000000000000..5c7af1f28a874
--- /dev/null
+++ b/llvm/test/CodeGen/WebAssembly/GlobalISel/irtranslator/ret-basics.ll
@@ -0,0 +1,153 @@
+; NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py UTC_ARGS: --version 6
+; RUN: llc -mtriple=wasm32 -global-isel -stop-after=irtranslator -verify-machineinstrs < %s | FileCheck %s -check-prefixes=CHECK,WASM32
+; RUN: llc -mtriple=wasm64 -global-isel -stop-after=irtranslator -verify-machineinstrs < %s | FileCheck %s -check-prefixes=CHECK,WASM64
+
+define void @test_ret_void() {
+ ; CHECK-LABEL: name: test_ret_void
+ ; CHECK: bb.1 (%ir-block.0):
+ ; CHECK-NEXT: liveins: $arguments
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: RETURN implicit-def $arguments
+ ret void
+}
+
+define i8 @test_ret_i8() {
+ ; CHECK-LABEL: name: test_ret_i8
+ ; CHECK: bb.1 (%ir-block.0):
+ ; CHECK-NEXT: liveins: $arguments
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: [[C:%[0-9]+]]:_(s8) = G_CONSTANT i8 0
+ ; CHECK-NEXT: [[ANYEXT:%[0-9]+]]:i32(s32) = G_ANYEXT [[C]](s8)
+ ; CHECK-NEXT: RETURN [[ANYEXT]](s32), implicit-def $arguments
+ ret i8 0
+}
+
+define zeroext i8 @test_ret_i8_zeroext() {
+ ; CHECK-LABEL: name: test_ret_i8_zeroext
+ ; CHECK: bb.1 (%ir-block.0):
+ ; CHECK-NEXT: liveins: $arguments
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: [[C:%[0-9]+]]:_(s8) = G_CONSTANT i8 -1
+ ; CHECK-NEXT: [[ZEXT:%[0-9]+]]:i32(s32) = G_ZEXT [[C]](s8)
+ ; CHECK-NEXT: RETURN [[ZEXT]](s32), implicit-def $arguments
+ ret i8 -1
+}
+
+define signext i8 @test_ret_i8_signext() {
+ ; CHECK-LABEL: name: test_ret_i8_signext
+ ; CHECK: bb.1 (%ir-block.0):
+ ; CHECK-NEXT: liveins: $arguments
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: [[C:%[0-9]+]]:_(s8) = G_CONSTANT i8 -1
+ ; CHECK-NEXT: [[SEXT:%[0-9]+]]:i32(s32) = G_SEXT [[C]](s8)
+ ; CHECK-NEXT: RETURN [[SEXT]](s32), implicit-def $arguments
+ ret i8 -1
+}
+
+
+define i16 @test_ret_i16() {
+ ; CHECK-LABEL: name: test_ret_i16
+ ; CHECK: bb.1 (%ir-block.0):
+ ; CHECK-NEXT: liveins: $arguments
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: [[C:%[0-9]+]]:_(s16) = G_CONSTANT i16 0
+ ; CHECK-NEXT: [[ANYEXT:%[0-9]+]]:i32(s32) = G_ANYEXT [[C]](s16)
+ ; CHECK-NEXT: RETURN [[ANYEXT]](s32), implicit-def $arguments
+ ret i16 0
+}
+
+define i32 @test_ret_i32() {
+ ; CHECK-LABEL: name: test_ret_i32
+ ; CHECK: bb.1 (%ir-block.0):
+ ; CHECK-NEXT: liveins: $arguments
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 0
+ ; CHECK-NEXT: RETURN [[C]](s32), implicit-def $arguments
+ ret i32 0
+}
+
+define i64 @test_ret_i64() {
+ ; CHECK-LABEL: name: test_ret_i64
+ ; CHECK: bb.1 (%ir-block.0):
+ ; CHECK-NEXT: liveins: $arguments
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: [[C:%[0-9]+]]:_(s64) = G_CONSTANT i64 0
+ ; CHECK-NEXT: RETURN [[C]](s64), implicit-def $arguments
+ ret i64 0
+}
+
+define ptr @test_ret_ptr() {
+ ; WASM32-LABEL: name: test_ret_ptr
+ ; WASM32: bb.1 (%ir-block.0):
+ ; WASM32-NEXT: liveins: $arguments
+ ; WASM32-NEXT: {{ $}}
+ ; WASM32-NEXT: [[C:%[0-9]+]]:_(p0) = G_CONSTANT i32 0
+ ; WASM32-NEXT: RETURN [[C]](p0), implicit-def $arguments
+ ;
+ ; WASM64-LABEL: name: test_ret_ptr
+ ; WASM64: bb.1 (%ir-block.0):
+ ; WASM64-NEXT: liveins: $arguments
+ ; WASM64-NEXT: {{ $}}
+ ; WASM64-NEXT: [[C:%[0-9]+]]:_(p0) = G_CONSTANT i64 0
+ ; WASM64-NEXT: RETURN [[C]](p0), implicit-def $arguments
+ ret ptr null
+}
+
+define half @test_ret_f16() {
+ ; CHECK-LABEL: name: test_ret_f16
+ ; CHECK: bb.1 (%ir-block.0):
+ ; CHECK-NEXT: liveins: $arguments
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: [[C:%[0-9]+]]:_(s16) = G_FCONSTANT half 0xH0000
+ ; CHECK-NEXT: [[ANYEXT:%[0-9]+]]:i32(s32) = G_ANYEXT [[C]](s16)
+ ; CHECK-NEXT: RETURN [[ANYEXT]](s32), implicit-def $arguments
+ ret half 0.0
+}
+
+define float @test_ret_f32() {
+ ; CHECK-LABEL: name: test_ret_f32
+ ; CHECK: bb.1 (%ir-block.0):
+ ; CHECK-NEXT: liveins: $arguments
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: [[C:%[0-9]+]]:_(s32) = G_FCONSTANT float 0.000000e+00
+ ; CHECK-NEXT: RETURN [[C]](s32), implicit-def $arguments
+ ret float 0.0
+}
+
+define double @test_ret_f64() {
+ ; CHECK-LABEL: name: test_ret_f64
+ ; CHECK: bb.1 (%ir-block.0):
+ ; CHECK-NEXT: liveins: $arguments
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: [[C:%[0-9]+]]:_(s64) = G_FCONSTANT double 0.000000e+00
+ ; CHECK-NEXT: RETURN [[C]](s64), implicit-def $arguments
+ ret double 0.0
+}
+
+%externref = type ptr addrspace(10)
+define %externref @test_ret_externref() {
+ ; CHECK-LABEL: name: test_ret_externref
+ ; CHECK: bb.1 (%ir-block.0):
+ ; CHECK-NEXT: liveins: $arguments
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: [[FRAME_INDEX:%[0-9]+]]:_(p0) = G_FRAME_INDEX %stack.0.ref_ptr
+ ; CHECK-NEXT: [[LOAD:%[0-9]+]]:_(p10) = G_LOAD [[FRAME_INDEX]](p0) :: (dereferenceable load (p10) from %ir.ref_ptr)
+ ; CHECK-NEXT: RETURN [[LOAD]](p10), implicit-def $arguments
+ %ref_ptr = alloca %externref
+ %ref = load %externref, ptr %ref_ptr
+ ret %externref %ref
+}
+
+%funcref = type ptr addrspace(20)
+define %funcref @test_ret_funcref() {
+ ; CHECK-LABEL: name: test_ret_funcref
+ ; CHECK: bb.1 (%ir-block.0):
+ ; CHECK-NEXT: liveins: $arguments
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: [[FRAME_INDEX:%[0-9]+]]:_(p0) = G_FRAME_INDEX %stack.0.ref_ptr
+ ; CHECK-NEXT: [[LOAD:%[0-9]+]]:_(p20) = G_LOAD [[FRAME_INDEX]](p0) :: (dereferenceable load (p20) from %ir.ref_ptr)
+ ; CHECK-NEXT: RETURN [[LOAD]](p20), implicit-def $arguments
+ %ref_ptr = alloca %funcref
+ %ref = load %funcref, ptr %ref_ptr
+ ret %funcref %ref
+}
diff --git a/llvm/test/CodeGen/WebAssembly/GlobalISel/irtranslator/ret-simd.ll b/llvm/test/CodeGen/WebAssembly/GlobalISel/irtranslator/ret-simd.ll
new file mode 100644
index 0000000000000..1c1462ff976f8
--- /dev/null
+++ b/llvm/test/CodeGen/WebAssembly/GlobalISel/irtranslator/ret-simd.ll
@@ -0,0 +1,90 @@
+; NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py UTC_ARGS: --version 6
+; RUN: llc -mtriple=wasm32 -mattr=+simd128 -global-isel -stop-after=irtranslator -verify-machineinstrs < %s | FileCheck %s -check-prefixes=CHECK,NO-FP16
+; RUN: llc -mtriple=wasm32 -mattr=+fp16,+simd128 -global-isel -stop-after=irtranslator -verify-machineinstrs < %s | FileCheck %s -check-prefixes=CHECK,FP16
+
+define <16 x i8> @test_ret_v16i8() {
+ ; CHECK-LABEL: name: test_ret_v16i8
+ ; CHECK: bb.1 (%ir-block.0):
+ ; CHECK-NEXT: liveins: $arguments
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: [[C:%[0-9]+]]:_(s8) = G_CONSTANT i8 0
+ ; CHECK-NEXT: [[BUILD_VECTOR:%[0-9]+]]:_(<16 x s8>) = G_BUILD_VECTOR [[C]](s8), [[C]](s8), [[C]](s8), [[C]](s8), [[C]](s8), [[C]](s8), [[C]](s8), [[C]](s8), [[C]](s8), [[C]](s8), [[C]](s8), [[C]](s8), [[C]](s8), [[C]](s8), [[C]](s8), [[C]](s8)
+ ; CHECK-NEXT: RETURN [[BUILD_VECTOR]](<16 x s8>), implicit-def $arguments
+ ret <16 x i8> zeroinitializer
+}
+
+define <8 x i16> @test_ret_v8i16() {
+ ; CHECK-LABEL: name: test_ret_v8i16
+ ; CHECK: bb.1 (%ir-block.0):
+ ; CHECK-NEXT: liveins: $arguments
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: [[C:%[0-9]+]]:_(s16) = G_CONSTANT i16 0
+ ; CHECK-NEXT: [[BUILD_VECTOR:%[0-9]+]]:_(<8 x s16>) = G_BUILD_VECTOR [[C]](s16), [[C]](s16), [[C]](s16), [[C]](s16), [[C]](s16), [[C]](s16), [[C]](s16), [[C]](s16)
+ ; CHECK-NEXT: RETURN [[BUILD_VECTOR]](<8 x s16>), implicit-def $arguments
+ ret <8 x i16> zeroinitializer
+}
+
+define <4 x i32> @test_ret_v4i32() {
+ ; CHECK-LABEL: name: test_ret_v4i32
+ ; CHECK: bb.1 (%ir-block.0):
+ ; CHECK-NEXT: liveins: $arguments
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 0
+ ; CHECK-NEXT: [[BUILD_VECTOR:%[0-9]+]]:_(<4 x s32>) = G_BUILD_VECTOR [[C]](s32), [[C]](s32), [[C]](s32), [[C]](s32)
+ ; CHECK-NEXT: RETURN [[BUILD_VECTOR]](<4 x s32>), implicit-def $arguments
+ ret <4 x i32> zeroinitializer
+}
+
+define <2 x i64> @test_ret_v2i64() {
+ ; CHECK-LABEL: name: test_ret_v2i64
+ ; CHECK: bb.1 (%ir-block.0):
+ ; CHECK-NEXT: liveins: $arguments
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: [[C:%[0-9]+]]:_(s64) = G_CONSTANT i64 0
+ ; CHECK-NEXT: [[BUILD_VECTOR:%[0-9]+]]:_(<2 x s64>) = G_BUILD_VECTOR [[C]](s64), [[C]](s64)
+ ; CHECK-NEXT: RETURN [[BUILD_VECTOR]](<2 x s64>), implicit-def $arguments
+ ret <2 x i64> zeroinitializer
+}
+
+define <8 x half> @test_ret_v8f16() {
+ ; NO-FP16-LABEL: name: test_ret_v8f16
+ ; NO-FP16: bb.1 (%ir-block.0):
+ ; NO-FP16-NEXT: liveins: $arguments
+ ; NO-FP16-NEXT: {{ $}}
+ ; NO-FP16-NEXT: [[ARGUMENT_i32_:%[0-9]+]]:i32(p0) = ARGUMENT_i32 0, implicit $arguments
+ ; NO-FP16-NEXT: [[C:%[0-9]+]]:_(s16) = G_FCONSTANT half 0xH0000
+ ; NO-FP16-NEXT: [[BUILD_VECTOR:%[0-9]+]]:_(<8 x s16>) = G_BUILD_VECTOR [[C]](s16), [[C]](s16), [[C]](s16), [[C]](s16), [[C]](s16), [[C]](s16), [[C]](s16), [[C]](s16)
+ ; NO-FP16-NEXT: G_STORE [[BUILD_VECTOR]](<8 x s16>), [[ARGUMENT_i32_]](p0) :: (store (<8 x s16>))
+ ; NO-FP16-NEXT: RETURN implicit-def $arguments
+ ;
+ ; FP16-LABEL: name: test_ret_v8f16
+ ; FP16: bb.1 (%ir-block.0):
+ ; FP16-NEXT: liveins: $arguments
+ ; FP16-NEXT: {{ $}}
+ ; FP16-NEXT: [[C:%[0-9]+]]:_(s16) = G_FCONSTANT half 0xH0000
+ ; FP16-NEXT: [[BUILD_VECTOR:%[0-9]+]]:_(<8 x s16>) = G_BUILD_VECTOR [[C]](s16), [[C]](s16), [[C]](s16), [[C]](s16), [[C]](s16), [[C]](s16), [[C]](s16), [[C]](s16)
+ ; FP16-NEXT: RETURN [[BUILD_VECTOR]](<8 x s16>), implicit-def $arguments
+ ret <8 x half> zeroinitializer
+}
+
+define <4 x float> @test_ret_v4f32() {
+ ; CHECK-LABEL: name: test_ret_v4f32
+ ; CHECK: bb.1 (%ir-block.0):
+ ; CHECK-NEXT: liveins: $arguments
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: [[C:%[0-9]+]]:_(s32) = G_FCONSTANT float 0.000000e+00
+ ; CHECK-NEXT: [[BUILD_VECTOR:%[0-9]+]]:_(<4 x s32>) = G_BUILD_VECTOR [[C]](s32), [[C]](s32), [[C]](s32), [[C]](s32)
+ ; CHECK-NEXT: RETURN [[BUILD_VECTOR]](<4 x s32>), implicit-def $arguments
+ ret <4 x float> zeroinitializer
+}
+
+define <2 x double> @test_ret_v2f64() {
+ ; CHECK-LABEL: name: test_ret_v2f64
+ ; CHECK: bb.1 (%ir-block.0):
+ ; CHECK-NEXT: liveins: $arguments
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: [[C:%[0-9]+]]:_(s64) = G_FCONSTANT double 0.000000e+00
+ ; CHECK-NEXT: [[BUILD_VECTOR:%[0-9]+]]:_(<2 x s64>) = G_BUILD_VECTOR [[C]](s64), [[C]](s64)
+ ; CHECK-NEXT: RETURN [[BUILD_VECTOR]](<2 x s64>), implicit-def $arguments
+ ret <2 x double> zeroinitializer
+}
More information about the llvm-commits
mailing list