[clang] [llvm] [clang][WebAssembly] support custom module name of import globals (PR #200722)
Changqing Jing via cfe-commits
cfe-commits at lists.llvm.org
Mon Jun 1 18:59:23 PDT 2026
https://github.com/Changqing-JING updated https://github.com/llvm/llvm-project/pull/200722
>From d21d4c1cb0766c4d451169f3c8c10ebc7647296f Mon Sep 17 00:00:00 2001
From: Changqing Jing <changqing.jing at bmw.com>
Date: Tue, 2 Jun 2026 09:59:07 +0800
Subject: [PATCH] [clang][WebAssembly] support custom module name of import
globals
---
clang/lib/CodeGen/Targets/WebAssembly.cpp | 45 +++++++++++++++++++
.../WebAssembly/wasm-global-import-module.cpp | 19 ++++++++
llvm/include/llvm/MC/MCSymbolWasm.h | 4 --
.../WebAssembly/WebAssemblyAsmPrinter.cpp | 22 ++++++++-
.../import-module-global-metadata.ll | 24 ++++++++++
5 files changed, 109 insertions(+), 5 deletions(-)
create mode 100644 clang/test/CodeGen/WebAssembly/wasm-global-import-module.cpp
create mode 100644 llvm/test/CodeGen/WebAssembly/import-module-global-metadata.ll
diff --git a/clang/lib/CodeGen/Targets/WebAssembly.cpp b/clang/lib/CodeGen/Targets/WebAssembly.cpp
index ebe996a4edd8d..6ba23eff096c1 100644
--- a/clang/lib/CodeGen/Targets/WebAssembly.cpp
+++ b/clang/lib/CodeGen/Targets/WebAssembly.cpp
@@ -8,10 +8,49 @@
#include "ABIInfoImpl.h"
#include "TargetInfo.h"
+#include "clang/AST/Expr.h"
+#include "clang/Basic/DiagnosticFrontend.h"
using namespace clang;
using namespace clang::CodeGen;
+namespace {
+
+void warnInvalidWebAssemblyImportModuleAnnotation(const AnnotateAttr *AA,
+ CodeGenModule &CGM) {
+ CGM.getDiags().Report(AA->getLocation(), diag::warn_fe_backend_unsupported)
+ << "ignoring 'annotate(\"wasm-import-module\", ...)' because it "
+ "requires exactly one string literal argument";
+}
+
+void maybeSetWebAssemblyImportModuleMetadata(const VarDecl *VD,
+ llvm::GlobalVariable *GV,
+ CodeGen::CodeGenModule &CGM) {
+ for (const auto *AA : VD->specific_attrs<AnnotateAttr>()) {
+ if (AA->getAnnotation() != "wasm-import-module")
+ continue;
+
+ if (AA->args_size() != 1) {
+ warnInvalidWebAssemblyImportModuleAnnotation(AA, CGM);
+ continue;
+ }
+
+ const auto *Module = dyn_cast<StringLiteral>(
+ (*AA->args_begin())->IgnoreUnlessSpelledInSource());
+ if (!Module) {
+ warnInvalidWebAssemblyImportModuleAnnotation(AA, CGM);
+ continue;
+ }
+
+ llvm::LLVMContext &Ctx = CGM.getLLVMContext();
+ GV->setMetadata(
+ "wasm.import.module",
+ llvm::MDNode::get(Ctx, llvm::MDString::get(Ctx, Module->getString())));
+ }
+}
+
+} // namespace
+
//===----------------------------------------------------------------------===//
// WebAssembly ABI Implementation
//
@@ -57,6 +96,12 @@ class WebAssemblyTargetCodeGenInfo final : public TargetCodeGenInfo {
void setTargetAttributes(const Decl *D, llvm::GlobalValue *GV,
CodeGen::CodeGenModule &CGM) const override {
TargetCodeGenInfo::setTargetAttributes(D, GV, CGM);
+ if (const auto *VD = dyn_cast_or_null<VarDecl>(D)) {
+ if (auto *Global = dyn_cast<llvm::GlobalVariable>(GV))
+ maybeSetWebAssemblyImportModuleMetadata(VD, Global, CGM);
+ return;
+ }
+
if (const auto *FD = dyn_cast_or_null<FunctionDecl>(D)) {
if (const auto *Attr = FD->getAttr<WebAssemblyImportModuleAttr>()) {
llvm::Function *Fn = cast<llvm::Function>(GV);
diff --git a/clang/test/CodeGen/WebAssembly/wasm-global-import-module.cpp b/clang/test/CodeGen/WebAssembly/wasm-global-import-module.cpp
new file mode 100644
index 0000000000000..62fe13af9e27a
--- /dev/null
+++ b/clang/test/CodeGen/WebAssembly/wasm-global-import-module.cpp
@@ -0,0 +1,19 @@
+// RUN: %clang_cc1 -triple wasm32-unknown-unknown-wasm -emit-llvm -verify -o - %s | FileCheck %s
+
+extern "C" {
+extern const int [[clang::address_space(1)]] imported_g
+ __attribute__((annotate("wasm-import-module", "js")));
+extern const int [[clang::address_space(1)]] bad_arity
+ __attribute__((annotate("wasm-import-module"))); // expected-warning {{ignoring 'annotate("wasm-import-module", ...)' because it requires exactly one string literal argument}}
+extern const int [[clang::address_space(1)]] bad_type
+ __attribute__((annotate("wasm-import-module", 42))); // expected-warning {{ignoring 'annotate("wasm-import-module", ...)' because it requires exactly one string literal argument}}
+extern const int [[clang::address_space(1)]] default_g;
+
+int get() { return imported_g + bad_arity + bad_type + default_g; }
+}
+
+// CHECK: @imported_g = external addrspace(1) constant i32, align 4, !wasm.import.module ![[MD:[0-9]+]]
+// CHECK: @bad_arity = external addrspace(1) constant i32, align 4
+// CHECK: @bad_type = external addrspace(1) constant i32, align 4
+// CHECK: @default_g = external addrspace(1) constant i32, align 4
+// CHECK: ![[MD]] = !{!"js"}
\ No newline at end of file
diff --git a/llvm/include/llvm/MC/MCSymbolWasm.h b/llvm/include/llvm/MC/MCSymbolWasm.h
index 5c9f14e5e6d64..9173aa4bc7a60 100644
--- a/llvm/include/llvm/MC/MCSymbolWasm.h
+++ b/llvm/include/llvm/MC/MCSymbolWasm.h
@@ -92,10 +92,6 @@ class MCSymbolWasm : public MCSymbol {
StringRef getImportModule() const {
if (ImportModule)
return *ImportModule;
- // Use a default module name of "env" for now, for compatibility with
- // existing tools.
- // TODO(sbc): Find a way to specify a default value in the object format
- // without picking a hardcoded value like this.
return "env";
}
void setImportModule(StringRef Name) { ImportModule = Name; }
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp
index edea99e629407..7d216531e49f3 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp
@@ -55,6 +55,18 @@ using namespace llvm;
#define DEBUG_TYPE "asm-printer"
+static StringRef getWasmImportModuleMetadata(const GlobalVariable &GV) {
+ MDNode *MD = GV.getMetadata("wasm.import.module");
+ if (!MD || MD->getNumOperands() == 0)
+ return {};
+
+ auto *Name = dyn_cast<MDString>(MD->getOperand(0));
+ if (!Name)
+ return {};
+
+ return Name->getString();
+}
+
extern cl::opt<bool> WasmKeepRegisters;
//===----------------------------------------------------------------------===//
@@ -211,6 +223,14 @@ void WebAssemblyAsmPrinter::emitGlobalVariable(const GlobalVariable *GV) {
emitVisibility(Sym, GV->getVisibility(), !GV->isDeclaration());
emitSymbolType(Sym);
+ if (GV->isDeclaration()) {
+ StringRef ImportModule = getWasmImportModuleMetadata(*GV);
+ if (!ImportModule.empty()) {
+ Sym->setImportModule(OutContext.allocateString(ImportModule));
+ getTargetStreamer()->emitImportModule(Sym, ImportModule);
+ }
+ }
+
if (GV->hasInitializer()) {
assert(getSymbolPreferLocal(*GV) == Sym);
emitLinkage(GV, Sym);
@@ -477,7 +497,7 @@ void WebAssemblyAsmPrinter::EmitProducerInfo(Module &M) {
OutStreamer->switchSection(Producers);
OutStreamer->emitULEB128IntValue(FieldCount);
for (auto &Producers : {std::make_pair("language", &Languages),
- std::make_pair("processed-by", &Tools)}) {
+ std::make_pair("processed-by", &Tools)}) {
if (Producers.second->empty())
continue;
OutStreamer->emitULEB128IntValue(strlen(Producers.first));
diff --git a/llvm/test/CodeGen/WebAssembly/import-module-global-metadata.ll b/llvm/test/CodeGen/WebAssembly/import-module-global-metadata.ll
new file mode 100644
index 0000000000000..35691585a7960
--- /dev/null
+++ b/llvm/test/CodeGen/WebAssembly/import-module-global-metadata.ll
@@ -0,0 +1,24 @@
+; RUN: llc < %s -asm-verbose=false | FileCheck --check-prefix=ASM %s
+; RUN: llc < %s --filetype=obj | obj2yaml | FileCheck --check-prefix=OBJ %s
+
+target triple = "wasm32-unknown-unknown"
+
+ at imported_g = external addrspace(1) global i32, !wasm.import.module !0
+
+define i32 @get() {
+ %v = load i32, ptr addrspace(1) @imported_g
+ ret i32 %v
+}
+
+; ASM: .globaltype imported_g, i32
+; ASM-NEXT: .import_module imported_g, "js"
+
+; OBJ: - Type: IMPORT
+; OBJ: Imports:
+; OBJ: - Module: js
+; OBJ-NEXT: Field: imported_g
+; OBJ-NEXT: Kind: GLOBAL
+; OBJ-NEXT: GlobalType: I32
+; OBJ-NEXT: GlobalMutable: true
+
+!0 = !{!"js"}
\ No newline at end of file
More information about the cfe-commits
mailing list