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

Reply via email to