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

>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/3] 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/3] 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

>From 45dd1636df63a354701176fbbf50c23483b0f121 Mon Sep 17 00:00:00 2001
From: LunaTheFoxgirl <[email protected]>
Date: Thu, 17 Sep 2026 20:19:19 +0200
Subject: [PATCH 3/3] Add R4300 Proc and infra

This also adds -mlong32 and -mlong64 options like GCC, however incomplete.
---
 clang/include/clang/Options/Options.td     |  4 +++
 clang/lib/Basic/Targets/Mips.cpp           | 22 +++++++++---
 clang/lib/Basic/Targets/Mips.h             | 40 +++++++++++++++++-----
 clang/lib/Driver/ToolChains/Arch/Mips.cpp  | 13 +++++++
 llvm/lib/Target/Mips/Mips.td               | 18 ++++++++--
 llvm/lib/Target/Mips/MipsSubtarget.cpp     | 26 ++++++++++++++
 llvm/lib/Target/Mips/MipsSubtarget.h       | 15 ++++++++
 llvm/lib/Target/Mips/MipsTargetMachine.cpp |  2 +-
 llvm/lib/TargetParser/TargetDataLayout.cpp |  8 +++--
 9 files changed, 130 insertions(+), 18 deletions(-)

diff --git a/clang/include/clang/Options/Options.td 
b/clang/include/clang/Options/Options.td
index 06461acdf216e..6ae7dafb061e6 100644
--- a/clang/include/clang/Options/Options.td
+++ b/clang/include/clang/Options/Options.td
@@ -6477,6 +6477,10 @@ def mfp64 : Flag<["-"], "mfp64">, 
Group<m_mips_Features_Group>,
   HelpText<"Use 64-bit floating point registers (MIPS only)">;
 def mfp32 : Flag<["-"], "mfp32">, Group<m_mips_Features_Group>,
   HelpText<"Use 32-bit floating point registers (MIPS only)">;
+def mlong32 : Flag<["-"], "mlong32">, Group<m_mips_Features_Group>,
+  HelpText<"Use 64-bit longs (MIPS only)">;
+def mlong64 : Flag<["-"], "mlong64">, Group<m_mips_Features_Group>,
+  HelpText<"Use 32-bit longs (MIPS only)">;
 def mgpopt : Flag<["-"], "mgpopt">, Group<m_mips_Features_Group>,
   HelpText<"Use GP relative accesses for symbols known to be in a small"
            " data section (MIPS)">;
diff --git a/clang/lib/Basic/Targets/Mips.cpp b/clang/lib/Basic/Targets/Mips.cpp
index 2531aa0074d06..d9917c93561bb 100644
--- a/clang/lib/Basic/Targets/Mips.cpp
+++ b/clang/lib/Basic/Targets/Mips.cpp
@@ -46,6 +46,7 @@ bool MipsTargetInfo::processorSupportsGPR64() const {
       .Case("mips64r6", true)
       .Case("octeon", true)
       .Case("octeon+", true)
+      .Case("r4300", true)
       .Case("r5900", true)
       .Case("i6400", true)
       .Case("i6500", true)
@@ -56,8 +57,8 @@ static constexpr llvm::StringLiteral ValidCPUNames[] = {
     {"mips1"},  {"mips2"},    {"mips3"},    {"mips4"},    {"mips5"},
     {"mips32"}, {"mips32r2"}, {"mips32r3"}, {"mips32r5"}, {"mips32r6"},
     {"mips64"}, {"mips64r2"}, {"mips64r3"}, {"mips64r5"}, {"mips64r6"},
-    {"octeon"}, {"octeon+"},  {"p5600"},    {"r5900"},    {"i6400"},
-    {"i6500"}};
+    {"octeon"}, {"octeon+"},  {"p5600"},    {"r4300"},    {"r5900"},
+    {"i6400"},  {"i6500"}};
 
 bool MipsTargetInfo::isValidCPUName(StringRef Name) const {
   return llvm::is_contained(ValidCPUNames, Name);
@@ -234,6 +235,8 @@ bool MipsTargetInfo::hasFeature(StringRef Feature) const {
       .Case("dspr2", DspRev >= DSP2)
       .Case("fp64", FPMode == FP64)
       .Case("msa", HasMSA)
+      .Case("long32", LongABI == Long32)
+      .Case("long64", LongABI == Long64)
       .Default(false);
 }
 
@@ -245,7 +248,7 @@ MipsTargetInfo::getTargetBuiltins() const {
 unsigned MipsTargetInfo::getUnwindWordWidth() const {
   return llvm::StringSwitch<unsigned>(ABI)
       .Case("o32", 32)
-      .Case("o64", 64)
+      .Case("o64", 32)
       .Case("n32", 64)
       .Case("n64", 64)
       .Default(getPointerWidth(LangAS::Default));
@@ -259,11 +262,22 @@ bool MipsTargetInfo::validateTarget(DiagnosticsEngine 
&Diags) const {
   }
 
   // 64-bit ABI's require 64-bit CPU's.
-  if (!processorSupportsGPR64() && (ABI == "o64" || ABI == "n32" || ABI == 
"n64")) {
+  if (!processorSupportsGPR64() && (LongABI == Long64 || ABI == "n32" || ABI 
== "n64")) {
     Diags.Report(diag::err_target_unsupported_abi) << ABI << CPU;
     return false;
   }
 
+  // -longxx is valid only for the o32 and o64 ABI
+  if (LongABI == Long32 && !(ABI == "o64" || ABI == "o32")) {
+    Diags.Report(diag::err_unsupported_abi_for_opt) << "-mlong32" << "o32" << 
"o64";
+    return false;
+  }
+
+  if (LongABI == Long64 && !(ABI == "o64" || ABI == "o32")) {
+    Diags.Report(diag::err_unsupported_abi_for_opt) << "-mlong64" << "o32" << 
"o64";
+    return false;
+  }
+
   // -fpxx is valid only for the o32 ABI
   if (FPMode == FPXX && (ABI == "n32" || ABI == "n64")) {
     Diags.Report(diag::err_unsupported_abi_for_opt) << "-mfpxx" << "o32";
diff --git a/clang/lib/Basic/Targets/Mips.h b/clang/lib/Basic/Targets/Mips.h
index 7ba46fdf1adf6..ff7eed8e47c6a 100644
--- a/clang/lib/Basic/Targets/Mips.h
+++ b/clang/lib/Basic/Targets/Mips.h
@@ -37,13 +37,14 @@ class LLVM_LIBRARY_VISIBILITY MipsTargetInfo : public 
TargetInfo {
   bool DisableMadd4;
   bool UseIndirectJumpHazard;
   bool NoOddSpreg;
+  enum MipsLongABI { LongDefault, Long32, Long64 } LongABI;
 
 protected:
   enum FPModeEnum { FPXX, FP32, FP64 } FPMode;
   std::string ABI;
 
 public:
-  MipsTargetInfo(const llvm::Triple &Triple, const TargetOptions &)
+  MipsTargetInfo(const llvm::Triple &Triple, const TargetOptions &TO)
       : TargetInfo(Triple), IsMips16(false), IsMicromips(false),
         IsNan2008(false), IsAbs2008(false), IsSingleFloat(false),
         IsNoABICalls(false), CanUseBSDABICalls(false), FloatABI(HardFloat),
@@ -109,30 +110,42 @@ class LLVM_LIBRARY_VISIBILITY MipsTargetInfo : public 
TargetInfo {
     return false;
   }
 
+  void setOABITypes() {
+    if (ABI == "o32" || ABI == "o64") {
+
+      // Default is 32-bit longs.
+      if (LongABI == LongDefault)
+        LongABI = Long32;
+
+      unsigned LongLength = (LongABI == Long64) ? 64 : 32;
+      LongWidth = LongAlign = LongLength;
+      PointerWidth = PointerAlign = LongLength;
+    }
+  }
+
   void setO32ABITypes() {
+    setOABITypes();
+
     Int64Type = SignedLongLong;
     IntMaxType = Int64Type;
     LongDoubleFormat = &llvm::APFloat::IEEEdouble();
     LongDoubleWidth = LongDoubleAlign = 64;
-    LongWidth = LongAlign = 32;
     MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 32;
-    PointerWidth = PointerAlign = 32;
     PtrDiffType = IntPtrType = SignedInt;
     SizeType = UnsignedInt;
     SuitableAlign = 64;
   }
 
   void setO64ABITypes() {
+    setOABITypes();
     Int64Type = SignedLongLong;
     IntMaxType = Int64Type;
-    LongDoubleFormat = &llvm::APFloat::IEEEquad();
-    LongDoubleWidth = LongDoubleAlign = 128;
-    LongWidth = LongAlign = 64;
+    LongDoubleFormat = &llvm::APFloat::IEEEdouble();
+    LongDoubleWidth = LongDoubleAlign = 64;
     MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 64;
-    PointerWidth = PointerAlign = 64;
     PtrDiffType = IntPtrType = SignedLong;
     SizeType = UnsignedLong;
-    SuitableAlign = 128;
+    SuitableAlign = 64;
   }
 
   void setN32N64ABITypes() {
@@ -324,6 +337,7 @@ class LLVM_LIBRARY_VISIBILITY MipsTargetInfo : public 
TargetInfo {
     DspRev = NoDSP;
     NoOddSpreg = false;
     FPMode = getDefaultFPMode();
+    LongABI = LongDefault;
     bool OddSpregGiven = false;
     bool StrictAlign = false;
     bool FpGiven = false;
@@ -333,6 +347,14 @@ class LLVM_LIBRARY_VISIBILITY MipsTargetInfo : public 
TargetInfo {
         IsSingleFloat = true;
       else if (Feature == "+soft-float")
         FloatABI = SoftFloat;
+      else if (Feature == "+long32") {
+        LongABI = Long32;
+        setOABITypes();
+      }
+      else if (Feature == "+long64") {
+        LongABI = Long64;
+        setOABITypes();
+      }
       else if (Feature == "+mips16")
         IsMips16 = true;
       else if (Feature == "+micromips")
@@ -440,7 +462,7 @@ class LLVM_LIBRARY_VISIBILITY MipsTargetInfo : public 
TargetInfo {
   }
 
   bool hasInt128Type() const override {
-    return (ABI == "o64" || ABI == "n32" || ABI == "n64") || 
getTargetOpts().ForceEnableInt128;
+    return (ABI == "n32" || ABI == "n64") || getTargetOpts().ForceEnableInt128;
   }
 
   unsigned getUnwindWordWidth() const override;
diff --git a/clang/lib/Driver/ToolChains/Arch/Mips.cpp 
b/clang/lib/Driver/ToolChains/Arch/Mips.cpp
index e3187351a0b55..e0c956bc14f2e 100644
--- a/clang/lib/Driver/ToolChains/Arch/Mips.cpp
+++ b/clang/lib/Driver/ToolChains/Arch/Mips.cpp
@@ -12,6 +12,7 @@
 #include "clang/Options/Options.h"
 #include "llvm/ADT/StringSwitch.h"
 #include "llvm/Option/ArgList.h"
+#include "llvm/Option/OptSpecifier.h"
 
 using namespace clang::driver;
 using namespace clang::driver::tools;
@@ -104,6 +105,7 @@ void mips::getMipsCPUAndABI(const ArgList &Args, const 
llvm::Triple &Triple,
                   .Case("p5600", "o32")
                   .Case("i6400", "n64")
                   .Case("i6500", "n64")
+                  .Case("r4300", "o64")
                   .Default("");
   }
 
@@ -116,6 +118,7 @@ void mips::getMipsCPUAndABI(const ArgList &Args, const 
llvm::Triple &Triple,
     // Deduce CPU name from ABI name.
     CPUName = llvm::StringSwitch<const char *>(ABIName)
                   .Case("o32", DefMips32CPU)
+                  .Case("o64", DefMips64CPU)
                   .Cases({"n32", "n64"}, DefMips64CPU)
                   .Default("");
   }
@@ -129,6 +132,7 @@ std::string mips::getMipsABILibSuffix(const ArgList &Args,
   tools::mips::getMipsCPUAndABI(Args, Triple, CPUName, ABIName);
   return llvm::StringSwitch<std::string>(ABIName)
       .Case("o32", "")
+      .Case("o64", "o64")
       .Case("n32", "32")
       .Case("n64", "64");
 }
@@ -415,6 +419,15 @@ void mips::getMIPSTargetFeatures(const Driver &D, const 
llvm::Triple &Triple,
       Features.push_back("+fp64");
   }
 
+  // Add the last -mlong32/-mlong64, if none are given and the ABI is O32
+  // pass -mlong32.
+  if (Arg *A = Args.getLastArg(options::OPT_mlong32, options::OPT_mlong64)) {
+    if (A->getOption().matches(options::OPT_mlong32))
+      Features.push_back("+long32");
+    else if (A->getOption().matches(options::OPT_mlong64))
+      Features.push_back("+long64");
+  }
+
   AddTargetFeature(Args, Features, options::OPT_mno_odd_spreg,
                    options::OPT_modd_spreg, "nooddspreg");
   AddTargetFeature(Args, Features, options::OPT_mno_madd4, options::OPT_mmadd4,
diff --git a/llvm/lib/Target/Mips/Mips.td b/llvm/lib/Target/Mips/Mips.td
index 3b78de8ec43ad..c84b9580d15a6 100644
--- a/llvm/lib/Target/Mips/Mips.td
+++ b/llvm/lib/Target/Mips/Mips.td
@@ -151,6 +151,12 @@ def FeatureMips64r6    : SubtargetFeature<"mips64r6", 
"MipsArchVersion",
 def FeatureSym32       : SubtargetFeature<"sym32", "HasSym32", "true",
                                           "Symbols are 32 bit on Mips64">;
 
+def FeatureLong32       : SubtargetFeature<"long32", "LongABI", "Long32",
+                                          "Longs are 32 bits on OABI">;
+def FeatureLong64       : SubtargetFeature<"long64", "LongABI", "Long64",
+                                          "Longs are 64 bits on OABI",
+                                          [FeatureGP64Bit, FeaturePTR64Bit]>;
+
 def FeatureMips16  : SubtargetFeature<"mips16", "InMips16Mode", "true",
                                       "Mips16 mode">;
 
@@ -186,9 +192,16 @@ def FeatureCnMipsP : SubtargetFeature<"cnmipsp", 
"HasCnMipsP",
                                       "true", "Octeon+ cnMIPS Support",
                                       [FeatureCnMips]>;
 
+def FeatureFixR4300 : SubtargetFeature<"fix-r4300", "FixR4300", "true",
+                                       "Enable R4300 mulmul erratum fix">;
+
 def FeatureFixR5900 : SubtargetFeature<"fix-r5900", "FixR5900", "true",
                                        "Enable R5900 short loop erratum fix">;
 
+def FeatureR4300 : SubtargetFeature<"r4300", "IsR4300", "true",
+                                    "R4300 (Nintendo 64 CPU-NUS) Support",
+                                    [FeatureMips64, FeatureFixR4300]>;
+
 def FeatureR5900 : SubtargetFeature<"r5900", "IsR5900", "true",
                                     "R5900 (PS2 Emotion Engine) Support",
                                     [FeatureMips3, FeatureSingleFloat,
@@ -228,9 +241,9 @@ def FeatureUseCompactBranches
 // Mips Instruction Predicate Definitions.
 
//===----------------------------------------------------------------------===//
 
-def IsPTR64bit    :   Predicate<"Subtarget->isABI_N64()">,
+def IsPTR64bit    :   Predicate<"Subtarget->isABI_64Bit()">,
                       AssemblerPredicate<(all_of FeaturePTR64Bit)>;
-def IsPTR32bit    :   Predicate<"!Subtarget->isABI_N64()">,
+def IsPTR32bit    :   Predicate<"!Subtarget->isABI_64Bit()">,
                       AssemblerPredicate<(all_of (not FeaturePTR64Bit))>;
 def UseCompactBranches : Predicate<"Subtarget->useCompactBranches()">,
                          AssemblerPredicate<(all_of 
FeatureUseCompactBranches)>;
@@ -307,6 +320,7 @@ def : Proc<"mips64r5", [FeatureMips64r5]>;
 def : Proc<"mips64r6", [FeatureMips64r6]>;
 def : Proc<"octeon", [FeatureMips64r2, FeatureCnMips]>;
 def : Proc<"octeon+", [FeatureMips64r2, FeatureCnMips, FeatureCnMipsP]>;
+def : Proc<"r4300", [FeatureR4300]>;
 def : ProcessorModel<"p5600", MipsP5600Model, [ImplP5600]>;
 def : Proc<"r5900", [FeatureR5900]>;
 def : ProcessorModel<"i6400", MipsI6400Model, [ImplI6400]>;
diff --git a/llvm/lib/Target/Mips/MipsSubtarget.cpp 
b/llvm/lib/Target/Mips/MipsSubtarget.cpp
index 26cad4a7d5228..3e6b5551bee44 100644
--- a/llvm/lib/Target/Mips/MipsSubtarget.cpp
+++ b/llvm/lib/Target/Mips/MipsSubtarget.cpp
@@ -224,6 +224,29 @@ MipsSubtarget::MipsSubtarget(const Triple &TT, StringRef 
CPU, StringRef FS,
     GINVWarningPrinted = true;
   }
 
+  // Handle OABI Long size.
+  if (isABI_O32() || isABI_O64()) {
+    if (LongABI != LongDefault && !LongABIWarningPrinted) {
+      errs()  << "warning: long32 and long64 are currently broken. "
+              << "expect compilation to fail.";
+      LongABIWarningPrinted = true;
+    }
+
+    switch(LongABI) {
+    case LongDefault:
+      LongABI = Long32;
+      [[clang::fallthrough]];
+    case Long32:
+      IsGP64bit = false;
+      IsPTR64bit = false;
+      break;
+    case Long64:
+      IsGP64bit = true;
+      IsPTR64bit = true;
+      break;
+    }
+  }
+
   TSInfo = std::make_unique<MipsSelectionDAGInfo>();
 
   CallLoweringInfo.reset(new MipsCallLowering(*getTargetLowering()));
@@ -293,6 +316,9 @@ 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(); }
+bool MipsSubtarget::isABI_64Bit() const { 
+  return (isABI_O64() && LongABI == Long64) || isABI_N64();
+}
 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 83127bfaf00d7..3a3c019bc6e98 100644
--- a/llvm/lib/Target/Mips/MipsSubtarget.h
+++ b/llvm/lib/Target/Mips/MipsSubtarget.h
@@ -55,6 +55,9 @@ class MipsSubtarget : public MipsGenSubtargetInfo {
 
   enum class CPU { Others, P5600, I6400, I6500 };
 
+  // Used to determine the size of longs on O32 and O64.
+  enum MipsLongABI { LongDefault, Long32, Long64 } LongABI = LongDefault;
+
   // Used to avoid printing dsp warnings multiple times.
   static bool DspWarningPrinted;
 
@@ -73,6 +76,9 @@ class MipsSubtarget : public MipsGenSubtargetInfo {
   // Used to avoid printing virt warnings multiple times.
   static bool VirtWarningPrinted;
 
+  // Used to avoid printing long abi warnings multiple times.
+  static bool LongABIWarningPrinted;
+
   // Mips architecture version
   MipsArchEnum MipsArchVersion;
 
@@ -127,6 +133,12 @@ class MipsSubtarget : public MipsGenSubtargetInfo {
   // CPU supports cnMIPSP (Cavium Networks Octeon+ CPU).
   bool HasCnMipsP;
 
+  // IsR4300 - CPU is R4300 (Nintendo 64 CPU-NUS).
+  bool IsR4300;
+
+  // FixR4300 - Enable R4300 mulmul erratum fix.
+  bool FixR4300;
+
   // IsR5900 - CPU is R5900 (PlayStation 2 Emotion Engine).
   bool IsR5900;
 
@@ -254,6 +266,7 @@ class MipsSubtarget : public MipsGenSubtargetInfo {
   bool isABI_N32() const;
   bool isABI_O32() const;
   bool isABI_O64() const;
+  bool isABI_64Bit() const;
   const MipsABIInfo &getABI() const;
   bool isABI_FPXX() const { return isABI_O32() && IsFPXX; }
 
@@ -310,6 +323,8 @@ class MipsSubtarget : public MipsGenSubtargetInfo {
 
   bool hasCnMips() const { return HasCnMips; }
   bool hasCnMipsP() const { return HasCnMipsP; }
+  bool isR4300() const { return IsR4300; }
+  bool fixR4300() const { return FixR4300; }
   bool isR5900() const { return IsR5900; }
   bool fixR5900() const { return FixR5900; }
 
diff --git a/llvm/lib/Target/Mips/MipsTargetMachine.cpp 
b/llvm/lib/Target/Mips/MipsTargetMachine.cpp
index 3b4a6aa0b7a54..6db0ea557eb59 100644
--- a/llvm/lib/Target/Mips/MipsTargetMachine.cpp
+++ b/llvm/lib/Target/Mips/MipsTargetMachine.cpp
@@ -283,7 +283,7 @@ void MipsPassConfig::addPreEmitPass() {
 
   // This pass inserts a nop instruction between two back-to-back 
multiplication
   // instructions when the "mfix4300" flag is passed.
-  if (EnableMulMulFix)
+  if (EnableMulMulFix || getMipsSubtarget().fixR4300())
     addPass(createMipsMulMulBugPass());
 
   // The delay slot filler pass can potientially create forbidden slot hazards
diff --git a/llvm/lib/TargetParser/TargetDataLayout.cpp 
b/llvm/lib/TargetParser/TargetDataLayout.cpp
index d7c4b123881d7..3c2d5831499df 100644
--- a/llvm/lib/TargetParser/TargetDataLayout.cpp
+++ b/llvm/lib/TargetParser/TargetDataLayout.cpp
@@ -178,6 +178,10 @@ static std::string computeMipsDataLayout(const Triple &TT, 
StringRef ABIName) {
   std::string Ret;
   MipsABI ABI = getMipsABI(TT, ABIName);
 
+  // TODO:  OABI allows for multiple pointer/long sizes, which is not
+  //        currently exposed, this might be a good idea to fix?
+  //        see -mlong32/-mlong64
+
   // There are both little and big endian mips.
   if (TT.isLittleEndian())
     Ret += "e";
@@ -190,7 +194,7 @@ static std::string computeMipsDataLayout(const Triple &TT, 
StringRef ABIName) {
     Ret += "-m:e";
 
   // Pointers are 32 bit on some ABIs.
-  if (ABI != MipsABI::N64 && ABI != MipsABI::O64)
+  if (ABI != MipsABI::N64)
     Ret += "-p:32:32";
 
   // 8 and 16 bit integers only need to have natural alignment, but try to
@@ -200,7 +204,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::O64 || ABI == MipsABI::N64 || ABI == MipsABI::N32)
+  if (ABI == MipsABI::N64 || ABI == MipsABI::N32)
     Ret += "-i128:128-n32:64-S128";
   else
     Ret += "-n32-S64";

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

Reply via email to