[lld] [llvm] [MC][WebAssembly] Allow strings for import modules and names in asm (PR #182896)
Sy Brand via llvm-commits
llvm-commits at lists.llvm.org
Tue Mar 3 04:02:40 PST 2026
https://github.com/TartanLlama updated https://github.com/llvm/llvm-project/pull/182896
>From 38138759c356bc9129431753c95b4c08edfba89a Mon Sep 17 00:00:00 2001
From: Sy Brand <sy.brand at fastly.com>
Date: Mon, 23 Feb 2026 16:49:06 +0000
Subject: [PATCH 01/12] Allow strings for import modules and names
---
.../AsmParser/WebAssemblyAsmParser.cpp | 23 ++++++++++++--
.../WebAssemblyTargetStreamer.cpp | 31 +++++++++++++++----
.../MC/WebAssembly/import-module-invalid.s | 2 +-
llvm/test/MC/WebAssembly/import-module.s | 14 +++++++++
.../test/MC/WebAssembly/import-name-invalid.s | 2 +-
5 files changed, 61 insertions(+), 11 deletions(-)
diff --git a/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp b/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp
index 9175b2731dac0..b48abe85aca91 100644
--- a/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp
+++ b/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp
@@ -415,6 +415,23 @@ class WebAssemblyAsmParser final : public MCTargetAsmParser {
return Name;
}
+ StringRef expectStringOrIdent() {
+ if (Lexer.is(AsmToken::String)) {
+ auto Str = Lexer.getTok().getString();
+ Parser.Lex();
+ Str.consume_front("\"");
+ Str.consume_back("\"");
+ return Str;
+ }
+ if (Lexer.is(AsmToken::Identifier)) {
+ auto Name = Lexer.getTok().getString();
+ Parser.Lex();
+ return Name;
+ }
+ error("Expected string or identifier, got: ", Lexer.getTok());
+ return StringRef();
+ }
+
bool parseRegTypeList(SmallVectorImpl<wasm::ValType> &Types) {
while (Lexer.is(AsmToken::Identifier)) {
auto Type = WebAssembly::parseType(Lexer.getTok().getString());
@@ -1041,7 +1058,7 @@ class WebAssemblyAsmParser final : public MCTargetAsmParser {
return ParseStatus::Failure;
if (expect(AsmToken::Comma, ","))
return ParseStatus::Failure;
- auto ExportName = expectIdent();
+ auto ExportName = expectStringOrIdent();
if (ExportName.empty())
return ParseStatus::Failure;
auto *WasmSym =
@@ -1057,7 +1074,7 @@ class WebAssemblyAsmParser final : public MCTargetAsmParser {
return ParseStatus::Failure;
if (expect(AsmToken::Comma, ","))
return ParseStatus::Failure;
- auto ImportModule = expectIdent();
+ auto ImportModule = expectStringOrIdent();
if (ImportModule.empty())
return ParseStatus::Failure;
auto *WasmSym =
@@ -1073,7 +1090,7 @@ class WebAssemblyAsmParser final : public MCTargetAsmParser {
return ParseStatus::Failure;
if (expect(AsmToken::Comma, ","))
return ParseStatus::Failure;
- auto ImportName = expectIdent();
+ StringRef ImportName = expectStringOrIdent();
if (ImportName.empty())
return ParseStatus::Failure;
auto *WasmSym =
diff --git a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.cpp b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.cpp
index c18de5fc1939e..916a42664279f 100644
--- a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.cpp
+++ b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.cpp
@@ -22,6 +22,15 @@
#include "llvm/Support/FormattedStream.h"
using namespace llvm;
+static bool shouldQuoteName(StringRef Name) {
+ // Wasm export/import names and import module names can contain characters
+ // that are not allowed in identifiers, so we need to quote them.
+ auto isValidStartChar = [](char C) { return isalpha(C) || C == '_' || C == '.'; };
+ auto isValidChar = [&](char C) { return isValidStartChar(C) || isdigit(C); };
+ return !(Name.size() > 0 && isValidStartChar(Name.front())) ||
+ llvm::any_of(Name, [&](char C) { return !isValidChar(C); });
+}
+
WebAssemblyTargetStreamer::WebAssemblyTargetStreamer(MCStreamer &S)
: MCTargetStreamer(S) {}
@@ -94,22 +103,32 @@ void WebAssemblyTargetAsmStreamer::emitTagType(const MCSymbolWasm *Sym) {
OS << "\n";
}
+static void emitNameWithQuoting(formatted_raw_ostream &OS, StringRef Name) {
+ if (shouldQuoteName(Name))
+ OS << '"' << Name << '"';
+ else
+ OS << Name;
+}
+
void WebAssemblyTargetAsmStreamer::emitImportModule(const MCSymbolWasm *Sym,
StringRef ImportModule) {
- OS << "\t.import_module\t" << Sym->getName() << ", "
- << ImportModule << '\n';
+ OS << "\t.import_module\t" << Sym->getName() << ", ";
+ emitNameWithQuoting(OS, ImportModule);
+ OS << '\n';
}
void WebAssemblyTargetAsmStreamer::emitImportName(const MCSymbolWasm *Sym,
StringRef ImportName) {
- OS << "\t.import_name\t" << Sym->getName() << ", "
- << ImportName << '\n';
+ OS << "\t.import_name\t" << Sym->getName() << ", ";
+ emitNameWithQuoting(OS, ImportName);
+ OS << '\n';
}
void WebAssemblyTargetAsmStreamer::emitExportName(const MCSymbolWasm *Sym,
StringRef ExportName) {
- OS << "\t.export_name\t" << Sym->getName() << ", "
- << ExportName << '\n';
+ OS << "\t.export_name\t" << Sym->getName() << ", ";
+ emitNameWithQuoting(OS, ExportName);
+ OS << '\n';
}
void WebAssemblyTargetAsmStreamer::emitIndIdx(const MCExpr *Value) {
diff --git a/llvm/test/MC/WebAssembly/import-module-invalid.s b/llvm/test/MC/WebAssembly/import-module-invalid.s
index a9f93e83dba39..daf18f2e6a505 100644
--- a/llvm/test/MC/WebAssembly/import-module-invalid.s
+++ b/llvm/test/MC/WebAssembly/import-module-invalid.s
@@ -6,7 +6,7 @@
# CHECK: [[#@LINE+1]]:19: error: Expected ,, instead got:
.import_module foo
-# CHECK: [[#@LINE+1]]:20: error: Expected identifier, got:
+# CHECK: [[#@LINE+1]]:20: error: Expected string or identifier, got:
.import_module foo,
# CHECK: [[#@LINE+1]]:24: error: Expected EOL, instead got: ,
diff --git a/llvm/test/MC/WebAssembly/import-module.s b/llvm/test/MC/WebAssembly/import-module.s
index 5d28d5b9c0b92..75090001755a9 100644
--- a/llvm/test/MC/WebAssembly/import-module.s
+++ b/llvm/test/MC/WebAssembly/import-module.s
@@ -3,16 +3,22 @@
.functype foo () -> ()
.functype plain () -> ()
+.functype __wasm_component_model_builtin_context_get_0 () -> (i32)
test:
.functype test () -> ()
call foo
call plain
+ call __wasm_component_model_builtin_context_get_0
+ drop
end_function
.import_module foo, bar
.import_name foo, qux
+ .import_module __wasm_component_model_builtin_context_get_0, "$root"
+ .import_name __wasm_component_model_builtin_context_get_0, "[context-get-0]"
+
# CHECK-ASM: .import_module foo, bar
# CHECK-ASM: .import_name foo, qux
@@ -26,9 +32,17 @@ test:
# CHECK-NEXT: Field: plain
# CHECK-NEXT: Kind: FUNCTION
+# CHECK: - Module: '$root'
+# CHECK-NEXT: Field: '[context-get-0]'
+# CHECK-NEXT: Kind: FUNCTION
+# CHECK-NEXT: SigIndex: 1
+
# CHECK: - Type: CUSTOM
# CHECK: Name: foo
# CHECK-NEXT: Flags: [ UNDEFINED, EXPLICIT_NAME ]
# CHECK: Name: plain
# CHECK-NEXT: Flags: [ UNDEFINED ]
+
+# CHECK: Name: __wasm_component_model_builtin_context_get_0
+# CHECK-NEXT: Flags: [ UNDEFINED, EXPLICIT_NAME ]
\ No newline at end of file
diff --git a/llvm/test/MC/WebAssembly/import-name-invalid.s b/llvm/test/MC/WebAssembly/import-name-invalid.s
index da8ed0d4617b0..df709f6380a06 100644
--- a/llvm/test/MC/WebAssembly/import-name-invalid.s
+++ b/llvm/test/MC/WebAssembly/import-name-invalid.s
@@ -6,7 +6,7 @@
# CHECK: [[#@LINE+1]]:17: error: Expected ,, instead got:
.import_name foo
-# CHECK: [[#@LINE+1]]:18: error: Expected identifier, got:
+# CHECK: [[#@LINE+1]]:18: error: Expected string or identifier, got:
.import_name foo,
# CHECK: [[#@LINE+1]]:22: error: Expected EOL, instead got: ,
>From 11a9778a689c1121b75e76b5e635a5382c78ae7a Mon Sep 17 00:00:00 2001
From: Sy Brand <sy.brand at fastly.com>
Date: Mon, 23 Feb 2026 16:50:02 +0000
Subject: [PATCH 02/12] Newline
---
llvm/test/MC/WebAssembly/import-module.s | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/llvm/test/MC/WebAssembly/import-module.s b/llvm/test/MC/WebAssembly/import-module.s
index 75090001755a9..5aa41f166e6c7 100644
--- a/llvm/test/MC/WebAssembly/import-module.s
+++ b/llvm/test/MC/WebAssembly/import-module.s
@@ -45,4 +45,4 @@ test:
# CHECK-NEXT: Flags: [ UNDEFINED ]
# CHECK: Name: __wasm_component_model_builtin_context_get_0
-# CHECK-NEXT: Flags: [ UNDEFINED, EXPLICIT_NAME ]
\ No newline at end of file
+# CHECK-NEXT: Flags: [ UNDEFINED, EXPLICIT_NAME ]
>From 6c1411c1211a2e0070cb40066ad893a23b51eb75 Mon Sep 17 00:00:00 2001
From: Sy Brand <sy.brand at fastly.com>
Date: Mon, 23 Feb 2026 17:16:56 +0000
Subject: [PATCH 03/12] More tests
---
llvm/test/MC/WebAssembly/export-name-invalid.s | 5 ++++-
llvm/test/MC/WebAssembly/export-name.s | 7 +++++++
llvm/test/MC/WebAssembly/import-module-invalid.s | 3 +++
llvm/test/MC/WebAssembly/import-name-invalid.s | 3 +++
4 files changed, 17 insertions(+), 1 deletion(-)
diff --git a/llvm/test/MC/WebAssembly/export-name-invalid.s b/llvm/test/MC/WebAssembly/export-name-invalid.s
index ad322ce949f5e..e6e1d2dfa8a8a 100644
--- a/llvm/test/MC/WebAssembly/export-name-invalid.s
+++ b/llvm/test/MC/WebAssembly/export-name-invalid.s
@@ -6,8 +6,11 @@
# CHECK: [[#@LINE+1]]:17: error: Expected ,, instead got:
.export_name foo
-# CHECK: [[#@LINE+1]]:18: error: Expected identifier, got:
+# CHECK: [[#@LINE+1]]:18: error: Expected string or identifier, got:
.export_name foo,
# CHECK: [[#@LINE+1]]:22: error: Expected EOL, instead got: ,
.export_name foo, bar,
+
+# CHECK: [[#@LINE+1]]:19: error: Expected string or identifier, got: "bar
+.export_name foo, "bar
\ No newline at end of file
diff --git a/llvm/test/MC/WebAssembly/export-name.s b/llvm/test/MC/WebAssembly/export-name.s
index 51e1bcf73dba2..d9f058a21660f 100644
--- a/llvm/test/MC/WebAssembly/export-name.s
+++ b/llvm/test/MC/WebAssembly/export-name.s
@@ -8,7 +8,14 @@ foo:
.export_name foo, bar
end_function
+square:
+ .globl square
+ .functype square () -> ()
+ .export_name square, "[square]"
+ end_function
+
# CHECK: .export_name foo, bar
+# CHECK: .export_name square, "[square]"
# CHECK-OBJ: - Type: EXPORT
# CHECK-OBJ-NEXT: Exports:
diff --git a/llvm/test/MC/WebAssembly/import-module-invalid.s b/llvm/test/MC/WebAssembly/import-module-invalid.s
index daf18f2e6a505..55745ea911b7e 100644
--- a/llvm/test/MC/WebAssembly/import-module-invalid.s
+++ b/llvm/test/MC/WebAssembly/import-module-invalid.s
@@ -11,3 +11,6 @@
# CHECK: [[#@LINE+1]]:24: error: Expected EOL, instead got: ,
.import_module foo, bar,
+
+# CHECK: [[#@LINE+1]]:21: error: Expected string or identifier, got: "bar
+.import_module foo, "bar
diff --git a/llvm/test/MC/WebAssembly/import-name-invalid.s b/llvm/test/MC/WebAssembly/import-name-invalid.s
index df709f6380a06..841c55eee3a18 100644
--- a/llvm/test/MC/WebAssembly/import-name-invalid.s
+++ b/llvm/test/MC/WebAssembly/import-name-invalid.s
@@ -11,3 +11,6 @@
# CHECK: [[#@LINE+1]]:22: error: Expected EOL, instead got: ,
.import_name foo, bar,
+
+# CHECK: [[#@LINE+1]]:19: error: Expected string or identifier, got: "bar
+.import_name foo, "bar
>From 4f1340601ed73b96a65d1acbb8af2b11f9f765b7 Mon Sep 17 00:00:00 2001
From: Sy Brand <sy.brand at fastly.com>
Date: Mon, 23 Feb 2026 17:18:25 +0000
Subject: [PATCH 04/12] Newline
---
llvm/test/MC/WebAssembly/export-name-invalid.s | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/llvm/test/MC/WebAssembly/export-name-invalid.s b/llvm/test/MC/WebAssembly/export-name-invalid.s
index e6e1d2dfa8a8a..31144dc16bf14 100644
--- a/llvm/test/MC/WebAssembly/export-name-invalid.s
+++ b/llvm/test/MC/WebAssembly/export-name-invalid.s
@@ -13,4 +13,4 @@
.export_name foo, bar,
# CHECK: [[#@LINE+1]]:19: error: Expected string or identifier, got: "bar
-.export_name foo, "bar
\ No newline at end of file
+.export_name foo, "bar
>From 8660f198ae5981e27a939cc547a3f63fb6934fd5 Mon Sep 17 00:00:00 2001
From: Sy Brand <sy.brand at fastly.com>
Date: Wed, 25 Feb 2026 08:48:53 +0000
Subject: [PATCH 05/12] Allow dollars in identifiers
---
.../AsmParser/WebAssemblyAsmParser.cpp | 4 +--
.../MCTargetDesc/WebAssemblyMCAsmInfo.cpp | 2 ++
.../WebAssemblyTargetStreamer.cpp | 2 +-
llvm/test/MC/WebAssembly/export-name.s | 29 +++++++++++++++++++
llvm/test/MC/WebAssembly/import-module.s | 14 +++++++++
5 files changed, 47 insertions(+), 4 deletions(-)
diff --git a/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp b/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp
index b48abe85aca91..79673f80701bb 100644
--- a/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp
+++ b/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp
@@ -417,10 +417,8 @@ class WebAssemblyAsmParser final : public MCTargetAsmParser {
StringRef expectStringOrIdent() {
if (Lexer.is(AsmToken::String)) {
- auto Str = Lexer.getTok().getString();
+ auto Str = Lexer.getTok().getStringContents();
Parser.Lex();
- Str.consume_front("\"");
- Str.consume_back("\"");
return Str;
}
if (Lexer.is(AsmToken::Identifier)) {
diff --git a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCAsmInfo.cpp b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCAsmInfo.cpp
index a783e5fd8521a..a69f0eb1db196 100644
--- a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCAsmInfo.cpp
+++ b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCAsmInfo.cpp
@@ -57,5 +57,7 @@ WebAssemblyMCAsmInfo::WebAssemblyMCAsmInfo(const Triple &T,
SupportsDebugInformation = true;
ExceptionsType = ExceptionHandling::None;
+ AllowDollarAtStartOfIdentifier = true;
+
initializeAtSpecifiers(atSpecifiers);
}
diff --git a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.cpp b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.cpp
index 916a42664279f..0e7f4614b7d36 100644
--- a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.cpp
+++ b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.cpp
@@ -25,7 +25,7 @@ using namespace llvm;
static bool shouldQuoteName(StringRef Name) {
// Wasm export/import names and import module names can contain characters
// that are not allowed in identifiers, so we need to quote them.
- auto isValidStartChar = [](char C) { return isalpha(C) || C == '_' || C == '.'; };
+ auto isValidStartChar = [](char C) { return isalpha(C) || C == '_' || C == '.' || C == '$'; };
auto isValidChar = [&](char C) { return isValidStartChar(C) || isdigit(C); };
return !(Name.size() > 0 && isValidStartChar(Name.front())) ||
llvm::any_of(Name, [&](char C) { return !isValidChar(C); });
diff --git a/llvm/test/MC/WebAssembly/export-name.s b/llvm/test/MC/WebAssembly/export-name.s
index d9f058a21660f..23cce3fd762ee 100644
--- a/llvm/test/MC/WebAssembly/export-name.s
+++ b/llvm/test/MC/WebAssembly/export-name.s
@@ -14,8 +14,22 @@ square:
.export_name square, "[square]"
end_function
+$dollar:
+ .globl $dollar
+ .functype $dollar () -> ()
+ .export_name $dollar, $dollar
+ end_function
+
+mid$dollar:
+ .globl mid$dollar
+ .functype mid$dollar () -> ()
+ .export_name mid$dollar, mid$dollar
+ end_function
+
# CHECK: .export_name foo, bar
# CHECK: .export_name square, "[square]"
+# CHECK: .export_name $dollar, $dollar
+# CHECK: .export_name mid$dollar, mid$dollar
# CHECK-OBJ: - Type: EXPORT
# CHECK-OBJ-NEXT: Exports:
@@ -31,3 +45,18 @@ square:
# CHECK-OBJ-NEXT: Name: foo
# CHECK-OBJ-NEXT: Flags: [ EXPORTED ]
# CHECK-OBJ-NEXT: Function: 0
+# CHECK-OBJ-NEXT: - Index: 1
+# CHECK-OBJ-NEXT: Kind: FUNCTION
+# CHECK-OBJ-NEXT: Name: square
+# CHECK-OBJ-NEXT: Flags: [ EXPORTED ]
+# CHECK-OBJ-NEXT: Function: 1
+# CHECK-OBJ-NEXT: - Index: 2
+# CHECK-OBJ-NEXT: Kind: FUNCTION
+# CHECK-OBJ-NEXT: Name: '$dollar'
+# CHECK-OBJ-NEXT: Flags: [ EXPORTED ]
+# CHECK-OBJ-NEXT: Function: 2
+# CHECK-OBJ-NEXT: - Index: 3
+# CHECK-OBJ-NEXT: Kind: FUNCTION
+# CHECK-OBJ-NEXT: Name: 'mid$dollar'
+# CHECK-OBJ-NEXT: Flags: [ EXPORTED ]
+# CHECK-OBJ-NEXT: Function: 3
diff --git a/llvm/test/MC/WebAssembly/import-module.s b/llvm/test/MC/WebAssembly/import-module.s
index 5aa41f166e6c7..110496fdb399e 100644
--- a/llvm/test/MC/WebAssembly/import-module.s
+++ b/llvm/test/MC/WebAssembly/import-module.s
@@ -4,6 +4,7 @@
.functype foo () -> ()
.functype plain () -> ()
.functype __wasm_component_model_builtin_context_get_0 () -> (i32)
+.functype __wasm_component_model_builtin_context_get_1 () -> (i32)
test:
.functype test () -> ()
@@ -11,6 +12,8 @@ test:
call plain
call __wasm_component_model_builtin_context_get_0
drop
+ call __wasm_component_model_builtin_context_get_1
+ drop
end_function
.import_module foo, bar
@@ -19,6 +22,9 @@ test:
.import_module __wasm_component_model_builtin_context_get_0, "$root"
.import_name __wasm_component_model_builtin_context_get_0, "[context-get-0]"
+ .import_module __wasm_component_model_builtin_context_get_1, $root
+ .import_name __wasm_component_model_builtin_context_get_1, "[context-get-1]"
+
# CHECK-ASM: .import_module foo, bar
# CHECK-ASM: .import_name foo, qux
@@ -37,6 +43,11 @@ test:
# CHECK-NEXT: Kind: FUNCTION
# CHECK-NEXT: SigIndex: 1
+# CHECK: - Module: '$root'
+# CHECK-NEXT: Field: '[context-get-1]'
+# CHECK-NEXT: Kind: FUNCTION
+# CHECK-NEXT: SigIndex: 1
+
# CHECK: - Type: CUSTOM
# CHECK: Name: foo
# CHECK-NEXT: Flags: [ UNDEFINED, EXPLICIT_NAME ]
@@ -46,3 +57,6 @@ test:
# CHECK: Name: __wasm_component_model_builtin_context_get_0
# CHECK-NEXT: Flags: [ UNDEFINED, EXPLICIT_NAME ]
+
+# CHECK: Name: __wasm_component_model_builtin_context_get_1
+# CHECK-NEXT: Flags: [ UNDEFINED, EXPLICIT_NAME ]
\ No newline at end of file
>From 45a0db289edd414b7a77b0e9bfa694cf87f28c7a Mon Sep 17 00:00:00 2001
From: Sy Brand <sy.brand at fastly.com>
Date: Wed, 25 Feb 2026 09:12:24 +0000
Subject: [PATCH 06/12] Add dollar symbol lld test
---
lld/test/wasm/dollar-symbol.s | 109 ++++++++++++++++++++++++++++++++++
1 file changed, 109 insertions(+)
create mode 100644 lld/test/wasm/dollar-symbol.s
diff --git a/lld/test/wasm/dollar-symbol.s b/lld/test/wasm/dollar-symbol.s
new file mode 100644
index 0000000000000..e35e7b4b797c2
--- /dev/null
+++ b/lld/test/wasm/dollar-symbol.s
@@ -0,0 +1,109 @@
+## Test linking of symbols with dollar signs in their names.
+# RUN: split-file %s %t
+# RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-unknown -o %t/dollar.o %t/dollar.s
+# RUN: obj2yaml %t/dollar.o | FileCheck %s --check-prefix=CHECK-OBJ-DOLLAR
+# RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-unknown -o %t/main.o %t/main.s
+# RUN: obj2yaml %t/main.o | FileCheck %s --check-prefix=CHECK-OBJ-MAIN
+# RUN: wasm-ld %t/dollar.o %t/main.o -o %t/out.wasm 2>&1
+# RUN: obj2yaml %t/out.wasm | FileCheck %s --check-prefix=CHECK-OUT
+
+# CHECK-OBJ-DOLLAR: SymbolTable:
+# CHECK-OBJ-DOLLAR-NEXT: - Index: 0
+# CHECK-OBJ-DOLLAR-NEXT: Kind: FUNCTION
+# CHECK-OBJ-DOLLAR-NEXT: Name: '$dollar_func'
+# CHECK-OBJ-DOLLAR-NEXT: Flags: [ ]
+# CHECK-OBJ-DOLLAR-NEXT: Function: 0
+# CHECK-OBJ-DOLLAR-NEXT: - Index: 1
+# CHECK-OBJ-DOLLAR-NEXT: Kind: FUNCTION
+# CHECK-OBJ-DOLLAR-NEXT: Name: 'mid$dollar_func'
+# CHECK-OBJ-DOLLAR-NEXT: Flags: [ ]
+# CHECK-OBJ-DOLLAR-NEXT: Function: 1
+# CHECK-OBJ-DOLLAR-NEXT: - Index: 2
+# CHECK-OBJ-DOLLAR-NEXT: Kind: DATA
+# CHECK-OBJ-DOLLAR-NEXT: Name: '$dollar_global'
+# CHECK-OBJ-DOLLAR-NEXT: Flags: [ ]
+# CHECK-OBJ-DOLLAR-NEXT: Segment: 0
+# CHECK-OBJ-DOLLAR-NEXT: Size: 4
+# CHECK-OBJ-DOLLAR-NEXT: - Index: 3
+# CHECK-OBJ-DOLLAR-NEXT: Kind: DATA
+# CHECK-OBJ-DOLLAR-NEXT: Name: 'mid$dollar_global'
+# CHECK-OBJ-DOLLAR-NEXT: Flags: [ ]
+# CHECK-OBJ-DOLLAR-NEXT: Segment: 1
+# CHECK-OBJ-DOLLAR-NEXT: Size: 4
+
+# CHECK-OBJ-MAIN: SymbolTable:
+# CHECK-OBJ-MAIN-NEXT: - Index: 0
+# CHECK-OBJ-MAIN-NEXT: Kind: DATA
+# CHECK-OBJ-MAIN-NEXT: Name: '$dollar_global'
+# CHECK-OBJ-MAIN-NEXT: Flags: [ UNDEFINED ]
+# CHECK-OBJ-MAIN-NEXT: - Index: 1
+# CHECK-OBJ-MAIN-NEXT: Kind: DATA
+# CHECK-OBJ-MAIN-NEXT: Name: 'mid$dollar_global'
+# CHECK-OBJ-MAIN-NEXT: Flags: [ UNDEFINED ]
+# CHECK-OBJ-MAIN-NEXT: - Index: 2
+# CHECK-OBJ-MAIN-NEXT: Kind: FUNCTION
+# CHECK-OBJ-MAIN-NEXT: Name: _start
+# CHECK-OBJ-MAIN-NEXT: Flags: [ ]
+# CHECK-OBJ-MAIN-NEXT: Function: 2
+# CHECK-OBJ-MAIN-NEXT: - Index: 3
+# CHECK-OBJ-MAIN-NEXT: Kind: FUNCTION
+# CHECK-OBJ-MAIN-NEXT: Name: '$dollar_func'
+# CHECK-OBJ-MAIN-NEXT: Flags: [ UNDEFINED ]
+# CHECK-OBJ-MAIN-NEXT: Function: 0
+# CHECK-OBJ-MAIN-NEXT: - Index: 4
+# CHECK-OBJ-MAIN-NEXT: Kind: FUNCTION
+# CHECK-OBJ-MAIN-NEXT: Name: 'mid$dollar_func'
+# CHECK-OBJ-MAIN-NEXT: Flags: [ UNDEFINED ]
+# CHECK-OBJ-MAIN-NEXT: Function: 1
+
+# CHECK-OUT: - Type: CUSTOM
+# CHECK-OUT-NEXT: Name: name
+# CHECK-OUT-NEXT: FunctionNames:
+# CHECK-OUT-NEXT: - Index: 0
+# CHECK-OUT-NEXT: Name: '$dollar_func'
+# CHECK-OUT-NEXT: - Index: 1
+# CHECK-OUT-NEXT: Name: 'mid$dollar_func'
+# CHECK-OUT-NEXT: - Index: 2
+
+#--- main.s
+
+.functype $dollar_func () -> ()
+.functype mid$dollar_func () -> ()
+
+.globl $dollar_global
+.globl mid$dollar_global
+
+.globl _start
+_start:
+ .functype _start () -> ()
+ call $dollar_func
+ call mid$dollar_func
+ i32.const $dollar_global
+ drop
+ i32.const mid$dollar_global
+ drop
+ end_function
+
+#--- dollar.s
+
+.globl $dollar_func
+$dollar_func:
+ .functype $dollar_func () -> ()
+ end_function
+
+.globl mid$dollar_func
+mid$dollar_func:
+ .functype mid$dollar_func () -> ()
+ end_function
+
+.globl $dollar_global
+.section ".data.$dollar_global","",@
+$dollar_global:
+ .int32 42
+ .size $dollar_global, 4
+
+.globl mid$dollar_global
+.section ".data.mid$dollar_global","",@
+mid$dollar_global:
+ .int32 43
+ .size mid$dollar_global, 4
>From fb81b6bb5c7a1df29b8346ba2e412bbd9e9f0a48 Mon Sep 17 00:00:00 2001
From: Sy Brand <sy.brand at fastly.com>
Date: Thu, 26 Feb 2026 08:24:04 +0000
Subject: [PATCH 07/12] Revert dollar changes
---
lld/test/wasm/dollar-symbol.s | 109 ------------------
.../MCTargetDesc/WebAssemblyMCAsmInfo.cpp | 2 -
.../WebAssemblyTargetStreamer.cpp | 4 +-
llvm/test/MC/WebAssembly/export-name.s | 14 +--
llvm/test/MC/WebAssembly/import-module.s | 11 --
5 files changed, 3 insertions(+), 137 deletions(-)
delete mode 100644 lld/test/wasm/dollar-symbol.s
diff --git a/lld/test/wasm/dollar-symbol.s b/lld/test/wasm/dollar-symbol.s
deleted file mode 100644
index e35e7b4b797c2..0000000000000
--- a/lld/test/wasm/dollar-symbol.s
+++ /dev/null
@@ -1,109 +0,0 @@
-## Test linking of symbols with dollar signs in their names.
-# RUN: split-file %s %t
-# RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-unknown -o %t/dollar.o %t/dollar.s
-# RUN: obj2yaml %t/dollar.o | FileCheck %s --check-prefix=CHECK-OBJ-DOLLAR
-# RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-unknown -o %t/main.o %t/main.s
-# RUN: obj2yaml %t/main.o | FileCheck %s --check-prefix=CHECK-OBJ-MAIN
-# RUN: wasm-ld %t/dollar.o %t/main.o -o %t/out.wasm 2>&1
-# RUN: obj2yaml %t/out.wasm | FileCheck %s --check-prefix=CHECK-OUT
-
-# CHECK-OBJ-DOLLAR: SymbolTable:
-# CHECK-OBJ-DOLLAR-NEXT: - Index: 0
-# CHECK-OBJ-DOLLAR-NEXT: Kind: FUNCTION
-# CHECK-OBJ-DOLLAR-NEXT: Name: '$dollar_func'
-# CHECK-OBJ-DOLLAR-NEXT: Flags: [ ]
-# CHECK-OBJ-DOLLAR-NEXT: Function: 0
-# CHECK-OBJ-DOLLAR-NEXT: - Index: 1
-# CHECK-OBJ-DOLLAR-NEXT: Kind: FUNCTION
-# CHECK-OBJ-DOLLAR-NEXT: Name: 'mid$dollar_func'
-# CHECK-OBJ-DOLLAR-NEXT: Flags: [ ]
-# CHECK-OBJ-DOLLAR-NEXT: Function: 1
-# CHECK-OBJ-DOLLAR-NEXT: - Index: 2
-# CHECK-OBJ-DOLLAR-NEXT: Kind: DATA
-# CHECK-OBJ-DOLLAR-NEXT: Name: '$dollar_global'
-# CHECK-OBJ-DOLLAR-NEXT: Flags: [ ]
-# CHECK-OBJ-DOLLAR-NEXT: Segment: 0
-# CHECK-OBJ-DOLLAR-NEXT: Size: 4
-# CHECK-OBJ-DOLLAR-NEXT: - Index: 3
-# CHECK-OBJ-DOLLAR-NEXT: Kind: DATA
-# CHECK-OBJ-DOLLAR-NEXT: Name: 'mid$dollar_global'
-# CHECK-OBJ-DOLLAR-NEXT: Flags: [ ]
-# CHECK-OBJ-DOLLAR-NEXT: Segment: 1
-# CHECK-OBJ-DOLLAR-NEXT: Size: 4
-
-# CHECK-OBJ-MAIN: SymbolTable:
-# CHECK-OBJ-MAIN-NEXT: - Index: 0
-# CHECK-OBJ-MAIN-NEXT: Kind: DATA
-# CHECK-OBJ-MAIN-NEXT: Name: '$dollar_global'
-# CHECK-OBJ-MAIN-NEXT: Flags: [ UNDEFINED ]
-# CHECK-OBJ-MAIN-NEXT: - Index: 1
-# CHECK-OBJ-MAIN-NEXT: Kind: DATA
-# CHECK-OBJ-MAIN-NEXT: Name: 'mid$dollar_global'
-# CHECK-OBJ-MAIN-NEXT: Flags: [ UNDEFINED ]
-# CHECK-OBJ-MAIN-NEXT: - Index: 2
-# CHECK-OBJ-MAIN-NEXT: Kind: FUNCTION
-# CHECK-OBJ-MAIN-NEXT: Name: _start
-# CHECK-OBJ-MAIN-NEXT: Flags: [ ]
-# CHECK-OBJ-MAIN-NEXT: Function: 2
-# CHECK-OBJ-MAIN-NEXT: - Index: 3
-# CHECK-OBJ-MAIN-NEXT: Kind: FUNCTION
-# CHECK-OBJ-MAIN-NEXT: Name: '$dollar_func'
-# CHECK-OBJ-MAIN-NEXT: Flags: [ UNDEFINED ]
-# CHECK-OBJ-MAIN-NEXT: Function: 0
-# CHECK-OBJ-MAIN-NEXT: - Index: 4
-# CHECK-OBJ-MAIN-NEXT: Kind: FUNCTION
-# CHECK-OBJ-MAIN-NEXT: Name: 'mid$dollar_func'
-# CHECK-OBJ-MAIN-NEXT: Flags: [ UNDEFINED ]
-# CHECK-OBJ-MAIN-NEXT: Function: 1
-
-# CHECK-OUT: - Type: CUSTOM
-# CHECK-OUT-NEXT: Name: name
-# CHECK-OUT-NEXT: FunctionNames:
-# CHECK-OUT-NEXT: - Index: 0
-# CHECK-OUT-NEXT: Name: '$dollar_func'
-# CHECK-OUT-NEXT: - Index: 1
-# CHECK-OUT-NEXT: Name: 'mid$dollar_func'
-# CHECK-OUT-NEXT: - Index: 2
-
-#--- main.s
-
-.functype $dollar_func () -> ()
-.functype mid$dollar_func () -> ()
-
-.globl $dollar_global
-.globl mid$dollar_global
-
-.globl _start
-_start:
- .functype _start () -> ()
- call $dollar_func
- call mid$dollar_func
- i32.const $dollar_global
- drop
- i32.const mid$dollar_global
- drop
- end_function
-
-#--- dollar.s
-
-.globl $dollar_func
-$dollar_func:
- .functype $dollar_func () -> ()
- end_function
-
-.globl mid$dollar_func
-mid$dollar_func:
- .functype mid$dollar_func () -> ()
- end_function
-
-.globl $dollar_global
-.section ".data.$dollar_global","",@
-$dollar_global:
- .int32 42
- .size $dollar_global, 4
-
-.globl mid$dollar_global
-.section ".data.mid$dollar_global","",@
-mid$dollar_global:
- .int32 43
- .size mid$dollar_global, 4
diff --git a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCAsmInfo.cpp b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCAsmInfo.cpp
index a69f0eb1db196..a783e5fd8521a 100644
--- a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCAsmInfo.cpp
+++ b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCAsmInfo.cpp
@@ -57,7 +57,5 @@ WebAssemblyMCAsmInfo::WebAssemblyMCAsmInfo(const Triple &T,
SupportsDebugInformation = true;
ExceptionsType = ExceptionHandling::None;
- AllowDollarAtStartOfIdentifier = true;
-
initializeAtSpecifiers(atSpecifiers);
}
diff --git a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.cpp b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.cpp
index 0e7f4614b7d36..5db51bad8c70c 100644
--- a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.cpp
+++ b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.cpp
@@ -25,8 +25,8 @@ using namespace llvm;
static bool shouldQuoteName(StringRef Name) {
// Wasm export/import names and import module names can contain characters
// that are not allowed in identifiers, so we need to quote them.
- auto isValidStartChar = [](char C) { return isalpha(C) || C == '_' || C == '.' || C == '$'; };
- auto isValidChar = [&](char C) { return isValidStartChar(C) || isdigit(C); };
+ auto isValidStartChar = [](char C) { return isalpha(C) || C == '_' || C == '.'; };
+ auto isValidChar = [&](char C) { return isValidStartChar(C) || isdigit(C) || C == '$'; };
return !(Name.size() > 0 && isValidStartChar(Name.front())) ||
llvm::any_of(Name, [&](char C) { return !isValidChar(C); });
}
diff --git a/llvm/test/MC/WebAssembly/export-name.s b/llvm/test/MC/WebAssembly/export-name.s
index 23cce3fd762ee..92be384ecf9ec 100644
--- a/llvm/test/MC/WebAssembly/export-name.s
+++ b/llvm/test/MC/WebAssembly/export-name.s
@@ -14,12 +14,6 @@ square:
.export_name square, "[square]"
end_function
-$dollar:
- .globl $dollar
- .functype $dollar () -> ()
- .export_name $dollar, $dollar
- end_function
-
mid$dollar:
.globl mid$dollar
.functype mid$dollar () -> ()
@@ -28,7 +22,6 @@ mid$dollar:
# CHECK: .export_name foo, bar
# CHECK: .export_name square, "[square]"
-# CHECK: .export_name $dollar, $dollar
# CHECK: .export_name mid$dollar, mid$dollar
# CHECK-OBJ: - Type: EXPORT
@@ -52,11 +45,6 @@ mid$dollar:
# CHECK-OBJ-NEXT: Function: 1
# CHECK-OBJ-NEXT: - Index: 2
# CHECK-OBJ-NEXT: Kind: FUNCTION
-# CHECK-OBJ-NEXT: Name: '$dollar'
-# CHECK-OBJ-NEXT: Flags: [ EXPORTED ]
-# CHECK-OBJ-NEXT: Function: 2
-# CHECK-OBJ-NEXT: - Index: 3
-# CHECK-OBJ-NEXT: Kind: FUNCTION
# CHECK-OBJ-NEXT: Name: 'mid$dollar'
# CHECK-OBJ-NEXT: Flags: [ EXPORTED ]
-# CHECK-OBJ-NEXT: Function: 3
+# CHECK-OBJ-NEXT: Function: 2
diff --git a/llvm/test/MC/WebAssembly/import-module.s b/llvm/test/MC/WebAssembly/import-module.s
index 110496fdb399e..f540c393cd118 100644
--- a/llvm/test/MC/WebAssembly/import-module.s
+++ b/llvm/test/MC/WebAssembly/import-module.s
@@ -22,9 +22,6 @@ test:
.import_module __wasm_component_model_builtin_context_get_0, "$root"
.import_name __wasm_component_model_builtin_context_get_0, "[context-get-0]"
- .import_module __wasm_component_model_builtin_context_get_1, $root
- .import_name __wasm_component_model_builtin_context_get_1, "[context-get-1]"
-
# CHECK-ASM: .import_module foo, bar
# CHECK-ASM: .import_name foo, qux
@@ -43,11 +40,6 @@ test:
# CHECK-NEXT: Kind: FUNCTION
# CHECK-NEXT: SigIndex: 1
-# CHECK: - Module: '$root'
-# CHECK-NEXT: Field: '[context-get-1]'
-# CHECK-NEXT: Kind: FUNCTION
-# CHECK-NEXT: SigIndex: 1
-
# CHECK: - Type: CUSTOM
# CHECK: Name: foo
# CHECK-NEXT: Flags: [ UNDEFINED, EXPLICIT_NAME ]
@@ -57,6 +49,3 @@ test:
# CHECK: Name: __wasm_component_model_builtin_context_get_0
# CHECK-NEXT: Flags: [ UNDEFINED, EXPLICIT_NAME ]
-
-# CHECK: Name: __wasm_component_model_builtin_context_get_1
-# CHECK-NEXT: Flags: [ UNDEFINED, EXPLICIT_NAME ]
\ No newline at end of file
>From aaf39fff960b31f17cc356931797e51a64b1b24a Mon Sep 17 00:00:00 2001
From: Sy Brand <sy.brand at fastly.com>
Date: Thu, 26 Feb 2026 08:28:28 +0000
Subject: [PATCH 08/12] Remove more changes
---
llvm/test/MC/WebAssembly/export-name.s | 12 ------------
1 file changed, 12 deletions(-)
diff --git a/llvm/test/MC/WebAssembly/export-name.s b/llvm/test/MC/WebAssembly/export-name.s
index 92be384ecf9ec..eb215b68d0be6 100644
--- a/llvm/test/MC/WebAssembly/export-name.s
+++ b/llvm/test/MC/WebAssembly/export-name.s
@@ -14,15 +14,8 @@ square:
.export_name square, "[square]"
end_function
-mid$dollar:
- .globl mid$dollar
- .functype mid$dollar () -> ()
- .export_name mid$dollar, mid$dollar
- end_function
-
# CHECK: .export_name foo, bar
# CHECK: .export_name square, "[square]"
-# CHECK: .export_name mid$dollar, mid$dollar
# CHECK-OBJ: - Type: EXPORT
# CHECK-OBJ-NEXT: Exports:
@@ -43,8 +36,3 @@ mid$dollar:
# CHECK-OBJ-NEXT: Name: square
# CHECK-OBJ-NEXT: Flags: [ EXPORTED ]
# CHECK-OBJ-NEXT: Function: 1
-# CHECK-OBJ-NEXT: - Index: 2
-# CHECK-OBJ-NEXT: Kind: FUNCTION
-# CHECK-OBJ-NEXT: Name: 'mid$dollar'
-# CHECK-OBJ-NEXT: Flags: [ EXPORTED ]
-# CHECK-OBJ-NEXT: Function: 2
>From a7bc50237483dfca836f23a0652f3e726513f2e0 Mon Sep 17 00:00:00 2001
From: Sy Brand <sy.brand at fastly.com>
Date: Thu, 26 Feb 2026 08:43:02 +0000
Subject: [PATCH 09/12] More testing
---
.../WebAssemblyTargetStreamer.cpp | 14 +++++---
llvm/test/MC/WebAssembly/export-name.s | 24 +++++++++++++
llvm/test/MC/WebAssembly/import-module.s | 34 ++++++++++++++++---
3 files changed, 64 insertions(+), 8 deletions(-)
diff --git a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.cpp b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.cpp
index 5db51bad8c70c..29158b67820e3 100644
--- a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.cpp
+++ b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.cpp
@@ -25,10 +25,16 @@ using namespace llvm;
static bool shouldQuoteName(StringRef Name) {
// Wasm export/import names and import module names can contain characters
// that are not allowed in identifiers, so we need to quote them.
- auto isValidStartChar = [](char C) { return isalpha(C) || C == '_' || C == '.'; };
- auto isValidChar = [&](char C) { return isValidStartChar(C) || isdigit(C) || C == '$'; };
- return !(Name.size() > 0 && isValidStartChar(Name.front())) ||
- llvm::any_of(Name, [&](char C) { return !isValidChar(C); });
+ // This logic is based on the expectations of MC/MCParser/AsmLexer as
+ // configured for WebAssembly.
+ auto isValidStartChar = [](char C) {
+ return isalpha(C) || C == '_' || C == '.';
+ };
+ auto isValidChar = [&](char C) {
+ return isValidStartChar(C) || isdigit(C) || C == '$' || C == '?';
+ };
+ return !(Name.size() > 0 && isValidStartChar(Name.front())) ||
+ llvm::any_of(Name, [&](char C) { return !isValidChar(C); });
}
WebAssemblyTargetStreamer::WebAssemblyTargetStreamer(MCStreamer &S)
diff --git a/llvm/test/MC/WebAssembly/export-name.s b/llvm/test/MC/WebAssembly/export-name.s
index eb215b68d0be6..d9d3818161f06 100644
--- a/llvm/test/MC/WebAssembly/export-name.s
+++ b/llvm/test/MC/WebAssembly/export-name.s
@@ -14,8 +14,22 @@ square:
.export_name square, "[square]"
end_function
+mid$dollar:
+ .globl mid$dollar
+ .functype mid$dollar () -> ()
+ .export_name mid$dollar, mid$dollar
+ end_function
+
+mid?question:
+ .globl mid?question
+ .functype mid?question () -> ()
+ .export_name mid?question, mid?question
+ end_function
+
# CHECK: .export_name foo, bar
# CHECK: .export_name square, "[square]"
+# CHECK: .export_name mid$dollar, mid$dollar
+# CHECK: .export_name mid?question, mid?question
# CHECK-OBJ: - Type: EXPORT
# CHECK-OBJ-NEXT: Exports:
@@ -36,3 +50,13 @@ square:
# CHECK-OBJ-NEXT: Name: square
# CHECK-OBJ-NEXT: Flags: [ EXPORTED ]
# CHECK-OBJ-NEXT: Function: 1
+# CHECK-OBJ-NEXT: - Index: 2
+# CHECK-OBJ-NEXT: Kind: FUNCTION
+# CHECK-OBJ-NEXT: Name: 'mid$dollar'
+# CHECK-OBJ-NEXT: Flags: [ EXPORTED ]
+# CHECK-OBJ-NEXT: Function: 2
+# CHECK-OBJ-NEXT: - Index: 3
+# CHECK-OBJ-NEXT: Kind: FUNCTION
+# CHECK-OBJ-NEXT: Name: 'mid?question'
+# CHECK-OBJ-NEXT: Flags: [ EXPORTED ]
+# CHECK-OBJ-NEXT: Function: 3
diff --git a/llvm/test/MC/WebAssembly/import-module.s b/llvm/test/MC/WebAssembly/import-module.s
index f540c393cd118..7051d72186f5a 100644
--- a/llvm/test/MC/WebAssembly/import-module.s
+++ b/llvm/test/MC/WebAssembly/import-module.s
@@ -4,7 +4,8 @@
.functype foo () -> ()
.functype plain () -> ()
.functype __wasm_component_model_builtin_context_get_0 () -> (i32)
-.functype __wasm_component_model_builtin_context_get_1 () -> (i32)
+.functype mid$dollar () -> ()
+.functype mid?question () -> ()
test:
.functype test () -> ()
@@ -12,8 +13,8 @@ test:
call plain
call __wasm_component_model_builtin_context_get_0
drop
- call __wasm_component_model_builtin_context_get_1
- drop
+ call mid$dollar
+ call mid?question
end_function
.import_module foo, bar
@@ -22,8 +23,20 @@ test:
.import_module __wasm_component_model_builtin_context_get_0, "$root"
.import_name __wasm_component_model_builtin_context_get_0, "[context-get-0]"
+ .import_module mid$dollar, another$mid$dollar
+ .import_name mid$dollar, mid$dollar
+
+ .import_module mid?question, another?mid?question
+ .import_name mid?question, mid?question
+
# CHECK-ASM: .import_module foo, bar
# CHECK-ASM: .import_name foo, qux
+# CHECK-ASM: .import_module __wasm_component_model_builtin_context_get_0, "$root"
+# CHECK-ASM: .import_name __wasm_component_model_builtin_context_get_0, "[context-get-0]"
+# CHECK-ASM: .import_module mid$dollar, another$mid$dollar
+# CHECK-ASM: .import_name mid$dollar, mid$dollar
+# CHECK-ASM: .import_module mid?question, another?mid?question
+# CHECK-ASM: .import_name mid?question, mid?question
# CHECK: - Type: IMPORT
# CHECK-NEXT: Imports:
@@ -38,7 +51,14 @@ test:
# CHECK: - Module: '$root'
# CHECK-NEXT: Field: '[context-get-0]'
# CHECK-NEXT: Kind: FUNCTION
-# CHECK-NEXT: SigIndex: 1
+
+# CHECK: - Module: 'another$mid$dollar'
+# CHECK-NEXT: Field: 'mid$dollar'
+# CHECK-NEXT: Kind: FUNCTION
+
+# CHECK: - Module: 'another?mid?question'
+# CHECK-NEXT: Field: 'mid?question'
+# CHECK-NEXT: Kind: FUNCTION
# CHECK: - Type: CUSTOM
# CHECK: Name: foo
@@ -49,3 +69,9 @@ test:
# CHECK: Name: __wasm_component_model_builtin_context_get_0
# CHECK-NEXT: Flags: [ UNDEFINED, EXPLICIT_NAME ]
+
+# CHECK: Name: 'mid$dollar'
+# CHECK-NEXT: Flags: [ UNDEFINED, EXPLICIT_NAME ]
+
+# CHECK: Name: 'mid?question'
+# CHECK-NEXT: Flags: [ UNDEFINED, EXPLICIT_NAME ]
>From e790f3d7bc208a4818e2fa9dee7754fe420c777b Mon Sep 17 00:00:00 2001
From: Sy Brand <sy.brand at fastly.com>
Date: Fri, 27 Feb 2026 08:22:53 +0000
Subject: [PATCH 10/12] Simplify changes
---
.../WebAssemblyTargetStreamer.cpp | 35 +++----------------
llvm/test/MC/WebAssembly/export-name.s | 15 ++++++--
llvm/test/MC/WebAssembly/import-module.s | 35 +++++++++----------
3 files changed, 33 insertions(+), 52 deletions(-)
diff --git a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.cpp b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.cpp
index 29158b67820e3..5cff8a9e092cd 100644
--- a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.cpp
+++ b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.cpp
@@ -22,21 +22,6 @@
#include "llvm/Support/FormattedStream.h"
using namespace llvm;
-static bool shouldQuoteName(StringRef Name) {
- // Wasm export/import names and import module names can contain characters
- // that are not allowed in identifiers, so we need to quote them.
- // This logic is based on the expectations of MC/MCParser/AsmLexer as
- // configured for WebAssembly.
- auto isValidStartChar = [](char C) {
- return isalpha(C) || C == '_' || C == '.';
- };
- auto isValidChar = [&](char C) {
- return isValidStartChar(C) || isdigit(C) || C == '$' || C == '?';
- };
- return !(Name.size() > 0 && isValidStartChar(Name.front())) ||
- llvm::any_of(Name, [&](char C) { return !isValidChar(C); });
-}
-
WebAssemblyTargetStreamer::WebAssemblyTargetStreamer(MCStreamer &S)
: MCTargetStreamer(S) {}
@@ -109,32 +94,20 @@ void WebAssemblyTargetAsmStreamer::emitTagType(const MCSymbolWasm *Sym) {
OS << "\n";
}
-static void emitNameWithQuoting(formatted_raw_ostream &OS, StringRef Name) {
- if (shouldQuoteName(Name))
- OS << '"' << Name << '"';
- else
- OS << Name;
-}
-
void WebAssemblyTargetAsmStreamer::emitImportModule(const MCSymbolWasm *Sym,
StringRef ImportModule) {
- OS << "\t.import_module\t" << Sym->getName() << ", ";
- emitNameWithQuoting(OS, ImportModule);
- OS << '\n';
+ OS << "\t.import_module\t" << Sym->getName() << ", \"" << ImportModule
+ << "\"\n";
}
void WebAssemblyTargetAsmStreamer::emitImportName(const MCSymbolWasm *Sym,
StringRef ImportName) {
- OS << "\t.import_name\t" << Sym->getName() << ", ";
- emitNameWithQuoting(OS, ImportName);
- OS << '\n';
+ OS << "\t.import_name\t" << Sym->getName() << ", \"" << ImportName << "\"\n";
}
void WebAssemblyTargetAsmStreamer::emitExportName(const MCSymbolWasm *Sym,
StringRef ExportName) {
- OS << "\t.export_name\t" << Sym->getName() << ", ";
- emitNameWithQuoting(OS, ExportName);
- OS << '\n';
+ OS << "\t.export_name\t" << Sym->getName() << ", \"" << ExportName << "\"\n";
}
void WebAssemblyTargetAsmStreamer::emitIndIdx(const MCExpr *Value) {
diff --git a/llvm/test/MC/WebAssembly/export-name.s b/llvm/test/MC/WebAssembly/export-name.s
index d9d3818161f06..29dee04c59f87 100644
--- a/llvm/test/MC/WebAssembly/export-name.s
+++ b/llvm/test/MC/WebAssembly/export-name.s
@@ -26,16 +26,25 @@ mid?question:
.export_name mid?question, mid?question
end_function
-# CHECK: .export_name foo, bar
+# CHECK: .export_name foo, "bar"
# CHECK: .export_name square, "[square]"
-# CHECK: .export_name mid$dollar, mid$dollar
-# CHECK: .export_name mid?question, mid?question
+# CHECK: .export_name mid$dollar, "mid$dollar"
+# CHECK: .export_name mid?question, "mid?question"
# CHECK-OBJ: - Type: EXPORT
# CHECK-OBJ-NEXT: Exports:
# CHECK-OBJ-NEXT: - Name: bar
# CHECK-OBJ-NEXT: Kind: FUNCTION
# CHECK-OBJ-NEXT: Index: 0
+# CHECK-OBJ-NEXT: - Name: '[square]'
+# CHECK-OBJ-NEXT: Kind: FUNCTION
+# CHECK-OBJ-NEXT: Index: 1
+# CHECK-OBJ-NEXT: - Name: 'mid$dollar'
+# CHECK-OBJ-NEXT: Kind: FUNCTION
+# CHECK-OBJ-NEXT: Index: 2
+# CHECK-OBJ-NEXT: - Name: 'mid?question'
+# CHECK-OBJ-NEXT: Kind: FUNCTION
+# CHECK-OBJ-NEXT: Index: 3
# CHECK-OBJ: Name: linking
# CHECK-OBJ-NEXT: Version: 2
diff --git a/llvm/test/MC/WebAssembly/import-module.s b/llvm/test/MC/WebAssembly/import-module.s
index 7051d72186f5a..fb07ed5c2baf0 100644
--- a/llvm/test/MC/WebAssembly/import-module.s
+++ b/llvm/test/MC/WebAssembly/import-module.s
@@ -3,7 +3,7 @@
.functype foo () -> ()
.functype plain () -> ()
-.functype __wasm_component_model_builtin_context_get_0 () -> (i32)
+.functype utf8_import() -> ()
.functype mid$dollar () -> ()
.functype mid?question () -> ()
@@ -11,17 +11,16 @@ test:
.functype test () -> ()
call foo
call plain
- call __wasm_component_model_builtin_context_get_0
- drop
- call mid$dollar
- call mid?question
+ call utf8_import
+ call mid$dollar
+ call mid?question
end_function
.import_module foo, bar
.import_name foo, qux
- .import_module __wasm_component_model_builtin_context_get_0, "$root"
- .import_name __wasm_component_model_builtin_context_get_0, "[context-get-0]"
+ .import_module utf8_import, "$café-Straßburg"
+ .import_name utf8_import, "[café-Straßburg]"
.import_module mid$dollar, another$mid$dollar
.import_name mid$dollar, mid$dollar
@@ -29,14 +28,14 @@ test:
.import_module mid?question, another?mid?question
.import_name mid?question, mid?question
-# CHECK-ASM: .import_module foo, bar
-# CHECK-ASM: .import_name foo, qux
-# CHECK-ASM: .import_module __wasm_component_model_builtin_context_get_0, "$root"
-# CHECK-ASM: .import_name __wasm_component_model_builtin_context_get_0, "[context-get-0]"
-# CHECK-ASM: .import_module mid$dollar, another$mid$dollar
-# CHECK-ASM: .import_name mid$dollar, mid$dollar
-# CHECK-ASM: .import_module mid?question, another?mid?question
-# CHECK-ASM: .import_name mid?question, mid?question
+# CHECK-ASM: .import_module foo, "bar"
+# CHECK-ASM: .import_name foo, "qux"
+# CHECK-ASM: .import_module utf8_import, "$café-Straßburg"
+# CHECK-ASM: .import_name utf8_import, "[café-Straßburg]"
+# CHECK-ASM: .import_module mid$dollar, "another$mid$dollar"
+# CHECK-ASM: .import_name mid$dollar, "mid$dollar"
+# CHECK-ASM: .import_module mid?question, "another?mid?question"
+# CHECK-ASM: .import_name mid?question, "mid?question"
# CHECK: - Type: IMPORT
# CHECK-NEXT: Imports:
@@ -48,8 +47,8 @@ test:
# CHECK-NEXT: Field: plain
# CHECK-NEXT: Kind: FUNCTION
-# CHECK: - Module: '$root'
-# CHECK-NEXT: Field: '[context-get-0]'
+# CHECK: - Module: "$café-Straßburg"
+# CHECK-NEXT: Field: "[café-Straßburg]"
# CHECK-NEXT: Kind: FUNCTION
# CHECK: - Module: 'another$mid$dollar'
@@ -67,7 +66,7 @@ test:
# CHECK: Name: plain
# CHECK-NEXT: Flags: [ UNDEFINED ]
-# CHECK: Name: __wasm_component_model_builtin_context_get_0
+# CHECK: Name: utf8_import
# CHECK-NEXT: Flags: [ UNDEFINED, EXPLICIT_NAME ]
# CHECK: Name: 'mid$dollar'
>From 9c226e0e0a469e0c991dc94277014251a6e54c6a Mon Sep 17 00:00:00 2001
From: Sy Brand <sy.brand at fastly.com>
Date: Fri, 27 Feb 2026 08:51:55 +0000
Subject: [PATCH 11/12] Fix tests
---
llvm/test/CodeGen/WebAssembly/export-name.ll | 4 ++--
llvm/test/CodeGen/WebAssembly/import-module.ll | 4 ++--
llvm/test/CodeGen/WebAssembly/lower-em-ehsjlj-options.ll | 8 ++++----
3 files changed, 8 insertions(+), 8 deletions(-)
diff --git a/llvm/test/CodeGen/WebAssembly/export-name.ll b/llvm/test/CodeGen/WebAssembly/export-name.ll
index 9941520f21918..815f6d3b4ed1e 100644
--- a/llvm/test/CodeGen/WebAssembly/export-name.ll
+++ b/llvm/test/CodeGen/WebAssembly/export-name.ll
@@ -12,5 +12,5 @@ declare void @test2() #1
attributes #0 = { "wasm-export-name"="foo" }
attributes #1 = { "wasm-export-name"="bar" }
-; CHECK: .export_name test, foo
-; CHECK: .export_name test2, bar
+; CHECK: .export_name test, "foo"
+; CHECK: .export_name test2, "bar"
diff --git a/llvm/test/CodeGen/WebAssembly/import-module.ll b/llvm/test/CodeGen/WebAssembly/import-module.ll
index 1d423fbf5426d..101459f47d482 100644
--- a/llvm/test/CodeGen/WebAssembly/import-module.ll
+++ b/llvm/test/CodeGen/WebAssembly/import-module.ll
@@ -14,6 +14,6 @@ declare void @plain()
attributes #0 = { "wasm-import-module"="bar" "wasm-import-name"="qux" }
; CHECK-NOT: .import_module plain
-; CHECK: .import_module foo, bar
-; CHECK: .import_name foo, qux
+; CHECK: .import_module foo, "bar"
+; CHECK: .import_name foo, "qux"
; CHECK-NOT: .import_module plain
diff --git a/llvm/test/CodeGen/WebAssembly/lower-em-ehsjlj-options.ll b/llvm/test/CodeGen/WebAssembly/lower-em-ehsjlj-options.ll
index 2c4d52937d944..d33b27ef7f327 100644
--- a/llvm/test/CodeGen/WebAssembly/lower-em-ehsjlj-options.ll
+++ b/llvm/test/CodeGen/WebAssembly/lower-em-ehsjlj-options.ll
@@ -5,11 +5,11 @@
target triple = "wasm32-unknown-unknown"
; EH: .functype invoke_vi (i32, i32) -> ()
-; EH: .import_module invoke_vi, env
-; EH: .import_name invoke_vi, invoke_vi
+; EH: .import_module invoke_vi, "env"
+; EH: .import_name invoke_vi, "invoke_vi"
; EH-NOT: .functype __invoke_void_i32
-; EH-NOT: .import_module __invoke_void_i32
-; EH-NOT: .import_name __invoke_void_i32
+; EH-NOT: .import_module "__invoke_void_i32"
+; EH-NOT: .import_name "__invoke_void_i32"
; SJLJ: .functype emscripten_longjmp (i32, i32) -> ()
; SJLJ-NOT: .functype emscripten_longjmp_jmpbuf
>From 704dffcaf7166192e75044d7892c5f32e1359e51 Mon Sep 17 00:00:00 2001
From: Sy Brand <sy.brand at fastly.com>
Date: Fri, 27 Feb 2026 19:03:52 +0000
Subject: [PATCH 12/12] Change import names for import-module test
---
llvm/test/MC/WebAssembly/import-module.s | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/llvm/test/MC/WebAssembly/import-module.s b/llvm/test/MC/WebAssembly/import-module.s
index fb07ed5c2baf0..7ac29980aaeb5 100644
--- a/llvm/test/MC/WebAssembly/import-module.s
+++ b/llvm/test/MC/WebAssembly/import-module.s
@@ -23,19 +23,19 @@ test:
.import_name utf8_import, "[café-Straßburg]"
.import_module mid$dollar, another$mid$dollar
- .import_name mid$dollar, mid$dollar
+ .import_name mid$dollar, mid$dollar$name
.import_module mid?question, another?mid?question
- .import_name mid?question, mid?question
+ .import_name mid?question, mid?question?name
# CHECK-ASM: .import_module foo, "bar"
# CHECK-ASM: .import_name foo, "qux"
# CHECK-ASM: .import_module utf8_import, "$café-Straßburg"
# CHECK-ASM: .import_name utf8_import, "[café-Straßburg]"
# CHECK-ASM: .import_module mid$dollar, "another$mid$dollar"
-# CHECK-ASM: .import_name mid$dollar, "mid$dollar"
+# CHECK-ASM: .import_name mid$dollar, "mid$dollar$name"
# CHECK-ASM: .import_module mid?question, "another?mid?question"
-# CHECK-ASM: .import_name mid?question, "mid?question"
+# CHECK-ASM: .import_name mid?question, "mid?question?name"
# CHECK: - Type: IMPORT
# CHECK-NEXT: Imports:
@@ -52,11 +52,11 @@ test:
# CHECK-NEXT: Kind: FUNCTION
# CHECK: - Module: 'another$mid$dollar'
-# CHECK-NEXT: Field: 'mid$dollar'
+# CHECK-NEXT: Field: 'mid$dollar$name'
# CHECK-NEXT: Kind: FUNCTION
# CHECK: - Module: 'another?mid?question'
-# CHECK-NEXT: Field: 'mid?question'
+# CHECK-NEXT: Field: 'mid?question?name'
# CHECK-NEXT: Kind: FUNCTION
# CHECK: - Type: CUSTOM
More information about the llvm-commits
mailing list