[clang] [llvm] [WIP] Add support for O64 Mips ABI (PR #223990)
via llvm-commits
llvm-commits at lists.llvm.org
Thu Sep 17 11:19:48 PDT 2026
https://github.com/LunaTheFoxgirl updated https://github.com/llvm/llvm-project/pull/223990
>From 51404516227ebe3faceaef9f01afce05dff58b2f Mon Sep 17 00:00:00 2001
From: LunaTheFoxgirl <luna at foxgirls.gay>
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 <luna at foxgirls.gay>
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 <luna at foxgirls.gay>
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";
More information about the llvm-commits
mailing list