[llvm] RISCV: Don't use MCTargetOptions::ABIName in the ELF target streamer (PR #224704)

Matt Arsenault via llvm-commits llvm-commits at lists.llvm.org
Wed Sep 23 01:29:09 PDT 2026


https://github.com/arsenm updated https://github.com/llvm/llvm-project/pull/224704

>From 717d6c4ec902572517a57efa11cfdb2304f7d3a0 Mon Sep 17 00:00:00 2001
From: Matt Arsenault <Matthew.Arsenault at amd.com>
Date: Fri, 18 Sep 2026 19:26:18 +0200
Subject: [PATCH 1/2] RISCV: Don't use MCTargetOptions::ABIName in the ELF
 target streamer

The abi name should come from the target-abi module flag in codegen,
which should be set up in the AsmPrinter. The ABI name field should
only be of practical use in the assembler, which reads the flag in
onBeginOfFile.

Co-Authored-By: Claude <noreply at anthropic.com> (Claude Opus 4.8)
---
 .../Target/RISCV/AsmParser/RISCVAsmParser.cpp  |  1 -
 .../RISCV/MCTargetDesc/RISCVELFStreamer.cpp    | 18 ------------------
 2 files changed, 19 deletions(-)

diff --git a/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp b/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
index e9e8ffe6171f3..478a2c785819b 100644
--- a/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
+++ b/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
@@ -344,7 +344,6 @@ class RISCVAsmParser : public MCTargetAsmParser {
   // location instead of being printed with no location information.
   void onBeginOfFile() override {
     // If the target streamer already has a resolved ABI (e.g. set by
-    // RISCVTargetELFStreamer for a valid -target-abi, or set by
     // RISCVAsmPrinter during codegen), skip ABI validation.
     if (getTargetStreamer().hasTargetABI())
       return;
diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.cpp
index 1fb45627a1d03..3a86e2e3e5631 100644
--- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.cpp
+++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.cpp
@@ -11,7 +11,6 @@
 //===----------------------------------------------------------------------===//
 
 #include "RISCVELFStreamer.h"
-#include "RISCVAsmBackend.h"
 #include "RISCVBaseInfo.h"
 #include "RISCVMCTargetDesc.h"
 #include "llvm/BinaryFormat/ELF.h"
@@ -28,23 +27,6 @@ using namespace llvm;
 RISCVTargetELFStreamer::RISCVTargetELFStreamer(MCStreamer &S,
                                                const MCSubtargetInfo &STI)
     : RISCVTargetStreamer(S), CurrentVendor("riscv") {
-  MCAssembler &MCA = getStreamer().getAssembler();
-  auto &MAB = static_cast<RISCVAsmBackend &>(MCA.getBackend());
-  StringRef ABIName = MAB.getTargetOptions().getABIName();
-  // We have to recompute the ABI rather than casting STI to RISCVSubtarget
-  // since MC tools like llvm-mc call this when STI is MCSubtargetInfo instead.
-  // Using RISCVSubtarget requires a TargetMachine, which the MC-only tools
-  // deliberately don't link.
-  // TODO: Might be cleaner to have callers set the ABI instead of computing
-  // it twice which introduces a chance of it being out of sync.
-  if (auto ABIOrErr = RISCVABI::computeTargetABI(STI, ABIName)) {
-    setTargetABI(*ABIOrErr);
-  } else {
-    // Do not set TargetABI here if invalid: RISCVSubtarget/RISCVAsmPrinter
-    // (in codegen) or RISCVAsmParser::onBeginOfFile() (in llvm-mc) will
-    // resolve or diagnose it with proper contexts.
-    consumeError(ABIOrErr.takeError());
-  }
   setFlagsFromFeatures(STI);
 
   // Compute the initial ISA string.  This serves two purposes:

>From f29eabb7ebc57c5d740d7328be2c12fc263048d0 Mon Sep 17 00:00:00 2001
From: Matt Arsenault <Matthew.Arsenault at amd.com>
Date: Tue, 22 Sep 2026 18:14:05 +0200
Subject: [PATCH 2/2] Synthesize the "target-abi" module flag from the
 -target-abi option

Also error on unrecognized abi
---
 llvm/lib/CodeGen/CommandFlags.cpp             | 10 +++++
 .../RISCV/MCTargetDesc/RISCVELFStreamer.cpp   |  2 +-
 llvm/lib/Target/RISCV/RISCVAsmPrinter.cpp     | 15 +++++--
 llvm/test/CodeGen/RISCV/target-abi-invalid.ll |  8 ++--
 .../RISCV/target-abi-synthesize-flag.ll       | 45 +++++++++++++++++++
 5 files changed, 71 insertions(+), 9 deletions(-)
 create mode 100644 llvm/test/CodeGen/RISCV/target-abi-synthesize-flag.ll

diff --git a/llvm/lib/CodeGen/CommandFlags.cpp b/llvm/lib/CodeGen/CommandFlags.cpp
index 4ab005f11e0e0..1bebecda62166 100644
--- a/llvm/lib/CodeGen/CommandFlags.cpp
+++ b/llvm/lib/CodeGen/CommandFlags.cpp
@@ -747,6 +747,16 @@ void codegen::setFunctionAttributes(Module &M, StringRef CPU,
     }
   }
 
+  // Synthesize the "target-abi" module flag from the -target-abi option.
+  //
+  // FIXME: verifyOptionsConsistency validates consistency for target-abi. We
+  // should consistently handle all ABI module flags either here or there.
+  StringRef ABIName = mc::getABIName();
+  if (!ABIName.empty() && !M.getModuleFlag("target-abi")) {
+    M.addModuleFlag(Module::Error, "target-abi",
+                    MDString::get(M.getContext(), ABIName));
+  }
+
   for (Function &F : M)
     setFunctionAttributes(F, CPU, Features, TuneCPU);
 }
diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.cpp
index 3a86e2e3e5631..524d0bb79d5f8 100644
--- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.cpp
+++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.cpp
@@ -139,7 +139,7 @@ void RISCVTargetELFStreamer::finish() {
     EFlags |= ELF::EF_RISCV_RVE;
     break;
   case RISCVABI::ABI_Unknown:
-    llvm_unreachable("Improperly initialised target ABI");
+    break;
   }
 
   W.setELFHeaderEFlags(EFlags);
diff --git a/llvm/lib/Target/RISCV/RISCVAsmPrinter.cpp b/llvm/lib/Target/RISCV/RISCVAsmPrinter.cpp
index 04da2ce2b2bfe..c2cadf361a0cd 100644
--- a/llvm/lib/Target/RISCV/RISCVAsmPrinter.cpp
+++ b/llvm/lib/Target/RISCV/RISCVAsmPrinter.cpp
@@ -646,12 +646,19 @@ void RISCVAsmPrinter::emitStartOfAsmFile(Module &M) {
   assert(OutStreamer->getTargetStreamer() &&
          "target streamer is uninitialized");
   RISCVTargetStreamer &RTS = getTargetStreamer();
-  if (const MDString *ModuleTargetABI =
-          dyn_cast_or_null<MDString>(M.getModuleFlag("target-abi")))
-    RTS.setTargetABI(RISCVABI::getTargetABI(ModuleTargetABI->getString()));
-  else if (!RTS.hasTargetABI())
+  StringRef ABIName = M.getTargetABIFromMD();
+  if (!ABIName.empty()) {
+    RISCVABI::ABI ABI = RISCVABI::getTargetABI(ABIName);
+    if (ABI == RISCVABI::ABI_Unknown) {
+      M.getContext().emitError(Twine('\'') + ABIName +
+                               "' is not a recognized ABI for this target");
+    } else {
+      RTS.setTargetABI(ABI);
+    }
+  } else if (!RTS.hasTargetABI()) {
     RTS.setTargetABI(
         cantFail(RISCVABI::computeTargetABI(TM.getMCSubtargetInfo(), "")));
+  }
 
   MCSubtargetInfo SubtargetInfo = TM.getMCSubtargetInfo();
 
diff --git a/llvm/test/CodeGen/RISCV/target-abi-invalid.ll b/llvm/test/CodeGen/RISCV/target-abi-invalid.ll
index 72e3cba6d8d00..994136d5fd748 100644
--- a/llvm/test/CodeGen/RISCV/target-abi-invalid.ll
+++ b/llvm/test/CodeGen/RISCV/target-abi-invalid.ll
@@ -1,10 +1,10 @@
-; RUN: llc -mtriple=riscv32 -target-abi foo < %s 2>&1 \
+; RUN: not llc -mtriple=riscv32 -target-abi foo < %s 2>&1 \
 ; RUN:   | FileCheck -check-prefix=RV32I-FOO %s
-; RUN: llc -mtriple=riscv32 -mattr=+f -target-abi ilp32foof < %s 2>&1 \
+; RUN: not llc -mtriple=riscv32 -mattr=+f -target-abi ilp32foof < %s 2>&1 \
 ; RUN:   | FileCheck -check-prefix=RV32IF-ILP32FOOF %s
 
-; RV32I-FOO: note: 'foo' is not a recognized ABI for this target (ignoring target-abi)
-; RV32IF-ILP32FOOF: note: 'ilp32foof' is not a recognized ABI for this target (ignoring target-abi)
+; RV32I-FOO: error: 'foo' is not a recognized ABI for this target
+; RV32IF-ILP32FOOF: error: 'ilp32foof' is not a recognized ABI for this target
 
 ; RUN: llc -mtriple=riscv64 -target-abi ilp32 < %s 2>&1 \
 ; RUN:   | FileCheck -check-prefix=RV64I-ILP32 %s
diff --git a/llvm/test/CodeGen/RISCV/target-abi-synthesize-flag.ll b/llvm/test/CodeGen/RISCV/target-abi-synthesize-flag.ll
new file mode 100644
index 0000000000000..50abdebc89c87
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/target-abi-synthesize-flag.ll
@@ -0,0 +1,45 @@
+; Check behavior of the -target-abi command-line option; it should
+; synthesize the "target-abi" module flag, unless one is already
+; present. A conflict is diagnosed by verifyOptionsConsistency.
+
+; RUN: split-file %s %t
+
+; -target-abi synthesizes the flag and selects the ABI, overriding the
+; extension default (lp64d).
+; RUN: llc -mtriple=riscv64 -mattr=+d -target-abi lp64f -filetype=obj < %t/none.ll | llvm-readelf -h - | FileCheck %s --check-prefix=LP64F
+
+; Without -target-abi, the extension-default ABI is used.
+; RUN: llc -mtriple=riscv64 -mattr=+d -filetype=obj < %t/none.ll | llvm-readelf -h - | FileCheck %s --check-prefix=LP64D
+
+; An unrecognized ABI name in the module flag is an error
+; RUN: not llc -mtriple=riscv64 -mattr=+d -filetype=null < %t/bogus.ll 2>&1 | FileCheck %s --check-prefix=BADABI
+
+; -target-abi matching an existing in-IR flag is accepted.
+; RUN: llc -mtriple=riscv64 -mattr=+d -target-abi lp64f -filetype=obj < %t/lp64f.ll | llvm-readelf -h - | FileCheck %s --check-prefix=LP64F
+
+; -target-abi conflicting with an existing in-IR flag is an error.
+; RUN: not llc -mtriple=riscv64 -mattr=+d -target-abi lp64d -filetype=null < %t/lp64f.ll 2>&1 | FileCheck %s --check-prefix=CONFLICT
+
+; LP64F: Flags: 0x2, single-float ABI
+; LP64D: Flags: 0x4, double-float ABI
+; BADABI: error: 'bogus' is not a recognized ABI for this target
+; CONFLICT: error: -target-abi option != target-abi module flag
+
+;--- none.ll
+define void @f() {
+  ret void
+}
+
+;--- lp64f.ll
+define void @f() {
+  ret void
+}
+!llvm.module.flags = !{!0}
+!0 = !{i32 1, !"target-abi", !"lp64f"}
+
+;--- bogus.ll
+define void @f() {
+  ret void
+}
+!llvm.module.flags = !{!0}
+!0 = !{i32 1, !"target-abi", !"bogus"}



More information about the llvm-commits mailing list