diff --git a/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp b/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp --- a/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp +++ b/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp @@ -339,6 +339,8 @@ .Case("f32", WebAssembly::BlockType::F32) .Case("f64", WebAssembly::BlockType::F64) .Case("v128", WebAssembly::BlockType::V128) + .Case("funcref", WebAssembly::BlockType::Funcref) + .Case("externref", WebAssembly::BlockType::Externref) .Case("exnref", WebAssembly::BlockType::Exnref) .Case("void", WebAssembly::BlockType::Void) .Default(WebAssembly::BlockType::Invalid); diff --git a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.h b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.h --- a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.h +++ b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.h @@ -138,6 +138,8 @@ F32 = unsigned(wasm::ValType::F32), F64 = unsigned(wasm::ValType::F64), V128 = unsigned(wasm::ValType::V128), + Externref = unsigned(wasm::ValType::EXTERNREF), + Funcref = unsigned(wasm::ValType::FUNCREF), Exnref = unsigned(wasm::ValType::EXNREF), // Multivalue blocks (and other non-void blocks) are only emitted when the // blocks will never be exited and are at the ends of functions (see diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyFastISel.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyFastISel.cpp --- a/llvm/lib/Target/WebAssembly/WebAssemblyFastISel.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyFastISel.cpp @@ -928,6 +928,14 @@ Opc = WebAssembly::SELECT_EXNREF; RC = &WebAssembly::EXNREFRegClass; break; + case MVT::funcref: + Opc = WebAssembly::SELECT_FUNCREF; + RC = &WebAssembly::FUNCREFRegClass; + break; + case MVT::externref: + Opc = WebAssembly::SELECT_EXTERNREF; + RC = &WebAssembly::EXTERNREFRegClass; + break; default: return false; } diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyInstrRef.td b/llvm/lib/Target/WebAssembly/WebAssemblyInstrRef.td --- a/llvm/lib/Target/WebAssembly/WebAssemblyInstrRef.td +++ b/llvm/lib/Target/WebAssembly/WebAssemblyInstrRef.td @@ -1,6 +1,6 @@ // WebAssemblyInstrRef.td - WebAssembly reference type codegen --*- tablegen -*- // -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// Pareg of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // @@ -11,27 +11,30 @@ /// //===----------------------------------------------------------------------===// -defm SELECT_EXNREF : I<(outs EXNREF:$dst), - (ins EXNREF:$lhs, EXNREF:$rhs, I32:$cond), - (outs), (ins), - [(set EXNREF:$dst, - (select I32:$cond, EXNREF:$lhs, EXNREF:$rhs))], - "exnref.select\t$dst, $lhs, $rhs, $cond", - "exnref.select", 0x1b>; +multiclass REF_I { + defm REF_NULL_#reg : I<(outs reg:$res), (ins HeapType:$heaptype), + (outs), (ins HeapType:$heaptype), + [], + "ref.null\t$res, $heaptype", + "ref.null\t$heaptype", + 0xd0>, + Requires<[HasReferenceTypes]>; + defm SELECT_#reg: I<(outs reg:$dst), (ins reg:$lhs, reg:$rhs, I32:$cond), + (outs), (ins), + [(set reg:$dst, + (select I32:$cond, reg:$lhs, reg:$rhs))], + vt#".select\t$dst, $lhs, $rhs, $cond", + vt#".select", 0x1b>, + Requires<[HasReferenceTypes]>; +} -def : Pat<(select (i32 (setne I32:$cond, 0)), EXNREF:$lhs, EXNREF:$rhs), - (SELECT_EXNREF EXNREF:$lhs, EXNREF:$rhs, I32:$cond)>; -def : Pat<(select (i32 (seteq I32:$cond, 0)), EXNREF:$lhs, EXNREF:$rhs), - (SELECT_EXNREF EXNREF:$rhs, EXNREF:$lhs, I32:$cond)>; +defm "" : REF_I; +defm "" : REF_I; +defm "" : REF_I; -multiclass REF { - defm REF_NULL_#rt : I<(outs rt:$res), (ins HeapType:$heaptype), - (outs), (ins HeapType:$heaptype), - [], - "ref.null\t$res, $heaptype", - "ref.null\t$heaptype", - 0xd0>; +foreach reg = [FUNCREF, EXTERNREF, EXNREF] in { +def : Pat<(select (i32 (setne I32:$cond, 0)), reg:$lhs, reg:$rhs), + (!cast("SELECT_"#reg) reg:$lhs, reg:$rhs, I32:$cond)>; +def : Pat<(select (i32 (seteq I32:$cond, 0)), reg:$lhs, reg:$rhs), + (!cast("SELECT_"#reg) reg:$rhs, reg:$lhs, I32:$cond)>; } - -defm "" : REF, Requires<[HasReferenceTypes]>; -defm "" : REF, Requires<[HasReferenceTypes]>; diff --git a/llvm/test/MC/WebAssembly/reference-types.s b/llvm/test/MC/WebAssembly/reference-types.s --- a/llvm/test/MC/WebAssembly/reference-types.s +++ b/llvm/test/MC/WebAssembly/reference-types.s @@ -1,20 +1,41 @@ # RUN: llvm-mc -show-encoding -triple=wasm32-unknown-unknown -mattr=+reference-types < %s | FileCheck %s # RUN: llvm-mc -show-encoding -triple=wasm64-unknown-unknown -mattr=+reference-types < %s | FileCheck %s -# CHECK: ref_null_externref: -# CHECK-NEXT: .functype ref_null_externref () -> (externref) -# CHECK: ref.null extern # encoding: [0xd0,0x6f] -# CHECK-NEXT: end_function -ref_null_externref: - .functype ref_null_externref () -> (externref) +# CHECK-LABEL: ref_null_test: +# CHECK: ref.null func # encoding: [0xd0,0x70] +# CHECK: ref.null extern # encoding: [0xd0,0x6f] +ref_null_test: + .functype ref_null_test() -> () + ref.null func + drop ref.null extern + drop end_function -# CHECK: ref_null_funcref: -# CHECK-NEXT: .functype ref_null_funcref () -> (funcref) -# CHECK: ref.null func # encoding: [0xd0,0x70] -# CHECK-NEXT: end_function -ref_null_funcref: - .functype ref_null_funcref () -> (funcref) +# CHECK-LABEL: ref_select_test: +# CHECK: funcref.select # encoding: [0x1b] +# CHECK: externref.select # encoding: [0x1b] +ref_select_test: + .functype ref_select_test () -> () + ref.null func ref.null func + i32.const 0 + funcref.select + drop + ref.null extern + ref.null extern + i32.const 0 + externref.select + drop + end_function + +# CHECK-LABEL: ref_block_test: +# CHECK: block funcref +# CHECK: block externref +ref_block_test: + .functype ref_block_test () -> () + block funcref + block externref + end_block + end_block end_function