From 2bcf69a2f60d2a2a17d99390222e11882f9493b0 Mon Sep 17 00:00:00 2001 From: serge-sans-paille Date: Wed, 9 Apr 2025 07:43:08 +0200 Subject: [PATCH] Partial support for common linkage for WebAssembly Emulate common linkage through weak linkage, the only difference between the two being mostly similar according to langref, with the notable exception that common linkage implies zero initializer. This is needed for fortran-to-web-assembly projects used in the python community, esp. https://github.com/emscripten-forge/recipes/tree/main/recipes/recipes_emscripten/libflang --- llvm/lib/MC/MCWasmStreamer.cpp | 25 ++++++++++- llvm/test/MC/WebAssembly/common.ll | 69 ++++++++++++++++++++++++++++++ 2 files changed, 93 insertions(+), 1 deletion(-) create mode 100644 llvm/test/MC/WebAssembly/common.ll diff --git a/llvm/lib/MC/MCWasmStreamer.cpp b/llvm/lib/MC/MCWasmStreamer.cpp index e3ef1117b4125..559552d71bfe2 100644 --- a/llvm/lib/MC/MCWasmStreamer.cpp +++ b/llvm/lib/MC/MCWasmStreamer.cpp @@ -14,6 +14,7 @@ #include "llvm/MC/MCAsmBackend.h" #include "llvm/MC/MCAssembler.h" #include "llvm/MC/MCCodeEmitter.h" +#include "llvm/MC/MCContext.h" #include "llvm/MC/MCExpr.h" #include "llvm/MC/MCFixup.h" #include "llvm/MC/MCObjectStreamer.h" @@ -131,7 +132,29 @@ bool MCWasmStreamer::emitSymbolAttribute(MCSymbol *S, MCSymbolAttr Attribute) { void MCWasmStreamer::emitCommonSymbol(MCSymbol *S, uint64_t Size, Align ByteAlignment) { - llvm_unreachable("Common symbols are not yet implemented for Wasm"); + auto *Symbol = cast(S); + + pushSection(); + + // Common symbols are very close to weak symbols, so manually build a weak + // symbol. + MCSectionWasm *SW = getContext().getWasmSection(".bss.common." + S->getName(), + SectionKind::getData()); + SW->setAlignment(ByteAlignment); + getAssembler().registerSection(*SW); + + switchSection(SW); + + MCFragment *F = getCurrentFragment(); + F->appendContents(Size, '\0'); + Symbol->setFragment(F); + + Symbol->setSize(MCConstantExpr::create(Size, getContext(), false, 8)); + Symbol->setWeak(true); + Symbol->setExternal(true); + getAssembler().registerSymbol(*Symbol); + + popSection(); } void MCWasmStreamer::emitELFSize(MCSymbol *Symbol, const MCExpr *Value) { diff --git a/llvm/test/MC/WebAssembly/common.ll b/llvm/test/MC/WebAssembly/common.ll new file mode 100644 index 0000000000000..50e7298684ccb --- /dev/null +++ b/llvm/test/MC/WebAssembly/common.ll @@ -0,0 +1,69 @@ +; RUN; llc -mcpu=mvp -filetype=obj %s -o - | obj2yaml | FileCheck %s +; RUN; llc -mcpu=mvp -filetype=asm %s -asm-verbose=false -o - | FileCheck --check-prefix=ASM %s +; RUN: llc -mcpu=mvp -filetype=asm %s -o - | llvm-mc -triple=wasm32 -filetype=obj -o - | obj2yaml | FileCheck %s + +target triple = "wasm32-unknown-unknown" +;target triple = "x86_64-redhat-linux-gnu" +@b = common dso_local global [10 x i32] zeroinitializer, align 4 +@c = common dso_local global [20 x i32] zeroinitializer, align 32 + +; CHECK-ASM: .file "common.ll" +; CHECK-ASM: .type b,@object +; CHECK-ASM: .comm b,40,2 +; CHECK-ASM: .type c,@object +; CHECK-ASM: .comm c,80,5 + + +; CHECK: --- !WASM +; CHECK-NEXT: FileHeader: +; CHECK-NEXT: Version: 0x1 +; CHECK-NEXT: Sections: +; CHECK-NEXT: - Type: IMPORT +; CHECK-NEXT: Imports: +; CHECK-NEXT: - Module: env +; CHECK-NEXT: Field: __linear_memory +; CHECK-NEXT: Kind: MEMORY +; CHECK-NEXT: Memory: +; CHECK-NEXT: Minimum: 0x1 +; CHECK-NEXT: - Type: DATACOUNT +; CHECK-NEXT: Count: 2 +; CHECK-NEXT: - Type: DATA +; CHECK-NEXT: Segments: +; CHECK-NEXT: - SectionOffset: 6 +; CHECK-NEXT: InitFlags: 0 +; CHECK-NEXT: Offset: +; CHECK-NEXT: Opcode: I32_CONST +; CHECK-NEXT: Value: 0 +; CHECK-NEXT: Content: '00000000000000000000000000000000000000000000000000000000000000000000000000000000' +; CHECK-NEXT: - SectionOffset: 52 +; CHECK-NEXT: InitFlags: 0 +; CHECK-NEXT: Offset: +; CHECK-NEXT: Opcode: I32_CONST +; CHECK-NEXT: Value: 64 +; CHECK-NEXT: Content: '0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000' +; CHECK-NEXT: - Type: CUSTOM +; CHECK-NEXT: Name: linking +; CHECK-NEXT: Version: 2 +; CHECK-NEXT: SymbolTable: +; CHECK-NEXT: - Index: 0 +; CHECK-NEXT: Kind: DATA +; CHECK-NEXT: Name: b +; CHECK-NEXT: Flags: [ BINDING_WEAK ] +; CHECK-NEXT: Segment: 0 +; CHECK-NEXT: Size: 40 +; CHECK-NEXT: - Index: 1 +; CHECK-NEXT: Kind: DATA +; CHECK-NEXT: Name: c +; CHECK-NEXT: Flags: [ BINDING_WEAK ] +; CHECK-NEXT: Segment: 1 +; CHECK-NEXT: Size: 80 +; CHECK-NEXT: SegmentInfo: +; CHECK-NEXT: - Index: 0 +; CHECK-NEXT: Name: .bss.common.b +; CHECK-NEXT: Alignment: 2 +; CHECK-NEXT: Flags: [ ] +; CHECK-NEXT: - Index: 1 +; CHECK-NEXT: Name: .bss.common.c +; CHECK-NEXT: Alignment: 5 +; CHECK-NEXT: Flags: [ ] +; CHECK-NEXT: ...