[WebAssembly] Implementation of (most) table instructions
authorPaulo Matos <pmatos@igalia.com>
Fri, 23 Oct 2020 15:36:06 +0000 (08:36 -0700)
committerSam Clegg <sbc@chromium.org>
Fri, 23 Oct 2020 15:42:54 +0000 (08:42 -0700)
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

19 files changed:
llvm/include/llvm/BinaryFormat/WasmRelocs.def
llvm/include/llvm/CodeGen/ValueTypes.td
llvm/include/llvm/Object/Wasm.h
llvm/include/llvm/Support/MachineValueType.h
llvm/lib/CodeGen/ValueTypes.cpp
llvm/lib/MC/WasmObjectWriter.cpp
llvm/lib/Object/RelocationResolver.cpp
llvm/lib/Object/WasmObjectFile.cpp
llvm/lib/Target/WebAssembly/Disassembler/WebAssemblyDisassembler.cpp
llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCCodeEmitter.cpp
llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.h
llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyWasmObjectWriter.cpp
llvm/lib/Target/WebAssembly/WebAssemblyExplicitLocals.cpp
llvm/lib/Target/WebAssembly/WebAssemblyFastISel.cpp
llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.td
llvm/lib/Target/WebAssembly/WebAssemblyInstrTable.td [new file with mode: 0644]
llvm/lib/Target/WebAssembly/WebAssemblyRegisterInfo.td
llvm/test/MC/WebAssembly/tables.s
llvm/utils/TableGen/CodeGenTarget.cpp

index b6ea2c5..76e2037 100644 (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)
index 43b3d5d..8d2fa7d 100644 (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
index 37e5a9a..292a05f 100644 (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;
index 011926e..0e9b464 100644 (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
       }
     }
 
index 7fdec16..b2c99bb 100644 (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";
   }
 }
 
index 4e673f2..f81a83d 100644 (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:
index 83170bb..d56e7be 100644 (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:
index 107a9ef..f8ca654 100644 (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();
 }
index 42fa6d5..8c93b59 100644 (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:
index dfed345..529674f 100644 (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:
index d4f3a28..2dcd312 100644 (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
 
index 23f8b4f..db1063c 100644 (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());
index 55925bc..e8367d1 100644 (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");
 }
 
index c2a0d3e..495af21 100644 (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;
     }
index 08b9645..94c1df3 100644 (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"
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyInstrTable.td b/llvm/lib/Target/WebAssembly/WebAssemblyInstrTable.td
new file mode 100644 (file)
index 0000000..97638c3
--- /dev/null
@@ -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]>;
index 6d3d6c7..8f7f0a4 100644 (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)>;
index 1c6837d..ea1eb4f 100644 (file)
-# 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:
 
+
+#      CHECK: bar:
+# CHECK-NEXT:         .tabletype bar, funcref
 bar:
-.tabletype bar, funcref
+    .tabletype bar, funcref
 
-# CHECK: .tabletype foo, externref
-# CHECK: foo:
+table1:
+    .tabletype table1, funcref
+table2:
+    .tabletype table2, funcref
 
-#      CHECK: bar:
-# CHECK-NEXT: .tabletype bar, 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
index af5e213..59a9379 100644 (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!");
   }
 }