[llvm] [RISCV] RFC: Add PE/COFF file output support (PR #148045)

Jason Xu via llvm-commits llvm-commits at lists.llvm.org
Thu Jul 10 14:54:03 PDT 2025


https://github.com/JasonBrave updated https://github.com/llvm/llvm-project/pull/148045

>From 05325c2360e8e2bea9ee9c3dccdda499c57276e2 Mon Sep 17 00:00:00 2001
From: Jason Xu <40355221+JasonBrave at users.noreply.github.com>
Date: Tue, 8 Jul 2025 22:56:34 -0400
Subject: [PATCH 1/5] Add RISC-V PE32+ Relocation Types

---
 llvm/include/llvm/BinaryFormat/COFF.h | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/llvm/include/llvm/BinaryFormat/COFF.h b/llvm/include/llvm/BinaryFormat/COFF.h
index f3b5d5e3f23c6..7b428d0e76c67 100644
--- a/llvm/include/llvm/BinaryFormat/COFF.h
+++ b/llvm/include/llvm/BinaryFormat/COFF.h
@@ -132,7 +132,8 @@ template <typename T> bool isAnyArm64(T Machine) {
 }
 
 template <typename T> bool is64Bit(T Machine) {
-  return Machine == IMAGE_FILE_MACHINE_AMD64 || isAnyArm64(Machine);
+  return Machine == IMAGE_FILE_MACHINE_AMD64 || isAnyArm64(Machine) ||
+         IMAGE_FILE_MACHINE_RISCV64;
 }
 
 enum Characteristics : unsigned {
@@ -726,7 +727,10 @@ enum BaseRelocationType : unsigned {
   IMAGE_REL_BASED_HIGHADJ = 4,
   IMAGE_REL_BASED_MIPS_JMPADDR = 5,
   IMAGE_REL_BASED_ARM_MOV32A = 5,
+  IMAGE_REL_BASED_RISCV_HI20 = 5,
   IMAGE_REL_BASED_ARM_MOV32T = 7,
+  IMAGE_REL_BASED_RISCV_LOW12I = 7,
+  IMAGE_REL_BASED_RISCV_LOW12S = 8,
   IMAGE_REL_BASED_MIPS_JMPADDR16 = 9,
   IMAGE_REL_BASED_DIR64 = 10
 };

>From 1bebbb292d43b87ffd9cc0e76d5cbda9a8cd17b3 Mon Sep 17 00:00:00 2001
From: Jason Xu <40355221+JasonBrave at users.noreply.github.com>
Date: Thu, 10 Jul 2025 15:41:49 -0400
Subject: [PATCH 2/5] Initial adding PE/COFF file output support to RISC-V
 target

---
 .../Target/RISCV/MCTargetDesc/CMakeLists.txt  |  2 +
 .../RISCV/MCTargetDesc/RISCVAsmBackend.cpp    | 29 +++++++++++
 .../RISCV/MCTargetDesc/RISCVMCAsmInfo.cpp     | 12 +++++
 .../RISCV/MCTargetDesc/RISCVMCAsmInfo.h       |  8 +++
 .../RISCV/MCTargetDesc/RISCVMCTargetDesc.cpp  | 18 ++++++-
 .../RISCV/MCTargetDesc/RISCVMCTargetDesc.h    | 12 +++++
 .../MCTargetDesc/RISCVWinCOFFObjectWriter.cpp | 51 +++++++++++++++++++
 .../MCTargetDesc/RISCVWinCOFFStreamer.cpp     | 33 ++++++++++++
 8 files changed, 164 insertions(+), 1 deletion(-)
 create mode 100644 llvm/lib/Target/RISCV/MCTargetDesc/RISCVWinCOFFObjectWriter.cpp
 create mode 100644 llvm/lib/Target/RISCV/MCTargetDesc/RISCVWinCOFFStreamer.cpp

diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/CMakeLists.txt b/llvm/lib/Target/RISCV/MCTargetDesc/CMakeLists.txt
index e68c956f888e4..19f8ab17bf32e 100644
--- a/llvm/lib/Target/RISCV/MCTargetDesc/CMakeLists.txt
+++ b/llvm/lib/Target/RISCV/MCTargetDesc/CMakeLists.txt
@@ -11,6 +11,8 @@ add_llvm_component_library(LLVMRISCVDesc
   RISCVMatInt.cpp
   RISCVTargetStreamer.cpp
   RISCVELFStreamer.cpp
+  RISCVWinCOFFObjectWriter.cpp
+  RISCVWinCOFFStreamer.cpp
 
   LINK_COMPONENTS
   MC
diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp
index 89a87798d71e4..b10f3e2174f81 100644
--- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp
+++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp
@@ -895,6 +895,30 @@ bool RISCVAsmBackend::shouldInsertFixupForCodeAlign(MCAssembler &Asm,
   return true;
 }
 
+namespace {
+
+class WindowsRISCVAsmBackend : public RISCVAsmBackend {
+  bool is64Bit;
+
+public:
+  WindowsRISCVAsmBackend(const Target &T, const MCSubtargetInfo &STI,
+                         const MCRegisterInfo &MRI,
+                         const MCTargetOptions &Options)
+      : RISCVAsmBackend(
+            STI,
+            MCELFObjectTargetWriter::getOSABI(STI.getTargetTriple().getOS()),
+            STI.getTargetTriple().isArch64Bit(), Options) {
+    is64Bit = STI.getTargetTriple().isArch64Bit();
+  }
+
+  std::unique_ptr<MCObjectTargetWriter>
+  createObjectTargetWriter() const override {
+    return createRISCVWinCOFFObjectWriter(is64Bit);
+  }
+};
+
+} // namespace
+
 std::unique_ptr<MCObjectTargetWriter>
 RISCVAsmBackend::createObjectTargetWriter() const {
   return createRISCVELFObjectWriter(OSABI, Is64Bit);
@@ -905,6 +929,11 @@ MCAsmBackend *llvm::createRISCVAsmBackend(const Target &T,
                                           const MCRegisterInfo &MRI,
                                           const MCTargetOptions &Options) {
   const Triple &TT = STI.getTargetTriple();
+
+  if (TT.isOSWindows() && TT.isOSBinFormatCOFF()) {
+    return new WindowsRISCVAsmBackend(T, STI, MRI, Options);
+  }
+
   uint8_t OSABI = MCELFObjectTargetWriter::getOSABI(TT.getOS());
   return new RISCVAsmBackend(STI, OSABI, TT.isArch64Bit(), Options);
 }
diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCAsmInfo.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCAsmInfo.cpp
index 090d331d99cab..8b6b13f239707 100644
--- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCAsmInfo.cpp
+++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCAsmInfo.cpp
@@ -57,3 +57,15 @@ void RISCVMCAsmInfo::printSpecifierExpr(raw_ostream &OS,
   if (HasSpecifier)
     OS << ')';
 }
+
+
+void RISCVCOFFMCAsmInfo::anchor() {}
+
+RISCVCOFFMCAsmInfo::RISCVCOFFMCAsmInfo() {
+  HasSingleParameterDotFile = true;
+  WinEHEncodingType = WinEH::EncodingType::Itanium;
+
+  ExceptionsType = ExceptionHandling::WinEH;
+
+  AllowAtInName = true;
+}
diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCAsmInfo.h b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCAsmInfo.h
index 097e94b6117c7..1403f07bb7888 100644
--- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCAsmInfo.h
+++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCAsmInfo.h
@@ -13,6 +13,7 @@
 #ifndef LLVM_LIB_TARGET_RISCV_MCTARGETDESC_RISCVMCASMINFO_H
 #define LLVM_LIB_TARGET_RISCV_MCTARGETDESC_RISCVMCASMINFO_H
 
+#include "llvm/MC/MCAsmInfoCOFF.h"
 #include "llvm/MC/MCAsmInfoELF.h"
 #include "llvm/MC/MCFixup.h"
 
@@ -31,6 +32,13 @@ class RISCVMCAsmInfo : public MCAsmInfoELF {
                           const MCSpecifierExpr &Expr) const override;
 };
 
+class RISCVCOFFMCAsmInfo : public MCAsmInfoGNUCOFF {
+  void anchor() override;
+
+public:
+  explicit RISCVCOFFMCAsmInfo();
+};
+
 namespace RISCV {
 using Specifier = uint16_t;
 // Specifiers mapping to relocation types below FirstTargetFixupKind are
diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCTargetDesc.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCTargetDesc.cpp
index f66c2d5f99cb3..75de3eeb096ba 100644
--- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCTargetDesc.cpp
+++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCTargetDesc.cpp
@@ -44,6 +44,13 @@
 
 using namespace llvm;
 
+namespace {
+class RISCVWinCOFFTargetStreamer : public RISCVTargetStreamer {
+public:
+  RISCVWinCOFFTargetStreamer(MCStreamer &S) : RISCVTargetStreamer(S) {}
+};
+} // end namespace
+
 static MCInstrInfo *createRISCVMCInstrInfo() {
   MCInstrInfo *X = new MCInstrInfo();
   InitRISCVMCInstrInfo(X);
@@ -59,7 +66,13 @@ static MCRegisterInfo *createRISCVMCRegisterInfo(const Triple &TT) {
 static MCAsmInfo *createRISCVMCAsmInfo(const MCRegisterInfo &MRI,
                                        const Triple &TT,
                                        const MCTargetOptions &Options) {
-  MCAsmInfo *MAI = new RISCVMCAsmInfo(TT);
+  MCAsmInfo *MAI;
+
+  if(TT.isOSWindows()){
+	  MAI = new RISCVCOFFMCAsmInfo();
+  } else {
+	  MAI = new RISCVMCAsmInfo(TT);
+  }
 
   unsigned SP = MRI.getDwarfRegNum(RISCV::X2, true);
   MCCFIInstruction Inst = MCCFIInstruction::cfiDefCfa(nullptr, SP, 0);
@@ -110,6 +123,8 @@ static MCInstPrinter *createRISCVMCInstPrinter(const Triple &T,
 static MCTargetStreamer *
 createRISCVObjectTargetStreamer(MCStreamer &S, const MCSubtargetInfo &STI) {
   const Triple &TT = STI.getTargetTriple();
+  if(TT.isOSBinFormatCOFF())
+	return new RISCVWinCOFFTargetStreamer(S);
   if (TT.isOSBinFormatELF())
     return new RISCVTargetELFStreamer(S, STI);
   return nullptr;
@@ -344,6 +359,7 @@ LLVMInitializeRISCVTargetMC() {
     TargetRegistry::RegisterMCInstPrinter(*T, createRISCVMCInstPrinter);
     TargetRegistry::RegisterMCSubtargetInfo(*T, createRISCVMCSubtargetInfo);
     TargetRegistry::RegisterELFStreamer(*T, createRISCVELFStreamer);
+	TargetRegistry::RegisterCOFFStreamer(*T, createRISCVWinCOFFStreamer);
     TargetRegistry::RegisterObjectTargetStreamer(
         *T, createRISCVObjectTargetStreamer);
     TargetRegistry::RegisterMCInstrAnalysis(*T, createRISCVInstrAnalysis);
diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCTargetDesc.h b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCTargetDesc.h
index bdee7ed4f011e..2cfd1abdc12b3 100644
--- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCTargetDesc.h
+++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCTargetDesc.h
@@ -13,6 +13,8 @@
 #ifndef LLVM_LIB_TARGET_RISCV_MCTARGETDESC_RISCVMCTARGETDESC_H
 #define LLVM_LIB_TARGET_RISCV_MCTARGETDESC_RISCVMCTARGETDESC_H
 
+#include "llvm/MC/MCObjectWriter.h"
+#include "llvm/MC/MCStreamer.h"
 #include "llvm/MC/MCTargetOptions.h"
 #include "llvm/Support/DataTypes.h"
 #include <memory>
@@ -23,7 +25,9 @@ class MCCodeEmitter;
 class MCContext;
 class MCInstrInfo;
 class MCObjectTargetWriter;
+class MCObjectWriter;
 class MCRegisterInfo;
+class MCStreamer;
 class MCSubtargetInfo;
 class Target;
 
@@ -34,8 +38,16 @@ MCAsmBackend *createRISCVAsmBackend(const Target &T, const MCSubtargetInfo &STI,
                                     const MCRegisterInfo &MRI,
                                     const MCTargetOptions &Options);
 
+MCStreamer *createRISCVWinCOFFStreamer(MCContext &C,
+                                       std::unique_ptr<MCAsmBackend> &&AB,
+                                       std::unique_ptr<MCObjectWriter> &&OW,
+                                       std::unique_ptr<MCCodeEmitter> &&CE);
+
 std::unique_ptr<MCObjectTargetWriter> createRISCVELFObjectWriter(uint8_t OSABI,
                                                                  bool Is64Bit);
+
+std::unique_ptr<MCObjectTargetWriter> createRISCVWinCOFFObjectWriter(bool Is64Bit);
+	
 } // namespace llvm
 
 // Defines symbolic names for RISC-V registers.
diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVWinCOFFObjectWriter.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVWinCOFFObjectWriter.cpp
new file mode 100644
index 0000000000000..207c81cd8c598
--- /dev/null
+++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVWinCOFFObjectWriter.cpp
@@ -0,0 +1,51 @@
+//===- RISCVWinCOFFObjectWriter.cpp-----------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===---------------------------------------------------------------------===//
+
+#include "MCTargetDesc/RISCVFixupKinds.h"
+#include "MCTargetDesc/RISCVMCTargetDesc.h"
+#include "llvm/BinaryFormat/COFF.h"
+#include "llvm/MC/MCContext.h"
+#include "llvm/MC/MCWinCOFFObjectWriter.h"
+
+using namespace llvm;
+
+namespace {
+
+class RISCVWinCOFFObjectWriter : public MCWinCOFFObjectTargetWriter {
+public:
+  RISCVWinCOFFObjectWriter(bool Is64Bit);
+
+  unsigned getRelocType(MCContext &Ctx, const MCValue &Target,
+                        const MCFixup &Fixup, bool IsCrossSection,
+                        const MCAsmBackend &MAB) const override;
+};
+
+} // namespace
+
+RISCVWinCOFFObjectWriter::RISCVWinCOFFObjectWriter(bool Is64Bit)
+    : MCWinCOFFObjectTargetWriter(Is64Bit ? COFF::IMAGE_FILE_MACHINE_RISCV64
+                                          : COFF::IMAGE_FILE_MACHINE_RISCV32) {}
+
+unsigned RISCVWinCOFFObjectWriter::getRelocType(MCContext &Ctx,
+                                                const MCValue &Target,
+                                                const MCFixup &Fixup,
+                                                bool IsCrossSection,
+                                                const MCAsmBackend &MAB) const {
+  unsigned FixupKind = Fixup.getKind();
+
+  switch (FixupKind) {
+  default:
+    Ctx.reportError(Fixup.getLoc(), "unsupported relocation type");
+    return COFF::IMAGE_REL_BASED_RISCV_HI20; // FIXME
+  }
+}
+
+std::unique_ptr<MCObjectTargetWriter>
+llvm::createRISCVWinCOFFObjectWriter(bool Is64Bit) {
+  return std::make_unique<RISCVWinCOFFObjectWriter>(Is64Bit);
+}
diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVWinCOFFStreamer.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVWinCOFFStreamer.cpp
new file mode 100644
index 0000000000000..7cc6dea804a83
--- /dev/null
+++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVWinCOFFStreamer.cpp
@@ -0,0 +1,33 @@
+//===- RISCVWinCOFFStreamer.cpp----------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===---------------------------------------------------------------------===//
+
+#include "RISCVMCTargetDesc.h"
+#include "llvm/MC/MCAsmBackend.h"
+#include "llvm/MC/MCAssembler.h"
+#include "llvm/MC/MCCodeEmitter.h"
+#include "llvm/MC/MCObjectWriter.h"
+#include "llvm/MC/MCWinCOFFStreamer.h"
+
+using namespace llvm;
+
+namespace {
+class RISCVWinCOFFStreamer : public MCWinCOFFStreamer {
+public:
+  RISCVWinCOFFStreamer(MCContext &C, std::unique_ptr<MCAsmBackend> AB,
+                       std::unique_ptr<MCCodeEmitter> CE,
+                       std::unique_ptr<MCObjectWriter> OW)
+      : MCWinCOFFStreamer(C, std::move(AB), std::move(CE), std::move(OW)) {}
+};
+} // namespace
+
+MCStreamer *llvm::createRISCVWinCOFFStreamer(
+    MCContext &C, std::unique_ptr<MCAsmBackend> &&AB,
+    std::unique_ptr<MCObjectWriter> &&OW, std::unique_ptr<MCCodeEmitter> &&CE) {
+  return new RISCVWinCOFFStreamer(C, std::move(AB), std::move(CE),
+                                  std::move(OW));
+}

>From 22b41cae3e0722b22c8d3dee57f46416d064d38f Mon Sep 17 00:00:00 2001
From: Jason Xu <40355221+JasonBrave at users.noreply.github.com>
Date: Thu, 10 Jul 2025 16:52:32 -0400
Subject: [PATCH 3/5] Update documentation

---
 llvm/docs/CodeGenerator.rst | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/llvm/docs/CodeGenerator.rst b/llvm/docs/CodeGenerator.rst
index 020eb09ba7e1e..21c6b289e8c26 100644
--- a/llvm/docs/CodeGenerator.rst
+++ b/llvm/docs/CodeGenerator.rst
@@ -723,7 +723,7 @@ The table below captures a snapshot of object file support in LLVM:
      ================== ========================================================
      Format              Supported Targets
      ================== ========================================================
-     ``COFF``            AArch64, ARM, X86
+     ``COFF``            AArch64, ARM, RISCV, X86
      ``DXContainer``     DirectX
      ``ELF``             AArch64, AMDGPU, ARM, AVR, BPF, CSKY, Hexagon, Lanai, LoongArch, M86k, MSP430, MIPS, PowerPC, RISCV, SPARC, SystemZ, VE, X86
      ``GOFF``            SystemZ

>From 10f3d967f18f7cd541c40ad7b78126af7da40cda Mon Sep 17 00:00:00 2001
From: Jason Xu <40355221+JasonBrave at users.noreply.github.com>
Date: Thu, 10 Jul 2025 17:10:28 -0400
Subject: [PATCH 4/5] Add COFF to RISCV Windows/UEFI Target Triple

---
 llvm/lib/TargetParser/Triple.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/llvm/lib/TargetParser/Triple.cpp b/llvm/lib/TargetParser/Triple.cpp
index 0584c941d2e6e..00ee55fd61726 100644
--- a/llvm/lib/TargetParser/Triple.cpp
+++ b/llvm/lib/TargetParser/Triple.cpp
@@ -927,6 +927,8 @@ static Triple::ObjectFormatType getDefaultFormat(const Triple &T) {
   case Triple::aarch64:
   case Triple::aarch64_32:
   case Triple::arm:
+  case Triple::riscv32:
+  case Triple::riscv64:
   case Triple::thumb:
   case Triple::x86:
   case Triple::x86_64:
@@ -966,8 +968,6 @@ static Triple::ObjectFormatType getDefaultFormat(const Triple &T) {
   case Triple::r600:
   case Triple::renderscript32:
   case Triple::renderscript64:
-  case Triple::riscv32:
-  case Triple::riscv64:
   case Triple::shave:
   case Triple::sparc:
   case Triple::sparcel:

>From 4a5963d708a3580b83c7dfb497d73d00f6d79a2d Mon Sep 17 00:00:00 2001
From: Jason Xu <40355221+JasonBrave at users.noreply.github.com>
Date: Thu, 10 Jul 2025 17:38:07 -0400
Subject: [PATCH 5/5] Add RISCV to CodeViewDebug

---
 llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp b/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp
index bc74daf983e40..277afa384927f 100644
--- a/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp
@@ -32,6 +32,7 @@
 #include "llvm/CodeGen/TargetSubtargetInfo.h"
 #include "llvm/Config/llvm-config.h"
 #include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
+#include "llvm/DebugInfo/CodeView/CodeView.h"
 #include "llvm/DebugInfo/CodeView/CodeViewRecordIO.h"
 #include "llvm/DebugInfo/CodeView/ContinuationRecordBuilder.h"
 #include "llvm/DebugInfo/CodeView/DebugInlineeLinesSubsection.h"
@@ -125,6 +126,9 @@ static CPUType mapArchToCVCPUType(Triple::ArchType Type) {
     return CPUType::ARM64;
   case Triple::ArchType::mipsel:
     return CPUType::MIPS;
+  case llvm::Triple::ArchType::riscv32:
+  case llvm::Triple::ArchType::riscv64:
+    return CPUType::Unknown;
   case Triple::ArchType::UnknownArch:
     return CPUType::Unknown;
   default:



More information about the llvm-commits mailing list