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 @@ -320,6 +322,10 @@ case WebAssembly::ARGUMENT_v4f32_S: case WebAssembly::ARGUMENT_v2f64: case WebAssembly::ARGUMENT_v2f64_S: + case WebAssembly::ARGUMENT_funcref: + case WebAssembly::ARGUMENT_funcref_S: + case WebAssembly::ARGUMENT_externref: + case WebAssembly::ARGUMENT_externref_S: case WebAssembly::ARGUMENT_exnref: case WebAssembly::ARGUMENT_exnref_S: return true; @@ -340,6 +346,10 @@ case WebAssembly::COPY_F64_S: case WebAssembly::COPY_V128: case WebAssembly::COPY_V128_S: + case WebAssembly::COPY_FUNCREF: + case WebAssembly::COPY_FUNCREF_S: + case WebAssembly::COPY_EXTERNREF: + case WebAssembly::COPY_EXTERNREF_S: case WebAssembly::COPY_EXNREF: case WebAssembly::COPY_EXNREF_S: return true; @@ -360,6 +370,10 @@ case WebAssembly::TEE_F64_S: case WebAssembly::TEE_V128: case WebAssembly::TEE_V128_S: + case WebAssembly::TEE_FUNCREF: + case WebAssembly::TEE_FUNCREF_S: + case WebAssembly::TEE_EXTERNREF: + case WebAssembly::TEE_EXTERNREF_S: case WebAssembly::TEE_EXNREF: case WebAssembly::TEE_EXNREF_S: return true; diff --git a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.cpp b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.cpp --- a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.cpp +++ b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.cpp @@ -147,6 +147,10 @@ case MVT::v4f32: case MVT::v2f64: return wasm::ValType::V128; + case MVT::funcref: + return wasm::ValType::FUNCREF; + case MVT::externref: + return wasm::ValType::EXTERNREF; case MVT::exnref: return wasm::ValType::EXNREF; default: diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyCFGStackify.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyCFGStackify.cpp --- a/llvm/lib/Target/WebAssembly/WebAssemblyCFGStackify.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyCFGStackify.cpp @@ -773,6 +773,10 @@ return WebAssembly::COPY_F64; if (RC == &WebAssembly::V128RegClass) return WebAssembly::COPY_V128; + if (RC == &WebAssembly::FUNCREFRegClass) + return WebAssembly::COPY_FUNCREF; + if (RC == &WebAssembly::EXTERNREFRegClass) + return WebAssembly::COPY_EXTERNREF; if (RC == &WebAssembly::EXNREFRegClass) return WebAssembly::COPY_EXNREF; llvm_unreachable("Unexpected register class"); diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyExplicitLocals.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyExplicitLocals.cpp --- a/llvm/lib/Target/WebAssembly/WebAssemblyExplicitLocals.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyExplicitLocals.cpp @@ -96,6 +96,10 @@ return WebAssembly::DROP_F64; if (RC == &WebAssembly::V128RegClass) return WebAssembly::DROP_V128; + if (RC == &WebAssembly::FUNCREFRegClass) + return WebAssembly::DROP_FUNCREF; + if (RC == &WebAssembly::EXTERNREFRegClass) + return WebAssembly::DROP_EXTERNREF; if (RC == &WebAssembly::EXNREFRegClass) return WebAssembly::DROP_EXNREF; llvm_unreachable("Unexpected register class"); 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 @@ -706,6 +706,14 @@ Opc = WebAssembly::ARGUMENT_v2f64; RC = &WebAssembly::V128RegClass; break; + case MVT::funcref: + Opc = WebAssembly::ARGUMENT_funcref; + RC = &WebAssembly::FUNCREFRegClass; + break; + case MVT::externref: + Opc = WebAssembly::ARGUMENT_externref; + RC = &WebAssembly::EXTERNREFRegClass; + break; case MVT::exnref: Opc = WebAssembly::ARGUMENT_exnref; RC = &WebAssembly::EXNREFRegClass; @@ -928,6 +936,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; } @@ -1329,6 +1345,8 @@ case MVT::v2i64: case MVT::v4f32: case MVT::v2f64: + case MVT::funcref: + case MVT::externref: case MVT::exnref: break; default: diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.cpp --- a/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.cpp @@ -76,6 +76,10 @@ CopyOpcode = WebAssembly::COPY_F64; else if (RC == &WebAssembly::V128RegClass) CopyOpcode = WebAssembly::COPY_V128; + else if (RC == &WebAssembly::FUNCREFRegClass) + CopyOpcode = WebAssembly::COPY_FUNCREF; + else if (RC == &WebAssembly::EXTERNREFRegClass) + CopyOpcode = WebAssembly::COPY_EXTERNREF; else if (RC == &WebAssembly::EXNREFRegClass) CopyOpcode = WebAssembly::COPY_EXNREF; else 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 @@ -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/lib/Target/WebAssembly/WebAssemblyPeephole.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyPeephole.cpp --- a/llvm/lib/Target/WebAssembly/WebAssemblyPeephole.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyPeephole.cpp @@ -111,6 +111,12 @@ case WebAssembly::V128RegClassID: CopyLocalOpc = WebAssembly::COPY_V128; break; + case WebAssembly::FUNCREFRegClassID: + CopyLocalOpc = WebAssembly::COPY_FUNCREF; + break; + case WebAssembly::EXTERNREFRegClassID: + CopyLocalOpc = WebAssembly::COPY_EXTERNREF; + break; case WebAssembly::EXNREFRegClassID: CopyLocalOpc = WebAssembly::COPY_EXNREF; break; 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,53 @@ # 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-LABEL: ref_sig_test_funcref: +# CHECK-NEXT: .functype ref_sig_test_funcref (funcref) -> (funcref) +ref_sig_test_funcref: + .functype ref_sig_test_funcref (funcref) -> (funcref) + end_function + +# CHECK-LABEL: ref_sig_test_externref: +# CHECK-NEXT: .functype ref_sig_test_externref (externref) -> (externref) +ref_sig_test_externref: + .functype ref_sig_test_externref (externref) -> (externref) 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