[llvm] [WebAssembly] Print type signature and table for call_indirect (PR #179120)

via llvm-commits llvm-commits at lists.llvm.org
Thu Feb 12 08:55:59 PST 2026


https://github.com/ParkHanbum updated https://github.com/llvm/llvm-project/pull/179120

>From 1d8dc5fd4dc506a7a34532d1cea363865b45da03 Mon Sep 17 00:00:00 2001
From: Hanbum Park <kese111 at gmail.com>
Date: Mon, 2 Feb 2026 00:26:29 +0900
Subject: [PATCH 1/5] [WebAssembly] Print type signature and table for
 call_indirect

Update WebAssemblyInstPrinter.cpp to correctly print type
and table operands for both register and stack modes.
---
 .../MCTargetDesc/WebAssemblyInstPrinter.cpp   | 18 +++++++++++
 .../WebAssembly/WebAssemblyInstrCall.td       |  4 +--
 llvm/test/CodeGen/WebAssembly/call-pic.ll     |  2 +-
 llvm/test/CodeGen/WebAssembly/call.ll         | 30 +++++++++----------
 .../CodeGen/WebAssembly/function-bitcasts.ll  |  2 +-
 llvm/test/CodeGen/WebAssembly/multivalue.ll   |  2 +-
 llvm/test/CodeGen/WebAssembly/reg-stackify.ll |  2 +-
 llvm/test/CodeGen/WebAssembly/swiftcc.ll      |  8 ++---
 llvm/test/CodeGen/WebAssembly/tailcall.ll     | 28 ++++++++---------
 9 files changed, 57 insertions(+), 39 deletions(-)

diff --git a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyInstPrinter.cpp b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyInstPrinter.cpp
index 651f631c1ee55..f883c5175a408 100644
--- a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyInstPrinter.cpp
+++ b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyInstPrinter.cpp
@@ -49,6 +49,24 @@ void WebAssemblyInstPrinter::printInst(const MCInst *MI, uint64_t Address,
                                        const MCSubtargetInfo &STI,
                                        raw_ostream &OS) {
   switch (MI->getOpcode()) {
+  case WebAssembly::CALL_INDIRECT:
+  case WebAssembly::RET_CALL_INDIRECT: {
+    OS << "\t" << getMnemonic(*MI).first << "\t";
+    unsigned TypeOperand = 0;
+    unsigned TableOperand = 1;
+    if (MI->getOpcode() == WebAssembly::CALL_INDIRECT) {
+      unsigned NumDefs = MI->getOperand(0).getImm();
+      TypeOperand = 1 + NumDefs;      // Type 위치 보정
+      TableOperand = 1 + NumDefs + 1; // Table 위치 보정
+    }
+    printOperand(MI, TableOperand, OS);
+    OS << ", ";
+    printOperand(MI, TypeOperand, OS);
+    if (MI->getOpcode() == WebAssembly::CALL_INDIRECT) {
+      OS << ", ";
+    }
+    break;
+  }
   case WebAssembly::CALL_INDIRECT_S:
   case WebAssembly::RET_CALL_INDIRECT_S: {
     // A special case for call_indirect (and ret_call_indirect), if the table
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyInstrCall.td b/llvm/lib/Target/WebAssembly/WebAssemblyInstrCall.td
index ca9a5ef9dda1c..485b12e256224 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyInstrCall.td
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyInstrCall.td
@@ -64,7 +64,7 @@ defm CALL_INDIRECT :
     (outs),
     (ins TypeIndex:$type, table32_op:$table),
     [],
-    "call_indirect", "call_indirect\t$type, $table", 0x11>;
+    "call_indirect\t$type, $table", "call_indirect\t$type, $table", 0x11>;
 
 let isReturn = 1, isTerminator = 1, hasCtrlDep = 1, isBarrier = 1 in
 defm RET_CALL :
@@ -77,7 +77,7 @@ let isReturn = 1, isTerminator = 1, hasCtrlDep = 1, isBarrier = 1 in
 defm RET_CALL_INDIRECT :
   I<(outs), (ins TypeIndex:$type, table32_op:$table, variable_ops),
     (outs), (ins TypeIndex:$type, table32_op:$table), [],
-    "return_call_indirect\t", "return_call_indirect\t$type, $table",
+    "return_call_indirect\t$type, $table", "return_call_indirect\t$type, $table",
     0x13>,
   Requires<[HasTailCall]>;
 
diff --git a/llvm/test/CodeGen/WebAssembly/call-pic.ll b/llvm/test/CodeGen/WebAssembly/call-pic.ll
index f6f24bdd0530c..53943246a8f92 100644
--- a/llvm/test/CodeGen/WebAssembly/call-pic.ll
+++ b/llvm/test/CodeGen/WebAssembly/call-pic.ll
@@ -19,7 +19,7 @@ define void @call_indirect_func() {
 ; CHECK-NEXT: i32.const $push[[L1:[0-9]+]]=, indirect_func at MBREL{{$}}
 ; CHECK-NEXT: i32.add $push[[L2:[0-9]+]]=, $pop[[L0]], $pop[[L1]]{{$}}
 ; CHECK-NEXT: i32.load $push[[L3:[0-9]+]]=, 0($pop[[L2]]){{$}}
-; CHECK-NEXT: call_indirect $push[[L4:[0-9]+]]=, $pop[[L3]]{{$}}
+; CHECK-NEXT: call_indirect __indirect_function_table, () -> (i32), $push[[L4:[0-9]+]]=, $pop[[L3]]{{$}}
   %1 = load ptr, ptr @indirect_func, align 4
   %call = call i32 %1()
   ret void
diff --git a/llvm/test/CodeGen/WebAssembly/call.ll b/llvm/test/CodeGen/WebAssembly/call.ll
index 2f7658ac5a6cc..2a1ad944ba6e0 100644
--- a/llvm/test/CodeGen/WebAssembly/call.ll
+++ b/llvm/test/CodeGen/WebAssembly/call.ll
@@ -94,7 +94,7 @@ define i32 @call_i32_binary(i32 %a, i32 %b) {
 ; CHECK-LABEL: call_indirect_void:
 ; CHECK-NEXT: .functype call_indirect_void (i32) -> (){{$}}
 ; CHECK-NEXT: local.get $push[[L0:[0-9]+]]=, 0{{$}}
-; CHECK-NEXT: {{^}} call_indirect $pop[[L0]]{{$}}
+; CHECK-NEXT: {{^}} call_indirect __indirect_function_table, () -> (), $pop[[L0]]{{$}}
 ; CHECK-NEXT: return{{$}}
 define void @call_indirect_void(ptr %callee) {
   call void %callee()
@@ -104,7 +104,7 @@ define void @call_indirect_void(ptr %callee) {
 ; CHECK-LABEL: call_indirect_i32:
 ; CHECK-NEXT: .functype call_indirect_i32 (i32) -> (i32){{$}}
 ; CHECK-NEXT: local.get $push[[L0:[0-9]+]]=, 0{{$}}
-; CHECK-NEXT: {{^}} call_indirect $push[[NUM:[0-9]+]]=, $pop[[L0]]{{$}}
+; CHECK-NEXT: call_indirect __indirect_function_table, () -> (i32), $push[[NUM:[0-9]+]]=, $pop[[L0]]{{$}}
 ; CHECK-NEXT: return $pop[[NUM]]{{$}}
 define i32 @call_indirect_i32(ptr %callee) {
   %t = call i32 %callee()
@@ -114,7 +114,7 @@ define i32 @call_indirect_i32(ptr %callee) {
 ; CHECK-LABEL: call_indirect_i64:
 ; CHECK-NEXT: .functype call_indirect_i64 (i32) -> (i64){{$}}
 ; CHECK-NEXT: local.get $push[[L0:[0-9]+]]=, 0{{$}}
-; CHECK-NEXT: {{^}} call_indirect $push[[NUM:[0-9]+]]=, $pop[[L0]]{{$}}
+; CHECK-NEXT: {{^}} call_indirect __indirect_function_table, () -> (i64), $push[[NUM:[0-9]+]]=, $pop[[L0]]{{$}}
 ; CHECK-NEXT: return $pop[[NUM]]{{$}}
 define i64 @call_indirect_i64(ptr %callee) {
   %t = call i64 %callee()
@@ -124,7 +124,7 @@ define i64 @call_indirect_i64(ptr %callee) {
 ; CHECK-LABEL: call_indirect_float:
 ; CHECK-NEXT: .functype call_indirect_float (i32) -> (f32){{$}}
 ; CHECK-NEXT: local.get $push[[L0:[0-9]+]]=, 0{{$}}
-; CHECK-NEXT: {{^}} call_indirect $push[[NUM:[0-9]+]]=, $pop[[L0]]{{$}}
+; CHECK-NEXT: {{^}} call_indirect __indirect_function_table, () -> (f32), $push[[NUM:[0-9]+]]=, $pop[[L0]]{{$}}
 ; CHECK-NEXT: return $pop[[NUM]]{{$}}
 define float @call_indirect_float(ptr %callee) {
   %t = call float %callee()
@@ -134,7 +134,7 @@ define float @call_indirect_float(ptr %callee) {
 ; CHECK-LABEL: call_indirect_double:
 ; CHECK-NEXT: .functype call_indirect_double (i32) -> (f64){{$}}
 ; CHECK-NEXT: local.get $push[[L0:[0-9]+]]=, 0{{$}}
-; CHECK-NEXT: {{^}} call_indirect $push[[NUM:[0-9]+]]=, $pop[[L0]]{{$}}
+; CHECK-NEXT: {{^}} call_indirect __indirect_function_table, () -> (f64), $push[[NUM:[0-9]+]]=, $pop[[L0]]{{$}}
 ; CHECK-NEXT: return $pop[[NUM]]{{$}}
 define double @call_indirect_double(ptr %callee) {
   %t = call double %callee()
@@ -144,7 +144,7 @@ define double @call_indirect_double(ptr %callee) {
 ; CHECK-LABEL: call_indirect_v128:
 ; CHECK-NEXT: .functype call_indirect_v128 (i32) -> (v128){{$}}
 ; CHECK-NEXT: local.get $push[[L0:[0-9]+]]=, 0{{$}}
-; CHECK-NEXT: {{^}} call_indirect $push[[NUM:[0-9]+]]=, $pop[[L0]]{{$}}
+; CHECK-NEXT: {{^}} call_indirect __indirect_function_table, () -> (v128), $push[[NUM:[0-9]+]]=, $pop[[L0]]{{$}}
 ; CHECK-NEXT: return $pop[[NUM]]{{$}}
 define <16 x i8> @call_indirect_v128(ptr %callee) {
   %t = call <16 x i8> %callee()
@@ -155,7 +155,7 @@ define <16 x i8> @call_indirect_v128(ptr %callee) {
 ; CHECK-NEXT: .functype call_indirect_arg (i32, i32) -> (){{$}}
 ; CHECK-NEXT: local.get $push[[L0:[0-9]+]]=, 1{{$}}
 ; CHECK-NEXT: local.get $push[[L1:[0-9]+]]=, 0{{$}}
-; CHECK-NEXT: {{^}} call_indirect $pop[[L0]], $pop[[L1]]{{$}}
+; CHECK-NEXT: {{^}} call_indirect __indirect_function_table, (i32) -> (), $pop[[L0]], $pop[[L1]]{{$}}
 ; CHECK-NEXT: return{{$}}
 define void @call_indirect_arg(ptr %callee, i32 %arg) {
   call void %callee(i32 %arg)
@@ -167,7 +167,7 @@ define void @call_indirect_arg(ptr %callee, i32 %arg) {
 ; CHECK-NEXT: local.get $push[[L0:[0-9]+]]=, 1{{$}}
 ; CHECK-NEXT: local.get $push[[L1:[0-9]+]]=, 2{{$}}
 ; CHECK-NEXT: local.get $push[[L2:[0-9]+]]=, 0{{$}}
-; CHECK-NEXT: {{^}} call_indirect $push[[NUM:[0-9]+]]=, $pop[[L0]], $pop[[L1]], $pop[[L2]]{{$}}
+; CHECK-NEXT: {{^}} call_indirect __indirect_function_table, (i32, i32) -> (i32), $push[[NUM:[0-9]+]]=, $pop[[L0]], $pop[[L1]], $pop[[L2]]{{$}}
 ; CHECK-NEXT: drop $pop[[NUM]]{{$}}
 ; CHECK-NEXT: return{{$}}
 define void @call_indirect_arg_2(ptr %callee, i32 %arg, i32 %arg2) {
@@ -219,7 +219,7 @@ define void @coldcc_tail_call_void_nullary() {
 ; CHECK-NEXT: i32.const	$push[[L3:[0-9]+]]=, void_nullary{{$}}
 ; CHECK-NEXT: i32.const	$push[[L2:[0-9]+]]=, other_void_nullary{{$}}
 ; CHECK-NEXT: i32.add 	$push[[L4:[0-9]+]]=, $pop[[L3]], $pop[[L2]]{{$}}
-; CHECK-NEXT: call_indirect	$pop[[L4]]{{$}}
+; CHECK-NEXT: call_indirect	__indirect_function_table, () -> (), $pop[[L4]]{{$}}
 ; CHECK-NEXT: call void_nullary{{$}}
 ; CHECK-NEXT: return{{$}}
 declare void @vararg_func(...)
@@ -243,7 +243,7 @@ bb2:
 ; CHECK-NEXT: local.get  $push{{.*}}=, [[L0]]
 ; CHECK-NEXT: i32.const  $push{{.*}}=, 12
 ; CHECK-NEXT: i32.add
-; CHECK-NEXT: call_indirect  $pop{{.*}}
+; CHECK-NEXT: call_indirect __indirect_function_table, () -> (), $pop{{.*}}
 define void @call_indirect_alloca() {
 entry:
   %ptr = alloca i32, align 4
@@ -254,9 +254,9 @@ entry:
 ; Calling non-functional globals should be lowered to call_indirects.
 ; CHECK-LABEL: call_indirect_int:
 ; CHECK:      i32.const  $push[[L0:[0-9]+]]=, global_i8
-; CHECK-NEXT: call_indirect  $pop[[L0]]
+; CHECK-NEXT: call_indirect __indirect_function_table, () -> (), $pop[[L0]]
 ; CHECK-NEXT: i32.const  $push[[L1:[0-9]+]]=, global_i32
-; CHECK-NEXT: call_indirect  $pop[[L1]]
+; CHECK-NEXT: call_indirect __indirect_function_table, () -> (), $pop[[L1]]
 @global_i8 = global i8 0
 @global_i32 = global i32 0
 define void @call_indirect_int() {
@@ -268,9 +268,9 @@ define void @call_indirect_int() {
 ; Calling aliases of non-functional globals should be lowered to call_indirects.
 ; CHECK-LABEL: call_indirect_int_alias:
 ; CHECK:      i32.const  $push[[L0:[0-9]+]]=, global_i8_alias
-; CHECK-NEXT: call_indirect  $pop[[L0]]
+; CHECK-NEXT: call_indirect __indirect_function_table, () -> (), $pop[[L0]]
 ; CHECK-NEXT: i32.const  $push[[L1:[0-9]+]]=, global_i32_alias
-; CHECK-NEXT: call_indirect  $pop[[L1]]
+; CHECK-NEXT: call_indirect __indirect_function_table, () -> (), $pop[[L1]]
 @global_i8_alias = alias i8, ptr @global_i8
 @global_i32_alias = alias i32, ptr @global_i32
 define void @call_indirect_int_alias() {
@@ -284,7 +284,7 @@ define void @call_indirect_int_alias() {
 ; CHECK-LABEL: call_func_alias:
 ; SLOW:      call  func_alias
 ; FAST:      i32.const  $push[[L0:[0-9]+]]=, func_alias
-; FAST-NEXT: call_indirect  $pop[[L0]]
+; FAST-NEXT: call_indirect __indirect_function_table, () -> (), $pop[[L0]]
 @func_alias = alias void (), ptr @call_void_nullary
 define void @call_func_alias() {
   call void @func_alias()
diff --git a/llvm/test/CodeGen/WebAssembly/function-bitcasts.ll b/llvm/test/CodeGen/WebAssembly/function-bitcasts.ll
index 0553f61ef9056..c623e7287c034 100644
--- a/llvm/test/CodeGen/WebAssembly/function-bitcasts.ll
+++ b/llvm/test/CodeGen/WebAssembly/function-bitcasts.ll
@@ -121,7 +121,7 @@ define void @test_store() {
 ; CHECK-NEXT: .functype test_load () -> (i32){{$}}
 ; CHECK-NEXT: i32.const   $push[[L0:[0-9]+]]=, 0{{$}}
 ; CHECK-NEXT: i32.load    $push[[L1:[0-9]+]]=, global_func($pop[[L0]]){{$}}
-; CHECK-NEXT: call_indirect $push{{[0-9]+}}=, $pop[[L1]]{{$}}
+; CHECK-NEXT: call_indirect __indirect_function_table, () -> (i32), $push{{[0-9]+}}=, $pop[[L1]]{{$}}
 define i32 @test_load() {
   %1 = load ptr, ptr @global_func
   %2 = call i32 %1()
diff --git a/llvm/test/CodeGen/WebAssembly/multivalue.ll b/llvm/test/CodeGen/WebAssembly/multivalue.ll
index 5001db7e57a1e..2fa6381e4c4c7 100644
--- a/llvm/test/CodeGen/WebAssembly/multivalue.ll
+++ b/llvm/test/CodeGen/WebAssembly/multivalue.ll
@@ -62,7 +62,7 @@ define %pair @pair_call_return() {
 ; CHECK-NEXT: call_indirect () -> (i32, i64){{$}}
 ; REF:        call_indirect __indirect_function_table, () -> (i32, i64){{$}}
 ; CHECK-NEXT: end_function{{$}}
-; REGS: call_indirect $push{{[0-9]+}}=, $push{{[0-9]+}}=, $0{{$}}
+; REGS: call_indirect 0, () -> (i32, i64), $push{{[0-9]+}}=, $push{{[0-9]+}}=, $0{{$}}
 define %pair @pair_call_indirect(ptr %f) {
   %p = call %pair %f()
   ret %pair %p
diff --git a/llvm/test/CodeGen/WebAssembly/reg-stackify.ll b/llvm/test/CodeGen/WebAssembly/reg-stackify.ll
index f1466a48e7394..f9c233d1be3a3 100644
--- a/llvm/test/CodeGen/WebAssembly/reg-stackify.ll
+++ b/llvm/test/CodeGen/WebAssembly/reg-stackify.ll
@@ -643,7 +643,7 @@ define i32 @stackpointer_dependency(ptr readnone) {
 ; CHECK-NEXT: local.tee $push[[L3:.+]]=, $0=, $pop[[L4]]
 ; CHECK-NEXT: i32.load  $push[[L0:.+]]=, 0($0)
 ; CHECK-NEXT: i32.load  $push[[L1:.+]]=, 0($pop[[L0]])
-; CHECK-NEXT: call_indirect $push{{.+}}=, $pop[[L3]], $1, $pop[[L1]]
+; CHECK-NEXT: call_indirect __indirect_function_table, (i32, i32) -> (i32), $push{{.+}}=, $pop[[L3]], $1, $pop[[L1]]
 ; NOREGS-LABEL: call_indirect_stackify:
 ; NOREGS: i32.load  0
 ; NOREGS-NEXT: local.tee 0
diff --git a/llvm/test/CodeGen/WebAssembly/swiftcc.ll b/llvm/test/CodeGen/WebAssembly/swiftcc.ll
index 0c5c3d8bbb0ff..b6cc6fb441ee0 100644
--- a/llvm/test/CodeGen/WebAssembly/swiftcc.ll
+++ b/llvm/test/CodeGen/WebAssembly/swiftcc.ll
@@ -18,21 +18,21 @@ define swiftcc void @bar() {
 ; REG: call    foo, $pop{{[0-9]+}}, $pop{{[0-9]+}}, $pop{{[0-9]+}}, $pop{{[0-9]+}}
   call swiftcc void @foo(i32 1, i32 2)
 
-; REG: call_indirect   $pop{{[0-9]+}}, $pop{{[0-9]+}}, $pop{{[0-9]+}}, $pop{{[0-9]+}}
+; REG: call_indirect  __indirect_function_table, (i32, i32, i32, i32) -> (), $pop{{[0-9]+}}, $pop{{[0-9]+}}, $pop{{[0-9]+}}, $pop{{[0-9]+}}
 ; CHECK: call_indirect __indirect_function_table, (i32, i32, i32, i32) -> ()
   call swiftcc void %1(i32 1, i32 2)
 
-; REG: call_indirect   $pop{{[0-9]+}}, $pop{{[0-9]+}}, $pop{{[0-9]+}}, $pop{{[0-9]+}}
+; REG: call_indirect  __indirect_function_table, (i32, i32, i32, i32) -> (), $pop{{[0-9]+}}, $pop{{[0-9]+}}, $pop{{[0-9]+}}, $pop{{[0-9]+}}
 ; CHECK: call_indirect __indirect_function_table, (i32, i32, i32, i32) -> ()
   call swiftcc void %1(i32 1, i32 2, i32 swiftself 3)
 
   %err = alloca swifterror ptr, align 4
 
-; REG: call_indirect   $pop{{[0-9]+}}, $pop{{[0-9]+}}, $pop{{[0-9]+}}, $pop{{[0-9]+}}
+; REG: call_indirect  __indirect_function_table, (i32, i32, i32, i32) -> (), $pop{{[0-9]+}}, $pop{{[0-9]+}}, $pop{{[0-9]+}}, $pop{{[0-9]+}}
 ; CHECK: call_indirect __indirect_function_table, (i32, i32, i32, i32) -> ()
   call swiftcc void %1(i32 1, i32 2, ptr swifterror %err)
 
-; REG: call_indirect   $pop{{[0-9]+}}, $pop{{[0-9]+}}, $pop{{[0-9]+}}, $pop{{[0-9]+}}
+; REG: call_indirect  __indirect_function_table, (i32, i32, i32, i32) -> (), $pop{{[0-9]+}}, $pop{{[0-9]+}}, $pop{{[0-9]+}}, $pop{{[0-9]+}}
 ; CHECK: call_indirect __indirect_function_table, (i32, i32, i32, i32) -> ()
   call swiftcc void %1(i32 1, i32 2, i32 swiftself 3, ptr swifterror %err)
 
diff --git a/llvm/test/CodeGen/WebAssembly/tailcall.ll b/llvm/test/CodeGen/WebAssembly/tailcall.ll
index 84bd142462e37..e05b65f51a073 100644
--- a/llvm/test/CodeGen/WebAssembly/tailcall.ll
+++ b/llvm/test/CodeGen/WebAssembly/tailcall.ll
@@ -82,7 +82,7 @@ define i32 @indirect_notail(%fn %f, i32 %x, i32 %y) {
 ; CHECK-LABEL: indirect_notail:
 ; CHECK:         .functype indirect_notail (i32, i32, i32) -> (i32)
 ; CHECK-NEXT:  # %bb.0:
-; CHECK-NEXT:    call_indirect $push0=, $0, $1, $2, $0 # Invalid depth argument!
+; CHECK-NEXT:    call_indirect 0, (i32, i32, i32) -> (i32), $push0=, $0, $1, $2, $0 # Invalid depth argument!
 ; CHECK-NEXT:    return $pop0
   %p = extractvalue %fn %f, 0
   %v = notail call i32 %p(%fn %f, i32 %x, i32 %y)
@@ -93,7 +93,7 @@ define i32 @indirect_musttail(%fn %f, i32 %x, i32 %y) {
 ; CHECK-LABEL: indirect_musttail:
 ; CHECK:         .functype indirect_musttail (i32, i32, i32) -> (i32)
 ; CHECK-NEXT:  # %bb.0:
-; CHECK-NEXT:    return_call_indirect , $0, $1, $2, $0
+; CHECK-NEXT:    return_call_indirect 0, (i32, i32, i32) -> (i32), $0, $1, $2, $0
   %p = extractvalue %fn %f, 0
   %v = musttail call i32 %p(%fn %f, i32 %x, i32 %y)
   ret i32 %v
@@ -103,7 +103,7 @@ define i32 @indirect_tail(%fn %f, i32 %x, i32 %y) {
 ; CHECK-LABEL: indirect_tail:
 ; CHECK:         .functype indirect_tail (i32, i32, i32) -> (i32)
 ; CHECK-NEXT:  # %bb.0:
-; CHECK-NEXT:    return_call_indirect , $0, $1, $2, $0
+; CHECK-NEXT:    return_call_indirect 0, (i32, i32, i32) -> (i32), $0, $1, $2, $0
   %p = extractvalue %fn %f, 0
   %v = tail call i32 %p(%fn %f, i32 %x, i32 %y)
   ret i32 %v
@@ -118,7 +118,7 @@ define i1 @choice_notail(i1 %x) {
 ; SLOW-NEXT:    i32.const $push0=, 1
 ; SLOW-NEXT:    i32.and $push1=, $0, $pop0
 ; SLOW-NEXT:    i32.select $push4=, $pop3, $pop2, $pop1
-; SLOW-NEXT:    call_indirect $push5=, $0, $pop4 # Invalid depth argument!
+; SLOW-NEXT:    call_indirect 0, (i32) -> (i32), $push5=, $0, $pop4 # Invalid depth argument!
 ; SLOW-NEXT:    return $pop5
 ;
 ; FAST-LABEL: choice_notail:
@@ -129,7 +129,7 @@ define i1 @choice_notail(i1 %x) {
 ; FAST-NEXT:    i32.const $push1=, 1
 ; FAST-NEXT:    i32.and $push2=, $0, $pop1
 ; FAST-NEXT:    i32.select $push5=, $pop3, $pop4, $pop2
-; FAST-NEXT:    call_indirect $push0=, $0, $pop5 # Invalid depth argument!
+; FAST-NEXT:    call_indirect 0, (i32) -> (i32), $push0=, $0, $pop5 # Invalid depth argument!
 ; FAST-NEXT:    return $pop0
   %p = select i1 %x, ptr @foo, ptr @bar
   %v = notail call i1 %p(i1 %x)
@@ -145,7 +145,7 @@ define i1 @choice_musttail(i1 %x) {
 ; SLOW-NEXT:    i32.const $push0=, 1
 ; SLOW-NEXT:    i32.and $push1=, $0, $pop0
 ; SLOW-NEXT:    i32.select $push4=, $pop3, $pop2, $pop1
-; SLOW-NEXT:    return_call_indirect , $0, $pop4
+; SLOW-NEXT:    return_call_indirect 0, (i32) -> (i32), $0, $pop4
 ;
 ; FAST-LABEL: choice_musttail:
 ; FAST:         .functype choice_musttail (i32) -> (i32)
@@ -155,7 +155,7 @@ define i1 @choice_musttail(i1 %x) {
 ; FAST-NEXT:    i32.const $push1=, 1
 ; FAST-NEXT:    i32.and $push2=, $0, $pop1
 ; FAST-NEXT:    i32.select $push0=, $pop4, $pop3, $pop2
-; FAST-NEXT:    return_call_indirect , $0, $pop0
+; FAST-NEXT:    return_call_indirect 0, (i32) -> (i32), $0, $pop0
   %p = select i1 %x, ptr @foo, ptr @bar
   %v = musttail call i1 %p(i1 %x)
   ret i1 %v
@@ -170,7 +170,7 @@ define i1 @choice_tail(i1 %x) {
 ; SLOW-NEXT:    i32.const $push0=, 1
 ; SLOW-NEXT:    i32.and $push1=, $0, $pop0
 ; SLOW-NEXT:    i32.select $push4=, $pop3, $pop2, $pop1
-; SLOW-NEXT:    return_call_indirect , $0, $pop4
+; SLOW-NEXT:    return_call_indirect 0, (i32) -> (i32), $0, $pop4
 ;
 ; FAST-LABEL: choice_tail:
 ; FAST:         .functype choice_tail (i32) -> (i32)
@@ -180,7 +180,7 @@ define i1 @choice_tail(i1 %x) {
 ; FAST-NEXT:    i32.const $push1=, 1
 ; FAST-NEXT:    i32.and $push2=, $0, $pop1
 ; FAST-NEXT:    i32.select $push5=, $pop3, $pop4, $pop2
-; FAST-NEXT:    call_indirect $push0=, $0, $pop5 # Invalid depth argument!
+; FAST-NEXT:    call_indirect  0, (i32) -> (i32), $push0=, $0, $pop5 # Invalid depth argument!
 ; FAST-NEXT:    return $pop0
   %p = select i1 %x, ptr @foo, ptr @bar
   %v = tail call i1 %p(i1 %x)
@@ -264,7 +264,7 @@ define void @mismatched_indirect_void(%fn %f, i32 %x, i32 %y) {
 ; CHECK-LABEL: mismatched_indirect_void:
 ; CHECK:         .functype mismatched_indirect_void (i32, i32, i32) -> ()
 ; CHECK-NEXT:  # %bb.0:
-; CHECK-NEXT:    call_indirect $drop=, $0, $1, $2, $0 # Invalid depth argument!
+; CHECK-NEXT:    call_indirect 0, (i32, i32, i32) -> (i32), $drop=, $0, $1, $2, $0 # Invalid depth argument!
 ; CHECK-NEXT:    return
   %p = extractvalue %fn %f, 0
   %v = tail call i32 %p(%fn %f, i32 %x, i32 %y)
@@ -275,7 +275,7 @@ define float @mismatched_indirect_f32(%fn %f, i32 %x, i32 %y) {
 ; CHECK-LABEL: mismatched_indirect_f32:
 ; CHECK:         .functype mismatched_indirect_f32 (i32, i32, i32) -> (f32)
 ; CHECK-NEXT:  # %bb.0:
-; CHECK-NEXT:    call_indirect $push0=, $0, $1, $2, $0 # Invalid depth argument!
+; CHECK-NEXT:    call_indirect 0, (i32, i32, i32) -> (i32), $push0=, $0, $1, $2, $0 # Invalid depth argument!
 ; CHECK-NEXT:    f32.reinterpret_i32 $push1=, $pop0
 ; CHECK-NEXT:    return $pop1
   %p = extractvalue %fn %f, 0
@@ -538,7 +538,7 @@ define i32 @indirect_epilogue(ptr %p) {
 ; CHECK-NEXT:    i32.const $push2=, 256
 ; CHECK-NEXT:    i32.add $push3=, $1, $pop2
 ; CHECK-NEXT:    global.set __stack_pointer, $pop3
-; CHECK-NEXT:    return_call_indirect , $0, $0
+; CHECK-NEXT:    return_call_indirect 0, (i32) -> (i32), $0, $0
   %a = alloca [64 x i32]
   %v = musttail call i32 %p(ptr %p)
   ret i32 %v
@@ -564,7 +564,7 @@ define i32 @unique_caller(ptr %p) {
 ; SLOW-NEXT:    i64.const $push2=, 0
 ; SLOW-NEXT:    f64.const $push1=, 0x0p0
 ; SLOW-NEXT:    i32.load $push0=, 0($0)
-; SLOW-NEXT:    return_call_indirect , $pop4, $pop3, $pop2, $pop1, $pop0
+; SLOW-NEXT:    return_call_indirect  0, (i32, f32, i64, f64) -> (i32), $pop4, $pop3, $pop2, $pop1, $pop0
 ;
 ; FAST-LABEL: unique_caller:
 ; FAST:         .functype unique_caller (i32) -> (i32)
@@ -576,7 +576,7 @@ define i32 @unique_caller(ptr %p) {
 ; FAST-NEXT:    i32.const $push6=, 0
 ; FAST-NEXT:    f64.convert_i32_s $push4=, $pop6
 ; FAST-NEXT:    i32.load $push5=, 0($0)
-; FAST-NEXT:    call_indirect $push0=, $pop1, $pop2, $pop3, $pop4, $pop5 # Invalid depth argument!
+; FAST-NEXT:    call_indirect 0, (i32, f32, i64, f64) -> (i32), $push0=, $pop1, $pop2, $pop3, $pop4, $pop5 # Invalid depth argument!
 ; FAST-NEXT:    return $pop0
   %f = load ptr, ptr %p
   %v = tail call i32 %f(i32 0, float 0., i64 0, double 0.)

>From 89caa96f44330967025b24b944722bee327b2822 Mon Sep 17 00:00:00 2001
From: Hanbum Park <kese111 at gmail.com>
Date: Mon, 9 Feb 2026 00:43:33 +0900
Subject: [PATCH 2/5] consolidate handling indirect  for register and stack

---
 .../MCTargetDesc/WebAssemblyInstPrinter.cpp   | 34 ++++++-------------
 llvm/test/CodeGen/WebAssembly/multivalue.ll   |  2 +-
 llvm/test/CodeGen/WebAssembly/tailcall.ll     | 28 +++++++--------
 3 files changed, 26 insertions(+), 38 deletions(-)

diff --git a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyInstPrinter.cpp b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyInstPrinter.cpp
index f883c5175a408..c59291b270ab9 100644
--- a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyInstPrinter.cpp
+++ b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyInstPrinter.cpp
@@ -48,25 +48,17 @@ void WebAssemblyInstPrinter::printInst(const MCInst *MI, uint64_t Address,
                                        StringRef Annot,
                                        const MCSubtargetInfo &STI,
                                        raw_ostream &OS) {
+
+  unsigned TypeOperand = 0;
+  unsigned TableOperand = 1;
   switch (MI->getOpcode()) {
-  case WebAssembly::CALL_INDIRECT:
-  case WebAssembly::RET_CALL_INDIRECT: {
-    OS << "\t" << getMnemonic(*MI).first << "\t";
-    unsigned TypeOperand = 0;
-    unsigned TableOperand = 1;
-    if (MI->getOpcode() == WebAssembly::CALL_INDIRECT) {
-      unsigned NumDefs = MI->getOperand(0).getImm();
-      TypeOperand = 1 + NumDefs;      // Type 위치 보정
-      TableOperand = 1 + NumDefs + 1; // Table 위치 보정
-    }
-    printOperand(MI, TableOperand, OS);
-    OS << ", ";
-    printOperand(MI, TypeOperand, OS);
-    if (MI->getOpcode() == WebAssembly::CALL_INDIRECT) {
-      OS << ", ";
-    }
-    break;
+  case WebAssembly::CALL_INDIRECT: {
+    unsigned NumDefs = MI->getOperand(0).getImm();
+    TypeOperand = NumDefs + 1;
+    TableOperand = NumDefs + 2;
+    [[fallthrough]];
   }
+  case WebAssembly::RET_CALL_INDIRECT:
   case WebAssembly::CALL_INDIRECT_S:
   case WebAssembly::RET_CALL_INDIRECT_S: {
     // A special case for call_indirect (and ret_call_indirect), if the table
@@ -77,17 +69,13 @@ void WebAssemblyInstPrinter::printInst(const MCInst *MI, uint64_t Address,
     OS << "\t";
     OS << getMnemonic(*MI).first;
     OS << " ";
-
-    assert(MI->getNumOperands() == 2);
-    const unsigned TypeOperand = 0;
-    const unsigned TableOperand = 1;
     if (MI->getOperand(TableOperand).isExpr()) {
       printOperand(MI, TableOperand, OS);
       OS << ", ";
-    } else {
-      assert(MI->getOperand(TableOperand).getImm() == 0);
     }
     printOperand(MI, TypeOperand, OS);
+    if (MI->getOpcode() == WebAssembly::CALL_INDIRECT)
+      OS << ", ";
     break;
   }
   default:
diff --git a/llvm/test/CodeGen/WebAssembly/multivalue.ll b/llvm/test/CodeGen/WebAssembly/multivalue.ll
index 2fa6381e4c4c7..537adff3f3405 100644
--- a/llvm/test/CodeGen/WebAssembly/multivalue.ll
+++ b/llvm/test/CodeGen/WebAssembly/multivalue.ll
@@ -62,7 +62,7 @@ define %pair @pair_call_return() {
 ; CHECK-NEXT: call_indirect () -> (i32, i64){{$}}
 ; REF:        call_indirect __indirect_function_table, () -> (i32, i64){{$}}
 ; CHECK-NEXT: end_function{{$}}
-; REGS: call_indirect 0, () -> (i32, i64), $push{{[0-9]+}}=, $push{{[0-9]+}}=, $0{{$}}
+; REGS: call_indirect () -> (i32, i64), $push{{[0-9]+}}=, $push{{[0-9]+}}=, $0{{$}}
 define %pair @pair_call_indirect(ptr %f) {
   %p = call %pair %f()
   ret %pair %p
diff --git a/llvm/test/CodeGen/WebAssembly/tailcall.ll b/llvm/test/CodeGen/WebAssembly/tailcall.ll
index e05b65f51a073..8900fe9cff24b 100644
--- a/llvm/test/CodeGen/WebAssembly/tailcall.ll
+++ b/llvm/test/CodeGen/WebAssembly/tailcall.ll
@@ -82,7 +82,7 @@ define i32 @indirect_notail(%fn %f, i32 %x, i32 %y) {
 ; CHECK-LABEL: indirect_notail:
 ; CHECK:         .functype indirect_notail (i32, i32, i32) -> (i32)
 ; CHECK-NEXT:  # %bb.0:
-; CHECK-NEXT:    call_indirect 0, (i32, i32, i32) -> (i32), $push0=, $0, $1, $2, $0 # Invalid depth argument!
+; CHECK-NEXT:    call_indirect (i32, i32, i32) -> (i32), $push0=, $0, $1, $2, $0 # Invalid depth argument!
 ; CHECK-NEXT:    return $pop0
   %p = extractvalue %fn %f, 0
   %v = notail call i32 %p(%fn %f, i32 %x, i32 %y)
@@ -93,7 +93,7 @@ define i32 @indirect_musttail(%fn %f, i32 %x, i32 %y) {
 ; CHECK-LABEL: indirect_musttail:
 ; CHECK:         .functype indirect_musttail (i32, i32, i32) -> (i32)
 ; CHECK-NEXT:  # %bb.0:
-; CHECK-NEXT:    return_call_indirect 0, (i32, i32, i32) -> (i32), $0, $1, $2, $0
+; CHECK-NEXT:    return_call_indirect (i32, i32, i32) -> (i32), $0, $1, $2, $0
   %p = extractvalue %fn %f, 0
   %v = musttail call i32 %p(%fn %f, i32 %x, i32 %y)
   ret i32 %v
@@ -103,7 +103,7 @@ define i32 @indirect_tail(%fn %f, i32 %x, i32 %y) {
 ; CHECK-LABEL: indirect_tail:
 ; CHECK:         .functype indirect_tail (i32, i32, i32) -> (i32)
 ; CHECK-NEXT:  # %bb.0:
-; CHECK-NEXT:    return_call_indirect 0, (i32, i32, i32) -> (i32), $0, $1, $2, $0
+; CHECK-NEXT:    return_call_indirect (i32, i32, i32) -> (i32), $0, $1, $2, $0
   %p = extractvalue %fn %f, 0
   %v = tail call i32 %p(%fn %f, i32 %x, i32 %y)
   ret i32 %v
@@ -118,7 +118,7 @@ define i1 @choice_notail(i1 %x) {
 ; SLOW-NEXT:    i32.const $push0=, 1
 ; SLOW-NEXT:    i32.and $push1=, $0, $pop0
 ; SLOW-NEXT:    i32.select $push4=, $pop3, $pop2, $pop1
-; SLOW-NEXT:    call_indirect 0, (i32) -> (i32), $push5=, $0, $pop4 # Invalid depth argument!
+; SLOW-NEXT:    call_indirect (i32) -> (i32), $push5=, $0, $pop4 # Invalid depth argument!
 ; SLOW-NEXT:    return $pop5
 ;
 ; FAST-LABEL: choice_notail:
@@ -129,7 +129,7 @@ define i1 @choice_notail(i1 %x) {
 ; FAST-NEXT:    i32.const $push1=, 1
 ; FAST-NEXT:    i32.and $push2=, $0, $pop1
 ; FAST-NEXT:    i32.select $push5=, $pop3, $pop4, $pop2
-; FAST-NEXT:    call_indirect 0, (i32) -> (i32), $push0=, $0, $pop5 # Invalid depth argument!
+; FAST-NEXT:    call_indirect (i32) -> (i32), $push0=, $0, $pop5 # Invalid depth argument!
 ; FAST-NEXT:    return $pop0
   %p = select i1 %x, ptr @foo, ptr @bar
   %v = notail call i1 %p(i1 %x)
@@ -145,7 +145,7 @@ define i1 @choice_musttail(i1 %x) {
 ; SLOW-NEXT:    i32.const $push0=, 1
 ; SLOW-NEXT:    i32.and $push1=, $0, $pop0
 ; SLOW-NEXT:    i32.select $push4=, $pop3, $pop2, $pop1
-; SLOW-NEXT:    return_call_indirect 0, (i32) -> (i32), $0, $pop4
+; SLOW-NEXT:    return_call_indirect (i32) -> (i32), $0, $pop4
 ;
 ; FAST-LABEL: choice_musttail:
 ; FAST:         .functype choice_musttail (i32) -> (i32)
@@ -155,7 +155,7 @@ define i1 @choice_musttail(i1 %x) {
 ; FAST-NEXT:    i32.const $push1=, 1
 ; FAST-NEXT:    i32.and $push2=, $0, $pop1
 ; FAST-NEXT:    i32.select $push0=, $pop4, $pop3, $pop2
-; FAST-NEXT:    return_call_indirect 0, (i32) -> (i32), $0, $pop0
+; FAST-NEXT:    return_call_indirect (i32) -> (i32), $0, $pop0
   %p = select i1 %x, ptr @foo, ptr @bar
   %v = musttail call i1 %p(i1 %x)
   ret i1 %v
@@ -170,7 +170,7 @@ define i1 @choice_tail(i1 %x) {
 ; SLOW-NEXT:    i32.const $push0=, 1
 ; SLOW-NEXT:    i32.and $push1=, $0, $pop0
 ; SLOW-NEXT:    i32.select $push4=, $pop3, $pop2, $pop1
-; SLOW-NEXT:    return_call_indirect 0, (i32) -> (i32), $0, $pop4
+; SLOW-NEXT:    return_call_indirect (i32) -> (i32), $0, $pop4
 ;
 ; FAST-LABEL: choice_tail:
 ; FAST:         .functype choice_tail (i32) -> (i32)
@@ -180,7 +180,7 @@ define i1 @choice_tail(i1 %x) {
 ; FAST-NEXT:    i32.const $push1=, 1
 ; FAST-NEXT:    i32.and $push2=, $0, $pop1
 ; FAST-NEXT:    i32.select $push5=, $pop3, $pop4, $pop2
-; FAST-NEXT:    call_indirect  0, (i32) -> (i32), $push0=, $0, $pop5 # Invalid depth argument!
+; FAST-NEXT:    call_indirect (i32) -> (i32), $push0=, $0, $pop5 # Invalid depth argument!
 ; FAST-NEXT:    return $pop0
   %p = select i1 %x, ptr @foo, ptr @bar
   %v = tail call i1 %p(i1 %x)
@@ -264,7 +264,7 @@ define void @mismatched_indirect_void(%fn %f, i32 %x, i32 %y) {
 ; CHECK-LABEL: mismatched_indirect_void:
 ; CHECK:         .functype mismatched_indirect_void (i32, i32, i32) -> ()
 ; CHECK-NEXT:  # %bb.0:
-; CHECK-NEXT:    call_indirect 0, (i32, i32, i32) -> (i32), $drop=, $0, $1, $2, $0 # Invalid depth argument!
+; CHECK-NEXT:    call_indirect (i32, i32, i32) -> (i32), $drop=, $0, $1, $2, $0 # Invalid depth argument!
 ; CHECK-NEXT:    return
   %p = extractvalue %fn %f, 0
   %v = tail call i32 %p(%fn %f, i32 %x, i32 %y)
@@ -275,7 +275,7 @@ define float @mismatched_indirect_f32(%fn %f, i32 %x, i32 %y) {
 ; CHECK-LABEL: mismatched_indirect_f32:
 ; CHECK:         .functype mismatched_indirect_f32 (i32, i32, i32) -> (f32)
 ; CHECK-NEXT:  # %bb.0:
-; CHECK-NEXT:    call_indirect 0, (i32, i32, i32) -> (i32), $push0=, $0, $1, $2, $0 # Invalid depth argument!
+; CHECK-NEXT:    call_indirect (i32, i32, i32) -> (i32), $push0=, $0, $1, $2, $0 # Invalid depth argument!
 ; CHECK-NEXT:    f32.reinterpret_i32 $push1=, $pop0
 ; CHECK-NEXT:    return $pop1
   %p = extractvalue %fn %f, 0
@@ -538,7 +538,7 @@ define i32 @indirect_epilogue(ptr %p) {
 ; CHECK-NEXT:    i32.const $push2=, 256
 ; CHECK-NEXT:    i32.add $push3=, $1, $pop2
 ; CHECK-NEXT:    global.set __stack_pointer, $pop3
-; CHECK-NEXT:    return_call_indirect 0, (i32) -> (i32), $0, $0
+; CHECK-NEXT:    return_call_indirect (i32) -> (i32), $0, $0
   %a = alloca [64 x i32]
   %v = musttail call i32 %p(ptr %p)
   ret i32 %v
@@ -564,7 +564,7 @@ define i32 @unique_caller(ptr %p) {
 ; SLOW-NEXT:    i64.const $push2=, 0
 ; SLOW-NEXT:    f64.const $push1=, 0x0p0
 ; SLOW-NEXT:    i32.load $push0=, 0($0)
-; SLOW-NEXT:    return_call_indirect  0, (i32, f32, i64, f64) -> (i32), $pop4, $pop3, $pop2, $pop1, $pop0
+; SLOW-NEXT:    return_call_indirect (i32, f32, i64, f64) -> (i32), $pop4, $pop3, $pop2, $pop1, $pop0
 ;
 ; FAST-LABEL: unique_caller:
 ; FAST:         .functype unique_caller (i32) -> (i32)
@@ -576,7 +576,7 @@ define i32 @unique_caller(ptr %p) {
 ; FAST-NEXT:    i32.const $push6=, 0
 ; FAST-NEXT:    f64.convert_i32_s $push4=, $pop6
 ; FAST-NEXT:    i32.load $push5=, 0($0)
-; FAST-NEXT:    call_indirect 0, (i32, f32, i64, f64) -> (i32), $push0=, $pop1, $pop2, $pop3, $pop4, $pop5 # Invalid depth argument!
+; FAST-NEXT:    call_indirect (i32, f32, i64, f64) -> (i32), $push0=, $pop1, $pop2, $pop3, $pop4, $pop5 # Invalid depth argument!
 ; FAST-NEXT:    return $pop0
   %f = load ptr, ptr %p
   %v = tail call i32 %f(i32 0, float 0., i64 0, double 0.)

>From 3ee0a2faea96dd9d019c5942edda6db0d420e3b8 Mon Sep 17 00:00:00 2001
From: Hanbum Park <kese111 at gmail.com>
Date: Thu, 12 Feb 2026 18:27:10 +0900
Subject: [PATCH 3/5] add test return-call-indirect

---
 .../WebAssembly/return-call-indirect.ll       | 29 +++++++++++++++++++
 1 file changed, 29 insertions(+)
 create mode 100644 llvm/test/CodeGen/WebAssembly/return-call-indirect.ll

diff --git a/llvm/test/CodeGen/WebAssembly/return-call-indirect.ll b/llvm/test/CodeGen/WebAssembly/return-call-indirect.ll
new file mode 100644
index 0000000000000..e8375aaedd752
--- /dev/null
+++ b/llvm/test/CodeGen/WebAssembly/return-call-indirect.ll
@@ -0,0 +1,29 @@
+; RUN: llc < %s -asm-verbose=false -mattr=-reference-types,+tail-call -O2 | FileCheck --check-prefixes=CHECK,NOREF %s
+; RUN: llc < %s -asm-verbose=false -mattr=+reference-types,+tail-call -O2 | FileCheck --check-prefixes=CHECK,REF %s
+; RUN: llc < %s -asm-verbose=false -mattr=+tail-call -O2 --filetype=obj | obj2yaml | FileCheck --check-prefix=OBJ %s
+
+; Test that compilation units with call_indirect but without any
+; function pointer declarations still get a table.
+
+target triple = "wasm32-unknown-unknown"
+
+; CHECK-LABEL: return_call_indirect:
+; CHECK-NEXT: .functype return_call_indirect (i32) -> (i32)
+; CHECK-NEXT: local.get 0
+; REF:       return_call_indirect     __indirect_function_table, () -> (i32)
+; NOREF:     return_call_indirect     __indirect_function_table, () -> (i32)
+; CHECK-NEXT: end_function
+define i32 @return_call_indirect(ptr %callee) {
+  %r = tail call i32 %callee()
+  ret i32 %r
+}
+
+; OBJ:    Imports:
+; OBJ-NEXT:      - Module:          env
+; OBJ-NEXT:        Field:           __linear_memory
+; OBJ-NEXT:        Kind:            MEMORY
+; OBJ-NEXT:        Memory:
+; OBJ-NEXT:          Minimum:         0x0
+; OBJ-NEXT:      - Module:          env
+; OBJ-NEXT:        Field:           __indirect_function_table
+; OBJ-NEXT:        Kind:            TABLE

>From 152693d307d659a9c32441f51e3f21f0ea612abc Mon Sep 17 00:00:00 2001
From: Hanbum Park <kese111 at gmail.com>
Date: Fri, 13 Feb 2026 01:43:55 +0900
Subject: [PATCH 4/5] remove blank line

---
 .../Target/WebAssembly/MCTargetDesc/WebAssemblyInstPrinter.cpp   | 1 -
 1 file changed, 1 deletion(-)

diff --git a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyInstPrinter.cpp b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyInstPrinter.cpp
index c59291b270ab9..660dab93d18c9 100644
--- a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyInstPrinter.cpp
+++ b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyInstPrinter.cpp
@@ -48,7 +48,6 @@ void WebAssemblyInstPrinter::printInst(const MCInst *MI, uint64_t Address,
                                        StringRef Annot,
                                        const MCSubtargetInfo &STI,
                                        raw_ostream &OS) {
-
   unsigned TypeOperand = 0;
   unsigned TableOperand = 1;
   switch (MI->getOpcode()) {

>From 06bdd8658540f99735f6961040999446c75d1707 Mon Sep 17 00:00:00 2001
From: Hanbum Park <kese111 at gmail.com>
Date: Fri, 13 Feb 2026 01:48:41 +0900
Subject: [PATCH 5/5] Fix conflict between printer and parser

When processing the `call_indirect` and `return_call_indirect`
instructions, WebAssemblyAsmParser only parsed the symbol table
when the `+reference-type` feature was present. However,
WebAssemblyInstPrinter always printed the symbol table, creating
a discrepancy. To resolve this, WebAssemblyInstPrinter has been
modified to print the symbol table only when the `+reference-type`
feature is present.
---
 .../Target/WebAssembly/MCTargetDesc/WebAssemblyInstPrinter.cpp | 3 ++-
 llvm/test/CodeGen/WebAssembly/return-call-indirect.ll          | 2 +-
 2 files changed, 3 insertions(+), 2 deletions(-)

diff --git a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyInstPrinter.cpp b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyInstPrinter.cpp
index 660dab93d18c9..963a2783aeba9 100644
--- a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyInstPrinter.cpp
+++ b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyInstPrinter.cpp
@@ -68,7 +68,8 @@ void WebAssemblyInstPrinter::printInst(const MCInst *MI, uint64_t Address,
     OS << "\t";
     OS << getMnemonic(*MI).first;
     OS << " ";
-    if (MI->getOperand(TableOperand).isExpr()) {
+    if (MI->getOperand(TableOperand).isExpr() &&
+        STI.checkFeatures("+reference-types")) {
       printOperand(MI, TableOperand, OS);
       OS << ", ";
     }
diff --git a/llvm/test/CodeGen/WebAssembly/return-call-indirect.ll b/llvm/test/CodeGen/WebAssembly/return-call-indirect.ll
index e8375aaedd752..0b4f4882ebcf2 100644
--- a/llvm/test/CodeGen/WebAssembly/return-call-indirect.ll
+++ b/llvm/test/CodeGen/WebAssembly/return-call-indirect.ll
@@ -11,7 +11,7 @@ target triple = "wasm32-unknown-unknown"
 ; CHECK-NEXT: .functype return_call_indirect (i32) -> (i32)
 ; CHECK-NEXT: local.get 0
 ; REF:       return_call_indirect     __indirect_function_table, () -> (i32)
-; NOREF:     return_call_indirect     __indirect_function_table, () -> (i32)
+; NOREF:     return_call_indirect     () -> (i32)
 ; CHECK-NEXT: end_function
 define i32 @return_call_indirect(ptr %callee) {
   %r = tail call i32 %callee()



More information about the llvm-commits mailing list