https://github.com/arsenm updated https://github.com/llvm/llvm-project/pull/224312
>From cd376de7a08cba0fecdb86fd11efbe699efad32e Mon Sep 17 00:00:00 2001 From: Matt Arsenault <[email protected]> Date: Thu, 17 Sep 2026 15:35:54 +0200 Subject: [PATCH] WebAssembly: Respect target-abi module flag Previously this relied on the TargetABI MCOptions field and ignored the IR flag. Co-authored-by: Claude (Claude-Opus-4.8) <[email protected]> --- clang/lib/CodeGen/CodeGenModule.cpp | 2 +- .../WebAssembly/target-abi-module-flag.c | 14 ++++++++ .../WebAssembly/WebAssemblyAsmPrinter.cpp | 5 +-- ...ssemblyCoalesceFeaturesAndStripAtomics.cpp | 3 +- .../WebAssembly/WebAssemblySubtarget.cpp | 7 ++-- .../Target/WebAssembly/WebAssemblySubtarget.h | 10 +++++- .../WebAssembly/WebAssemblyTargetMachine.cpp | 13 ++++---- .../WebAssembly/WebAssemblyTargetMachine.h | 7 ++-- .../WebAssembly/WebAssemblyUtilities.cpp | 6 ++-- .../Target/WebAssembly/WebAssemblyUtilities.h | 12 +++++++ .../WebAssembly/multivalue-module-abi.ll | 32 +++++++++++++++++++ 11 files changed, 88 insertions(+), 23 deletions(-) create mode 100644 clang/test/CodeGen/WebAssembly/target-abi-module-flag.c create mode 100644 llvm/test/CodeGen/WebAssembly/multivalue-module-abi.ll diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index 6fd2c8533eb061..3520e10dcda091 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -1518,7 +1518,7 @@ void CodeGenModule::Release() { // non-empty value. if (StringRef ABIStr = Target.getABI(); !ABIStr.empty() && (T.isARM() || T.isThumb() || T.isRISCV() || - T.isPPC() || T.isLoongArch())) { + T.isPPC() || T.isLoongArch() || T.isWasm())) { getModule().addModuleFlag(llvm::Module::Error, "target-abi", llvm::MDString::get(VMContext, ABIStr)); } diff --git a/clang/test/CodeGen/WebAssembly/target-abi-module-flag.c b/clang/test/CodeGen/WebAssembly/target-abi-module-flag.c new file mode 100644 index 00000000000000..e0de201e7a67a8 --- /dev/null +++ b/clang/test/CodeGen/WebAssembly/target-abi-module-flag.c @@ -0,0 +1,14 @@ +// Check that clang emits the "target-abi" module flag for WebAssembly + +// RUN: %clang_cc1 -triple wasm32-unknown-unknown -target-abi experimental-mv -emit-llvm -o - %s | FileCheck --check-prefix=MULTIVALUE %s +// RUN: %clang_cc1 -triple wasm64-unknown-unknown -target-abi experimental-mv -emit-llvm -o - %s | FileCheck --check-prefix=MULTIVALUE %s +// RUN: %clang_cc1 -triple wasm32-unknown-unknown -target-abi mvp -emit-llvm -o - %s | FileCheck --check-prefix=MVP %s + +// No -target-abi: WebAssembly's default ABI is empty, so no flag is emitted. +// RUN: %clang_cc1 -triple wasm32-unknown-unknown -emit-llvm -o - %s | FileCheck --check-prefix=NONE %s + +// MULTIVALUE: !{i32 1, !"target-abi", !"experimental-mv"} +// MVP: !{i32 1, !"target-abi", !"mvp"} +// NONE-NOT: !"target-abi" + +int x; diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp index 6bb03c614af191..84bab9487f0c8b 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp @@ -225,7 +225,8 @@ void WebAssemblyAsmPrinter::emitGlobalVariable(const GlobalVariable *GV) { // module-wide subtarget to compute legal value types. auto &WasmTM = static_cast<const WebAssemblyTargetMachine &>(TM); const WebAssemblySubtarget *ST = WasmTM.getSubtargetImpl( - WasmTM.getTargetCPU(), WasmTM.getTargetFeatureString()); + WasmTM.getTargetCPU(), WasmTM.getTargetFeatureString(), + WasmTM.getTargetABIName(*GV->getParent())); const WebAssemblyTargetLowering &TLI = *ST->getTargetLowering(); computeLegalValueVTs(TLI, GV->getParent()->getContext(), GV->getDataLayout(), GlobalVT, VTs); @@ -612,7 +613,7 @@ void WebAssemblyAsmPrinter::EmitTargetFeatures(Module &M) { // If we never compiled a single function, Subtarget is null. if (!Subtarget) { Subtarget = static_cast<WebAssemblyTargetMachine &>(TM).getSubtargetImpl( - TM.getTargetCPU(), TM.getTargetFeatureString()); + TM.getTargetCPU(), TM.getTargetFeatureString(), TM.getTargetABIName(M)); } for (const SubtargetFeatureKV &KV : Subtarget->getAllProcessorFeatures()) { EmitFeature(KV.key()); diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyCoalesceFeaturesAndStripAtomics.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyCoalesceFeaturesAndStripAtomics.cpp index 08479e0f27617f..2cdd7d908994b6 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyCoalesceFeaturesAndStripAtomics.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyCoalesceFeaturesAndStripAtomics.cpp @@ -177,7 +177,8 @@ static bool coalesceFeaturesAndStripAtomics(Module &M, // In cooperative threading mode, thread locals are meaningful even without // atomics. const WebAssemblySubtarget *ST = WasmTM->getSubtargetImpl( - WasmTM->getTargetCPU(), WasmTM->getTargetFeatureString()); + WasmTM->getTargetCPU(), WasmTM->getTargetFeatureString(), + WasmTM->getTargetABIName(M)); bool CooperativeThreading = ST->hasCooperativeMultithreading(); if (!Features[WebAssembly::FeatureAtomics]) { diff --git a/llvm/lib/Target/WebAssembly/WebAssemblySubtarget.cpp b/llvm/lib/Target/WebAssembly/WebAssemblySubtarget.cpp index 1f964259fd4cad..ed9473b47e5bd7 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblySubtarget.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblySubtarget.cpp @@ -52,10 +52,11 @@ WebAssemblySubtarget::initializeSubtargetDependencies(StringRef CPU, WebAssemblySubtarget::WebAssemblySubtarget(const Triple &TT, StringRef CPU, StringRef FS, - const TargetMachine &TM) + const TargetMachine &TM, + StringRef ABIName) : WebAssemblyGenSubtargetInfo(TT, CPU, /*TuneCPU*/ CPU, FS), - TargetTriple(TT), InstrInfo(initializeSubtargetDependencies(CPU, FS)), - TLInfo(TM, *this) { + TargetTriple(TT), TargetABI(WebAssembly::getABI(ABIName)), + InstrInfo(initializeSubtargetDependencies(CPU, FS)), TLInfo(TM, *this) { CallLoweringInfo.reset(new WebAssemblyCallLowering(*getTargetLowering())); Legalizer.reset(new WebAssemblyLegalizerInfo(*this)); auto *RBI = new WebAssemblyRegisterBankInfo(*getRegisterInfo()); diff --git a/llvm/lib/Target/WebAssembly/WebAssemblySubtarget.h b/llvm/lib/Target/WebAssembly/WebAssemblySubtarget.h index 149c49dd344731..4b62f56d7bea74 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblySubtarget.h +++ b/llvm/lib/Target/WebAssembly/WebAssemblySubtarget.h @@ -20,6 +20,7 @@ #include "WebAssemblyISelLowering.h" #include "WebAssemblyInstrInfo.h" #include "WebAssemblySelectionDAGInfo.h" +#include "WebAssemblyUtilities.h" #include "llvm/CodeGen/GlobalISel/CallLowering.h" #include "llvm/CodeGen/GlobalISel/InstructionSelector.h" #include "llvm/CodeGen/GlobalISel/LegalizerInfo.h" @@ -63,6 +64,9 @@ class WebAssemblySubtarget final : public WebAssemblyGenSubtargetInfo { /// What processor and OS we're targeting. Triple TargetTriple; + /// The ABI in use. + WebAssembly::WebAssemblyABI TargetABI = WebAssembly::WebAssemblyABI::MVP; + WebAssemblyFrameLowering FrameLowering; WebAssemblyInstrInfo InstrInfo; WebAssemblySelectionDAGInfo TSInfo; @@ -80,7 +84,7 @@ class WebAssemblySubtarget final : public WebAssemblyGenSubtargetInfo { /// This constructor initializes the data members to match that /// of the specified triple. WebAssemblySubtarget(const Triple &TT, StringRef CPU, StringRef FS, - const TargetMachine &TM); + const TargetMachine &TM, StringRef ABIName); const WebAssemblySelectionDAGInfo *getSelectionDAGInfo() const override { return &TSInfo; @@ -130,6 +134,10 @@ class WebAssemblySubtarget final : public WebAssemblyGenSubtargetInfo { bool hasTailCall() const { return HasTailCall; } bool hasWideArithmetic() const { return HasWideArithmetic; } + bool usesMultivalueABI() const { + return TargetABI == WebAssembly::WebAssemblyABI::ExperimentalMV; + } + /// Parses features string setting specified subtarget options. Definition of /// function is auto generated by tblgen. void ParseSubtargetFeatures(StringRef CPU, StringRef TuneCPU, StringRef FS); diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp index 066e8329e7f39d..20fb4cd2b9c3a2 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp @@ -190,8 +190,7 @@ WebAssemblyTargetMachine::WebAssemblyTargetMachine( : CodeGenTargetMachineImpl(T, TT.computeDataLayout(), TT, CPU, FS, Options, getEffectiveRelocModel(RM), getEffectiveCodeModel(CM, CodeModel::Large), OL), - TLOF(new WebAssemblyTargetObjectFile()), - UsesMultivalueABI(Options.MCOptions.getABIName() == "experimental-mv") { + TLOF(new WebAssemblyTargetObjectFile()) { // WebAssembly type-checks instructions, but a noreturn function with a return // type that doesn't match the context will cause a check failure. So we lower // LLVM 'unreachable' to ISD::TRAP and then lower that to WebAssembly's @@ -221,10 +220,12 @@ WebAssemblyTargetMachine::WebAssemblyTargetMachine( WebAssemblyTargetMachine::~WebAssemblyTargetMachine() = default; // anchor. const WebAssemblySubtarget * -WebAssemblyTargetMachine::getSubtargetImpl(StringRef CPU, StringRef FS) const { - auto &I = SubtargetMap[CPU.str() + FS.str()]; +WebAssemblyTargetMachine::getSubtargetImpl(StringRef CPU, StringRef FS, + StringRef ABIName) const { + auto &I = SubtargetMap[CPU.str() + FS.str() + ABIName.str()]; if (!I) { - I = std::make_unique<WebAssemblySubtarget>(TargetTriple, CPU, FS, *this); + I = std::make_unique<WebAssemblySubtarget>(TargetTriple, CPU, FS, *this, + ABIName); } return I.get(); } @@ -237,7 +238,7 @@ WebAssemblyTargetMachine::getSubtargetImpl(const Function &F) const { StringRef CPU = CPUAttr.isValid() ? CPUAttr.getValueAsString() : TargetCPU; StringRef FS = FSAttr.isValid() ? FSAttr.getValueAsString() : TargetFS; - return getSubtargetImpl(CPU, FS); + return getSubtargetImpl(CPU, FS, getTargetABIName(*F.getParent())); } namespace { diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.h b/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.h index f21dc4b81dda45..faaea4da266624 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.h +++ b/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.h @@ -33,7 +33,6 @@ extern cl::opt<bool> WasmUseLegacyEH; // Legacy Wasm EH class WebAssemblyTargetMachine final : public CodeGenTargetMachineImpl { std::unique_ptr<TargetLoweringObjectFile> TLOF; mutable StringMap<std::unique_ptr<WebAssemblySubtarget>> SubtargetMap; - bool UsesMultivalueABI = false; public: WebAssemblyTargetMachine(const Target &T, const Triple &TT, StringRef CPU, @@ -44,8 +43,8 @@ class WebAssemblyTargetMachine final : public CodeGenTargetMachineImpl { ~WebAssemblyTargetMachine() override; - const WebAssemblySubtarget *getSubtargetImpl(StringRef CPU, - StringRef FS) const; + const WebAssemblySubtarget *getSubtargetImpl(StringRef CPU, StringRef FS, + StringRef ABIName) const; const WebAssemblySubtarget * getSubtargetImpl(const Function &F) const override; @@ -72,8 +71,6 @@ class WebAssemblyTargetMachine final : public CodeGenTargetMachineImpl { SMDiagnostic &Error, SMRange &SourceRange) const override; - bool usesMultivalueABI() const { return UsesMultivalueABI; } - void registerPassBuilderCallbacks(PassBuilder &PbB) override; Error buildCodeGenPipeline(ModulePassManager &MPM, ModuleAnalysisManager &MAM, diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.cpp index ac8df67fe7557c..4c0a776e3a750f 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.cpp @@ -13,7 +13,7 @@ #include "WebAssemblyUtilities.h" #include "WebAssemblyMachineFunctionInfo.h" -#include "WebAssemblyTargetMachine.h" +#include "WebAssemblySubtarget.h" #include "llvm/CodeGen/MachineInstr.h" #include "llvm/IR/Function.h" #include "llvm/MC/MCContext.h" @@ -185,9 +185,7 @@ unsigned WebAssembly::getCopyOpcodeForRegClass(const TargetRegisterClass *RC) { bool WebAssembly::canLowerMultivalueReturn( const WebAssemblySubtarget *Subtarget) { - const auto &TM = static_cast<const WebAssemblyTargetMachine &>( - Subtarget->getTargetLowering()->getTargetMachine()); - return Subtarget->hasMultivalue() && TM.usesMultivalueABI(); + return Subtarget->hasMultivalue() && Subtarget->usesMultivalueABI(); } bool WebAssembly::canLowerReturn(size_t ResultSize, diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.h b/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.h index 14ef9d142f36e2..24eddeb980ae01 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.h +++ b/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.h @@ -15,6 +15,7 @@ #ifndef LLVM_LIB_TARGET_WEBASSEMBLY_UTILS_WEBASSEMBLYUTILITIES_H #define LLVM_LIB_TARGET_WEBASSEMBLY_UTILS_WEBASSEMBLYUTILITIES_H +#include "llvm/ADT/StringRef.h" #include "llvm/CodeGen/SelectionDAGNodes.h" #include "llvm/Support/CommandLine.h" @@ -35,6 +36,17 @@ class SelectionDAG; namespace WebAssembly { +enum class WebAssemblyABI { + MVP, + ExperimentalMV, +}; + +/// Parse an ABI name into the corresponding enum. +inline WebAssemblyABI getABI(StringRef Name) { + return Name == "experimental-mv" ? WebAssemblyABI::ExperimentalMV + : WebAssemblyABI::MVP; +} + bool isChild(const MachineInstr &MI, const WebAssemblyFunctionInfo &MFI); bool mayThrow(const MachineInstr &MI); diff --git a/llvm/test/CodeGen/WebAssembly/multivalue-module-abi.ll b/llvm/test/CodeGen/WebAssembly/multivalue-module-abi.ll new file mode 100644 index 00000000000000..00372ecf73dab8 --- /dev/null +++ b/llvm/test/CodeGen/WebAssembly/multivalue-module-abi.ll @@ -0,0 +1,32 @@ +; RUN: split-file %s %t +; RUN: llc -mattr=+multivalue < %t/mv.ll | FileCheck %s --check-prefix=MV +; RUN: llc -mattr=+multivalue < %t/mvp.ll | FileCheck %s --check-prefix=MVP + +; Test that the ABI is selected from the "target-abi" module flag: the +; multivalue return is lowered directly only for "experimental-mv". + +;--- mv.ll +target triple = "wasm32-unknown-unknown" + +%pair = type { i32, i64 } + +; MV: .functype pair_const () -> (i32, i64) +define %pair @pair_const() { + ret %pair { i32 42, i64 42 } +} + +!llvm.module.flags = !{!0} +!0 = !{i32 1, !"target-abi", !"experimental-mv"} + +;--- mvp.ll +target triple = "wasm32-unknown-unknown" + +%pair = type { i32, i64 } + +; MVP: .functype pair_const (i32) -> () +define %pair @pair_const() { + ret %pair { i32 42, i64 42 } +} + +!llvm.module.flags = !{!0} +!0 = !{i32 1, !"target-abi", !"mvp"} _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
