[WebAssembly] Implementation of (most) table instructions

Implementation of instructions table.get, table.set, table.grow,
table.size, table.fill, table.copy.

Missing instructions are table.init and elem.drop as they deal with
element sections which are not yet implemented.

Added more tests to tables.s

Differential Revision: https://reviews.llvm.org/D89797
This commit is contained in:
Paulo Matos 2020-10-23 08:36:06 -07:00 committed by Sam Clegg
parent e7d37742a2
commit 69e2797eae
19 changed files with 320 additions and 36 deletions

View File

@ -22,3 +22,4 @@ WASM_RELOC(R_WASM_MEMORY_ADDR_I64, 16)
WASM_RELOC(R_WASM_MEMORY_ADDR_REL_SLEB64, 17)
WASM_RELOC(R_WASM_TABLE_INDEX_SLEB64, 18)
WASM_RELOC(R_WASM_TABLE_INDEX_I64, 19)
WASM_RELOC(R_WASM_TABLE_NUMBER_LEB, 20)

View File

@ -194,6 +194,9 @@ def FlagVT : ValueType<0 , 158>; // Pre-RA sched glue
def isVoid : ValueType<0 , 159>; // Produces no value
def untyped: ValueType<8 , 160>; // Produces an untyped value
def exnref : ValueType<0 , 161>; // WebAssembly's exnref type
def funcref : ValueType<0 , 162>; // WebAssembly's funcref type
def externref : ValueType<0 , 163>; // WebAssembly's externref type
def token : ValueType<0 , 248>; // TokenTy
def MetadataVT: ValueType<0, 249>; // Metadata

View File

@ -51,6 +51,8 @@ public:
return Info.Kind == wasm::WASM_SYMBOL_TYPE_FUNCTION;
}
bool isTypeTable() const { return Info.Kind == wasm::WASM_SYMBOL_TYPE_TABLE; }
bool isTypeData() const { return Info.Kind == wasm::WASM_SYMBOL_TYPE_DATA; }
bool isTypeGlobal() const {
@ -222,6 +224,7 @@ private:
bool isValidEventIndex(uint32_t Index) const;
bool isDefinedEventIndex(uint32_t Index) const;
bool isValidFunctionSymbol(uint32_t Index) const;
bool isValidTableSymbol(uint32_t Index) const;
bool isValidGlobalSymbol(uint32_t Index) const;
bool isValidEventSymbol(uint32_t Index) const;
bool isValidDataSymbol(uint32_t Index) const;

View File

@ -245,9 +245,11 @@ namespace llvm {
// will be determined by the opcode.
exnref = 161, // WebAssembly's exnref type
funcref = 162, // WebAssembly's funcref type
externref = 163, // WebAssembly's externref type
FIRST_VALUETYPE = 1, // This is always the beginning of the list.
LAST_VALUETYPE = 162, // This always remains at the end of the list.
LAST_VALUETYPE = 164, // This always remains at the end of the list.
// This is the current maximum for LAST_VALUETYPE.
// MVT::MAX_ALLOWED_VALUETYPE is used for asserts and to size bit vectors
@ -973,7 +975,9 @@ namespace llvm {
case v1024f32: return TypeSize::Fixed(32768);
case v2048i32:
case v2048f32: return TypeSize::Fixed(65536);
case exnref: return TypeSize::Fixed(0); // opaque type
case exnref:
case funcref:
case externref: return TypeSize::Fixed(0); // opaque type
}
}

View File

@ -158,15 +158,17 @@ std::string EVT::getEVTString() const {
if (isFloatingPoint())
return "f" + utostr(getSizeInBits());
llvm_unreachable("Invalid EVT!");
case MVT::bf16: return "bf16";
case MVT::ppcf128: return "ppcf128";
case MVT::isVoid: return "isVoid";
case MVT::Other: return "ch";
case MVT::Glue: return "glue";
case MVT::x86mmx: return "x86mmx";
case MVT::Metadata:return "Metadata";
case MVT::Untyped: return "Untyped";
case MVT::exnref : return "exnref";
case MVT::bf16: return "bf16";
case MVT::ppcf128: return "ppcf128";
case MVT::isVoid: return "isVoid";
case MVT::Other: return "ch";
case MVT::Glue: return "glue";
case MVT::x86mmx: return "x86mmx";
case MVT::Metadata: return "Metadata";
case MVT::Untyped: return "Untyped";
case MVT::exnref: return "exnref";
case MVT::funcref: return "funcref";
case MVT::externref: return "externref";
}
}

View File

@ -559,6 +559,7 @@ WasmObjectWriter::getProvisionalValue(const WasmRelocationEntry &RelEntry,
case wasm::R_WASM_GLOBAL_INDEX_LEB:
case wasm::R_WASM_GLOBAL_INDEX_I32:
case wasm::R_WASM_EVENT_INDEX_LEB:
case wasm::R_WASM_TABLE_NUMBER_LEB:
// Provisional value is function/global/event Wasm index
assert(WasmIndices.count(RelEntry.Symbol) > 0 && "symbol not found in wasm index space");
return WasmIndices[RelEntry.Symbol];
@ -663,6 +664,7 @@ void WasmObjectWriter::applyRelocations(
case wasm::R_WASM_GLOBAL_INDEX_LEB:
case wasm::R_WASM_MEMORY_ADDR_LEB:
case wasm::R_WASM_EVENT_INDEX_LEB:
case wasm::R_WASM_TABLE_NUMBER_LEB:
writePatchableLEB<5>(Stream, Value, Offset);
break;
case wasm::R_WASM_MEMORY_ADDR_LEB64:

View File

@ -552,6 +552,7 @@ static bool supportsWasm32(uint64_t Type) {
case wasm::R_WASM_SECTION_OFFSET_I32:
case wasm::R_WASM_EVENT_INDEX_LEB:
case wasm::R_WASM_GLOBAL_INDEX_I32:
case wasm::R_WASM_TABLE_NUMBER_LEB:
return true;
default:
return false;
@ -585,6 +586,7 @@ static uint64_t resolveWasm32(RelocationRef R, uint64_t S, uint64_t A) {
case wasm::R_WASM_SECTION_OFFSET_I32:
case wasm::R_WASM_EVENT_INDEX_LEB:
case wasm::R_WASM_GLOBAL_INDEX_I32:
case wasm::R_WASM_TABLE_NUMBER_LEB:
// For wasm section, its offset at 0 -- ignoring Value
return A;
default:

View File

@ -822,6 +822,11 @@ Error WasmObjectFile::parseRelocSection(StringRef Name, ReadContext &Ctx) {
return make_error<GenericBinaryError>("Bad relocation function index",
object_error::parse_failed);
break;
case wasm::R_WASM_TABLE_NUMBER_LEB:
if (!isValidTableSymbol(Reloc.Index))
return make_error<GenericBinaryError>("Bad relocation table index",
object_error::parse_failed);
break;
case wasm::R_WASM_TYPE_INDEX_LEB:
if (Reloc.Index >= Signatures.size())
return make_error<GenericBinaryError>("Bad relocation type index",
@ -1181,6 +1186,10 @@ bool WasmObjectFile::isValidFunctionSymbol(uint32_t Index) const {
return Index < Symbols.size() && Symbols[Index].isTypeFunction();
}
bool WasmObjectFile::isValidTableSymbol(uint32_t Index) const {
return Index < Symbols.size() && Symbols[Index].isTypeTable();
}
bool WasmObjectFile::isValidGlobalSymbol(uint32_t Index) const {
return Index < Symbols.size() && Symbols[Index].isTypeGlobal();
}

View File

@ -198,6 +198,7 @@ MCDisassembler::DecodeStatus WebAssemblyDisassembler::getInstruction(
case WebAssembly::OPERAND_LOCAL:
case WebAssembly::OPERAND_GLOBAL:
case WebAssembly::OPERAND_FUNCTION32:
case WebAssembly::OPERAND_TABLE:
case WebAssembly::OPERAND_OFFSET32:
case WebAssembly::OPERAND_OFFSET64:
case WebAssembly::OPERAND_P2ALIGN:

View File

@ -151,6 +151,7 @@ void WebAssemblyMCCodeEmitter::encodeInstruction(
PaddedSize = 10;
break;
case WebAssembly::OPERAND_FUNCTION32:
case WebAssembly::OPERAND_TABLE:
case WebAssembly::OPERAND_OFFSET32:
case WebAssembly::OPERAND_SIGNATURE:
case WebAssembly::OPERAND_TYPEINDEX:

View File

@ -76,6 +76,8 @@ enum OperandType {
OPERAND_EVENT,
/// A list of branch targets for br_list.
OPERAND_BRLIST,
/// 32-bit unsigned table number.
OPERAND_TABLE,
};
} // end namespace WebAssembly

View File

@ -102,6 +102,8 @@ unsigned WebAssemblyWasmObjectWriter::getRelocType(const MCValue &Target,
return wasm::R_WASM_FUNCTION_INDEX_LEB;
if (SymA.isEvent())
return wasm::R_WASM_EVENT_INDEX_LEB;
if (SymA.isTable())
return wasm::R_WASM_TABLE_NUMBER_LEB;
return wasm::R_WASM_MEMORY_ADDR_LEB;
case WebAssembly::fixup_uleb128_i64:
assert(SymA.isData());

View File

@ -115,6 +115,10 @@ static unsigned getLocalGetOpcode(const TargetRegisterClass *RC) {
return WebAssembly::LOCAL_GET_V128;
if (RC == &WebAssembly::EXNREFRegClass)
return WebAssembly::LOCAL_GET_EXNREF;
if (RC == &WebAssembly::FUNCREFRegClass)
return WebAssembly::LOCAL_GET_FUNCREF;
if (RC == &WebAssembly::EXTERNREFRegClass)
return WebAssembly::LOCAL_GET_EXTERNREF;
llvm_unreachable("Unexpected register class");
}
@ -132,6 +136,10 @@ static unsigned getLocalSetOpcode(const TargetRegisterClass *RC) {
return WebAssembly::LOCAL_SET_V128;
if (RC == &WebAssembly::EXNREFRegClass)
return WebAssembly::LOCAL_SET_EXNREF;
if (RC == &WebAssembly::FUNCREFRegClass)
return WebAssembly::LOCAL_SET_FUNCREF;
if (RC == &WebAssembly::EXTERNREFRegClass)
return WebAssembly::LOCAL_SET_EXTERNREF;
llvm_unreachable("Unexpected register class");
}
@ -149,6 +157,10 @@ static unsigned getLocalTeeOpcode(const TargetRegisterClass *RC) {
return WebAssembly::LOCAL_TEE_V128;
if (RC == &WebAssembly::EXNREFRegClass)
return WebAssembly::LOCAL_TEE_EXNREF;
if (RC == &WebAssembly::FUNCREFRegClass)
return WebAssembly::LOCAL_TEE_FUNCREF;
if (RC == &WebAssembly::EXTERNREFRegClass)
return WebAssembly::LOCAL_TEE_EXTERNREF;
llvm_unreachable("Unexpected register class");
}
@ -166,6 +178,10 @@ static MVT typeForRegClass(const TargetRegisterClass *RC) {
return MVT::v16i8;
if (RC == &WebAssembly::EXNREFRegClass)
return MVT::exnref;
if (RC == &WebAssembly::FUNCREFRegClass)
return MVT::funcref;
if (RC == &WebAssembly::EXTERNREFRegClass)
return MVT::externref;
llvm_unreachable("unrecognized register class");
}

View File

@ -129,6 +129,8 @@ private:
case MVT::f32:
case MVT::f64:
case MVT::exnref:
case MVT::funcref:
case MVT::externref:
return VT;
case MVT::f16:
return MVT::f32;
@ -809,6 +811,12 @@ bool WebAssemblyFastISel::selectCall(const Instruction *I) {
case MVT::exnref:
ResultReg = createResultReg(&WebAssembly::EXNREFRegClass);
break;
case MVT::funcref:
ResultReg = createResultReg(&WebAssembly::FUNCREFRegClass);
break;
case MVT::externref:
ResultReg = createResultReg(&WebAssembly::EXTERNREFRegClass);
break;
default:
return false;
}

View File

@ -163,6 +163,9 @@ def vec_i64imm_op : Operand<i64>;
let OperandType = "OPERAND_FUNCTION32" in
def function32_op : Operand<i32>;
let OperandType = "OPERAND_TABLE" in
def table32_op : Operand<i32>;
let OperandType = "OPERAND_OFFSET32" in
def offset32_op : Operand<i32>;
@ -237,6 +240,8 @@ defm "": ARGUMENT<I64, i64>;
defm "": ARGUMENT<F32, f32>;
defm "": ARGUMENT<F64, f64>;
defm "": ARGUMENT<EXNREF, exnref>;
defm "": ARGUMENT<FUNCREF, funcref>;
defm "": ARGUMENT<EXTERNREF, externref>;
// local.get and local.set are not generated by instruction selection; they
// are implied by virtual register uses and defs.
@ -307,6 +312,8 @@ defm "" : LOCAL<F32>;
defm "" : LOCAL<F64>;
defm "" : LOCAL<V128>, Requires<[HasSIMD128]>;
defm "" : LOCAL<EXNREF>, Requires<[HasExceptionHandling]>;
defm "" : LOCAL<FUNCREF>, Requires<[HasReferenceTypes]>;
defm "" : LOCAL<EXTERNREF>, Requires<[HasReferenceTypes]>;
let isMoveImm = 1, isAsCheapAsAMove = 1, isReMaterializable = 1 in {
defm CONST_I32 : I<(outs I32:$res), (ins i32imm_op:$imm),
@ -365,3 +372,4 @@ include "WebAssemblyInstrAtomics.td"
include "WebAssemblyInstrSIMD.td"
include "WebAssemblyInstrRef.td"
include "WebAssemblyInstrBulkMemory.td"
include "WebAssemblyInstrTable.td"

View File

@ -0,0 +1,64 @@
// WebAssemblyInstrTable.td - WebAssembly Table codegen support -*- tablegen -*-
//
// Part 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
//
//===----------------------------------------------------------------------===//
///
/// \file
/// WebAssembly Table operand code-gen constructs.
/// Instructions that handle tables
//===----------------------------------------------------------------------===//
multiclass TABLE<WebAssemblyRegClass rt> {
defm TABLE_GET_#rt : I<(outs rt:$res), (ins table32_op:$table),
(outs), (ins table32_op:$table),
[],
"table.get\t$res, $table",
"table.get\t$table",
0x25>;
defm TABLE_SET_#rt : I<(outs), (ins table32_op:$table, rt:$val, I32:$i),
(outs), (ins table32_op:$table),
[],
"table.set\t$table, $val, $i",
"table.set\t$table",
0x26>;
defm TABLE_GROW_#rt : I<(outs I32:$sz), (ins table32_op:$table, I32:$n, rt:$val),
(outs), (ins table32_op:$table),
[],
"table.grow\t$sz, $table, $n, $val",
"table.grow\t$table",
0xfc0f>;
defm TABLE_FILL_#rt : I<(outs), (ins table32_op:$table, I32:$n, rt:$val, I32:$i),
(outs), (ins table32_op:$table),
[],
"table.fill\t$table, $n, $val, $i",
"table.fill\t$table",
0xfc11>;
}
defm "" : TABLE<FUNCREF>, Requires<[HasReferenceTypes]>;
defm "" : TABLE<EXTERNREF>, Requires<[HasReferenceTypes]>;
defm TABLE_SIZE : I<(outs I32:$sz), (ins table32_op:$table),
(outs), (ins table32_op:$table),
[],
"table.size\t$sz, $table",
"table.size\t$table",
0xfc10>,
Requires<[HasReferenceTypes]>;
defm TABLE_COPY : I<(outs), (ins table32_op:$table1, table32_op:$table2, I32:$n, I32:$s, I32:$d),
(outs), (ins table32_op:$table1, table32_op:$table2),
[],
"table.copy\t$table1, $table2, $n, $s, $d",
"table.copy\t$table1, $table2",
0xfc0e>,
Requires<[HasReferenceTypes]>;

View File

@ -44,6 +44,8 @@ def F64_0 : WebAssemblyReg<"%f64.0">;
def V128_0: WebAssemblyReg<"%v128">;
def EXNREF_0 : WebAssemblyReg<"%exnref.0">;
def FUNCREF_0 : WebAssemblyReg<"%funcref.0">;
def EXTERNREF_0 : WebAssemblyReg<"%externref.0">;
// The value stack "register". This is an opaque entity which serves to order
// uses and defs that must remain in LIFO order.
@ -65,3 +67,5 @@ def F64 : WebAssemblyRegClass<[f64], 64, (add F64_0)>;
def V128 : WebAssemblyRegClass<[v4f32, v2f64, v2i64, v4i32, v16i8, v8i16], 128,
(add V128_0)>;
def EXNREF : WebAssemblyRegClass<[exnref], 0, (add EXNREF_0)>;
def FUNCREF : WebAssemblyRegClass<[funcref], 0, (add FUNCREF_0)>;
def EXTERNREF : WebAssemblyRegClass<[externref], 0, (add EXTERNREF_0)>;

View File

@ -1,19 +1,123 @@
# RUN: llvm-mc -triple=wasm32-unknown-unknown < %s | FileCheck %s
# RUN: llvm-mc -triple=wasm32-unknown-unknown -filetype=obj < %s | obj2yaml | FileCheck -check-prefix=BIN %s
# RUN: llvm-mc -triple=wasm32-unknown-unknown -mattr=+reference-types < %s | FileCheck %s
# RUN: llvm-mc -show-encoding -triple=wasm32-unknown-unknown -mattr=+reference-types < %s | FileCheck -check-prefix=ENC %s
# RUN: llvm-mc -triple=wasm32-unknown-unknown -mattr=+reference-types -filetype=obj < %s | obj2yaml | FileCheck -check-prefix=BIN %s
# Test creating several empty tables
# Creating several empty tables
.tabletype foo, externref
# CHECK: .tabletype foo, externref
# CHECK: foo:
.tabletype foo, externref
foo:
bar:
.tabletype bar, funcref
# CHECK: .tabletype foo, externref
# CHECK: foo:
# CHECK: bar:
# CHECK-NEXT: .tabletype bar, funcref
# CHECK-NEXT: .tabletype bar, funcref
bar:
.tabletype bar, funcref
table1:
.tabletype table1, funcref
table2:
.tabletype table2, funcref
# Table instructions
# CHECK: copy_tables:
# CHECK-NEXT: .functype copy_tables (i32, i32) -> ()
# CHECK-NEXT: local.get 0
# CHECK-NEXT: local.get 1
# CHECK: table.size table1
# CHECK: table.copy table1, table2
# CHECK-NEXT: end_function
# CHECK-NEXT:.Ltmp0:
# CHECK-NEXT: .size copy_tables, .Ltmp0-copy_tables
copy_tables:
.functype copy_tables (i32, i32) -> ()
local.get 0
local.get 1
# ENC: table.size table1 # encoding: [0xfc,0x10,0x80'A',0x80'A',0x80'A',0x80'A',A]
table.size table1
# ENC: table.copy table1, table2 # encoding: [0xfc,0x0e,0x80'A',0x80'A',0x80'A',0x80'A',A,0x80'B',0x80'B',0x80'B',0x80'B',B]
table.copy table1, table2
end_function
# CHECK: table_get:
# CHECK-NEXT: .functype table_get (i32) -> (externref)
# CHECK-NEXT: local.get 0
# CHECK: table.get foo
# CHECK-NEXT: end_function
# CHECK-NEXT: .Ltmp1:
# CHECK-NEXT: .size table_get, .Ltmp1-table_get
table_get:
.functype table_get (i32) -> (externref)
local.get 0
# ENC: table.get foo # encoding: [0x25,0x80'A',0x80'A',0x80'A',0x80'A',A]
table.get foo
end_function
# CHECK: table_set:
# CHECK-NEXT: .functype table_set (i32, externref) -> ()
# CHECK-NEXT: local.get 0
# CHECK-NEXT: local.get 1
# CHECK: table.set foo
# CHECK-NEXT: end_function
# CHECK-NEXT: .Ltmp2:
# CHECK-NEXT: .size table_set, .Ltmp2-table_set
table_set:
.functype table_set (i32, externref) -> ()
local.get 0
local.get 1
# ENC: table.set foo # encoding: [0x26,0x80'A',0x80'A',0x80'A',0x80'A',A]
table.set foo
end_function
# CHECK: table_grow:
# CHECK-NEXT: .functype table_grow (i32) -> (i32)
# CHECK-NEXT: i32.const 0
# CHECK-NEXT: table.get foo
# CHECK-NEXT: local.get 0
# CHECK: table.grow foo
# CHECK-NEXT: local.get 0
# CHECK-NEXT: i32.add
# CHECK-NEXT: end_function
# CHECK-NEXT: .Ltmp3:
# CHECK-NEXT: .size table_grow, .Ltmp3-table_grow
table_grow:
.functype table_grow (i32) -> (i32)
i32.const 0
table.get foo
local.get 0
# ENC: table.grow foo # encoding: [0xfc,0x0f,0x80'A',0x80'A',0x80'A',0x80'A',A]
table.grow foo
local.get 0
i32.add
end_function
# CHECK: table_fill:
# CHECK-NEXT: .functype table_fill (i32, i32) -> ()
# CHECK-NEXT: local.get 0
# CHECK-NEXT: i32.const 0
# CHECK-NEXT: table.get table1
# CHECK-NEXT: local.get 1
# CHECK: table.fill table1
# CHECK-NEXT: end_function
# CHECK-NEXT: .Ltmp4:
# CHECK-NEXT: .size table_fill, .Ltmp4-table_fill
table_fill:
.functype table_fill (i32, i32) -> ()
local.get 0
i32.const 0
table.get table1
local.get 1
# ENC: table.fill table1 # encoding: [0xfc,0x11,0x80'A',0x80'A',0x80'A',0x80'A',A]
table.fill table1
end_function
# BIN: - Type: TABLE
# BIN-NEXT: Tables:
@ -26,6 +130,52 @@ bar:
# BIN-NEXT: Limits:
# BIN-NEXT: Initial: 0x00000000
# BIN: - Type: CODE
# BIN-NEXT: Relocations:
# BIN-NEXT: - Type: R_WASM_TABLE_NUMBER_LEB
# BIN-NEXT: Index: 2
# BIN-NEXT: Offset: 0x00000009
# BIN-NEXT: - Type: R_WASM_TABLE_NUMBER_LEB
# BIN-NEXT: Index: 2
# BIN-NEXT: Offset: 0x00000010
# BIN-NEXT: - Type: R_WASM_TABLE_NUMBER_LEB
# BIN-NEXT: Index: 3
# BIN-NEXT: Offset: 0x00000015
# BIN-NEXT: - Type: R_WASM_TABLE_NUMBER_LEB
# BIN-NEXT: Index: 0
# BIN-NEXT: Offset: 0x00000020
# BIN-NEXT: - Type: R_WASM_TABLE_NUMBER_LEB
# BIN-NEXT: Index: 0
# BIN-NEXT: Offset: 0x0000002D
# BIN-NEXT: - Type: R_WASM_TABLE_NUMBER_LEB
# BIN-NEXT: Index: 0
# BIN-NEXT: Offset: 0x00000038
# BIN-NEXT: - Type: R_WASM_TABLE_NUMBER_LEB
# BIN-NEXT: Index: 0
# BIN-NEXT: Offset: 0x00000041
# BIN-NEXT: - Type: R_WASM_TABLE_NUMBER_LEB
# BIN-NEXT: Index: 2
# BIN-NEXT: Offset: 0x00000051
# BIN-NEXT: - Type: R_WASM_TABLE_NUMBER_LEB
# BIN-NEXT: Index: 2
# BIN-NEXT: Offset: 0x0000005A
# BIN-NEXT: Functions:
# BIN-NEXT: - Index: 0
# BIN-NEXT: Locals: []
# BIN-NEXT: Body: 20002001FC108380808000FC0E838080800084808080000B
# BIN-NEXT: - Index: 1
# BIN-NEXT: Locals: []
# BIN-NEXT: Body: 20002581808080000B
# BIN-NEXT: - Index: 2
# BIN-NEXT: Locals: []
# BIN-NEXT: Body: 200020012681808080000B
# BIN-NEXT: - Index: 3
# BIN-NEXT: Locals: []
# BIN-NEXT: Body: 41002581808080002000FC0F818080800020006A0B
# BIN-NEXT: - Index: 4
# BIN-NEXT: Locals: []
# BIN-NEXT: Body: 200041002583808080002001FC1183808080000B
# BIN: - Type: CUSTOM
# BIN-NEXT: Name: linking
# BIN-NEXT: Version: 2

View File

@ -211,21 +211,23 @@ StringRef llvm::getEnumName(MVT::SimpleValueType T) {
case MVT::nxv2bf16: return "MVT::nxv2bf16";
case MVT::nxv4bf16: return "MVT::nxv4bf16";
case MVT::nxv8bf16: return "MVT::nxv8bf16";
case MVT::nxv1f32: return "MVT::nxv1f32";
case MVT::nxv2f32: return "MVT::nxv2f32";
case MVT::nxv4f32: return "MVT::nxv4f32";
case MVT::nxv8f32: return "MVT::nxv8f32";
case MVT::nxv16f32: return "MVT::nxv16f32";
case MVT::nxv1f64: return "MVT::nxv1f64";
case MVT::nxv2f64: return "MVT::nxv2f64";
case MVT::nxv4f64: return "MVT::nxv4f64";
case MVT::nxv8f64: return "MVT::nxv8f64";
case MVT::token: return "MVT::token";
case MVT::Metadata: return "MVT::Metadata";
case MVT::iPTR: return "MVT::iPTR";
case MVT::iPTRAny: return "MVT::iPTRAny";
case MVT::Untyped: return "MVT::Untyped";
case MVT::exnref: return "MVT::exnref";
case MVT::nxv1f32: return "MVT::nxv1f32";
case MVT::nxv2f32: return "MVT::nxv2f32";
case MVT::nxv4f32: return "MVT::nxv4f32";
case MVT::nxv8f32: return "MVT::nxv8f32";
case MVT::nxv16f32: return "MVT::nxv16f32";
case MVT::nxv1f64: return "MVT::nxv1f64";
case MVT::nxv2f64: return "MVT::nxv2f64";
case MVT::nxv4f64: return "MVT::nxv4f64";
case MVT::nxv8f64: return "MVT::nxv8f64";
case MVT::token: return "MVT::token";
case MVT::Metadata: return "MVT::Metadata";
case MVT::iPTR: return "MVT::iPTR";
case MVT::iPTRAny: return "MVT::iPTRAny";
case MVT::Untyped: return "MVT::Untyped";
case MVT::exnref: return "MVT::exnref";
case MVT::funcref: return "MVT::funcref";
case MVT::externref: return "MVT::externref";
default: llvm_unreachable("ILLEGAL VALUE TYPE!");
}
}