[llvm] [MC][WebAssembly] Add parameter to set table address type (PR #173063)

via llvm-commits llvm-commits at lists.llvm.org
Fri Dec 19 09:56:39 PST 2025


https://github.com/daxpedda created https://github.com/llvm/llvm-project/pull/173063

This adds an extra optional parameters to `.tabletype` to set the tables address type.

Unfortunately, to not break any existing code, I had to add an optional parameter that can be skipped in favor of subsequent optional parameters. This is a bit messed up, so I'm all ears for alternatives.

Fixes: https://github.com/llvm/llvm-project/issues/172907

>From e34b30a6438ba1937f8c4dc03c159bffef23fc5e Mon Sep 17 00:00:00 2001
From: daxpedda <daxpedda at gmail.com>
Date: Fri, 19 Dec 2025 18:48:27 +0100
Subject: [PATCH] [MC][WebAssembly] Add parameter to set table address type

---
 .../AsmParser/WebAssemblyAsmParser.cpp        | 27 ++++++-
 .../AsmParser/WebAssemblyAsmTypeCheck.cpp     | 48 ++++++++----
 .../AsmParser/WebAssemblyAsmTypeCheck.h       |  3 +-
 .../WebAssemblyTargetStreamer.cpp             |  4 +
 llvm/test/MC/WebAssembly/wasm64.s             | 75 +++++++++++++++----
 5 files changed, 122 insertions(+), 35 deletions(-)

diff --git a/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp b/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp
index 9175b2731dac0..28ea6e5ed5155 100644
--- a/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp
+++ b/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp
@@ -958,7 +958,7 @@ class WebAssemblyAsmParser final : public MCTargetAsmParser {
     }
 
     if (DirectiveID.getString() == ".tabletype") {
-      // .tabletype SYM, ELEMTYPE[, MINSIZE[, MAXSIZE]]
+      // .tabletype SYM, ELEMTYPE[, ADDR_TYPE[, MINSIZE[, MAXSIZE]]]
       auto SymName = expectIdent();
       if (SymName.empty())
         return ParseStatus::Failure;
@@ -975,6 +975,28 @@ class WebAssemblyAsmParser final : public MCTargetAsmParser {
         return error("Unknown type in .tabletype directive: ", ElemTypeTok);
 
       wasm::WasmLimits Limits = defaultLimits();
+
+      if (Is64) {
+        Limits.Flags |= wasm::WASM_LIMITS_FLAG_IS_64;
+      }
+
+      auto NextTok = Lexer.peekTok();
+
+      if (Lexer.is(AsmToken::Comma) && !NextTok.is(AsmToken::Integer)) {
+        auto AddrType = Lexer.Lex().getString();
+        Parser.Lex();
+
+        if (AddrType == "i32")
+          Limits.Flags &= ~wasm::WASM_LIMITS_FLAG_IS_64;
+        else if (AddrType == "i64")
+          Limits.Flags |= wasm::WASM_LIMITS_FLAG_IS_64;
+        else
+          return error(std::string(
+              "Expected address type or integer constant, instead got: ",
+              Lexer.getTok()));
+        ;
+      }
+
       if (isNext(AsmToken::Comma) && parseLimits(&Limits))
         return ParseStatus::Failure;
 
@@ -983,9 +1005,6 @@ class WebAssemblyAsmParser final : public MCTargetAsmParser {
       auto *WasmSym =
           static_cast<MCSymbolWasm *>(Ctx.getOrCreateSymbol(SymName));
       WasmSym->setType(wasm::WASM_SYMBOL_TYPE_TABLE);
-      if (Is64) {
-        Limits.Flags |= wasm::WASM_LIMITS_FLAG_IS_64;
-      }
       wasm::WasmTableType Type = {*ElemType, Limits};
       WasmSym->setTableType(Type);
       TOut.emitTableType(WasmSym);
diff --git a/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmTypeCheck.cpp b/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmTypeCheck.cpp
index 694388869040a..e8899ee8ee000 100644
--- a/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmTypeCheck.cpp
+++ b/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmTypeCheck.cpp
@@ -282,7 +282,8 @@ bool WebAssemblyAsmTypeCheck::getGlobal(SMLoc ErrorLoc,
 }
 
 bool WebAssemblyAsmTypeCheck::getTable(SMLoc ErrorLoc, const MCOperand &TableOp,
-                                       wasm::ValType &Type) {
+                                       wasm::ValType &Type,
+                                       wasm::ValType &AddrType) {
   const MCSymbolRefExpr *SymRef;
   if (getSymRef(ErrorLoc, TableOp, SymRef))
     return true;
@@ -291,7 +292,12 @@ bool WebAssemblyAsmTypeCheck::getTable(SMLoc ErrorLoc, const MCOperand &TableOp,
       wasm::WASM_SYMBOL_TYPE_TABLE)
     return typeError(ErrorLoc, StringRef("symbol ") + WasmSym->getName() +
                                    ": missing .tabletype");
-  Type = static_cast<wasm::ValType>(WasmSym->getTableType().ElemType);
+  auto Table = WasmSym->getTableType();
+  Type = static_cast<wasm::ValType>(Table.ElemType);
+  if (Table.Limits.Flags & wasm::WASM_LIMITS_FLAG_IS_64)
+    AddrType = wasm::ValType::I64;
+  else
+    AddrType = wasm::ValType::I32;
   return false;
 }
 
@@ -396,6 +402,7 @@ bool WebAssemblyAsmTypeCheck::typeCheck(SMLoc ErrorLoc, const MCInst &Inst,
   auto Name = getMnemonic(Opc);
   dumpTypeStack("typechecking " + Name + ": ");
   wasm::ValType Type;
+  wasm::ValType AddrType;
 
   if (Name == "local.get") {
     if (!getLocal(Operands[1]->getStartLoc(), Inst.getOperand(0), Type)) {
@@ -441,61 +448,70 @@ bool WebAssemblyAsmTypeCheck::typeCheck(SMLoc ErrorLoc, const MCInst &Inst,
   }
 
   if (Name == "table.get") {
-    bool Error = popType(ErrorLoc, wasm::ValType::I32);
-    if (!getTable(Operands[1]->getStartLoc(), Inst.getOperand(0), Type)) {
+    if (!getTable(Operands[1]->getStartLoc(), Inst.getOperand(0), Type,
+                  AddrType)) {
+      bool Error = popType(ErrorLoc, AddrType);
       pushType(Type);
       return Error;
+    } else {
+      popType(ErrorLoc, Any{});
+      pushType(Any{});
+      return true;
     }
-    pushType(Any{});
-    return true;
   }
 
   if (Name == "table.set") {
     bool Error = false;
     SmallVector<StackType, 2> PopTypes;
-    PopTypes.push_back(wasm::ValType::I32);
-    if (!getTable(Operands[1]->getStartLoc(), Inst.getOperand(0), Type)) {
+    if (!getTable(Operands[1]->getStartLoc(), Inst.getOperand(0), Type,
+                  AddrType)) {
+      PopTypes.push_back(AddrType);
       PopTypes.push_back(Type);
     } else {
       Error = true;
       PopTypes.push_back(Any{});
+      PopTypes.push_back(Any{});
     }
     Error |= popTypes(ErrorLoc, PopTypes);
     return Error;
   }
 
   if (Name == "table.size") {
-    bool Error = getTable(Operands[1]->getStartLoc(), Inst.getOperand(0), Type);
-    pushType(wasm::ValType::I32);
+    bool Error = getTable(Operands[1]->getStartLoc(), Inst.getOperand(0), Type,
+                          AddrType);
+    pushType(AddrType);
     return Error;
   }
 
   if (Name == "table.grow") {
     bool Error = false;
     SmallVector<StackType, 2> PopTypes;
-    if (!getTable(Operands[1]->getStartLoc(), Inst.getOperand(0), Type)) {
+    if (!getTable(Operands[1]->getStartLoc(), Inst.getOperand(0), Type,
+                  AddrType)) {
       PopTypes.push_back(Type);
     } else {
       Error = true;
       PopTypes.push_back(Any{});
     }
-    PopTypes.push_back(wasm::ValType::I32);
+    PopTypes.push_back(AddrType);
     Error |= popTypes(ErrorLoc, PopTypes);
-    pushType(wasm::ValType::I32);
+    pushType(AddrType);
     return Error;
   }
 
   if (Name == "table.fill") {
     bool Error = false;
     SmallVector<StackType, 2> PopTypes;
-    PopTypes.push_back(wasm::ValType::I32);
-    if (!getTable(Operands[1]->getStartLoc(), Inst.getOperand(0), Type)) {
+    if (!getTable(Operands[1]->getStartLoc(), Inst.getOperand(0), Type,
+                  AddrType)) {
+      PopTypes.push_back(AddrType);
       PopTypes.push_back(Type);
     } else {
       Error = true;
       PopTypes.push_back(Any{});
+      PopTypes.push_back(Any{});
     }
-    PopTypes.push_back(wasm::ValType::I32);
+    PopTypes.push_back(AddrType);
     Error |= popTypes(ErrorLoc, PopTypes);
     return Error;
   }
diff --git a/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmTypeCheck.h b/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmTypeCheck.h
index e6fddf9806026..22b6ea14d4a39 100644
--- a/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmTypeCheck.h
+++ b/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmTypeCheck.h
@@ -79,7 +79,8 @@ class WebAssemblyAsmTypeCheck final {
                  const MCSymbolRefExpr *&SymRef);
   bool getGlobal(SMLoc ErrorLoc, const MCOperand &GlobalOp,
                  wasm::ValType &Type);
-  bool getTable(SMLoc ErrorLoc, const MCOperand &TableOp, wasm::ValType &Type);
+  bool getTable(SMLoc ErrorLoc, const MCOperand &TableOp, wasm::ValType &Type,
+                wasm::ValType &AddrType);
   bool getSignature(SMLoc ErrorLoc, const MCOperand &SigOp,
                     wasm::WasmSymbolType Type, const wasm::WasmSignature *&Sig);
   bool checkTryTable(SMLoc ErrorLoc, const MCInst &Inst);
diff --git a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.cpp b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.cpp
index c18de5fc1939e..9f9ffca4eddf9 100644
--- a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.cpp
+++ b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.cpp
@@ -78,6 +78,10 @@ void WebAssemblyTargetAsmStreamer::emitTableType(const MCSymbolWasm *Sym) {
   const wasm::WasmTableType &Type = Sym->getTableType();
   OS << "\t.tabletype\t" << Sym->getName() << ", "
      << WebAssembly::typeToString(static_cast<wasm::ValType>(Type.ElemType));
+  if (Type.Limits.Flags & wasm::WASM_LIMITS_FLAG_IS_64)
+    OS << ", i64";
+  else
+    OS << ", i32";
   bool HasMaximum = Type.Limits.Flags & wasm::WASM_LIMITS_FLAG_HAS_MAX;
   if (Type.Limits.Minimum != 0 || HasMaximum) {
     OS << ", " << Type.Limits.Minimum;
diff --git a/llvm/test/MC/WebAssembly/wasm64.s b/llvm/test/MC/WebAssembly/wasm64.s
index 0c939b47db4f2..2617043f0a764 100644
--- a/llvm/test/MC/WebAssembly/wasm64.s
+++ b/llvm/test/MC/WebAssembly/wasm64.s
@@ -1,11 +1,16 @@
-# RUN: llvm-mc -triple=wasm64-unknown-unknown -mattr=+atomics,+simd128,+nontrapping-fptoint,+exception-handling < %s | FileCheck %s
-# RUN: llvm-mc -triple=wasm64-unknown-unknown -filetype=obj -mattr=+atomics,+simd128,+nontrapping-fptoint,+exception-handling -o - < %s | obj2yaml | FileCheck %s -check-prefix=BIN
+# RUN: llvm-mc -triple=wasm64-unknown-unknown -mattr=+atomics,+reference-types,+simd128,+nontrapping-fptoint,+exception-handling < %s | FileCheck %s -dump-input=always
+# RUN: llvm-mc -triple=wasm64-unknown-unknown -filetype=obj -mattr=+atomics,+reference-types,+simd128,+nontrapping-fptoint,+exception-handling -o - < %s | obj2yaml | FileCheck %s -check-prefix=BIN -dump-input=always
 
 # Most of our other tests are for wasm32, this one adds some wasm64 specific tests.
 
 .globaltype myglob64, i64
 .globaltype __stack_pointer, i64
 
+table1:
+    .tabletype table1, funcref, i32
+table2:
+    .tabletype table2, funcref, i64
+
 test:
     .functype   test (i64) -> ()
     .local      i64
@@ -59,6 +64,18 @@ test:
     global.get  __stack_pointer
     drop
 
+    ### table address type
+
+    ref.null_func
+    i32.const 0
+    table.grow table1
+    drop
+
+    ref.null_func
+    i64.const 0
+    table.grow table2
+    drop
+
     end_function
 
     .section    .rodata..L.str,"",@
@@ -72,6 +89,9 @@ test:
 
 # CHECK:              .globaltype     myglob64, i64
 
+# CHECK:              .tabletype table1, funcref, i32  
+# CHECK:              .tabletype table2, funcref, i64  
+
 # CHECK:              .functype       test (i64) -> ()
 # CHECK-NEXT:         .local          i64
 
@@ -159,41 +179,58 @@ test:
 # BIN-NEXT:         GlobalMutable:   true
 # BIN-NEXT:   - Type:            FUNCTION
 # BIN-NEXT:     FunctionTypes:   [ 0 ]
+# BIN-NEXT:   - Type:            TABLE
+# BIN-NEXT:     Tables:
+# BIN-NEXT:       - Index:           0
+# BIN-NEXT:         ElemType:        FUNCREF
+# BIN-NEXT:         Limits:
+# BIN-NEXT:           Minimum:         0x0
+# BIN-NEXT:       - Index:           1
+# BIN-NEXT:         ElemType:        FUNCREF
+# BIN-NEXT:         Limits:
+# BIN-NEXT:           Flags:           [ IS_64 ]
+# BIN-NEXT:           Minimum:         0x0
 # BIN-NEXT:   - Type:            DATACOUNT
 # BIN-NEXT:     Count:           1
 # BIN-NEXT:   - Type:            CODE
 # BIN-NEXT:     Relocations:
 # BIN-NEXT:       - Type:            R_WASM_MEMORY_ADDR_SLEB64
-# BIN-NEXT:         Index:           1
+# BIN-NEXT:         Index:           3
 # BIN-NEXT:         Offset:          0x13
 # BIN-NEXT:       - Type:            R_WASM_GLOBAL_INDEX_LEB
-# BIN-NEXT:         Index:           2
+# BIN-NEXT:         Index:           4
 # BIN-NEXT:         Offset:          0x22
 # BIN-NEXT:       - Type:            R_WASM_MEMORY_ADDR_LEB64
-# BIN-NEXT:         Index:           1
+# BIN-NEXT:         Index:           3
 # BIN-NEXT:         Offset:          0x2F
 # BIN-NEXT:       - Type:            R_WASM_MEMORY_ADDR_SLEB64
-# BIN-NEXT:         Index:           1
+# BIN-NEXT:         Index:           3
 # BIN-NEXT:         Offset:          0x4F
 # BIN-NEXT:       - Type:            R_WASM_GLOBAL_INDEX_LEB
-# BIN-NEXT:         Index:           2
+# BIN-NEXT:         Index:           4
 # BIN-NEXT:         Offset:          0x62
 # BIN-NEXT:       - Type:            R_WASM_MEMORY_ADDR_LEB64
-# BIN-NEXT:         Index:           1
+# BIN-NEXT:         Index:           3
 # BIN-NEXT:         Offset:          0x78
 # BIN-NEXT:       - Type: R_WASM_GLOBAL_INDEX_LEB
-# BIN-NEXT:         Index: 3
+# BIN-NEXT:         Index: 5
 # BIN-NEXT:         Offset: 0x83
+# BIN-NEXT:       - Type: R_WASM_TABLE_NUMBER_LEB
+# BIN-NEXT:         Index: 0
+# BIN-NEXT:         Offset: 0x8F
+# BIN-NEXT:       - Type: R_WASM_TABLE_NUMBER_LEB
+# BIN-NEXT:         Index: 1
+# BIN-NEXT:         Offset: 0x9B
 # BIN-NEXT:     Functions:
 # BIN-NEXT:       - Index:           0
 # BIN-NEXT:         Locals:
 # BIN-NEXT:           - Type:            I64
 # BIN-NEXT:             Count:           1
-# BIN-NEXT:         Body:            42002A02001A20002A02001A42808080808080808080002A02001A2380808080002A02001A42002A02808080808080808080001A4200430000000038020020004300000000380200428080808080808080800043000000003802002380808080004300000000380200420043000000003802808080808080808080002381808080001A0B
+# BIN-NEXT:         Body:            42002A02001A20002A02001A42808080808080808080002A02001A2380808080002A02001A42002A02808080808080808080001A4200430000000038020020004300000000380200428080808080808080800043000000003802002380808080004300000000380200420043000000003802808080808080808080002381808080001AD0704100FC0F80808080001AD0704200FC0F81808080001A0B
 # BIN-NEXT:   - Type:            DATA
 # BIN-NEXT:     Relocations:
 # BIN-NEXT:       - Type:            R_WASM_MEMORY_ADDR_I64
-# BIN-NEXT:         Index:           1
+# BIN-NEXT:         Index:           3
 # BIN-NEXT:         Offset:          0x16
 # BIN-NEXT:     Segments:
 # BIN-NEXT:       - SectionOffset:   6
@@ -207,22 +244,32 @@ test:
 # BIN-NEXT:     Version:         2
 # BIN-NEXT:     SymbolTable:
 # BIN-NEXT:       - Index:           0
+# BIN-NEXT:         Kind:            TABLE
+# BIN-NEXT:         Name:            table1
+# BIN-NEXT:         Flags:           [ BINDING_LOCAL ]
+# BIN-NEXT:         Table:           0
+# BIN-NEXT:       - Index:           1
+# BIN-NEXT:         Kind:            TABLE
+# BIN-NEXT:         Name:            table2
+# BIN-NEXT:         Flags:           [ BINDING_LOCAL ]
+# BIN-NEXT:         Table:           1
+# BIN-NEXT:       - Index:           2
 # BIN-NEXT:         Kind:            FUNCTION
 # BIN-NEXT:         Name:            test
 # BIN-NEXT:         Flags:           [ BINDING_LOCAL ]
 # BIN-NEXT:         Function:        0
-# BIN-NEXT:       - Index:           1
+# BIN-NEXT:       - Index:           3
 # BIN-NEXT:         Kind:            DATA
 # BIN-NEXT:         Name:            .L.str
 # BIN-NEXT:         Flags:           [ BINDING_LOCAL, VISIBILITY_HIDDEN ]
 # BIN-NEXT:         Segment:         0
 # BIN-NEXT:         Size:            24
-# BIN-NEXT:       - Index:           2
+# BIN-NEXT:       - Index:           4
 # BIN-NEXT:         Kind:            GLOBAL
 # BIN-NEXT:         Name:            myglob64
 # BIN-NEXT:         Flags:           [ UNDEFINED ]
 # BIN-NEXT:         Global:          0
-# BIN-NEXT:       - Index:           3
+# BIN-NEXT:       - Index:           5
 # BIN-NEXT:         Kind:            GLOBAL
 # BIN-NEXT:         Name:            __stack_pointer
 # BIN-NEXT:         Flags:           [ UNDEFINED ]



More information about the llvm-commits mailing list