[RISCV] Add basic Mach-O triple support. by fpetrogalli · Pull Request #141682 · llvm/llvm-project

7 min read Original article ↗

@llvm/pr-subscribers-llvm-binary-utilities

@llvm/pr-subscribers-backend-risc-v

Author: Francesco Petrogalli (fpetrogalli)

Changes

Based on a patch written by Tim
Northover (https://github.com/TNorthover).


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

13 Files Affected:

  • (modified) llvm/lib/BinaryFormat/MachO.cpp (+8)
  • (modified) llvm/lib/Object/MachOObjectFile.cpp (+13)
  • (modified) llvm/lib/Target/RISCV/MCTargetDesc/CMakeLists.txt (+1)
  • (modified) llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp (+18)
  • (modified) llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.h (+1)
  • (modified) llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCAsmInfo.cpp (+13)
  • (modified) llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCAsmInfo.h (+6)
  • (modified) llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCTargetDesc.cpp (+5-1)
  • (modified) llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCTargetDesc.h (+3)
  • (added) llvm/lib/Target/RISCV/MCTargetDesc/RISCVMachObjectWriter.cpp (+57)
  • (modified) llvm/lib/Target/RISCV/RISCVTargetMachine.cpp (+13-1)
  • (added) llvm/test/CodeGen/RISCV/riscv-macho.ll (+13)
  • (added) llvm/test/MC/RISCV/riscv-macho.s (+26)
diff --git a/llvm/lib/BinaryFormat/MachO.cpp b/llvm/lib/BinaryFormat/MachO.cpp
index f46b9d5147ff1..369b5ba927136 100644
--- a/llvm/lib/BinaryFormat/MachO.cpp
+++ b/llvm/lib/BinaryFormat/MachO.cpp
@@ -74,6 +74,10 @@ static Error unsupported(const char *Str, const Triple &T) {
                            T.str().c_str());
 }
 
+static MachO::CPUSubTypeRISCV getRISCVSubType(const Triple &T) {
+  return MachO::CPU_SUBTYPE_RISCV_ALL;
+}
+
 Expected<uint32_t> MachO::getCPUType(const Triple &T) {
   if (!T.isOSBinFormatMachO())
     return unsupported("type", T);
@@ -89,6 +93,8 @@ Expected<uint32_t> MachO::getCPUType(const Triple &T) {
     return MachO::CPU_TYPE_POWERPC;
   if (T.getArch() == Triple::ppc64)
     return MachO::CPU_TYPE_POWERPC64;
+  if (T.getArch() == Triple::riscv32)
+    return MachO::CPU_TYPE_RISCV;
   return unsupported("type", T);
 }
 
@@ -103,6 +109,8 @@ Expected<uint32_t> MachO::getCPUSubType(const Triple &T) {
     return getARM64SubType(T);
   if (T.getArch() == Triple::ppc || T.getArch() == Triple::ppc64)
     return getPowerPCSubType(T);
+  if (T.getArch() == Triple::riscv32)
+    return getRISCVSubType(T);
   return unsupported("subtype", T);
 }
 
diff --git a/llvm/lib/Object/MachOObjectFile.cpp b/llvm/lib/Object/MachOObjectFile.cpp
index 5db264207ffb7..d0713dc77303b 100644
--- a/llvm/lib/Object/MachOObjectFile.cpp
+++ b/llvm/lib/Object/MachOObjectFile.cpp
@@ -2668,6 +2668,8 @@ StringRef MachOObjectFile::getFileFormatName() const {
       return "Mach-O arm64 (ILP32)";
     case MachO::CPU_TYPE_POWERPC:
       return "Mach-O 32-bit ppc";
+    case MachO::CPU_TYPE_RISCV:
+      return "Mach-O 32-bit RISC-V";
     default:
       return "Mach-O 32-bit unknown";
     }
@@ -2701,6 +2703,8 @@ Triple::ArchType MachOObjectFile::getArch(uint32_t CPUType, uint32_t CPUSubType)
     return Triple::ppc;
   case MachO::CPU_TYPE_POWERPC64:
     return Triple::ppc64;
+  case MachO::CPU_TYPE_RISCV:
+    return Triple::riscv32;
   default:
     return Triple::UnknownArch;
   }
@@ -2838,6 +2842,15 @@ Triple MachOObjectFile::getArchTriple(uint32_t CPUType, uint32_t CPUSubType,
     default:
       return Triple();
     }
+  case MachO::CPU_TYPE_RISCV:
+    switch (CPUSubType & ~MachO::CPU_SUBTYPE_MASK) {
+    case MachO::CPU_SUBTYPE_RISCV_ALL:
+      if (ArchFlag)
+        *ArchFlag = "riscv32";
+      return Triple("riscv32-apple-macho");
+    default:
+      return Triple();
+    }
   default:
     return Triple();
   }
diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/CMakeLists.txt b/llvm/lib/Target/RISCV/MCTargetDesc/CMakeLists.txt
index e68c956f888e4..1a8dd50327dde 100644
--- a/llvm/lib/Target/RISCV/MCTargetDesc/CMakeLists.txt
+++ b/llvm/lib/Target/RISCV/MCTargetDesc/CMakeLists.txt
@@ -3,6 +3,7 @@ add_llvm_component_library(LLVMRISCVDesc
   RISCVBaseInfo.cpp
   RISCVELFObjectWriter.cpp
   RISCVInstPrinter.cpp
+  RISCVMachObjectWriter.cpp
   RISCVMCAsmInfo.cpp
   RISCVMCCodeEmitter.cpp
   RISCVMCExpr.cpp
diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp
index f7f39439249e8..19f05522755c4 100644
--- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp
+++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp
@@ -15,6 +15,7 @@
 #include "llvm/MC/MCELFObjectWriter.h"
 #include "llvm/MC/MCExpr.h"
 #include "llvm/MC/MCFragment.h"
+#include "llvm/MC/MCMachObjectWriter.h"
 #include "llvm/MC/MCObjectWriter.h"
 #include "llvm/MC/MCSymbol.h"
 #include "llvm/MC/MCValue.h"
@@ -757,11 +758,28 @@ RISCVAsmBackend::createObjectTargetWriter() const {
   return createRISCVELFObjectWriter(OSABI, Is64Bit);
 }
 
+class DarwinRISCVAsmBackend : public RISCVAsmBackend {
+public:
+  DarwinRISCVAsmBackend(const MCSubtargetInfo &STI, uint8_t OSABI, bool Is64Bit,
+                        const MCTargetOptions &Options)
+      : RISCVAsmBackend(STI, OSABI, Is64Bit, Options) {}
+
+  std::unique_ptr<MCObjectTargetWriter>
+  createObjectTargetWriter() const override {
+    const Triple &TT = STI.getTargetTriple();
+    uint32_t CPUType = cantFail(MachO::getCPUType(TT));
+    uint32_t CPUSubType = cantFail(MachO::getCPUSubType(TT));
+    return createRISCVMachObjectWriter(CPUType, CPUSubType);
+  }
+};
+
 MCAsmBackend *llvm::createRISCVAsmBackend(const Target &T,
                                           const MCSubtargetInfo &STI,
                                           const MCRegisterInfo &MRI,
                                           const MCTargetOptions &Options) {
   const Triple &TT = STI.getTargetTriple();
   uint8_t OSABI = MCELFObjectTargetWriter::getOSABI(TT.getOS());
+  if (TT.isOSBinFormatMachO())
+    return new DarwinRISCVAsmBackend(STI, OSABI, TT.isArch64Bit(), Options);
   return new RISCVAsmBackend(STI, OSABI, TT.isArch64Bit(), Options);
 }
diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.h b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.h
index 4dffbb82e07c7..061332796e78c 100644
--- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.h
+++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.h
@@ -22,6 +22,7 @@ class MCObjectTargetWriter;
 class raw_ostream;
 
 class RISCVAsmBackend : public MCAsmBackend {
+protected:
   const MCSubtargetInfo &STI;
   uint8_t OSABI;
   bool Is64Bit;
diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCAsmInfo.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCAsmInfo.cpp
index e75bc521d47ca..4b9402391fe2c 100644
--- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCAsmInfo.cpp
+++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCAsmInfo.cpp
@@ -47,3 +47,16 @@ const MCExpr *RISCVMCAsmInfo::getExprForFDESymbol(const MCSymbol *Sym,
   assert(Encoding & dwarf::DW_EH_PE_sdata4 && "Unexpected encoding");
   return RISCVMCExpr::create(ME, ELF::R_RISCV_32_PCREL, Ctx);
 }
+
+RISCVMCAsmInfoDarwin::RISCVMCAsmInfoDarwin() {
+  CodePointerSize = 4;
+  PrivateGlobalPrefix = "L";
+  PrivateLabelPrefix = "L";
+  SeparatorString = "%%";
+  CommentString = ";";
+  AlignmentIsInBytes = false;
+  SupportsDebugInformation = true;
+  ExceptionsType = ExceptionHandling::DwarfCFI;
+  Data16bitsDirective = "\t.half\t";
+  Data32bitsDirective = "\t.word\t";
+}
diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCAsmInfo.h b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCAsmInfo.h
index bceeb1256471d..73271f6278f5f 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/MCAsmInfoDarwin.h"
 #include "llvm/MC/MCAsmInfoELF.h"
 
 namespace llvm {
@@ -28,6 +29,11 @@ class RISCVMCAsmInfo : public MCAsmInfoELF {
                                     MCStreamer &Streamer) const override;
 };
 
+class RISCVMCAsmInfoDarwin : public MCAsmInfoDarwin {
+public:
+  explicit RISCVMCAsmInfoDarwin();
+};
+
 } // namespace llvm
 
 #endif
diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCTargetDesc.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCTargetDesc.cpp
index d1bc6aa9a1e33..9d2caa1106ef5 100644
--- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCTargetDesc.cpp
+++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCTargetDesc.cpp
@@ -58,7 +58,11 @@ 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 = nullptr;
+  if (TT.isOSBinFormatELF())
+    MAI = new RISCVMCAsmInfo(TT);
+  else if (TT.isOSBinFormatMachO())
+    MAI = new RISCVMCAsmInfoDarwin();
 
   unsigned SP = MRI.getDwarfRegNum(RISCV::X2, true);
   MCCFIInstruction Inst = MCCFIInstruction::cfiDefCfa(nullptr, SP, 0);
diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCTargetDesc.h b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCTargetDesc.h
index bdee7ed4f011e..2a4afdb05d0f1 100644
--- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCTargetDesc.h
+++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCTargetDesc.h
@@ -36,6 +36,9 @@ MCAsmBackend *createRISCVAsmBackend(const Target &T, const MCSubtargetInfo &STI,
 
 std::unique_ptr<MCObjectTargetWriter> createRISCVELFObjectWriter(uint8_t OSABI,
                                                                  bool Is64Bit);
+std::unique_ptr<MCObjectTargetWriter>
+createRISCVMachObjectWriter(uint32_t CPUType, uint32_t CPUSubtype);
+
 } // namespace llvm
 
 // Defines symbolic names for RISC-V registers.
diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMachObjectWriter.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMachObjectWriter.cpp
new file mode 100644
index 0000000000000..aa1f6122f6992
--- /dev/null
+++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMachObjectWriter.cpp
@@ -0,0 +1,57 @@
+//===-- RISCVMachObjectWriter.cpp - RISC-V Mach Object Writer -------------===//
+//
+// 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/RISCVMCExpr.h"
+#include "MCTargetDesc/RISCVMCTargetDesc.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/BinaryFormat/MachO.h"
+#include "llvm/MC/MCAsmInfo.h"
+// #include "llvm/MC/MCAsmLayout.h"
+#include "llvm/MC/MCAssembler.h"
+#include "llvm/MC/MCContext.h"
+#include "llvm/MC/MCExpr.h"
+#include "llvm/MC/MCFixup.h"
+#include "llvm/MC/MCFragment.h"
+#include "llvm/MC/MCMachObjectWriter.h"
+#include "llvm/MC/MCSection.h"
+#include "llvm/MC/MCSectionMachO.h"
+#include "llvm/MC/MCSymbol.h"
+#include "llvm/MC/MCValue.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/MathExtras.h"
+#include <cassert>
+#include <cstdint>
+
+using namespace llvm;
+
+namespace {
+
+class RISCVMachObjectWriter : public MCMachObjectTargetWriter {
+public:
+  RISCVMachObjectWriter(uint32_t CPUType, uint32_t CPUSubtype)
+      : MCMachObjectTargetWriter(false, CPUType, CPUSubtype) {}
+
+  void recordRelocation(MachObjectWriter *Writer, MCAssembler &Asm,
+                        const MCFragment *Fragment, const MCFixup &Fixup,
+                        MCValue Target, uint64_t &FixedValue) override;
+};
+
+} // end anonymous namespace
+
+void RISCVMachObjectWriter::recordRelocation(
+    MachObjectWriter *Writer, MCAssembler &Asm, const MCFragment *Fragment,
+    const MCFixup &Fixup, MCValue Target, uint64_t &FixedValue) {
+  llvm_unreachable("unimplemented");
+}
+
+std::unique_ptr<MCObjectTargetWriter>
+llvm::createRISCVMachObjectWriter(uint32_t CPUType, uint32_t CPUSubtype) {
+  return std::make_unique<RISCVMachObjectWriter>(CPUType, CPUSubtype);
+}
diff --git a/llvm/lib/Target/RISCV/RISCVTargetMachine.cpp b/llvm/lib/Target/RISCV/RISCVTargetMachine.cpp
index 15dd4d57727dd..779a2bde1166a 100644
--- a/llvm/lib/Target/RISCV/RISCVTargetMachine.cpp
+++ b/llvm/lib/Target/RISCV/RISCVTargetMachine.cpp
@@ -156,6 +156,9 @@ extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeRISCVTarget() {
 static StringRef computeDataLayout(const Triple &TT,
                                    const TargetOptions &Options) {
   StringRef ABIName = Options.MCOptions.getABIName();
+  if (TT.isOSBinFormatMachO())
+    return "e-m:o-p:32:32-i64:64-n32-S128";
+
   if (TT.isArch64Bit()) {
     if (ABIName == "lp64e")
       return "e-m:e-p:64:64-i64:64-i128:128-n32:64-S64";
@@ -175,6 +178,15 @@ static Reloc::Model getEffectiveRelocModel(const Triple &TT,
   return RM.value_or(Reloc::Static);
 }
 
+static std::unique_ptr<TargetLoweringObjectFile> createTLOF(const Triple &TT) {
+  if (TT.isOSBinFormatELF())
+    return std::make_unique<RISCVELFTargetObjectFile>();
+  else if (TT.isOSBinFormatMachO())
+    return std::make_unique<TargetLoweringObjectFileMachO>();
+  else
+    return std::unique_ptr<TargetLoweringObjectFile>();
+}
+
 RISCVTargetMachine::RISCVTargetMachine(const Target &T, const Triple &TT,
                                        StringRef CPU, StringRef FS,
                                        const TargetOptions &Options,
@@ -184,7 +196,7 @@ RISCVTargetMachine::RISCVTargetMachine(const Target &T, const Triple &TT,
     : CodeGenTargetMachineImpl(T, computeDataLayout(TT, Options), TT, CPU, FS,
                                Options, getEffectiveRelocModel(TT, RM),
                                getEffectiveCodeModel(CM, CodeModel::Small), OL),
-      TLOF(std::make_unique<RISCVELFTargetObjectFile>()) {
+      TLOF(createTLOF(TT)) {
   initAsmInfo();
 
   // RISC-V supports the MachineOutliner.
diff --git a/llvm/test/CodeGen/RISCV/riscv-macho.ll b/llvm/test/CodeGen/RISCV/riscv-macho.ll
new file mode 100644
index 0000000000000..19d5fc026bbee
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/riscv-macho.ll
@@ -0,0 +1,13 @@
+; RUN: llc -mtriple=riscv32-apple-macho %s -o - | FileCheck %s
+; RUN: llc -mtriple=riscv32-apple-macho -filetype=obj %s -o %t.o
+; RUN: llvm-objdump -d %t.o | FileCheck %s --check-prefix=CHECK-OBJ
+
+; CHECK-LABEL: _main:
+; CHECK: li a0, 0
+; CHECK: ret
+
+; CHECK-OBJ: li a0, 0
+; CHECK-OBJ: ret
+define i32 @main() nounwind {
+  ret i32 0
+}
diff --git a/llvm/test/MC/RISCV/riscv-macho.s b/llvm/test/MC/RISCV/riscv-macho.s
new file mode 100644
index 0000000000000..f2cec7bf08ebb
--- /dev/null
+++ b/llvm/test/MC/RISCV/riscv-macho.s
@@ -0,0 +1,26 @@
+; RUN: llvm-mc -triple riscv32-apple-macho %s -o - | FileCheck %s
+; RUN: llvm-mc -triple riscv32-apple-macho -filetype=obj %s -o %t.o
+; RUN: llvm-objdump -d %t.o | FileCheck %s --check-prefix=CHECK-DIS
+; RUN: llvm-nm %t.o | FileCheck %s --check-prefix=CHECK-SYMS
+
+        nop
+        .half 42
+        .word 42
+Lfoo:
+lfoo:
+foo:
+
+; CHECK: nop
+; CHECK: .half 42
+; CHECK: .word 42
+
+; CHECK-DIS: file format mach-o 32-bit risc-v
+; CHECK-DIS: Disassembly of section __TEXT,__text:
+; CHECK-DIS: nop
+; CHECK-DIS: 002a <unknown>
+; CHECK-DIS: 002a <unknown>
+; CHECK-DIS: 0000 <unknown>
+
+; CHECK-SYMS-NOT: Lfoo
+; CHECK-SYMS: foo
+; CHECK-SYMS: lfoo