[llvm] [WebAssembly] Support binary generation for new EH (PR #109027)

via llvm-commits llvm-commits at lists.llvm.org
Tue Sep 17 11:41:44 PDT 2024


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-mc

@llvm/pr-subscribers-backend-webassembly

Author: Heejin Ahn (aheejin)

<details>
<summary>Changes</summary>

This adds support for binary generation for the new EH proposal.

So far the only case that we emitted variable immediate operands in binary has been `br_table`'s destinations. (Other `variable_ops` uses in TableGen files are register operands, such as the operands of `call`, so they don't get emitted in binary as a part of the same instruction.)

With this PR, variable immediate operands can include `try_table`'s operands:
- The number of of catch clauses
- catch clauses sub-opcodes
  - `catch`: 0x00
  - `catch_ref`: 0x01
  - `catch_all`: 0x02
  - `catch_all_ref`: 0x03
- catch clauses' destinations

With `try_table`, we now have variable expr operands for `try_table`'s catch clauses' tags. We treat their fixups in the same way we do for tags in other instructions such as in `throw`.

Diff without whitespace will be easier to view.

---
Full diff: https://github.com/llvm/llvm-project/pull/109027.diff


3 Files Affected:

- (modified) llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCCodeEmitter.cpp (+41-29) 
- (modified) llvm/test/CodeGen/WebAssembly/exception.ll (+1) 
- (modified) llvm/test/MC/WebAssembly/eh-assembly.s (+2) 


``````````diff
diff --git a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCCodeEmitter.cpp b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCCodeEmitter.cpp
index aaca213c4afe9b..3e7487dbd8f54e 100644
--- a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCCodeEmitter.cpp
+++ b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCCodeEmitter.cpp
@@ -82,14 +82,15 @@ void WebAssemblyMCCodeEmitter::encodeInstruction(
   // For br_table instructions, encode the size of the table. In the MCInst,
   // there's an index operand (if not a stack instruction), one operand for
   // each table entry, and the default operand.
-  if (MI.getOpcode() == WebAssembly::BR_TABLE_I32_S ||
-      MI.getOpcode() == WebAssembly::BR_TABLE_I64_S)
+  unsigned Opcode = MI.getOpcode();
+  if (Opcode == WebAssembly::BR_TABLE_I32_S ||
+      Opcode == WebAssembly::BR_TABLE_I64_S)
     encodeULEB128(MI.getNumOperands() - 1, OS);
-  if (MI.getOpcode() == WebAssembly::BR_TABLE_I32 ||
-      MI.getOpcode() == WebAssembly::BR_TABLE_I64)
+  if (Opcode == WebAssembly::BR_TABLE_I32 ||
+      Opcode == WebAssembly::BR_TABLE_I64)
     encodeULEB128(MI.getNumOperands() - 2, OS);
 
-  const MCInstrDesc &Desc = MCII.get(MI.getOpcode());
+  const MCInstrDesc &Desc = MCII.get(Opcode);
   for (unsigned I = 0, E = MI.getNumOperands(); I < E; ++I) {
     const MCOperand &MO = MI.getOperand(I);
     if (MO.isReg()) {
@@ -136,7 +137,12 @@ void WebAssemblyMCCodeEmitter::encodeInstruction(
           encodeULEB128(uint64_t(MO.getImm()), OS);
         }
       } else {
-        encodeULEB128(uint64_t(MO.getImm()), OS);
+        // Variadic immediate operands are br_table's destination operands or
+        // try_table's operands (# of catch clauses, catch sub-opcodes, or catch
+        // clause destinations)
+        assert(WebAssembly::isBrTable(Opcode) ||
+               Opcode == WebAssembly::TRY_TABLE_S);
+        encodeULEB128(uint32_t(MO.getImm()), OS);
       }
 
     } else if (MO.isSFPImm()) {
@@ -146,32 +152,38 @@ void WebAssemblyMCCodeEmitter::encodeInstruction(
       uint64_t D = MO.getDFPImm();
       support::endian::write<uint64_t>(OS, D, llvm::endianness::little);
     } else if (MO.isExpr()) {
-      const MCOperandInfo &Info = Desc.operands()[I];
       llvm::MCFixupKind FixupKind;
       size_t PaddedSize = 5;
-      switch (Info.OperandType) {
-      case WebAssembly::OPERAND_I32IMM:
-        FixupKind = MCFixupKind(WebAssembly::fixup_sleb128_i32);
-        break;
-      case WebAssembly::OPERAND_I64IMM:
-        FixupKind = MCFixupKind(WebAssembly::fixup_sleb128_i64);
-        PaddedSize = 10;
-        break;
-      case WebAssembly::OPERAND_FUNCTION32:
-      case WebAssembly::OPERAND_TABLE:
-      case WebAssembly::OPERAND_OFFSET32:
-      case WebAssembly::OPERAND_SIGNATURE:
-      case WebAssembly::OPERAND_TYPEINDEX:
-      case WebAssembly::OPERAND_GLOBAL:
-      case WebAssembly::OPERAND_TAG:
+      if (I < Desc.getNumOperands()) {
+        const MCOperandInfo &Info = Desc.operands()[I];
+        switch (Info.OperandType) {
+        case WebAssembly::OPERAND_I32IMM:
+          FixupKind = MCFixupKind(WebAssembly::fixup_sleb128_i32);
+          break;
+        case WebAssembly::OPERAND_I64IMM:
+          FixupKind = MCFixupKind(WebAssembly::fixup_sleb128_i64);
+          PaddedSize = 10;
+          break;
+        case WebAssembly::OPERAND_FUNCTION32:
+        case WebAssembly::OPERAND_TABLE:
+        case WebAssembly::OPERAND_OFFSET32:
+        case WebAssembly::OPERAND_SIGNATURE:
+        case WebAssembly::OPERAND_TYPEINDEX:
+        case WebAssembly::OPERAND_GLOBAL:
+        case WebAssembly::OPERAND_TAG:
+          FixupKind = MCFixupKind(WebAssembly::fixup_uleb128_i32);
+          break;
+        case WebAssembly::OPERAND_OFFSET64:
+          FixupKind = MCFixupKind(WebAssembly::fixup_uleb128_i64);
+          PaddedSize = 10;
+          break;
+        default:
+          llvm_unreachable("unexpected symbolic operand kind");
+        }
+      } else {
+        // Variadic expr operands are try_table's catch/catch_ref clauses' tags.
+        assert(Opcode == WebAssembly::TRY_TABLE_S);
         FixupKind = MCFixupKind(WebAssembly::fixup_uleb128_i32);
-        break;
-      case WebAssembly::OPERAND_OFFSET64:
-        FixupKind = MCFixupKind(WebAssembly::fixup_uleb128_i64);
-        PaddedSize = 10;
-        break;
-      default:
-        llvm_unreachable("unexpected symbolic operand kind");
       }
       Fixups.push_back(MCFixup::create(OS.tell() - Start, MO.getExpr(),
                                        FixupKind, MI.getLoc()));
diff --git a/llvm/test/CodeGen/WebAssembly/exception.ll b/llvm/test/CodeGen/WebAssembly/exception.ll
index 7259761d6313b6..1ad4c84f1c0237 100644
--- a/llvm/test/CodeGen/WebAssembly/exception.ll
+++ b/llvm/test/CodeGen/WebAssembly/exception.ll
@@ -1,6 +1,7 @@
 ; RUN: llc < %s -asm-verbose=false -wasm-enable-eh -exception-model=wasm -mattr=+exception-handling -wasm-enable-exnref -verify-machineinstrs | FileCheck --implicit-check-not=ehgcr -allow-deprecated-dag-overlap %s
 ; RUN: llc < %s -asm-verbose=false -wasm-enable-eh -exception-model=wasm -mattr=+exception-handling -wasm-enable-exnref -verify-machineinstrs -O0
 ; RUN: llc < %s -wasm-enable-eh -exception-model=wasm -mattr=+exception-handling -wasm-enable-exnref
+; RUN: llc < %s -wasm-enable-eh -exception-model=wasm -mattr=+exception-handling -wasm-enable-exnref -filetype=obj
 
 target triple = "wasm32-unknown-unknown"
 
diff --git a/llvm/test/MC/WebAssembly/eh-assembly.s b/llvm/test/MC/WebAssembly/eh-assembly.s
index a769bc447d0ba9..b4d6b324d96e3e 100644
--- a/llvm/test/MC/WebAssembly/eh-assembly.s
+++ b/llvm/test/MC/WebAssembly/eh-assembly.s
@@ -1,4 +1,6 @@
 # RUN: llvm-mc -triple=wasm32-unknown-unknown -mattr=+exception-handling --no-type-check < %s | FileCheck %s
+# Check that it converts to .o without errors, but don't check any output:
+# RUN: llvm-mc -triple=wasm32-unknown-unknown -filetype=obj -mattr=+exception-handling --no-type-check -o %t.o < %s
 
   .tagtype  __cpp_exception i32
   .tagtype  __c_longjmp i32

``````````

</details>


https://github.com/llvm/llvm-project/pull/109027


More information about the llvm-commits mailing list