[llvm-branch-commits] [clang] [llvm] WebAssembly: Respect target-abi module flag (PR #224312)

via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Thu Sep 17 06:57:53 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-backend-webassembly

Author: Matt Arsenault (arsenm)

<details>
<summary>Changes</summary>

Previously this relied on the TargetABI MCOptions field and ignored
the IR flag.

Co-authored-by: Claude (Claude-Opus-4.8) <noreply@<!-- -->anthropic.com>

---
Full diff: https://github.com/llvm/llvm-project/pull/224312.diff


10 Files Affected:

- (modified) clang/lib/CodeGen/CodeGenModule.cpp (+1-1) 
- (added) clang/test/CodeGen/WebAssembly/target-abi-module-flag.c (+14) 
- (modified) llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp (+4-2) 
- (modified) llvm/lib/Target/WebAssembly/WebAssemblyCoalesceFeaturesAndStripAtomics.cpp (+2-1) 
- (modified) llvm/lib/Target/WebAssembly/WebAssemblySubtarget.cpp (+4-3) 
- (modified) llvm/lib/Target/WebAssembly/WebAssemblySubtarget.h (+7-1) 
- (modified) llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp (+11-6) 
- (modified) llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.h (+2-5) 
- (modified) llvm/lib/Target/WebAssembly/WebAssemblyUtilities.cpp (+2-4) 
- (added) llvm/test/CodeGen/WebAssembly/multivalue-module-abi.ll (+17) 


``````````diff
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..c20c6675f970cf 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()) == "experimental-mv");
     const WebAssemblyTargetLowering &TLI = *ST->getTargetLowering();
     computeLegalValueVTs(TLI, GV->getParent()->getContext(),
                          GV->getDataLayout(), GlobalVT, VTs);
@@ -612,7 +613,8 @@ 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) == "experimental-mv");
   }
   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..92eeff4bc477bc 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) == "experimental-mv");
   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..b16b47ccb5a86e 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,
+                                           bool UsesMultivalueABI)
     : WebAssemblyGenSubtargetInfo(TT, CPU, /*TuneCPU*/ CPU, FS),
-      TargetTriple(TT), InstrInfo(initializeSubtargetDependencies(CPU, FS)),
-      TLInfo(TM, *this) {
+      TargetTriple(TT), UsesMultivalueABI(UsesMultivalueABI),
+      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..f9ecf561134f03 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblySubtarget.h
+++ b/llvm/lib/Target/WebAssembly/WebAssemblySubtarget.h
@@ -63,6 +63,10 @@ class WebAssemblySubtarget final : public WebAssemblyGenSubtargetInfo {
   /// What processor and OS we're targeting.
   Triple TargetTriple;
 
+  /// Whether the multivalue ABI is in use, derived from the "target-abi" module
+  /// flag.
+  bool UsesMultivalueABI = false;
+
   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, bool UsesMultivalueABI);
 
   const WebAssemblySelectionDAGInfo *getSelectionDAGInfo() const override {
     return &TSInfo;
@@ -130,6 +134,8 @@ class WebAssemblySubtarget final : public WebAssemblyGenSubtargetInfo {
   bool hasTailCall() const { return HasTailCall; }
   bool hasWideArithmetic() const { return HasWideArithmetic; }
 
+  bool usesMultivalueABI() const { return UsesMultivalueABI; }
+
   /// 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..a732049357a7f9 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,13 @@ 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,
+                                           bool UsesMultivalueABI) const {
+  auto &I =
+      SubtargetMap[CPU.str() + FS.str() + (UsesMultivalueABI ? "+mv" : "")];
   if (!I) {
-    I = std::make_unique<WebAssemblySubtarget>(TargetTriple, CPU, FS, *this);
+    I = std::make_unique<WebAssemblySubtarget>(TargetTriple, CPU, FS, *this,
+                                               UsesMultivalueABI);
   }
   return I.get();
 }
@@ -237,7 +239,10 @@ WebAssemblyTargetMachine::getSubtargetImpl(const Function &F) const {
   StringRef CPU = CPUAttr.isValid() ? CPUAttr.getValueAsString() : TargetCPU;
   StringRef FS = FSAttr.isValid() ? FSAttr.getValueAsString() : TargetFS;
 
-  return getSubtargetImpl(CPU, FS);
+  bool UsesMultivalueABI =
+      getTargetABIName(*F.getParent()) == "experimental-mv";
+
+  return getSubtargetImpl(CPU, FS, UsesMultivalueABI);
 }
 
 namespace {
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.h b/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.h
index f21dc4b81dda45..cb35cea91de324 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,
+                                               bool UsesMultivalueABI) 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/test/CodeGen/WebAssembly/multivalue-module-abi.ll b/llvm/test/CodeGen/WebAssembly/multivalue-module-abi.ll
new file mode 100644
index 00000000000000..c27e464ef55c56
--- /dev/null
+++ b/llvm/test/CodeGen/WebAssembly/multivalue-module-abi.ll
@@ -0,0 +1,17 @@
+; RUN: llc -mattr=+multivalue < %s | FileCheck %s
+
+; Test that the multivalue ABI can be selected via the "target-abi"
+; module flag
+
+target triple = "wasm32-unknown-unknown"
+
+%pair = type { i32, i64 }
+
+; CHECK-LABEL: pair_const:
+; CHECK-NEXT: .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"}

``````````

</details>


https://github.com/llvm/llvm-project/pull/224312


More information about the llvm-branch-commits mailing list