https://github.com/LunaTheFoxgirl created 
https://github.com/llvm/llvm-project/pull/223990

This PR adds support for the O64 ABI which sees use in console homebrew (eg. 
N64), convention was popularized by SGI.

>From 51404516227ebe3faceaef9f01afce05dff58b2f Mon Sep 17 00:00:00 2001
From: LunaTheFoxgirl <[email protected]>
Date: Fri, 5 Jun 2026 07:07:15 +0200
Subject: [PATCH 1/2] Add o64 ABI to MIPS

---
 clang/lib/Basic/Targets/Mips.cpp              | 11 +++++++---
 clang/lib/Basic/Targets/Mips.h                | 22 +++++++++++++++++--
 .../Target/Mips/MCTargetDesc/MipsABIInfo.cpp  | 15 +++++++++++--
 .../Target/Mips/MCTargetDesc/MipsABIInfo.h    |  7 ++++--
 .../Mips/MCTargetDesc/MipsMCAsmInfo.cpp       |  4 ++--
 llvm/lib/Target/Mips/MipsRegisterInfo.cpp     | 22 +++++++++++++++----
 llvm/lib/Target/Mips/MipsSubtarget.cpp        |  5 +++--
 llvm/lib/Target/Mips/MipsSubtarget.h          |  1 +
 llvm/lib/TargetParser/TargetDataLayout.cpp    |  8 ++++---
 9 files changed, 75 insertions(+), 20 deletions(-)

diff --git a/clang/lib/Basic/Targets/Mips.cpp b/clang/lib/Basic/Targets/Mips.cpp
index 76c9081567053..2531aa0074d06 100644
--- a/clang/lib/Basic/Targets/Mips.cpp
+++ b/clang/lib/Basic/Targets/Mips.cpp
@@ -112,6 +112,10 @@ void MipsTargetInfo::getTargetDefines(const LangOptions 
&Opts,
     Builder.defineMacro("__mips_o32");
     Builder.defineMacro("_ABIO32", "1");
     Builder.defineMacro("_MIPS_SIM", "_ABIO32");
+  } else if (ABI == "o64") {
+    Builder.defineMacro("__mips_o64");
+    Builder.defineMacro("_ABIO64", "4");
+    Builder.defineMacro("_MIPS_SIM", "_ABIO64");
   } else if (ABI == "n32") {
     Builder.defineMacro("__mips_n32");
     Builder.defineMacro("_ABIN32", "2");
@@ -219,7 +223,7 @@ void MipsTargetInfo::getTargetDefines(const LangOptions 
&Opts,
   // found in 64-bit processors. In the case of O32 on a 64-bit processor,
   // the instructions exist but using them violates the ABI since they
   // require 64-bit GPRs and O32 only supports 32-bit GPRs.
-  if (ABI == "n32" || ABI == "n64")
+  if (ABI == "o64" || ABI == "n32" || ABI == "n64")
     Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8");
 }
 
@@ -241,6 +245,7 @@ MipsTargetInfo::getTargetBuiltins() const {
 unsigned MipsTargetInfo::getUnwindWordWidth() const {
   return llvm::StringSwitch<unsigned>(ABI)
       .Case("o32", 32)
+      .Case("o64", 64)
       .Case("n32", 64)
       .Case("n64", 64)
       .Default(getPointerWidth(LangAS::Default));
@@ -254,7 +259,7 @@ bool MipsTargetInfo::validateTarget(DiagnosticsEngine 
&Diags) const {
   }
 
   // 64-bit ABI's require 64-bit CPU's.
-  if (!processorSupportsGPR64() && (ABI == "n32" || ABI == "n64")) {
+  if (!processorSupportsGPR64() && (ABI == "o64" || ABI == "n32" || ABI == 
"n64")) {
     Diags.Report(diag::err_target_unsupported_abi) << ABI << CPU;
     return false;
   }
@@ -297,7 +302,7 @@ bool MipsTargetInfo::validateTarget(DiagnosticsEngine 
&Diags) const {
   }
   // Option -mmsa permitted on Mips32 iff revision 2 or higher is present
   if (HasMSA && (CPU == "mips1" || CPU == "mips2" || getISARev() < 2) &&
-      ABI == "o32") {
+      (ABI == "o32" || ABI == "o64")) {
     Diags.Report(diag::err_mips_fp64_req) << "-mmsa";
     return false;
   }
diff --git a/clang/lib/Basic/Targets/Mips.h b/clang/lib/Basic/Targets/Mips.h
index 4c09390c3c6d5..43907b3462116 100644
--- a/clang/lib/Basic/Targets/Mips.h
+++ b/clang/lib/Basic/Targets/Mips.h
@@ -90,6 +90,11 @@ class LLVM_LIBRARY_VISIBILITY MipsTargetInfo : public 
TargetInfo {
       ABI = Name;
       return true;
     }
+    if (Name == "o64") {
+      setO64ABITypes();
+      ABI = Name;
+      return true;
+    }
 
     if (Name == "n32") {
       setN32ABITypes();
@@ -117,6 +122,19 @@ class LLVM_LIBRARY_VISIBILITY MipsTargetInfo : public 
TargetInfo {
     SuitableAlign = 64;
   }
 
+  void setO64ABITypes() {
+    Int64Type = SignedLongLong;
+    IntMaxType = Int64Type;
+    LongDoubleFormat = &llvm::APFloat::IEEEquad();
+    LongDoubleWidth = LongDoubleAlign = 128;
+    LongWidth = LongAlign = 64;
+    MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 64;
+    PointerWidth = PointerAlign = 64;
+    PtrDiffType = IntPtrType = SignedLong;
+    SizeType = UnsignedLong;
+    SuitableAlign = 128;
+  }
+
   void setN32N64ABITypes() {
     LongDoubleWidth = LongDoubleAlign = 128;
     LongDoubleFormat = &llvm::APFloat::IEEEquad();
@@ -416,13 +434,13 @@ class LLVM_LIBRARY_VISIBILITY MipsTargetInfo : public 
TargetInfo {
         {{"gp"}, "$28"}, {{"sp", "$sp"}, "$29"}, {{"fp", "$fp"}, "$30"},
         {{"ra"}, "$31"}
     };
-    if (ABI == "o32")
+    if (ABI == "o64" || ABI == "o32")
       return llvm::ArrayRef(O32RegAliases);
     return llvm::ArrayRef(NewABIRegAliases);
   }
 
   bool hasInt128Type() const override {
-    return (ABI == "n32" || ABI == "n64") || getTargetOpts().ForceEnableInt128;
+    return (ABI == "o64" || ABI == "n32" || ABI == "n64") || 
getTargetOpts().ForceEnableInt128;
   }
 
   unsigned getUnwindWordWidth() const override;
diff --git a/llvm/lib/Target/Mips/MCTargetDesc/MipsABIInfo.cpp 
b/llvm/lib/Target/Mips/MCTargetDesc/MipsABIInfo.cpp
index 59c8e7c72224e..281522d66ff3f 100644
--- a/llvm/lib/Target/Mips/MCTargetDesc/MipsABIInfo.cpp
+++ b/llvm/lib/Target/Mips/MCTargetDesc/MipsABIInfo.cpp
@@ -27,6 +27,7 @@ cl::opt<bool>
 
 namespace {
 static const MCPhysReg O32IntRegs[4] = {Mips::A0, Mips::A1, Mips::A2, 
Mips::A3};
+static const MCPhysReg O64IntRegs[4] = {Mips::A0_64, Mips::A1_64, Mips::A2_64, 
Mips::A3_64};
 
 static const MCPhysReg Mips64IntRegs[8] = {
     Mips::A0_64, Mips::A1_64, Mips::A2_64, Mips::A3_64,
@@ -36,6 +37,8 @@ static const MCPhysReg Mips64IntRegs[8] = {
 ArrayRef<MCPhysReg> MipsABIInfo::GetByValArgRegs() const {
   if (IsO32())
     return ArrayRef(O32IntRegs);
+  if (IsO64())
+    return ArrayRef(O64IntRegs);
   if (IsN32() || IsN64())
     return ArrayRef(Mips64IntRegs);
   llvm_unreachable("Unhandled ABI");
@@ -48,13 +51,19 @@ ArrayRef<MCPhysReg> MipsABIInfo::getVarArgRegs(bool 
isGP64bit) const {
     else
       return ArrayRef(O32IntRegs);
   }
+  if (IsO64()) {
+    if (isGP64bit)
+      return ArrayRef(Mips64IntRegs);
+    else
+      return ArrayRef(O64IntRegs);
+  }
   if (IsN32() || IsN64())
     return ArrayRef(Mips64IntRegs);
   llvm_unreachable("Unhandled ABI");
 }
 
 unsigned MipsABIInfo::GetCalleeAllocdArgSizeInBytes(CallingConv::ID CC) const {
-  if (IsO32())
+  if (IsO32() || IsO64())
     return CC != CallingConv::Fast ? 16 : 0;
   if (IsN32() || IsN64())
     return 0;
@@ -63,6 +72,8 @@ unsigned 
MipsABIInfo::GetCalleeAllocdArgSizeInBytes(CallingConv::ID CC) const {
 
 MipsABIInfo MipsABIInfo::computeTargetABI(const Triple &TT, StringRef ABIName) 
{
   if (ABIName.starts_with("o32"))
+    return MipsABIInfo::O64();
+  if (ABIName.starts_with("o64"))
     return MipsABIInfo::O32();
   if (ABIName.starts_with("n32"))
     return MipsABIInfo::N32();
@@ -129,5 +140,5 @@ unsigned MipsABIInfo::GetEhDataReg(unsigned I) const {
     Mips::A0_64, Mips::A1_64, Mips::A2_64, Mips::A3_64
   };
 
-  return IsN64() ? EhDataReg64[I] : EhDataReg[I];
+  return (IsABI64()) ? EhDataReg64[I] : EhDataReg[I];
 }
diff --git a/llvm/lib/Target/Mips/MCTargetDesc/MipsABIInfo.h 
b/llvm/lib/Target/Mips/MCTargetDesc/MipsABIInfo.h
index d8003d2fcc164..e1ce417c228a4 100644
--- a/llvm/lib/Target/Mips/MCTargetDesc/MipsABIInfo.h
+++ b/llvm/lib/Target/Mips/MCTargetDesc/MipsABIInfo.h
@@ -21,7 +21,7 @@ class StringRef;
 
 class MipsABIInfo {
 public:
-  enum class ABI { Unknown, O32, N32, N64 };
+  enum class ABI { Unknown, O32, O64, N32, N64 };
 
 protected:
   ABI ThisABI;
@@ -31,14 +31,17 @@ class MipsABIInfo {
 
   static MipsABIInfo Unknown() { return MipsABIInfo(ABI::Unknown); }
   static MipsABIInfo O32() { return MipsABIInfo(ABI::O32); }
+  static MipsABIInfo O64() { return MipsABIInfo(ABI::O64); }
   static MipsABIInfo N32() { return MipsABIInfo(ABI::N32); }
   static MipsABIInfo N64() { return MipsABIInfo(ABI::N64); }
   static MipsABIInfo computeTargetABI(const Triple &TT, StringRef ABIName);
 
   bool IsKnown() const { return ThisABI != ABI::Unknown; }
   bool IsO32() const { return ThisABI == ABI::O32; }
+  bool IsO64() const { return ThisABI == ABI::O64; }
   bool IsN32() const { return ThisABI == ABI::N32; }
   bool IsN64() const { return ThisABI == ABI::N64; }
+  bool IsABI64() const { return ThisABI == ABI::N64 || ThisABI == ABI::O64; }
   ABI GetEnumValue() const { return ThisABI; }
 
   /// The registers to use for byval arguments.
@@ -69,7 +72,7 @@ class MipsABIInfo {
   unsigned GetPtrSubuOp() const;
   unsigned GetPtrAndOp() const;
   unsigned GetGPRMoveOp() const;
-  inline bool ArePtrs64bit() const { return IsN64(); }
+  inline bool ArePtrs64bit() const { return IsO64() || IsN64(); }
   inline bool AreGprs64bit() const { return IsN32() || IsN64(); }
 
   unsigned GetEhDataReg(unsigned I) const;
diff --git a/llvm/lib/Target/Mips/MCTargetDesc/MipsMCAsmInfo.cpp 
b/llvm/lib/Target/Mips/MCTargetDesc/MipsMCAsmInfo.cpp
index dbb0af75f3651..762595ab323cd 100644
--- a/llvm/lib/Target/Mips/MCTargetDesc/MipsMCAsmInfo.cpp
+++ b/llvm/lib/Target/Mips/MCTargetDesc/MipsMCAsmInfo.cpp
@@ -28,10 +28,10 @@ MipsELFMCAsmInfo::MipsELFMCAsmInfo(const Triple &TheTriple,
   MipsABIInfo ABI =
       MipsABIInfo::computeTargetABI(TheTriple, Options.getABIName());
 
-  if (TheTriple.isMIPS64() && !ABI.IsN32())
+  if (TheTriple.isMIPS64() && !(ABI.IsN32() || ABI.IsO64()))
     CodePointerSize = CalleeSaveStackSlotSize = 8;
 
-  if (ABI.IsO32())
+  if (ABI.IsO32() || ABI.IsO64())
     InternalSymbolPrefix = "$";
   else if (ABI.IsN32() || ABI.IsN64())
     InternalSymbolPrefix = ".L";
diff --git a/llvm/lib/Target/Mips/MipsRegisterInfo.cpp 
b/llvm/lib/Target/Mips/MipsRegisterInfo.cpp
index 948d4db8585db..540e2f67b8055 100644
--- a/llvm/lib/Target/Mips/MipsRegisterInfo.cpp
+++ b/llvm/lib/Target/Mips/MipsRegisterInfo.cpp
@@ -106,16 +106,30 @@ MipsRegisterInfo::getCalleeSavedRegs(const 
MachineFunction *MF) const {
   }
 
   // O32 ABI
+  if (Subtarget.isABI_O32()) {
+    if (Subtarget.isSingleFloat())
+      return CSR_O32_SingleFloat_SaveList;
+
+    if (Subtarget.isFP64bit())
+      return CSR_O32_FP64_SaveList;
+
+    if (Subtarget.isFPXX())
+      return CSR_O32_FPXX_SaveList;
+
+    return CSR_O32_SaveList;
+  }
+
+  // O64 ABI
   if (Subtarget.isSingleFloat())
-    return CSR_O32_SingleFloat_SaveList;
+    return CSR_O64_SingleFloat_SaveList;
 
   if (Subtarget.isFP64bit())
-    return CSR_O32_FP64_SaveList;
+    return CSR_O64_FP64_SaveList;
 
   if (Subtarget.isFPXX())
-    return CSR_O32_FPXX_SaveList;
+    return CSR_O64_FPXX_SaveList;
 
-  return CSR_O32_SaveList;
+  return CSR_O64_SaveList;
 }
 
 const uint32_t *
diff --git a/llvm/lib/Target/Mips/MipsSubtarget.cpp 
b/llvm/lib/Target/Mips/MipsSubtarget.cpp
index 287a4cbbf5af4..356601c33f650 100644
--- a/llvm/lib/Target/Mips/MipsSubtarget.cpp
+++ b/llvm/lib/Target/Mips/MipsSubtarget.cpp
@@ -265,14 +265,14 @@ MipsSubtarget::initializeSubtargetDependencies(StringRef 
CPU, StringRef FS,
 
   if (StackAlignOverride)
     stackAlignment = *StackAlignOverride;
-  else if (isABI_N32() || isABI_N64())
+  else if (isABI_O64() || isABI_N32() || isABI_N64())
     stackAlignment = Align(16);
   else {
     assert(isABI_O32() && "Unknown ABI for stack alignment!");
     stackAlignment = Align(8);
   }
 
-  if ((isABI_N32() || isABI_N64()) && !isGP64bit())
+  if ((isABI_O64() || isABI_N32() || isABI_N64()) && !isGP64bit())
     reportFatalUsageError("64-bit code requested on a subtarget that doesn't "
                           "support it!");
 
@@ -292,6 +292,7 @@ Reloc::Model MipsSubtarget::getRelocationModel() const {
 bool MipsSubtarget::isABI_N64() const { return getABI().IsN64(); }
 bool MipsSubtarget::isABI_N32() const { return getABI().IsN32(); }
 bool MipsSubtarget::isABI_O32() const { return getABI().IsO32(); }
+bool MipsSubtarget::isABI_O64() const { return getABI().IsO64(); }
 const MipsABIInfo &MipsSubtarget::getABI() const { return TM.getABI(); }
 
 const SelectionDAGTargetInfo *MipsSubtarget::getSelectionDAGInfo() const {
diff --git a/llvm/lib/Target/Mips/MipsSubtarget.h 
b/llvm/lib/Target/Mips/MipsSubtarget.h
index 3acfaa82965ab..dcd9420d69940 100644
--- a/llvm/lib/Target/Mips/MipsSubtarget.h
+++ b/llvm/lib/Target/Mips/MipsSubtarget.h
@@ -249,6 +249,7 @@ class MipsSubtarget : public MipsGenSubtargetInfo {
   bool isABI_N64() const;
   bool isABI_N32() const;
   bool isABI_O32() const;
+  bool isABI_O64() const;
   const MipsABIInfo &getABI() const;
   bool isABI_FPXX() const { return isABI_O32() && IsFPXX; }
 
diff --git a/llvm/lib/TargetParser/TargetDataLayout.cpp 
b/llvm/lib/TargetParser/TargetDataLayout.cpp
index a2125eeb82932..49668a47a71cb 100644
--- a/llvm/lib/TargetParser/TargetDataLayout.cpp
+++ b/llvm/lib/TargetParser/TargetDataLayout.cpp
@@ -151,7 +151,7 @@ static std::string computeM68kDataLayout(const Triple &TT) {
 }
 
 namespace {
-enum class MipsABI { Unknown, O32, N32, N64 };
+enum class MipsABI { Unknown, O32, O64, N32, N64 };
 }
 
 // FIXME: This duplicates MipsABIInfo::computeTargetABI, but duplicating this 
is
@@ -161,6 +161,8 @@ enum class MipsABI { Unknown, O32, N32, N64 };
 static MipsABI getMipsABI(const Triple &TT, StringRef ABIName) {
   if (ABIName.starts_with("o32"))
     return MipsABI::O32;
+  if (ABIName.starts_with("o64"))
+    return MipsABI::O64;
   if (ABIName.starts_with("n32"))
     return MipsABI::N32;
   if (ABIName.starts_with("n64"))
@@ -184,7 +186,7 @@ static std::string computeMipsDataLayout(const Triple &TT, 
StringRef ABIName) {
   else
     Ret += "E";
 
-  if (ABI == MipsABI::O32)
+  if (ABI == MipsABI::O32 || ABI == MipsABI::O64)
     Ret += "-m:m";
   else
     Ret += "-m:e";
@@ -200,7 +202,7 @@ static std::string computeMipsDataLayout(const Triple &TT, 
StringRef ABIName) {
   // 32 bit registers are always available and the stack is at least 64 bit
   // aligned. On N64 64 bit registers are also available and the stack is
   // 128 bit aligned.
-  if (ABI == MipsABI::N64 || ABI == MipsABI::N32)
+  if (ABI == MipsABI::O64 || ABI == MipsABI::N64 || ABI == MipsABI::N32)
     Ret += "-i128:128-n32:64-S128";
   else
     Ret += "-n32-S64";

>From 78edbe46ff9f2a21a4bb472bc849297ed833aa9a Mon Sep 17 00:00:00 2001
From: LunaTheFoxgirl <[email protected]>
Date: Wed, 16 Sep 2026 13:59:14 +0200
Subject: [PATCH 2/2] Implement more of O64 ABI

---
 .../Target/Mips/AsmParser/MipsAsmParser.cpp   |   2 +
 .../Target/Mips/MCTargetDesc/MipsABIInfo.cpp  |   4 +-
 llvm/lib/Target/Mips/MipsAsmPrinter.cpp       |   1 +
 llvm/lib/Target/Mips/MipsCallingConv.td       |  53 ++++++
 llvm/lib/Target/Mips/MipsFastISel.cpp         |  17 ++
 llvm/lib/Target/Mips/MipsISelLowering.cpp     | 153 ++++++++++++++++++
 llvm/lib/Target/Mips/MipsRegisterInfo.cpp     |  27 ++--
 llvm/lib/Target/Mips/MipsSubtarget.cpp        |   4 +-
 llvm/lib/TargetParser/TargetDataLayout.cpp    |   2 +-
 9 files changed, 245 insertions(+), 18 deletions(-)

diff --git a/llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp 
b/llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp
index 928bd03b57c60..17234925199f2 100644
--- a/llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp
+++ b/llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp
@@ -12,6 +12,7 @@
 #include "MCTargetDesc/MipsMCAsmInfo.h"
 #include "MCTargetDesc/MipsMCTargetDesc.h"
 #include "MCTargetDesc/MipsTargetStreamer.h"
+#include "MipsRegisterInfo.h"
 #include "TargetInfo/MipsTargetInfo.h"
 #include "llvm/ADT/APFloat.h"
 #include "llvm/ADT/SmallVector.h"
@@ -598,6 +599,7 @@ class MipsAsmParser : public MCTargetAsmParser {
   bool isABI_N32() const { return ABI.IsN32(); }
   bool isABI_N64() const { return ABI.IsN64(); }
   bool isABI_O32() const { return ABI.IsO32(); }
+  bool isABI_O64() const { return ABI.IsO64(); }
   bool isABI_FPXX() const {
     return getSTI().hasFeature(Mips::FeatureFPXX);
   }
diff --git a/llvm/lib/Target/Mips/MCTargetDesc/MipsABIInfo.cpp 
b/llvm/lib/Target/Mips/MCTargetDesc/MipsABIInfo.cpp
index 281522d66ff3f..c9b24fb959387 100644
--- a/llvm/lib/Target/Mips/MCTargetDesc/MipsABIInfo.cpp
+++ b/llvm/lib/Target/Mips/MCTargetDesc/MipsABIInfo.cpp
@@ -72,9 +72,9 @@ unsigned 
MipsABIInfo::GetCalleeAllocdArgSizeInBytes(CallingConv::ID CC) const {
 
 MipsABIInfo MipsABIInfo::computeTargetABI(const Triple &TT, StringRef ABIName) 
{
   if (ABIName.starts_with("o32"))
-    return MipsABIInfo::O64();
-  if (ABIName.starts_with("o64"))
     return MipsABIInfo::O32();
+  if (ABIName.starts_with("o64"))
+    return MipsABIInfo::O64();
   if (ABIName.starts_with("n32"))
     return MipsABIInfo::N32();
   if (ABIName.starts_with("n64"))
diff --git a/llvm/lib/Target/Mips/MipsAsmPrinter.cpp 
b/llvm/lib/Target/Mips/MipsAsmPrinter.cpp
index 715b96e52e6c8..5411d226a99cf 100644
--- a/llvm/lib/Target/Mips/MipsAsmPrinter.cpp
+++ b/llvm/lib/Target/Mips/MipsAsmPrinter.cpp
@@ -386,6 +386,7 @@ void MipsAsmPrinter::emitFrameDirective() {
 const char *MipsAsmPrinter::getCurrentABIString() const {
   switch (static_cast<MipsTargetMachine &>(TM).getABI().GetEnumValue()) {
   case MipsABIInfo::ABI::O32:  return "abi32";
+  case MipsABIInfo::ABI::O64:  return "abiO64";
   case MipsABIInfo::ABI::N32:  return "abiN32";
   case MipsABIInfo::ABI::N64:  return "abi64";
   default: llvm_unreachable("Unknown Mips ABI");
diff --git a/llvm/lib/Target/Mips/MipsCallingConv.td 
b/llvm/lib/Target/Mips/MipsCallingConv.td
index 748162525b091..dc39cf08ac9b3 100644
--- a/llvm/lib/Target/Mips/MipsCallingConv.td
+++ b/llvm/lib/Target/Mips/MipsCallingConv.td
@@ -107,6 +107,49 @@ def CC_MipsO32_FP : CallingConv<[
   CCIfSubtarget<"isFP64bit()", CCDelegateTo<CC_MipsO32_FP64>>
 ]>;
 
+//===----------------------------------------------------------------------===//
+// Mips O64 Calling Convention
+//===----------------------------------------------------------------------===//
+
+def CC_MipsO64 : CallingConv<[
+  // Promote i8/i16 arguments to i32.
+  CCIfType<[i1, i8, i16], CCPromoteToType<i32>>,
+
+  // Integer values get stored in stack slots that are 4 bytes in
+  // size and 8-byte aligned.
+  CCIfType<[i32, f32], CCAssignToStack<4, 8>>,
+
+  // Integer values get stored in stack slots that are 8 bytes in
+  // size and 8-byte aligned.
+  CCIfType<[i64, f64], CCAssignToStack<8, 8>>
+]>;
+
+// Only the return rules are defined here for O64. The rules for argument
+// passing are defined in MipsISelLowering.cpp.
+def RetCC_MipsO64 : CallingConv<[
+  // Promote i1/i8/i16 return values to i32.
+  CCIfType<[i1, i8, i16], CCPromoteToType<i32>>,
+
+  // i64 are returned in registers V0, V1, A0, A1, unless the original return
+  // type was a vector of floats.
+  CCIfOrigArgWasNotVectorFloat<CCIfType<[i64],
+                                        CCAssignToReg<[V0_64, V1_64, A0_64, 
A1_64]>>>,
+
+  // f32 are returned in registers F12, F13
+  CCIfType<[f32], CCAssignToReg<[F12, F13]>>,
+
+  // f64 are returned in registers D12, D13
+  CCIfType<[f64], CCAssignToReg<[D12_64, D13_64]>>,
+]>;
+
+def CC_MipsO64_FP32 : CustomCallingConv;
+def CC_MipsO64_FP64 : CustomCallingConv;
+
+def CC_MipsO64_FP : CallingConv<[
+  CCIfSubtargetNot<"isFP64bit()", CCDelegateTo<CC_MipsO64_FP32>>,
+  CCIfSubtarget<"isFP64bit()", CCDelegateTo<CC_MipsO64_FP64>>
+]>;
+
 
//===----------------------------------------------------------------------===//
 // Mips N32/64 Calling Convention
 
//===----------------------------------------------------------------------===//
@@ -284,11 +327,13 @@ def CC_Mips_FastCC : CallingConv<[
 def RetCC_Mips : CallingConv<[
   CCIfSubtarget<"isABI_N32()", CCDelegateTo<RetCC_MipsN>>,
   CCIfSubtarget<"isABI_N64()", CCDelegateTo<RetCC_MipsN>>,
+  CCIfSubtarget<"isABI_O64()", CCDelegateTo<RetCC_MipsO64>>,
   CCDelegateTo<RetCC_MipsO32>
 ]>;
 
 def CC_Mips_ByVal : CallingConv<[
   CCIfSubtarget<"isABI_O32()", CCIfByVal<CCPassByVal<4, 4>>>,
+  CCIfSubtarget<"isABI_O64()", CCIfByVal<CCPassByVal<4, 8>>>,
   CCIfByVal<CCPassByVal<8, 8>>
 ]>;
 
@@ -325,6 +370,7 @@ def CC_Mips_FixedArg : CallingConv<[
   CCIfCC<"CallingConv::Fast", CCDelegateTo<CC_Mips_FastCC>>,
 
   CCIfSubtarget<"isABI_O32()", CCIfSubtargetNot<"isGP64bit()", 
CCDelegateTo<CC_MipsO32_FP>>>,
+  CCIfSubtarget<"isABI_O64()", CCDelegateTo<CC_MipsO64_FP>>,
   CCDelegateTo<CC_MipsN>
 ]>;
 
@@ -332,6 +378,7 @@ def CC_Mips_VarArg : CallingConv<[
   CCIfByVal<CCDelegateTo<CC_Mips_ByVal>>,
 
   CCIfSubtarget<"isABI_O32()", CCDelegateTo<CC_MipsO32_FP>>,
+  CCIfSubtarget<"isABI_O64()", CCDelegateTo<CC_MipsO64_FP>>,
   CCDelegateTo<CC_MipsN_VarArg>
 ]>;
 
@@ -359,6 +406,12 @@ def CSR_O32_FP64 :
   CalleeSavedRegs<(add (decimate (sequence "D%u_64", 30, 20), 2), RA, FP,
                        (sequence "S%u", 7, 0))>;
 
+def CSR_O64 : CalleeSavedRegs<(add (sequence "D%u_64", 15, 10), RA_64, FP_64,
+                                   (sequence "S%u_64", 7, 0))>;
+
+def CSR_O64_SingleFloat : CalleeSavedRegs<(add(sequence "F%u", 31, 20), RA_64, 
FP_64,
+                              (sequence "S%u_64", 7, 0))>;
+
 def CSR_N32 : CalleeSavedRegs<(add(decimate(sequence "D%u_64", 30, 20), 2),
                   RA_64, FP_64, GP_64, (sequence "S%u_64", 7, 0))>;
 
diff --git a/llvm/lib/Target/Mips/MipsFastISel.cpp 
b/llvm/lib/Target/Mips/MipsFastISel.cpp
index 9645fb5293609..0d2b0756c3cec 100644
--- a/llvm/lib/Target/Mips/MipsFastISel.cpp
+++ b/llvm/lib/Target/Mips/MipsFastISel.cpp
@@ -285,9 +285,26 @@ static bool CC_MipsO32_FP64(unsigned ValNo, MVT ValVT, MVT 
LocVT,
   llvm_unreachable("should not be called");
 }
 
+
+static bool CC_MipsO64_FP32(unsigned ValNo, MVT ValVT, MVT LocVT,
+                            CCValAssign::LocInfo LocInfo,
+                            ISD::ArgFlagsTy ArgFlags, Type *OrigTy,
+                            CCState &State) {
+  llvm_unreachable("should not be called");
+}
+
+static bool CC_MipsO64_FP64(unsigned ValNo, MVT ValVT, MVT LocVT,
+                            CCValAssign::LocInfo LocInfo,
+                            ISD::ArgFlagsTy ArgFlags, Type *OrigTy,
+                            CCState &State) {
+  llvm_unreachable("should not be called");
+}
+
 #include "MipsGenCallingConv.inc"
 
 CCAssignFn *MipsFastISel::CCAssignFnForCall(CallingConv::ID CC) const {
+  if (getABI().IsO64())
+    return CC_MipsO64;
   return CC_MipsO32;
 }
 
diff --git a/llvm/lib/Target/Mips/MipsISelLowering.cpp 
b/llvm/lib/Target/Mips/MipsISelLowering.cpp
index 298b525e48cff..ac4aa085440e9 100644
--- a/llvm/lib/Target/Mips/MipsISelLowering.cpp
+++ b/llvm/lib/Target/Mips/MipsISelLowering.cpp
@@ -3138,6 +3138,158 @@ static bool CC_MipsO32_FP64(unsigned ValNo, MVT ValVT, 
MVT LocVT,
                                         ISD::ArgFlagsTy ArgFlags, Type *OrigTy,
                                         CCState &State);
 
+//===----------------------------------------------------------------------===//
+// TODO: Implement a generic logic using tblgen that can support this.
+// Mips O64 ABI rules:
+// ---
+// i64 - Passed in A0, A1, A2, A3 and stack
+// f32 - Only passed in f32 registers if no int reg has been used yet to hold
+//       an argument. Otherwise, passed in A1, A2, A3 and stack.
+// f64 - Only passed in two aliased f32 registers if no int reg has been used
+//       yet to hold an argument. Otherwise, use A2, A3 and stack. If A1 is
+//       not used, it must be shadowed. If only A3 is available, shadow it and
+//       go to stack.
+// vXiX - Received as scalarized i32s, passed in A0 - A3 and the stack.
+// vXf32 - Passed in either a pair of registers {A0, A1}, {A2, A3} or {A0 - A3}
+//         with the remainder spilled to the stack.
+// vXf64 - Passed in either {A0, A1, A2, A3} or {A2, A3} and in both cases
+//         spilling the remainder to the stack.
+//
+//  For vararg functions, all arguments are passed in A0, A1, A2, A3 and stack.
+//===----------------------------------------------------------------------===//
+
+static bool CC_MipsO64(unsigned ValNo, MVT ValVT, MVT LocVT,
+                       CCValAssign::LocInfo LocInfo, ISD::ArgFlagsTy ArgFlags,
+                       Type *OrigTy, CCState &State,
+                       ArrayRef<MCPhysReg> F64Regs) {
+  const MipsSubtarget &Subtarget = static_cast<const MipsSubtarget &>(
+      State.getMachineFunction().getSubtarget());
+
+  static const MCPhysReg IntRegs[] = { Mips::A0_64, Mips::A1_64, Mips::A2_64, 
Mips::A3_64 };
+  static const MCPhysReg Int32Regs[] = { Mips::A0, Mips::A1, Mips::A2, 
Mips::A3 };
+  static const MCPhysReg FloatVectorIntRegs[] = { Mips::A0_64, Mips::A2_64 };
+
+  // Do not process byval args here.
+  if (ArgFlags.isByVal())
+    return true;
+
+  // Promote i8 and i16
+  if (ArgFlags.isInReg() && !Subtarget.isLittle()) {
+    if (LocVT == MVT::i8 || LocVT == MVT::i16 || LocVT == MVT::i32) {
+      LocVT = MVT::i32;
+      if (ArgFlags.isSExt())
+        LocInfo = CCValAssign::SExtUpper;
+      else if (ArgFlags.isZExt())
+        LocInfo = CCValAssign::ZExtUpper;
+      else
+        LocInfo = CCValAssign::AExtUpper;
+    }
+  }
+
+  // Promote i8, i16
+  if (LocVT == MVT::i8 || LocVT == MVT::i16) {
+    LocVT = MVT::i32;
+    if (ArgFlags.isSExt())
+      LocInfo = CCValAssign::SExt;
+    else if (ArgFlags.isZExt())
+      LocInfo = CCValAssign::ZExt;
+    else
+      LocInfo = CCValAssign::AExt;
+  }
+
+  unsigned Reg;
+
+  // f32 and f64 are allocated in A0, A1, A2, A3 when either of the following
+  // is true: function is vararg, argument is 3rd or higher, there is previous
+  // argument which is not f32 or f64.
+  bool AllocateFloatsInIntReg = State.isVarArg() || ValNo > 1 ||
+                                State.getFirstUnallocated(F64Regs) != ValNo;
+  Align OrigAlign = ArgFlags.getNonZeroOrigAlign();
+  bool isVectorFloat = OrigTy->isVectorTy() && OrigTy->isFPOrFPVectorTy();
+
+  // The MIPS vector ABI for floats passes them in a pair of registers
+  if (ValVT == MVT::i32 && isVectorFloat) {
+    // This is the start of an vector that was scalarized into an unknown 
number
+    // of components. It doesn't matter how many there are. Allocate one of the
+    // notional 8 byte aligned registers which map onto the argument stack, and
+    // shadow the register lost to alignment requirements.
+    if (ArgFlags.isSplit()) {
+      Reg = State.AllocateReg(FloatVectorIntRegs);
+      if (Reg == Mips::A2_64)
+        State.AllocateReg(Mips::A1_64);
+      else if (Reg == 0)
+        State.AllocateReg(Mips::A3_64);
+    } else {
+      // If we're an intermediate component of the split, we can just attempt 
to
+      // allocate a register directly.
+      Reg = State.AllocateReg(IntRegs);
+    }
+  } else if (ValVT == MVT::i32 ||
+             (ValVT == MVT::f32 && AllocateFloatsInIntReg)) {
+    Reg = State.AllocateReg(Int32Regs);
+    LocVT = MVT::i32;
+  } else if (ValVT == MVT::i64 ||
+             (ValVT == MVT::f64 && AllocateFloatsInIntReg)) {
+    Reg = State.AllocateReg(IntRegs);
+    LocVT = MVT::i64;
+  } else if (ValVT == MVT::f64 && AllocateFloatsInIntReg) {
+    // Allocate int register and shadow next int register. If first
+    // available register is Mips::A1 or Mips::A3, shadow it too.
+    Reg = State.AllocateReg(IntRegs);
+    if (Reg) {
+      LocVT = MVT::i64;
+      State.addLoc(CCValAssign::getCustomReg(ValNo, ValVT, Reg, LocVT, 
LocInfo));
+      return false;
+    }
+  } else if (ValVT.isFloatingPoint() && !AllocateFloatsInIntReg) {
+    // we are guaranteed to find an available float register
+    if (ValVT == MVT::f32) {
+      Reg = State.AllocateReg(F64Regs);
+      // Shadow int register
+      State.AllocateReg(IntRegs);
+    } else {
+      Reg = State.AllocateReg(F64Regs);
+      // Shadow int registers
+      State.AllocateReg(IntRegs);
+    }
+  } else
+    llvm_unreachable("Cannot handle this ValVT.");
+
+  if (!Reg) {
+    unsigned Offset = State.AllocateStack(ValVT.getStoreSize(), OrigAlign);
+    State.addLoc(CCValAssign::getMem(ValNo, ValVT, Offset, LocVT, LocInfo));
+  } else
+    State.addLoc(CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, LocInfo));
+
+  return false;
+}
+
+static bool CC_MipsO64_FP32(unsigned ValNo, MVT ValVT, MVT LocVT,
+                            CCValAssign::LocInfo LocInfo,
+                            ISD::ArgFlagsTy ArgFlags, Type *OrigTy,
+                            CCState &State) {
+  static const MCPhysReg F64Regs[] = { Mips::D12_64, Mips::D13_64 };
+
+  return CC_MipsO64(ValNo, ValVT, LocVT, LocInfo, ArgFlags, OrigTy, State,
+                    F64Regs);
+}
+
+static bool CC_MipsO64_FP64(unsigned ValNo, MVT ValVT, MVT LocVT,
+                            CCValAssign::LocInfo LocInfo,
+                            ISD::ArgFlagsTy ArgFlags, Type *OrigTy,
+                            CCState &State) {
+  static const MCPhysReg F64Regs[] = { Mips::D12_64, Mips::D13_64 };
+
+  return CC_MipsO64(ValNo, ValVT, LocVT, LocInfo, ArgFlags, OrigTy, State,
+                    F64Regs);
+}
+
+[[maybe_unused]] static bool CC_MipsO64(unsigned ValNo, MVT ValVT, MVT LocVT,
+                                        CCValAssign::LocInfo LocInfo,
+                                        ISD::ArgFlagsTy ArgFlags, Type *OrigTy,
+                                        CCState &State);
+
+
 #include "MipsGenCallingConv.inc"
 
  CCAssignFn *MipsTargetLowering::CCAssignFnForCall() const{
@@ -3147,6 +3299,7 @@ static bool CC_MipsO32_FP64(unsigned ValNo, MVT ValVT, 
MVT LocVT,
  CCAssignFn *MipsTargetLowering::CCAssignFnForReturn() const{
    return RetCC_Mips;
  }
+
 
//===----------------------------------------------------------------------===//
 //                  Call Calling Convention Implementation
 
//===----------------------------------------------------------------------===//
diff --git a/llvm/lib/Target/Mips/MipsRegisterInfo.cpp 
b/llvm/lib/Target/Mips/MipsRegisterInfo.cpp
index 540e2f67b8055..d75b050fa6a3b 100644
--- a/llvm/lib/Target/Mips/MipsRegisterInfo.cpp
+++ b/llvm/lib/Target/Mips/MipsRegisterInfo.cpp
@@ -123,12 +123,6 @@ MipsRegisterInfo::getCalleeSavedRegs(const MachineFunction 
*MF) const {
   if (Subtarget.isSingleFloat())
     return CSR_O64_SingleFloat_SaveList;
 
-  if (Subtarget.isFP64bit())
-    return CSR_O64_FP64_SaveList;
-
-  if (Subtarget.isFPXX())
-    return CSR_O64_FPXX_SaveList;
-
   return CSR_O64_SaveList;
 }
 
@@ -153,16 +147,23 @@ MipsRegisterInfo::getCallPreservedMask(const 
MachineFunction &MF,
   }
 
   // O32 ABI
-  if (Subtarget.isSingleFloat())
-    return CSR_O32_SingleFloat_RegMask;
+  if (Subtarget.isABI_O32()) {
+    if (Subtarget.isSingleFloat())
+      return CSR_O32_SingleFloat_RegMask;
 
-  if (Subtarget.isFP64bit())
-    return CSR_O32_FP64_RegMask;
+    if (Subtarget.isFP64bit())
+      return CSR_O32_FP64_RegMask;
 
-  if (Subtarget.isFPXX())
-    return CSR_O32_FPXX_RegMask;
+    if (Subtarget.isFPXX())
+      return CSR_O32_FPXX_RegMask;
+
+    return CSR_O32_RegMask;
+  }
 
-  return CSR_O32_RegMask;
+  // O64 ABI
+  if (Subtarget.isSingleFloat())
+    return CSR_O64_SingleFloat_RegMask;
+  return CSR_O64_RegMask;
 }
 
 const uint32_t *MipsRegisterInfo::getMips16RetHelperMask() {
diff --git a/llvm/lib/Target/Mips/MipsSubtarget.cpp 
b/llvm/lib/Target/Mips/MipsSubtarget.cpp
index 356601c33f650..26cad4a7d5228 100644
--- a/llvm/lib/Target/Mips/MipsSubtarget.cpp
+++ b/llvm/lib/Target/Mips/MipsSubtarget.cpp
@@ -265,10 +265,10 @@ MipsSubtarget::initializeSubtargetDependencies(StringRef 
CPU, StringRef FS,
 
   if (StackAlignOverride)
     stackAlignment = *StackAlignOverride;
-  else if (isABI_O64() || isABI_N32() || isABI_N64())
+  else if (isABI_N32() || isABI_N64())
     stackAlignment = Align(16);
   else {
-    assert(isABI_O32() && "Unknown ABI for stack alignment!");
+    assert((isABI_O32() || isABI_O64()) && "Unknown ABI for stack alignment!");
     stackAlignment = Align(8);
   }
 
diff --git a/llvm/lib/TargetParser/TargetDataLayout.cpp 
b/llvm/lib/TargetParser/TargetDataLayout.cpp
index 49668a47a71cb..89a37e753acd0 100644
--- a/llvm/lib/TargetParser/TargetDataLayout.cpp
+++ b/llvm/lib/TargetParser/TargetDataLayout.cpp
@@ -192,7 +192,7 @@ static std::string computeMipsDataLayout(const Triple &TT, 
StringRef ABIName) {
     Ret += "-m:e";
 
   // Pointers are 32 bit on some ABIs.
-  if (ABI != MipsABI::N64)
+  if (ABI != MipsABI::N64 && ABI != MipsABI::O64)
     Ret += "-p:32:32";
 
   // 8 and 16 bit integers only need to have natural alignment, but try to

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to