aboutsummaryrefslogtreecommitdiffstats
path: root/lib/Target/Mips
diff options
context:
space:
mode:
authorBruno Cardoso Lopes <bruno.cardoso@gmail.com>2008-07-05 19:05:21 +0000
committerBruno Cardoso Lopes <bruno.cardoso@gmail.com>2008-07-05 19:05:21 +0000
commit225ca9cdd70de3d12641b0aba7daf6cb568a7ebd (patch)
tree4e9448b1e96f4e7792d2dcb85781c53ddef8dd39 /lib/Target/Mips
parent126d90770bdb17e6925b2fe26de99aa079b7b9b3 (diff)
downloadexternal_llvm-225ca9cdd70de3d12641b0aba7daf6cb568a7ebd.zip
external_llvm-225ca9cdd70de3d12641b0aba7daf6cb568a7ebd.tar.gz
external_llvm-225ca9cdd70de3d12641b0aba7daf6cb568a7ebd.tar.bz2
Several changes to Mips backend, experimental fp support being the most
important. - Cleanup in the Subtarget info with addition of new features, not all support yet, but they allow the future inclusion of features easier. Among new features, we have : Arch family info (mips1, mips2, ...), ABI info (o32, eabi), 64-bit integer and float registers, allegrex vector FPU (VFPU), single float only support. - TargetMachine now detects allegrex core. - Added allegrex (Mips32r2) sext_inreg instructions. - *Added Float Point Instructions*, handling single float only, and aliased accesses for 32-bit FPUs. - Some cleanup in FP instruction formats and FP register classes. - Calling conventions improved to support mips 32-bit EABI. - Added Asm Printer support for fp cond codes. - Added support for sret copy to a return register. - EABI support added into LowerCALL and FORMAL_ARGS. - MipsFunctionInfo now keeps a virtual register per function to track the sret on function entry until function ret. - MipsInstrInfo FP support into methods (isMoveInstr, isLoadFromStackSlot, ...), FP cond codes mapping and initial FP Branch Analysis. - Two new Mips SDNode to handle fp branch and compare instructions : FPBrcond, FPCmp - MipsTargetLowering : handling different FP classes, Allegrex support, sret return copy, no homing location within EABI, non 32-bit stack objects arguments, and asm constraint for float. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@53146 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Target/Mips')
-rw-r--r--lib/Target/Mips/Mips.td39
-rw-r--r--lib/Target/Mips/MipsAsmPrinter.cpp9
-rw-r--r--lib/Target/Mips/MipsCallingConv.td66
-rw-r--r--lib/Target/Mips/MipsISelDAGToDAG.cpp9
-rw-r--r--lib/Target/Mips/MipsISelLowering.cpp180
-rw-r--r--lib/Target/Mips/MipsISelLowering.h9
-rw-r--r--lib/Target/Mips/MipsInstrFPU.td296
-rw-r--r--lib/Target/Mips/MipsInstrFormats.td37
-rw-r--r--lib/Target/Mips/MipsInstrInfo.cpp382
-rw-r--r--lib/Target/Mips/MipsInstrInfo.h78
-rw-r--r--lib/Target/Mips/MipsInstrInfo.td111
-rw-r--r--lib/Target/Mips/MipsMachineFunction.h41
-rw-r--r--lib/Target/Mips/MipsRegisterInfo.cpp76
-rw-r--r--lib/Target/Mips/MipsRegisterInfo.td267
-rw-r--r--lib/Target/Mips/MipsSubtarget.cpp18
-rw-r--r--lib/Target/Mips/MipsSubtarget.h52
-rw-r--r--lib/Target/Mips/MipsTargetMachine.cpp20
17 files changed, 1247 insertions, 443 deletions
diff --git a/lib/Target/Mips/Mips.td b/lib/Target/Mips/Mips.td
index 50a5f65..1199cc4 100644
--- a/lib/Target/Mips/Mips.td
+++ b/lib/Target/Mips/Mips.td
@@ -16,7 +16,7 @@
include "../Target.td"
//===----------------------------------------------------------------------===//
-// Descriptions
+// Register File, Calling Conv, Instruction Descriptions
//===----------------------------------------------------------------------===//
include "MipsRegisterInfo.td"
@@ -30,22 +30,43 @@ def MipsInstrInfo : InstrInfo {
}
//===----------------------------------------------------------------------===//
-// CPU Directives //
+// Mips Subtarget features //
//===----------------------------------------------------------------------===//
-// Not currently supported, but work as SubtargetFeature placeholder.
-def FeatureMipsIII : SubtargetFeature<"mips3", "IsMipsIII", "true",
- "MipsIII ISA Support">;
+def FeatureGP64Bit : SubtargetFeature<"gp64", "IsGP64bit", "true",
+ "General Purpose Registers are 64-bit wide.">;
+def FeatureFP64Bit : SubtargetFeature<"fp64", "IsFP64bit", "true",
+ "Support 64-bit FP registers.">;
+def FeatureSingleFloat : SubtargetFeature<"single-float", "IsSingleFloat",
+ "true", "Only supports single precision float">;
+def FeatureAllegrexVFPU : SubtargetFeature<"allegrex-vfpu", "HasAllegrexVFPU",
+ "true", "Enable Allegrex VFPU instructions.">;
+def FeatureMips2 : SubtargetFeature<"mips2", "MipsArchVersion", "Mips2",
+ "Mips2 ISA Support">;
+def FeatureO32 : SubtargetFeature<"o32", "MipsABI", "O32",
+ "Enable o32 ABI">;
+def FeatureEABI : SubtargetFeature<"eabi", "MipsABI", "EABI",
+ "Enable eabi ABI">;
//===----------------------------------------------------------------------===//
// Mips processors supported.
//===----------------------------------------------------------------------===//
-def : Processor<"mips1", MipsGenericItineraries, []>;
-def : Processor<"r2000", MipsGenericItineraries, []>;
-def : Processor<"r3000", MipsGenericItineraries, []>;
+class Proc<string Name, list<SubtargetFeature> Features>
+ : Processor<Name, MipsGenericItineraries, Features>;
+
+def : Proc<"mips1", []>;
+def : Proc<"r2000", []>;
+def : Proc<"r3000", []>;
+
+def : Proc<"mips2", [FeatureMips2]>;
+def : Proc<"r6000", [FeatureMips2]>;
+
+// Allegrex is a 32bit subset of r4000, both for interger and fp registers,
+// but much more similar to Mips2 than Mips3.
+def : Proc<"allegrex", [FeatureMips2, FeatureSingleFloat, FeatureAllegrexVFPU,
+ FeatureEABI]>;
def Mips : Target {
let InstructionSet = MipsInstrInfo;
}
-
diff --git a/lib/Target/Mips/MipsAsmPrinter.cpp b/lib/Target/Mips/MipsAsmPrinter.cpp
index 0587d98..11f14e1 100644
--- a/lib/Target/Mips/MipsAsmPrinter.cpp
+++ b/lib/Target/Mips/MipsAsmPrinter.cpp
@@ -62,6 +62,8 @@ namespace {
void printOperand(const MachineInstr *MI, int opNum);
void printMemOperand(const MachineInstr *MI, int opNum,
const char *Modifier = 0);
+ void printFCCOperand(const MachineInstr *MI, int opNum,
+ const char *Modifier = 0);
unsigned int getSavedRegsBitmask(bool isFloat, MachineFunction &MF);
void printHex32(unsigned int Value);
@@ -428,6 +430,13 @@ printMemOperand(const MachineInstr *MI, int opNum, const char *Modifier)
O << ")";
}
+void MipsAsmPrinter::
+printFCCOperand(const MachineInstr *MI, int opNum, const char *Modifier)
+{
+ const MachineOperand& MO = MI->getOperand(opNum);
+ O << Mips::MipsFCCToString((Mips::CondCode)MO.getImm());
+}
+
bool MipsAsmPrinter::
doInitialization(Module &M)
{
diff --git a/lib/Target/Mips/MipsCallingConv.td b/lib/Target/Mips/MipsCallingConv.td
index 85f019d..c05e82d 100644
--- a/lib/Target/Mips/MipsCallingConv.td
+++ b/lib/Target/Mips/MipsCallingConv.td
@@ -14,26 +14,76 @@ class CCIfSubtarget<string F, CCAction A>:
CCIf<!strconcat("State.getTarget().getSubtarget<MipsSubtarget>().", F), A>;
//===----------------------------------------------------------------------===//
-// Mips Return Value Calling Convention
+// Mips O32 Calling Convention
//===----------------------------------------------------------------------===//
-def RetCC_Mips : CallingConv<[
+def CC_MipsO32 : CallingConv<[
+ // Promote i8/i16 arguments to i32.
+ CCIfType<[i8, i16], CCPromoteToType<i32>>,
+
+ // The first 4 integer arguments are passed in integer registers.
+ CCIfType<[i32], CCAssignToReg<[A0, A1, A2, A3]>>,
+
+ // Integer values get stored in stack slots that are 4 bytes in
+ // size and 4-byte aligned.
+ CCIfType<[i32], CCAssignToStack<4, 4>>
+]>;
+
+def RetCC_MipsO32 : CallingConv<[
// i32 are returned in registers V0, V1
CCIfType<[i32], CCAssignToReg<[V0, V1]>>
]>;
-
//===----------------------------------------------------------------------===//
-// Mips Argument Calling Conventions
+// Mips EABI Calling Convention
//===----------------------------------------------------------------------===//
-def CC_Mips : CallingConv<[
+def CC_MipsEABI : CallingConv<[
// Promote i8/i16 arguments to i32.
CCIfType<[i8, i16], CCPromoteToType<i32>>,
- // The first 4 integer arguments are passed in integer registers.
- CCIfType<[i32], CCAssignToReg<[A0, A1, A2, A3]>>,
+ // Integer arguments are passed in integer registers.
+ CCIfType<[i32], CCAssignToReg<[A0, A1, A2, A3, T0, T1, T2, T3]>>,
+
+ // Single fp arguments are passed in pairs within 32-bit mode
+ CCIfType<[f32], CCIfSubtarget<"isSingleFloat()",
+ CCAssignToReg<[F12, F13, F14, F15, F16, F17, F18, F19]>>>,
+
+ CCIfType<[f32], CCIfSubtarget<"isNotSingleFloat()",
+ CCAssignToReg<[F12, F14, F16, F18]>>>,
+
+ // The first 4 doubl fp arguments are passed in single fp registers.
+ CCIfType<[f64], CCIfSubtarget<"isNotSingleFloat()",
+ CCAssignToReg<[D6, D7, D8, D9]>>>,
// Integer values get stored in stack slots that are 4 bytes in
// size and 4-byte aligned.
- CCIfType<[i32], CCAssignToStack<4, 4>>
+ CCIfType<[i32, f32], CCAssignToStack<4, 4>>,
+
+ // Integer values get stored in stack slots that are 8 bytes in
+ // size and 8-byte aligned.
+ CCIfType<[f64], CCIfSubtarget<"isNotSingleFloat()", CCAssignToStack<8, 8>>>
+]>;
+
+def RetCC_MipsEABI : CallingConv<[
+ // i32 are returned in registers V0, V1
+ CCIfType<[i32], CCAssignToReg<[V0, V1]>>,
+
+ // f32 are returned in registers F0, F1
+ CCIfType<[f32], CCAssignToReg<[F0, F1]>>,
+
+ // f64 are returned in register D0
+ CCIfType<[f64], CCIfSubtarget<"isNotSingleFloat()", CCAssignToReg<[D0]>>>
]>;
+//===----------------------------------------------------------------------===//
+// Mips Calling Convention Dispatch
+//===----------------------------------------------------------------------===//
+
+def CC_Mips : CallingConv<[
+ CCIfSubtarget<"isABI_EABI()", CCDelegateTo<CC_MipsEABI>>,
+ CCDelegateTo<CC_MipsO32>
+]>;
+
+def RetCC_Mips : CallingConv<[
+ CCIfSubtarget<"isABI_EABI()", CCDelegateTo<RetCC_MipsEABI>>,
+ CCDelegateTo<RetCC_MipsO32>
+]>;
diff --git a/lib/Target/Mips/MipsISelDAGToDAG.cpp b/lib/Target/Mips/MipsISelDAGToDAG.cpp
index 0c967e2..4822e01 100644
--- a/lib/Target/Mips/MipsISelDAGToDAG.cpp
+++ b/lib/Target/Mips/MipsISelDAGToDAG.cpp
@@ -58,13 +58,12 @@ class VISIBILITY_HIDDEN MipsDAGToDAGISel : public SelectionDAGISel {
/// Subtarget - Keep a pointer to the MipsSubtarget around so that we can
/// make the right decision when generating code for different targets.
- //TODO: add initialization on constructor
- //const MipsSubtarget *Subtarget;
+ const MipsSubtarget &Subtarget;
public:
- MipsDAGToDAGISel(MipsTargetMachine &tm) :
- SelectionDAGISel(MipsLowering),
- TM(tm), MipsLowering(*TM.getTargetLowering()) {}
+ MipsDAGToDAGISel(MipsTargetMachine &tm) : SelectionDAGISel(MipsLowering),
+ TM(tm), MipsLowering(*TM.getTargetLowering()),
+ Subtarget(tm.getSubtarget<MipsSubtarget>()) {}
virtual void InstructionSelect(SelectionDAG &SD);
diff --git a/lib/Target/Mips/MipsISelLowering.cpp b/lib/Target/Mips/MipsISelLowering.cpp
index 18cedcf..7fb5390 100644
--- a/lib/Target/Mips/MipsISelLowering.cpp
+++ b/lib/Target/Mips/MipsISelLowering.cpp
@@ -17,6 +17,7 @@
#include "MipsISelLowering.h"
#include "MipsMachineFunction.h"
#include "MipsTargetMachine.h"
+#include "MipsSubtarget.h"
#include "llvm/DerivedTypes.h"
#include "llvm/Function.h"
#include "llvm/Intrinsics.h"
@@ -44,6 +45,8 @@ getTargetNodeName(unsigned Opcode) const
case MipsISD::Lo : return "MipsISD::Lo";
case MipsISD::Ret : return "MipsISD::Ret";
case MipsISD::SelectCC : return "MipsISD::SelectCC";
+ case MipsISD::FPBrcond : return "MipsISD::FPBrcond";
+ case MipsISD::FPCmp : return "MipsISD::FPCmp";
default : return NULL;
}
}
@@ -51,6 +54,8 @@ getTargetNodeName(unsigned Opcode) const
MipsTargetLowering::
MipsTargetLowering(MipsTargetMachine &TM): TargetLowering(TM)
{
+ Subtarget = &TM.getSubtarget<MipsSubtarget>();
+
// Mips does not have i1 type, so use i32 for
// setcc operations results (slt, sgt, ...).
setSetCCResultContents(ZeroOrOneSetCCResult);
@@ -61,12 +66,24 @@ MipsTargetLowering(MipsTargetMachine &TM): TargetLowering(TM)
// Set up the register classes
addRegisterClass(MVT::i32, Mips::CPURegsRegisterClass);
+ // When dealing with single precision only, use libcalls
+ if (!Subtarget->isSingleFloat()) {
+ addRegisterClass(MVT::f32, Mips::AFGR32RegisterClass);
+ if (!Subtarget->isFP64bit())
+ addRegisterClass(MVT::f64, Mips::AFGR64RegisterClass);
+ } else
+ addRegisterClass(MVT::f32, Mips::FGR32RegisterClass);
+
// Custom
setOperationAction(ISD::GlobalAddress, MVT::i32, Custom);
setOperationAction(ISD::GlobalTLSAddress, MVT::i32, Custom);
setOperationAction(ISD::RET, MVT::Other, Custom);
setOperationAction(ISD::JumpTable, MVT::i32, Custom);
setOperationAction(ISD::SELECT_CC, MVT::i32, Custom);
+ setOperationAction(ISD::SELECT_CC, MVT::f32, Custom);
+
+ if (Subtarget->isSingleFloat())
+ setOperationAction(ISD::SELECT_CC, MVT::f64, Expand);
// Load extented operations for i1 types must be promoted
setLoadXAction(ISD::EXTLOAD, MVT::i1, Promote);
@@ -80,6 +97,11 @@ MipsTargetLowering(MipsTargetMachine &TM): TargetLowering(TM)
setOperationAction(ISD::SELECT, MVT::i32, Expand);
setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i1, Expand);
+ if (!Subtarget->isAllegrex()) {
+ setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i8, Expand);
+ setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i16, Expand);
+ }
+
// Mips not supported intrinsics.
setOperationAction(ISD::MEMBARRIER, MVT::Other, Expand);
@@ -323,7 +345,7 @@ LowerCALL(SDOperand Op, SelectionDAG &DAG)
/// LowerCCCCallTo - functions arguments are copied from virtual
/// regs to (physical regs)/(stack frame), CALLSEQ_START and
/// CALLSEQ_END are emitted.
-/// TODO: isVarArg, isTailCall, sret.
+/// TODO: isVarArg, isTailCall.
SDOperand MipsTargetLowering::
LowerCCCCallTo(SDOperand Op, SelectionDAG &DAG, unsigned CC)
{
@@ -351,10 +373,14 @@ LowerCCCCallTo(SDOperand Op, SelectionDAG &DAG, unsigned CC)
Chain = DAG.getCALLSEQ_START(Chain,DAG.getConstant(NumBytes,
getPointerTy()));
- SmallVector<std::pair<unsigned, SDOperand>, 8> RegsToPass;
+ // With EABI is it possible to have 16 args on registers.
+ SmallVector<std::pair<unsigned, SDOperand>, 16> RegsToPass;
SmallVector<SDOperand, 8> MemOpChains;
- int LastStackLoc = 0;
+ // First/LastArgStackLoc contains the first/last
+ // "at stack" argument location.
+ int LastArgStackLoc = 0;
+ unsigned FirstStackArgLoc = (Subtarget->isABI_EABI() ? 0 : 16);
// Walk the register/memloc assignments, inserting copies/loads.
for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) {
@@ -385,14 +411,16 @@ LowerCCCCallTo(SDOperand Op, SelectionDAG &DAG, unsigned CC)
continue;
}
+ // Register cant get to this point...
assert(VA.isMemLoc());
// Create the frame index object for this incoming parameter
// This guarantees that when allocating Local Area the firsts
- // 16 bytes which are alwayes reserved won't be overwritten.
- LastStackLoc = (16 + VA.getLocMemOffset());
+ // 16 bytes which are alwayes reserved won't be overwritten
+ // if O32 ABI is used. For EABI the first address is zero.
+ LastArgStackLoc = (FirstStackArgLoc + VA.getLocMemOffset());
int FI = MFI->CreateFixedObject(VA.getValVT().getSizeInBits()/8,
- LastStackLoc);
+ LastArgStackLoc);
SDOperand PtrOff = DAG.getFrameIndex(FI,getPointerTy());
@@ -401,8 +429,8 @@ LowerCCCCallTo(SDOperand Op, SelectionDAG &DAG, unsigned CC)
MemOpChains.push_back(DAG.getStore(Chain, Arg, PtrOff, NULL, 0));
}
- // Transform all store nodes into one single node because
- // all store nodes are independent of each other.
+ // Transform all store nodes into one single node because all store
+ // nodes are independent of each other.
if (!MemOpChains.empty())
Chain = DAG.getNode(ISD::TokenFactor, MVT::Other,
&MemOpChains[0], MemOpChains.size());
@@ -460,18 +488,18 @@ LowerCCCCallTo(SDOperand Op, SelectionDAG &DAG, unsigned CC)
// emited CALL's to restore GP.
if (getTargetMachine().getRelocationModel() == Reloc::PIC_) {
// Function can have an arbitrary number of calls, so
- // hold the LastStackLoc with the biggest offset.
+ // hold the LastArgStackLoc with the biggest offset.
int FI;
MipsFunctionInfo *MipsFI = MF.getInfo<MipsFunctionInfo>();
- if (LastStackLoc >= MipsFI->getGPStackOffset()) {
- LastStackLoc = (!LastStackLoc) ? (16) : (LastStackLoc+4);
+ if (LastArgStackLoc >= MipsFI->getGPStackOffset()) {
+ LastArgStackLoc = (!LastArgStackLoc) ? (16) : (LastArgStackLoc+4);
// Create the frame index only once. SPOffset here can be anything
// (this will be fixed on processFunctionBeforeFrameFinalized)
if (MipsFI->getGPStackOffset() == -1) {
FI = MFI->CreateFixedObject(4, 0);
MipsFI->setGPFI(FI);
}
- MipsFI->setGPStackOffset(LastStackLoc);
+ MipsFI->setGPStackOffset(LastArgStackLoc);
}
// Reload GP value.
@@ -543,7 +571,7 @@ LowerFORMAL_ARGUMENTS(SDOperand Op, SelectionDAG &DAG)
/// LowerCCCArguments - transform physical registers into
/// virtual registers and generate load operations for
/// arguments places on the stack.
-/// TODO: isVarArg, sret
+/// TODO: isVarArg
SDOperand MipsTargetLowering::
LowerCCCArguments(SDOperand Op, SelectionDAG &DAG)
{
@@ -566,9 +594,11 @@ LowerCCCArguments(SDOperand Op, SelectionDAG &DAG)
CCState CCInfo(CC, isVarArg, getTargetMachine(), ArgLocs);
CCInfo.AnalyzeFormalArguments(Op.Val, CC_Mips);
- SmallVector<SDOperand, 8> ArgValues;
+ SmallVector<SDOperand, 16> ArgValues;
SDOperand StackPtr;
+ unsigned FirstStackArgLoc = (Subtarget->isABI_EABI() ? 0 : 16);
+
for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) {
CCValAssign &VA = ArgLocs[i];
@@ -579,9 +609,17 @@ LowerCCCArguments(SDOperand Op, SelectionDAG &DAG)
TargetRegisterClass *RC;
if (RegVT == MVT::i32)
- RC = Mips::CPURegsRegisterClass;
- else
- assert(0 && "support only Mips::CPURegsRegisterClass");
+ RC = Mips::CPURegsRegisterClass;
+ else if (RegVT == MVT::f32) {
+ if (Subtarget->isSingleFloat())
+ RC = Mips::FGR32RegisterClass;
+ else
+ RC = Mips::AFGR32RegisterClass;
+ } else if (RegVT == MVT::f64) {
+ if (!Subtarget->isSingleFloat())
+ RC = Mips::AFGR64RegisterClass;
+ } else
+ assert(0 && "RegVT not supported by FORMAL_ARGUMENTS Lowering");
// Transform the arguments stored on
// physical registers into virtual ones
@@ -605,8 +643,7 @@ LowerCCCArguments(SDOperand Op, SelectionDAG &DAG)
// To meet ABI, when VARARGS are passed on registers, the registers
// must have their values written to the caller stack frame.
- if (isVarArg) {
-
+ if ((isVarArg) && (Subtarget->isABI_O32())) {
if (StackPtr.Val == 0)
StackPtr = DAG.getRegister(StackReg, getPointerTy());
@@ -627,7 +664,8 @@ LowerCCCArguments(SDOperand Op, SelectionDAG &DAG)
ArgValues.push_back(DAG.getStore(Root, ArgValue, PtrOff, NULL, 0));
}
- } else {
+ } else { // VA.isRegLoc()
+
// sanity check
assert(VA.isMemLoc());
@@ -639,14 +677,30 @@ LowerCCCArguments(SDOperand Op, SelectionDAG &DAG)
// be used on emitPrologue) to avoid mis-calc of the first stack
// offset on PEI::calculateFrameObjectOffsets.
// Arguments are always 32-bit.
- int FI = MFI->CreateFixedObject(4, 0);
- MipsFI->recordLoadArgsFI(FI, -(4+(16+VA.getLocMemOffset())));
+ unsigned ArgSize = VA.getLocVT().getSizeInBits()/8;
+ int FI = MFI->CreateFixedObject(ArgSize, 0);
+ MipsFI->recordLoadArgsFI(FI, -(ArgSize+
+ (FirstStackArgLoc + VA.getLocMemOffset())));
// Create load nodes to retrieve arguments from the stack
SDOperand FIN = DAG.getFrameIndex(FI, getPointerTy());
ArgValues.push_back(DAG.getLoad(VA.getValVT(), Root, FIN, NULL, 0));
}
}
+
+ // The mips ABIs for returning structs by value requires that we copy
+ // the sret argument into $v0 for the return. Save the argument into
+ // a virtual register so that we can access it from the return points.
+ if (DAG.getMachineFunction().getFunction()->hasStructRetAttr()) {
+ unsigned Reg = MipsFI->getSRetReturnReg();
+ if (!Reg) {
+ Reg = MF.getRegInfo().createVirtualRegister(getRegClassFor(MVT::i32));
+ MipsFI->setSRetReturnReg(Reg);
+ }
+ SDOperand Copy = DAG.getCopyToReg(DAG.getEntryNode(), Reg, ArgValues[0]);
+ Root = DAG.getNode(ISD::TokenFactor, MVT::Other, Copy, Root);
+ }
+
ArgValues.push_back(Root);
// Return the new list of results.
@@ -699,6 +753,23 @@ LowerRET(SDOperand Op, SelectionDAG &DAG)
Flag = Chain.getValue(1);
}
+ // The mips ABIs for returning structs by value requires that we copy
+ // the sret argument into $v0 for the return. We saved the argument into
+ // a virtual register in the entry block, so now we copy the value out
+ // and into $v0.
+ if (DAG.getMachineFunction().getFunction()->hasStructRetAttr()) {
+ MachineFunction &MF = DAG.getMachineFunction();
+ MipsFunctionInfo *MipsFI = MF.getInfo<MipsFunctionInfo>();
+ unsigned Reg = MipsFI->getSRetReturnReg();
+
+ if (!Reg)
+ assert(0 && "sret virtual register not created in the entry block");
+ SDOperand Val = DAG.getCopyFromReg(Chain, Reg, getPointerTy());
+
+ Chain = DAG.getCopyToReg(Chain, Mips::V0, Val, Flag);
+ Flag = Chain.getValue(1);
+ }
+
// Return on Mips is always a "jr $ra"
if (Flag.Val)
return DAG.getNode(MipsISD::Ret, MVT::Other,
@@ -717,19 +788,20 @@ LowerRET(SDOperand Op, SelectionDAG &DAG)
MipsTargetLowering::ConstraintType MipsTargetLowering::
getConstraintType(const std::string &Constraint) const
{
+ // Mips specific constrainy
+ // GCC config/mips/constraints.md
+ //
+ // 'd' : An address register. Equivalent to r
+ // unless generating MIPS16 code.
+ // 'y' : Equivalent to r; retained for
+ // backwards compatibility.
+ // 'f' : Float Point registers.
if (Constraint.size() == 1) {
- // Mips specific constrainy
- // GCC config/mips/constraints.md
- //
- // 'd' : An address register. Equivalent to r
- // unless generating MIPS16 code.
- // 'y' : Equivalent to r; retained for
- // backwards compatibility.
- //
switch (Constraint[0]) {
default : break;
case 'd':
case 'y':
+ case 'f':
return C_RegisterClass;
break;
}
@@ -737,6 +809,9 @@ getConstraintType(const std::string &Constraint) const
return TargetLowering::getConstraintType(Constraint);
}
+/// getRegClassForInlineAsmConstraint - Given a constraint letter (e.g. "r"),
+/// return a list of registers that can be used to satisfy the constraint.
+/// This should only be used for C_RegisterClass constraints.
std::pair<unsigned, const TargetRegisterClass*> MipsTargetLowering::
getRegForInlineAsmConstraint(const std::string &Constraint, MVT VT) const
{
@@ -744,12 +819,23 @@ getRegForInlineAsmConstraint(const std::string &Constraint, MVT VT) const
switch (Constraint[0]) {
case 'r':
return std::make_pair(0U, Mips::CPURegsRegisterClass);
- break;
+ case 'f':
+ if (VT == MVT::f32)
+ if (Subtarget->isSingleFloat())
+ return std::make_pair(0U, Mips::FGR32RegisterClass);
+ else
+ return std::make_pair(0U, Mips::AFGR32RegisterClass);
+ if (VT == MVT::f64)
+ if ((!Subtarget->isSingleFloat()) && (!Subtarget->isFP64bit()))
+ return std::make_pair(0U, Mips::AFGR64RegisterClass);
}
}
return TargetLowering::getRegForInlineAsmConstraint(Constraint, VT);
}
+/// Given a register class constraint, like 'r', if this corresponds directly
+/// to an LLVM register class, return a register of 0 and the register class
+/// pointer.
std::vector<unsigned> MipsTargetLowering::
getRegClassForInlineAsmConstraint(const std::string &Constraint,
MVT VT) const
@@ -763,15 +849,29 @@ getRegClassForInlineAsmConstraint(const std::string &Constraint,
// GCC Mips Constraint Letters
case 'd':
case 'y':
- return make_vector<unsigned>(Mips::V0, Mips::V1, Mips::A0,
- Mips::A1, Mips::A2, Mips::A3,
- Mips::T0, Mips::T1, Mips::T2,
- Mips::T3, Mips::T4, Mips::T5,
- Mips::T6, Mips::T7, Mips::S0,
- Mips::S1, Mips::S2, Mips::S3,
- Mips::S4, Mips::S5, Mips::S6,
- Mips::S7, Mips::T8, Mips::T9, 0);
- break;
+ return make_vector<unsigned>(Mips::T0, Mips::T1, Mips::T2, Mips::T3,
+ Mips::T4, Mips::T5, Mips::T6, Mips::T7, Mips::S0, Mips::S1,
+ Mips::S2, Mips::S3, Mips::S4, Mips::S5, Mips::S6, Mips::S7,
+ Mips::T8, 0);
+
+ case 'f':
+ if (VT == MVT::f32)
+ if (Subtarget->isSingleFloat())
+ return make_vector<unsigned>(Mips::F2, Mips::F3, Mips::F4, Mips::F5,
+ Mips::F6, Mips::F7, Mips::F8, Mips::F9, Mips::F10, Mips::F11,
+ Mips::F20, Mips::F21, Mips::F22, Mips::F23, Mips::F24,
+ Mips::F25, Mips::F26, Mips::F27, Mips::F28, Mips::F29,
+ Mips::F30, Mips::F31, 0);
+ else
+ return make_vector<unsigned>(Mips::F2, Mips::F4, Mips::F6, Mips::F8,
+ Mips::F10, Mips::F20, Mips::F22, Mips::F24, Mips::F26,
+ Mips::F28, Mips::F30, 0);
+
+ if (VT == MVT::f64)
+ if ((!Subtarget->isSingleFloat()) && (!Subtarget->isFP64bit()))
+ return make_vector<unsigned>(Mips::D1, Mips::D2, Mips::D3, Mips::D4,
+ Mips::D5, Mips::D10, Mips::D11, Mips::D12, Mips::D13,
+ Mips::D14, Mips::D15, 0);
}
return std::vector<unsigned>();
}
diff --git a/lib/Target/Mips/MipsISelLowering.h b/lib/Target/Mips/MipsISelLowering.h
index 6f621b4..bd4b004 100644
--- a/lib/Target/Mips/MipsISelLowering.h
+++ b/lib/Target/Mips/MipsISelLowering.h
@@ -40,6 +40,12 @@ namespace llvm {
// Select CC Pseudo Instruction
SelectCC,
+ // Float Point Branch Conditional
+ FPBrcond,
+
+ // Float Point Compare
+ FPCmp,
+
// Return
Ret
};
@@ -69,6 +75,9 @@ namespace llvm {
MVT getSetCCResultType(const SDOperand &) const;
private:
+ // Subtarget Info
+ const MipsSubtarget *Subtarget;
+
// Lower Operand helpers
SDOperand LowerCCCArguments(SDOperand Op, SelectionDAG &DAG);
SDOperand LowerCCCCallTo(SDOperand Op, SelectionDAG &DAG, unsigned CC);
diff --git a/lib/Target/Mips/MipsInstrFPU.td b/lib/Target/Mips/MipsInstrFPU.td
new file mode 100644
index 0000000..a185a35
--- /dev/null
+++ b/lib/Target/Mips/MipsInstrFPU.td
@@ -0,0 +1,296 @@
+//===- MipsInstrFPU.td - Mips FPU Instruction Information -------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains the Mips implementation of the TargetInstrInfo class.
+//
+//===----------------------------------------------------------------------===//
+
+//===----------------------------------------------------------------------===//
+// Float Point Instructions
+// ------------------------
+// * 64bit fp:
+// - 32 64-bit registers (default mode)
+// - 16 even 32-bit registers (32-bit compatible mode) for
+// single and double access.
+// * 32bit fp:
+// - 16 even 32-bit registers - single and double (aliased)
+// - 32 32-bit registers (within single-only mode)
+//===----------------------------------------------------------------------===//
+
+// Float Point Compare and Branch
+def SDT_MipsFPBrcond : SDTypeProfile<0, 3, [SDTCisSameAs<0, 2>, SDTCisInt<0>,
+ SDTCisVT<1, OtherVT>]>;
+def SDT_MipsFPCmp : SDTypeProfile<0, 3, [SDTCisSameAs<0, 1>, SDTCisFP<0>,
+ SDTCisInt<2>]>;
+def MipsFPBrcond : SDNode<"MipsISD::FPBrcond", SDT_MipsFPBrcond,
+ [SDNPHasChain]>;
+def MipsFPCmp : SDNode<"MipsISD::FPCmp", SDT_MipsFPCmp>;
+
+// Operand for printing out a condition code.
+let PrintMethod = "printFCCOperand" in
+ def condcode : Operand<i32>;
+
+//===----------------------------------------------------------------------===//
+// Feature predicates.
+//===----------------------------------------------------------------------===//
+
+def In32BitMode : Predicate<"!Subtarget.isFP64bit()">;
+def In64BitMode : Predicate<"Subtarget.isFP64bit()">;
+def IsSingleFloat : Predicate<"Subtarget.isSingleFloat()">;
+def IsNotSingleFloat : Predicate<"!Subtarget.isSingleFloat()">;
+
+//===----------------------------------------------------------------------===//
+// Instruction Class Templates
+//
+// A set of multiclasses is used to address this in one shot.
+// SO32 - single precision only, uses all 32 32-bit fp registers
+// require FGR32 Register Class and IsSingleFloat
+// AS32 - 16 even fp registers are used for single precision
+// require AFGR32 Register Class and In32BitMode
+// S64 - 32 64 bit registers are used to hold 32-bit single precision values.
+// require FGR64 Register Class and In64BitMode
+// D32 - 16 even fp registers are used for double precision
+// require AFGR64 Register Class and In32BitMode
+// D64 - 32 64 bit registers are used to hold 64-bit double precision values.
+// require FGR64 Register Class and In64BitMode
+//
+// Only SO32, AS32 and D32 are supported right now.
+//
+//===----------------------------------------------------------------------===//
+
+multiclass FFR1_1<bits<6> funct, string asmstr>
+{
+ def _SO32 : FFR<0x11, funct, 0x0, (outs FGR32:$fd), (ins FGR32:$fs),
+ !strconcat(asmstr, ".s $fd, $fs"), []>, Requires<[IsSingleFloat]>;
+
+ def _AS32 : FFR<0x11, funct, 0x0, (outs AFGR32:$fd), (ins AFGR32:$fs),
+ !strconcat(asmstr, ".s $fd, $fs"), []>, Requires<[In32BitMode]>;
+
+ def _D32 : FFR<0x11, funct, 0x1, (outs AFGR64:$fd), (ins AFGR64:$fs),
+ !strconcat(asmstr, ".d $fd, $fs"), []>, Requires<[In32BitMode]>;
+}
+
+multiclass FFR1_2<bits<6> funct, string asmstr, SDNode FOp>
+{
+ def _SO32 : FFR<0x11, funct, 0x0, (outs FGR32:$fd), (ins FGR32:$fs),
+ !strconcat(asmstr, ".s $fd, $fs"),
+ [(set FGR32:$fd, (FOp FGR32:$fs))]>, Requires<[IsSingleFloat]>;
+
+ def _AS32 : FFR<0x11, funct, 0x0, (outs AFGR32:$fd), (ins AFGR32:$fs),
+ !strconcat(asmstr, ".s $fd, $fs"),
+ [(set AFGR32:$fd, (FOp AFGR32:$fs))]>, Requires<[In32BitMode]>;
+
+ def _D32 : FFR<0x11, funct, 0x1, (outs AFGR64:$fd), (ins AFGR64:$fs),
+ !strconcat(asmstr, ".d $fd, $fs"),
+ [(set AFGR64:$fd, (FOp AFGR64:$fs))]>, Requires<[In32BitMode]>;
+}
+
+class FFR1_3<bits<6> funct, bits<5> fmt, RegisterClass RcSrc,
+ RegisterClass RcDst, string asmstr>:
+ FFR<0x11, funct, fmt, (outs RcSrc:$fd), (ins RcDst:$fs),
+ !strconcat(asmstr, " $fd, $fs"), []>;
+
+
+multiclass FFR1_4<bits<6> funct, string asmstr, SDNode FOp> {
+ def _SO32 : FFR<0x11, funct, 0x0, (outs FGR32:$fd), (ins FGR32:$fs, FGR32:$ft),
+ !strconcat(asmstr, ".s $fd, $fs, $ft"),
+ [(set FGR32:$fd, (FOp FGR32:$fs, FGR32:$ft))]>,
+ Requires<[IsSingleFloat]>;
+
+ def _AS32 : FFR<0x11, funct, 0x0, (outs AFGR32:$fd),
+ (ins AFGR32:$fs, AFGR32:$ft),
+ !strconcat(asmstr, ".s $fd, $fs, $ft"),
+ [(set AFGR32:$fd, (FOp AFGR32:$fs, AFGR32:$ft))]>,
+ Requires<[In32BitMode]>;
+
+ def _D32 : FFR<0x11, funct, 0x1, (outs AFGR64:$fd),
+ (ins AFGR64:$fs, AFGR64:$ft),
+ !strconcat(asmstr, ".d $fd, $fs, $ft"),
+ [(set AFGR64:$fd, (FOp AFGR64:$fs, AFGR64:$ft))]>,
+ Requires<[In32BitMode]>;
+}
+
+//===----------------------------------------------------------------------===//
+// Float Point Instructions
+//===----------------------------------------------------------------------===//
+
+let ft = 0 in {
+ defm FLOOR_W : FFR1_1<0b001111, "floor.w">;
+ defm CEIL_W : FFR1_1<0b001110, "ceil.w">;
+ defm ROUND_W : FFR1_1<0b001100, "round.w">;
+ defm TRUNC_W : FFR1_1<0b001101, "trunc.w">;
+ defm CVTW : FFR1_1<0b100100, "cvt.w">;
+ defm FMOV : FFR1_1<0b000110, "mov">;
+
+ defm FABS : FFR1_2<0b000101, "abs", fabs>;
+ defm FNEG : FFR1_2<0b000111, "neg", fneg>;
+ defm FSQRT : FFR1_2<0b000100, "sqrt", fsqrt>;
+
+ let Predicates = [IsNotSingleFloat] in {
+ /// Ceil to long signed integer
+ def CEIL_LS : FFR1_3<0b001010, 0x0, AFGR32, AFGR32, "ceil.l">;
+ def CEIL_LD : FFR1_3<0b001010, 0x1, AFGR64, AFGR64, "ceil.l">;
+
+ /// Round to long signed integer
+ def ROUND_LS : FFR1_3<0b001000, 0x0, AFGR32, AFGR32, "round.l">;
+ def ROUND_LD : FFR1_3<0b001000, 0x1, AFGR64, AFGR64, "round.l">;
+
+ /// Floor to long signed integer
+ def FLOOR_LS : FFR1_3<0b001011, 0x0, AFGR32, AFGR32, "floor.l">;
+ def FLOOR_LD : FFR1_3<0b001011, 0x1, AFGR64, AFGR64, "floor.l">;
+
+ /// Trunc to long signed integer
+ def TRUNC_LS : FFR1_3<0b001001, 0x0, AFGR32, AFGR32, "trunc.l">;
+ def TRUNC_LD : FFR1_3<0b001001, 0x1, AFGR64, AFGR64, "trunc.l">;
+
+ /// Convert to long signed integer
+ def CVTL_S : FFR1_3<0b100101, 0x0, AFGR32, AFGR32, "cvt.l">;
+ def CVTL_D : FFR1_3<0b100101, 0x1, AFGR64, AFGR64, "cvt.l">;
+
+ /// Convert to Double Precison
+ def CVTD_S32 : FFR1_3<0b100001, 0x0, AFGR64, FGR32, "cvt.d.s">;
+ def CVTD_W32 : FFR1_3<0b100001, 0x2, AFGR64, FGR32, "cvt.d.w">;
+ def CVTD_L32 : FFR1_3<0b100001, 0x3, AFGR64, AFGR64, "cvt.d.l">;
+
+ /// Convert to Single Precison
+ def CVTS_D32 : FFR1_3<0b100000, 0x1, FGR32, AFGR64, "cvt.s.d">;
+ def CVTS_L32 : FFR1_3<0b100000, 0x3, FGR32, AFGR64, "cvt.s.l">;
+ }
+
+ /// Convert to Single Precison
+ def CVTS_W32 : FFR1_3<0b100000, 0x2, FGR32, FGR32, "cvt.s.w">,
+ Requires<[IsSingleFloat]>;
+}
+
+// The odd-numbered registers are only referenced when doing loads,
+// stores, and moves between floating-point and integer registers.
+// When defining instructions, we reference all 32-bit registers,
+// regardless of register aliasing.
+let fd = 0 in {
+ /// Move Control Registers From/To CPU Registers
+ ///def CFC1 : FFR<0x11, 0x0, 0x2, (outs CPURegs:$rt), (ins FGR32:$fs),
+ /// "cfc1 $rt, $fs", []>;
+
+ ///def CTC1 : FFR<0x11, 0x0, 0x6, (outs CPURegs:$rt), (ins FGR32:$fs),
+ /// "ctc1 $rt, $fs", []>;
+ ///
+ ///def CFC1A : FFR<0x11, 0x0, 0x2, (outs CPURegs:$rt), (ins AFGR32:$fs),
+ /// "cfc1 $rt, $fs", []>;
+
+ ///def CTC1A : FFR<0x11, 0x0, 0x6, (outs CPURegs:$rt), (ins AFGR32:$fs),
+ /// "ctc1 $rt, $fs", []>;
+
+ def MFC1 : FFR<0x11, 0x00, 0x00, (outs CPURegs:$rt), (ins FGR32:$fs),
+ "mfc1 $rt, $fs", []>;
+
+ def MTC1 : FFR<0x11, 0x00, 0x04, (outs FGR32:$fs), (ins CPURegs:$rt),
+ "mtc1 $fs, $rt", []>;
+
+ def MFC1A : FFR<0x11, 0x00, 0x00, (outs CPURegs:$rt), (ins AFGR32:$fs),
+ "mfc1 $rt, $fs", []>;
+
+ def MTC1A : FFR<0x11, 0x00, 0x04, (outs AFGR32:$fs), (ins CPURegs:$rt),
+ "mtc1 $fs, $rt", []>;
+}
+
+/// Float Point Memory Instructions
+let Predicates = [IsNotSingleFloat] in {
+ def LDC1 : FFI<0b110101, (outs AFGR64:$ft), (ins mem:$addr),
+ "ldc1 $ft, $addr", [(set AFGR64:$ft, (load addr:$addr))]>;
+
+ def SDC1 : FFI<0b111101, (outs), (ins AFGR64:$ft, mem:$addr),
+ "sdc1 $ft, $addr", [(store AFGR64:$ft, addr:$addr)]>;
+}
+
+// LWC1 and SWC1 can always be emited with odd registers.
+def LWC1 : FFI<0b110001, (outs FGR32:$ft), (ins mem:$addr), "lwc1 $ft, $addr",
+ [(set FGR32:$ft, (load addr:$addr))]>;
+def SWC1 : FFI<0b111001, (outs), (ins FGR32:$ft, mem:$addr), "swc1 $ft, $addr",
+ [(store FGR32:$ft, addr:$addr)]>;
+
+def LWC1A : FFI<0b110001, (outs AFGR32:$ft), (ins mem:$addr), "lwc1 $ft, $addr",
+ [(set AFGR32:$ft, (load addr:$addr))]>;
+def SWC1A : FFI<0b111001, (outs), (ins AFGR32:$ft, mem:$addr), "swc1 $ft, $addr",
+ [(store AFGR32:$ft, addr:$addr)]>;
+
+/// Floating-point Aritmetic
+defm FADD : FFR1_4<0x10, "add", fadd>;
+defm FDIV : FFR1_4<0x03, "div", fdiv>;
+defm FMUL : FFR1_4<0x02, "mul", fmul>;
+defm FSUB : FFR1_4<0x01, "sub", fsub>;
+
+//===----------------------------------------------------------------------===//
+// Float Point Branch Codes
+//===----------------------------------------------------------------------===//
+// Mips branch codes. These correspond to condcode in MipsInstrInfo.h.
+// They must be kept in synch.
+def MIPS_BRANCH_F : PatLeaf<(i32 0)>;
+def MIPS_BRANCH_T : PatLeaf<(i32 1)>;
+def MIPS_BRANCH_FL : PatLeaf<(i32 2)>;
+def MIPS_BRANCH_TL : PatLeaf<(i32 3)>;
+
+/// Float Point Branch of False/True (Likely)
+let isBranch=1, isTerminator=1, hasDelaySlot=1, base=0x8, Uses=[FCR31] in {
+ class FBRANCH<PatLeaf op, string asmstr> : FFI<0x11, (ops),
+ (ins brtarget:$dst), !strconcat(asmstr, " $dst"),
+ [(MipsFPBrcond op, bb:$dst, FCR31)]>;
+}
+def BC1F : FBRANCH<MIPS_BRANCH_F, "bc1f">;
+def BC1T : FBRANCH<MIPS_BRANCH_T, "bc1t">;
+def BC1FL : FBRANCH<MIPS_BRANCH_FL, "bc1fl">;
+def BC1TL : FBRANCH<MIPS_BRANCH_TL, "bc1tl">;
+
+//===----------------------------------------------------------------------===//
+// Float Point Flag Conditions
+//===----------------------------------------------------------------------===//
+// Mips condition codes. They must correspond to condcode in MipsInstrInfo.h.
+// They must be kept in synch.
+def MIPS_FCOND_F : PatLeaf<(i32 0)>;
+def MIPS_FCOND_UN : PatLeaf<(i32 1)>;
+def MIPS_FCOND_EQ : PatLeaf<(i32 2)>;
+def MIPS_FCOND_UEQ : PatLeaf<(i32 3)>;
+def MIPS_FCOND_OLT : PatLeaf<(i32 4)>;
+def MIPS_FCOND_ULT : PatLeaf<(i32 5)>;
+def MIPS_FCOND_OLE : PatLeaf<(i32 6)>;
+def MIPS_FCOND_ULE : PatLeaf<(i32 7)>;
+def MIPS_FCOND_SF : PatLeaf<(i32 8)>;
+def MIPS_FCOND_NGLE : PatLeaf<(i32 9)>;
+def MIPS_FCOND_SEQ : PatLeaf<(i32 10)>;
+def MIPS_FCOND_NGL : PatLeaf<(i32 11)>;
+def MIPS_FCOND_LT : PatLeaf<(i32 12)>;
+def MIPS_FCOND_NGE : PatLeaf<(i32 13)>;
+def MIPS_FCOND_LE : PatLeaf<(i32 14)>;
+def MIPS_FCOND_NGT : PatLeaf<(i32 15)>;
+
+/// Floating Point Compare
+let hasDelaySlot = 1, Defs=[FCR31] in {
+
+//multiclass FCC1_1<RegisterClass RC>
+
+ def FCMP_SO32 : FCC<0x0, (outs), (ins FGR32:$fs, FGR32:$ft, condcode:$cc),
+ "c.$cc.s $fs $ft", [(MipsFPCmp FGR32:$fs, FGR32:$ft, imm:$cc),
+ (implicit FCR31)]>, Requires<[IsSingleFloat]>;
+
+ def FCMP_AS32 : FCC<0x0, (outs), (ins AFGR32:$fs, AFGR32:$ft, condcode:$cc),
+ "c.$cc.s $fs $ft", [(MipsFPCmp AFGR32:$fs, AFGR32:$ft, imm:$cc),
+ (implicit FCR31)]>, Requires<[In32BitMode]>;
+
+ def FCMP_D32 : FCC<0x1, (outs), (ins AFGR64:$fs, AFGR64:$ft, condcode:$cc),
+ "c.$cc.d $fs $ft", [(MipsFPCmp AFGR64:$fs, AFGR64:$ft, imm:$cc),
+ (implicit FCR31)]>, Requires<[In32BitMode]>;
+}
+
+//===----------------------------------------------------------------------===//
+// Float Point Patterns
+//===----------------------------------------------------------------------===//
+def : Pat<(f32 (sint_to_fp CPURegs:$src)), (CVTS_W32 (MTC1 CPURegs:$src))>;
+def : Pat<(f64 (sint_to_fp CPURegs:$src)), (CVTD_W32 (MTC1 CPURegs:$src))>;
+def : Pat<(i32 (fp_to_sint FGR32:$src)), (MFC1 (CVTW_SO32 FGR32:$src))>;
+def : Pat<(i32 (fp_to_sint AFGR32:$src)), (MFC1 (CVTW_AS32 AFGR32:$src))>;
+
diff --git a/lib/Target/Mips/MipsInstrFormats.td b/lib/Target/Mips/MipsInstrFormats.td
index f82c3f5..226377f 100644
--- a/lib/Target/Mips/MipsInstrFormats.td
+++ b/lib/Target/Mips/MipsInstrFormats.td
@@ -120,8 +120,8 @@ class FJ<bits<6> op, dag outs, dag ins, string asmstr, list<dag> pattern,
//===----------------------------------------------------------------------===//
class FFR<bits<6> op, bits<6> _funct, bits<5> _fmt, dag outs, dag ins,
- string asmstr, list<dag> pattern, InstrItinClass itin> :
- MipsInst<outs, ins, asmstr, pattern, itin>
+ string asmstr, list<dag> pattern> :
+ MipsInst<outs, ins, asmstr, pattern, NoItinerary>
{
bits<5> fd;
bits<5> fs;
@@ -141,21 +141,42 @@ class FFR<bits<6> op, bits<6> _funct, bits<5> _fmt, dag outs, dag ins,
}
//===----------------------------------------------------------------------===//
-// Format FI instruction class in Mips : <|opcode|fmt|ft|immediate|>
+// Format FI instruction class in Mips : <|opcode|base|ft|immediate|>
//===----------------------------------------------------------------------===//
-class FFI<bits<6> op, bits<5> _fmt, dag outs, dag ins, string asmstr,
- list<dag> pattern, InstrItinClass itin>:
- MipsInst<outs, ins, asmstr, pattern, itin>
+class FFI<bits<6> op, dag outs, dag ins, string asmstr, list<dag> pattern>:
+ MipsInst<outs, ins, asmstr, pattern, NoItinerary>
{
bits<5> ft;
- bits<5> fmt;
+ bits<5> base;
bits<16> imm16;
let opcode = op;
+
+ let Inst{25-21} = base;
+ let Inst{20-16} = ft;
+ let Inst{15-0} = imm16;
+}
+
+//===----------------------------------------------------------------------===//
+// Compare instruction class in Mips : <|010001|fmt|ft|fs|0000011|condcode|>
+//===----------------------------------------------------------------------===//
+
+class FCC<bits<5> _fmt, dag outs, dag ins, string asmstr, list<dag> pattern> :
+ MipsInst<outs, ins, asmstr, pattern, NoItinerary>
+{
+ bits<5> fs;
+ bits<5> ft;
+ bits<4> cc;
+ bits<5> fmt;
+
+ let opcode = 0x11;
let fmt = _fmt;
let Inst{25-21} = fmt;
let Inst{20-16} = ft;
- let Inst{15-0} = imm16;
+ let Inst{15-11} = fs;
+ let Inst{10-6} = 0;
+ let Inst{5-4} = 0b11;
+ let Inst{3-0} = cc;
}
diff --git a/lib/Target/Mips/MipsInstrInfo.cpp b/lib/Target/Mips/MipsInstrInfo.cpp
index c7bc1e9..cc29bae 100644
--- a/lib/Target/Mips/MipsInstrInfo.cpp
+++ b/lib/Target/Mips/MipsInstrInfo.cpp
@@ -19,7 +19,6 @@
using namespace llvm;
-// TODO: Add the subtarget support on this constructor
MipsInstrInfo::MipsInstrInfo(MipsTargetMachine &tm)
: TargetInstrInfoImpl(MipsInsts, array_lengthof(MipsInsts)),
TM(tm), RI(*this) {}
@@ -35,8 +34,7 @@ isMoveInstr(const MachineInstr &MI, unsigned &SrcReg, unsigned &DstReg) const
{
// addu $dst, $src, $zero || addu $dst, $zero, $src
// or $dst, $src, $zero || or $dst, $zero, $src
- if ((MI.getOpcode() == Mips::ADDu) || (MI.getOpcode() == Mips::OR))
- {
+ if ((MI.getOpcode() == Mips::ADDu) || (MI.getOpcode() == Mips::OR)) {
if (MI.getOperand(1).getReg() == Mips::ZERO) {
DstReg = MI.getOperand(0).getReg();
SrcReg = MI.getOperand(2).getReg();
@@ -48,9 +46,20 @@ isMoveInstr(const MachineInstr &MI, unsigned &SrcReg, unsigned &DstReg) const
}
}
+ // mov $fpDst, $fpSrc
+ // mfc $gpDst, $fpSrc
+ // mtc $fpDst, $gpSrc
+ if (MI.getOpcode() == Mips::FMOV_SO32 || MI.getOpcode() == Mips::FMOV_AS32 ||
+ MI.getOpcode() == Mips::FMOV_D32 || MI.getOpcode() == Mips::MFC1A ||
+ MI.getOpcode() == Mips::MFC1 || MI.getOpcode() == Mips::MTC1A ||
+ MI.getOpcode() == Mips::MTC1 ) {
+ DstReg = MI.getOperand(0).getReg();
+ SrcReg = MI.getOperand(1).getReg();
+ return true;
+ }
+
// addiu $dst, $src, 0
- if (MI.getOpcode() == Mips::ADDiu)
- {
+ if (MI.getOpcode() == Mips::ADDiu) {
if ((MI.getOperand(1).isRegister()) && (isZeroImm(MI.getOperand(2)))) {
DstReg = MI.getOperand(0).getReg();
SrcReg = MI.getOperand(1).getReg();
@@ -68,12 +77,11 @@ isMoveInstr(const MachineInstr &MI, unsigned &SrcReg, unsigned &DstReg) const
unsigned MipsInstrInfo::
isLoadFromStackSlot(MachineInstr *MI, int &FrameIndex) const
{
- if (MI->getOpcode() == Mips::LW)
- {
+ if ((MI->getOpcode() == Mips::LW) || (MI->getOpcode() == Mips::LWC1) ||
+ (MI->getOpcode() == Mips::LWC1A) || (MI->getOpcode() == Mips::LDC1)) {
if ((MI->getOperand(2).isFrameIndex()) && // is a stack slot
(MI->getOperand(1).isImmediate()) && // the imm is zero
- (isZeroImm(MI->getOperand(1))))
- {
+ (isZeroImm(MI->getOperand(1)))) {
FrameIndex = MI->getOperand(2).getIndex();
return MI->getOperand(0).getReg();
}
@@ -90,11 +98,11 @@ isLoadFromStackSlot(MachineInstr *MI, int &FrameIndex) const
unsigned MipsInstrInfo::
isStoreToStackSlot(MachineInstr *MI, int &FrameIndex) const
{
- if (MI->getOpcode() == Mips::SW) {
+ if ((MI->getOpcode() == Mips::SW) || (MI->getOpcode() == Mips::SWC1) ||
+ (MI->getOpcode() == Mips::SWC1A) || (MI->getOpcode() == Mips::SDC1)) {
if ((MI->getOperand(0).isFrameIndex()) && // is a stack slot
(MI->getOperand(1).isImmediate()) && // the imm is zero
- (isZeroImm(MI->getOperand(1))))
- {
+ (isZeroImm(MI->getOperand(1)))) {
FrameIndex = MI->getOperand(0).getIndex();
return MI->getOperand(2).getReg();
}
@@ -110,6 +118,208 @@ insertNoop(MachineBasicBlock &MBB, MachineBasicBlock::iterator MI) const
BuildMI(MBB, MI, get(Mips::NOP));
}
+void MipsInstrInfo::
+copyRegToReg(MachineBasicBlock &MBB, MachineBasicBlock::iterator I,
+ unsigned DestReg, unsigned SrcReg,
+ const TargetRegisterClass *DestRC,
+ const TargetRegisterClass *SrcRC) const {
+ if (DestRC != SrcRC) {
+ if ((DestRC == Mips::CPURegsRegisterClass) &&
+ (SrcRC == Mips::FGR32RegisterClass))
+ BuildMI(MBB, I, get(Mips::MFC1), DestReg).addReg(SrcReg);
+ else if ((DestRC == Mips::CPURegsRegisterClass) &&
+ (SrcRC == Mips::AFGR32RegisterClass))
+ BuildMI(MBB, I, get(Mips::MFC1A), DestReg).addReg(SrcReg);
+ else if ((DestRC == Mips::FGR32RegisterClass) &&
+ (SrcRC == Mips::CPURegsRegisterClass))
+ BuildMI(MBB, I, get(Mips::MTC1), DestReg).addReg(SrcReg);
+ else if ((DestRC == Mips::AFGR32RegisterClass) &&
+ (SrcRC == Mips::CPURegsRegisterClass))
+ BuildMI(MBB, I, get(Mips::MTC1A), DestReg).addReg(SrcReg);
+ else
+ assert (0 && "DestRC != SrcRC, Can't copy this register");
+ }
+
+ if (DestRC == Mips::CPURegsRegisterClass)
+ BuildMI(MBB, I, get(Mips::ADDu), DestReg).addReg(Mips::ZERO)
+ .addReg(SrcReg);
+ else if (DestRC == Mips::FGR32RegisterClass)
+ BuildMI(MBB, I, get(Mips::FMOV_SO32), DestReg).addReg(SrcReg);
+ else if (DestRC == Mips::AFGR32RegisterClass)
+ BuildMI(MBB, I, get(Mips::FMOV_AS32), DestReg).addReg(SrcReg);
+ else if (DestRC == Mips::AFGR64RegisterClass)
+ BuildMI(MBB, I, get(Mips::FMOV_D32), DestReg).addReg(SrcReg);
+ else
+ assert (0 && "Can't copy this register");
+}
+
+void MipsInstrInfo::
+storeRegToStackSlot(MachineBasicBlock &MBB, MachineBasicBlock::iterator I,
+ unsigned SrcReg, bool isKill, int FI,
+ const TargetRegisterClass *RC) const
+{
+ unsigned Opc;
+ if (RC == Mips::CPURegsRegisterClass)
+ Opc = Mips::SW;
+ else if (RC == Mips::FGR32RegisterClass)
+ Opc = Mips::SWC1;
+ else if (RC == Mips::AFGR32RegisterClass)
+ Opc = Mips::SWC1A;
+ else if (RC == Mips::AFGR64RegisterClass)
+ Opc = Mips::SDC1;
+ else
+ assert(0 && "Can't store this register to stack slot");
+
+ BuildMI(MBB, I, get(Opc)).addReg(SrcReg, false, false, isKill)
+ .addImm(0).addFrameIndex(FI);
+}
+
+void MipsInstrInfo::storeRegToAddr(MachineFunction &MF, unsigned SrcReg,
+ bool isKill, SmallVectorImpl<MachineOperand> &Addr,
+ const TargetRegisterClass *RC, SmallVectorImpl<MachineInstr*> &NewMIs) const
+{
+ unsigned Opc;
+ if (RC == Mips::CPURegsRegisterClass)
+ Opc = Mips::SW;
+ else if (RC == Mips::FGR32RegisterClass)
+ Opc = Mips::SWC1;
+ else if (RC == Mips::AFGR32RegisterClass)
+ Opc = Mips::SWC1A;
+ else if (RC == Mips::AFGR64RegisterClass)
+ Opc = Mips::SDC1;
+ else
+ assert(0 && "Can't store this register");
+
+ MachineInstrBuilder MIB = BuildMI(get(Opc))
+ .addReg(SrcReg, false, false, isKill);
+ for (unsigned i = 0, e = Addr.size(); i != e; ++i) {
+ MachineOperand &MO = Addr[i];
+ if (MO.isRegister())
+ MIB.addReg(MO.getReg());
+ else if (MO.isImmediate())
+ MIB.addImm(MO.getImm());
+ else
+ MIB.addFrameIndex(MO.getIndex());
+ }
+ NewMIs.push_back(MIB);
+ return;
+}
+
+void MipsInstrInfo::
+loadRegFromStackSlot(MachineBasicBlock &MBB, MachineBasicBlock::iterator I,
+ unsigned DestReg, int FI,
+ const TargetRegisterClass *RC) const
+{
+ unsigned Opc;
+ if (RC == Mips::CPURegsRegisterClass)
+ Opc = Mips::LW;
+ else if (RC == Mips::FGR32RegisterClass)
+ Opc = Mips::LWC1;
+ else if (RC == Mips::AFGR32RegisterClass)
+ Opc = Mips::LWC1A;
+ else if (RC == Mips::AFGR64RegisterClass)
+ Opc = Mips::LDC1;
+ else
+ assert(0 && "Can't load this register from stack slot");
+
+ BuildMI(MBB, I, get(Opc), DestReg).addImm(0).addFrameIndex(FI);
+}
+
+void MipsInstrInfo::loadRegFromAddr(MachineFunction &MF, unsigned DestReg,
+ SmallVectorImpl<MachineOperand> &Addr,
+ const TargetRegisterClass *RC,
+ SmallVectorImpl<MachineInstr*> &NewMIs) const {
+ unsigned Opc;
+ if (RC == Mips::CPURegsRegisterClass)
+ Opc = Mips::LW;
+ else if (RC == Mips::FGR32RegisterClass)
+ Opc = Mips::LWC1;
+ else if (RC == Mips::AFGR32RegisterClass)
+ Opc = Mips::LWC1A;
+ else if (RC == Mips::AFGR64RegisterClass)
+ Opc = Mips::LDC1;
+ else
+ assert(0 && "Can't load this register");
+
+ MachineInstrBuilder MIB = BuildMI(get(Opc), DestReg);
+ for (unsigned i = 0, e = Addr.size(); i != e; ++i) {
+ MachineOperand &MO = Addr[i];
+ if (MO.isRegister())
+ MIB.addReg(MO.getReg());
+ else if (MO.isImmediate())
+ MIB.addImm(MO.getImm());
+ else
+ MIB.addFrameIndex(MO.getIndex());
+ }
+ NewMIs.push_back(MIB);
+ return;
+}
+
+MachineInstr *MipsInstrInfo::
+foldMemoryOperand(MachineFunction &MF,
+ MachineInstr* MI,
+ SmallVectorImpl<unsigned> &Ops, int FI) const
+{
+ if (Ops.size() != 1) return NULL;
+
+ MachineInstr *NewMI = NULL;
+
+ switch (MI->getOpcode()) {
+ case Mips::ADDu:
+ if ((MI->getOperand(0).isRegister()) &&
+ (MI->getOperand(1).isRegister()) &&
+ (MI->getOperand(1).getReg() == Mips::ZERO) &&
+ (MI->getOperand(2).isRegister())) {
+ if (Ops[0] == 0) { // COPY -> STORE
+ unsigned SrcReg = MI->getOperand(2).getReg();
+ bool isKill = MI->getOperand(2).isKill();
+ NewMI = BuildMI(get(Mips::SW)).addFrameIndex(FI)
+ .addImm(0).addReg(SrcReg, false, false, isKill);
+ } else { // COPY -> LOAD
+ unsigned DstReg = MI->getOperand(0).getReg();
+ bool isDead = MI->getOperand(0).isDead();
+ NewMI = BuildMI(get(Mips::LW))
+ .addReg(DstReg, true, false, false, isDead)
+ .addImm(0).addFrameIndex(FI);
+ }
+ }
+ break;
+ case Mips::FMOV_SO32:
+ case Mips::FMOV_AS32:
+ case Mips::FMOV_D32:
+ if ((MI->getOperand(0).isRegister()) &&
+ (MI->getOperand(1).isRegister())) {
+ const TargetRegisterClass *RC = RI.getRegClass(MI->getOperand(0).getReg());
+ unsigned StoreOpc, LoadOpc;
+
+ if (RC == Mips::FGR32RegisterClass) {
+ LoadOpc = Mips::LWC1; StoreOpc = Mips::SWC1;
+ } else if (RC == Mips::AFGR32RegisterClass) {
+ LoadOpc = Mips::LWC1A; StoreOpc = Mips::SWC1A;
+ } else if (RC == Mips::AFGR64RegisterClass) {
+ LoadOpc = Mips::LDC1; StoreOpc = Mips::SDC1;
+ } else
+ assert(0 && "foldMemoryOperand register unknown");
+
+ if (Ops[0] == 0) { // COPY -> STORE
+ unsigned SrcReg = MI->getOperand(1).getReg();
+ bool isKill = MI->getOperand(1).isKill();
+ NewMI = BuildMI(get(StoreOpc)).addFrameIndex(FI)
+ .addImm(0).addReg(SrcReg, false, false, isKill);
+ } else { // COPY -> LOAD
+ unsigned DstReg = MI->getOperand(0).getReg();
+ bool isDead = MI->getOperand(0).isDead();
+ NewMI = BuildMI(get(LoadOpc))
+ .addReg(DstReg, true, false, false, isDead)
+ .addImm(0).addFrameIndex(FI);
+ }
+ }
+ break;
+ }
+
+ return NewMI;
+}
+
//===----------------------------------------------------------------------===//
// Branch Analysis
//===----------------------------------------------------------------------===//
@@ -120,12 +330,12 @@ static Mips::CondCode GetCondFromBranchOpc(unsigned BrOpc)
{
switch (BrOpc) {
default: return Mips::COND_INVALID;
- case Mips::BEQ : return Mips::COND_E;
- case Mips::BNE : return Mips::COND_NE;
- case Mips::BGTZ : return Mips::COND_GZ;
- case Mips::BGEZ : return Mips::COND_GEZ;
- case Mips::BLTZ : return Mips::COND_LZ;
- case Mips::BLEZ : return Mips::COND_LEZ;
+ case Mips::BEQ : return Mips::COND_E;
+ case Mips::BNE : return Mips::COND_NE;
+ case Mips::BGTZ : return Mips::COND_GZ;
+ case Mips::BGEZ : return Mips::COND_GEZ;
+ case Mips::BLTZ : return Mips::COND_LZ;
+ case Mips::BLEZ : return Mips::COND_LEZ;
}
}
@@ -156,6 +366,22 @@ Mips::CondCode Mips::GetOppositeBranchCondition(Mips::CondCode CC)
case Mips::COND_GEZ : return Mips::COND_LZ;
case Mips::COND_LZ : return Mips::COND_GEZ;
case Mips::COND_LEZ : return Mips::COND_GZ;
+ case Mips::FCOND_F : return Mips::FCOND_T;
+ case Mips::FCOND_UN : return Mips::FCOND_OR;
+ case Mips::FCOND_EQ : return Mips::FCOND_NEQ;
+ case Mips::FCOND_UEQ: return Mips::FCOND_OGL;
+ case Mips::FCOND_OLT: return Mips::FCOND_UGE;
+ case Mips::FCOND_ULT: return Mips::FCOND_OGE;
+ case Mips::FCOND_OLE: return Mips::FCOND_UGT;
+ case Mips::FCOND_ULE: return Mips::FCOND_OGT;
+ case Mips::FCOND_SF: return Mips::FCOND_ST;
+ case Mips::FCOND_NGLE:return Mips::FCOND_GLE;
+ case Mips::FCOND_SEQ: return Mips::FCOND_SNE;
+ case Mips::FCOND_NGL: return Mips::FCOND_GL;
+ case Mips::FCOND_LT: return Mips::FCOND_NLT;
+ case Mips::FCOND_NGE: return Mips::FCOND_GE;
+ case Mips::FCOND_LE: return Mips::FCOND_NLE;
+ case Mips::FCOND_NGT: return Mips::FCOND_GT;
}
}
@@ -287,124 +513,6 @@ InsertBranch(MachineBasicBlock &MBB, MachineBasicBlock *TBB,
return 2;
}
-void MipsInstrInfo::
-copyRegToReg(MachineBasicBlock &MBB, MachineBasicBlock::iterator I,
- unsigned DestReg, unsigned SrcReg,
- const TargetRegisterClass *DestRC,
- const TargetRegisterClass *SrcRC) const {
- if (DestRC != SrcRC) {
- cerr << "Not yet supported!";
- abort();
- }
-
- if (DestRC == Mips::CPURegsRegisterClass)
- BuildMI(MBB, I, get(Mips::ADDu), DestReg).addReg(Mips::ZERO)
- .addReg(SrcReg);
- else
- assert (0 && "Can't copy this register");
-}
-
-void MipsInstrInfo::
-storeRegToStackSlot(MachineBasicBlock &MBB, MachineBasicBlock::iterator I,
- unsigned SrcReg, bool isKill, int FI,
- const TargetRegisterClass *RC) const
-{
- if (RC == Mips::CPURegsRegisterClass)
- BuildMI(MBB, I, get(Mips::SW)).addReg(SrcReg, false, false, isKill)
- .addImm(0).addFrameIndex(FI);
- else
- assert(0 && "Can't store this register to stack slot");
-}
-
-void MipsInstrInfo::storeRegToAddr(MachineFunction &MF, unsigned SrcReg,
- bool isKill,
- SmallVectorImpl<MachineOperand> &Addr,
- const TargetRegisterClass *RC,
- SmallVectorImpl<MachineInstr*> &NewMIs) const {
- if (RC != Mips::CPURegsRegisterClass)
- assert(0 && "Can't store this register");
- MachineInstrBuilder MIB = BuildMI(get(Mips::SW))
- .addReg(SrcReg, false, false, isKill);
- for (unsigned i = 0, e = Addr.size(); i != e; ++i) {
- MachineOperand &MO = Addr[i];
- if (MO.isRegister())
- MIB.addReg(MO.getReg());
- else if (MO.isImmediate())
- MIB.addImm(MO.getImm());
- else
- MIB.addFrameIndex(MO.getIndex());
- }
- NewMIs.push_back(MIB);
- return;
-}
-
-void MipsInstrInfo::
-loadRegFromStackSlot(MachineBasicBlock &MBB, MachineBasicBlock::iterator I,
- unsigned DestReg, int FI,
- const TargetRegisterClass *RC) const
-{
- if (RC == Mips::CPURegsRegisterClass)
- BuildMI(MBB, I, get(Mips::LW), DestReg).addImm(0).addFrameIndex(FI);
- else
- assert(0 && "Can't load this register from stack slot");
-}
-
-void MipsInstrInfo::loadRegFromAddr(MachineFunction &MF, unsigned DestReg,
- SmallVectorImpl<MachineOperand> &Addr,
- const TargetRegisterClass *RC,
- SmallVectorImpl<MachineInstr*> &NewMIs) const {
- if (RC != Mips::CPURegsRegisterClass)
- assert(0 && "Can't load this register");
- MachineInstrBuilder MIB = BuildMI(get(Mips::LW), DestReg);
- for (unsigned i = 0, e = Addr.size(); i != e; ++i) {
- MachineOperand &MO = Addr[i];
- if (MO.isRegister())
- MIB.addReg(MO.getReg());
- else if (MO.isImmediate())
- MIB.addImm(MO.getImm());
- else
- MIB.addFrameIndex(MO.getIndex());
- }
- NewMIs.push_back(MIB);
- return;
-}
-
-MachineInstr *MipsInstrInfo::
-foldMemoryOperand(MachineFunction &MF,
- MachineInstr* MI,
- SmallVectorImpl<unsigned> &Ops, int FI) const
-{
- if (Ops.size() != 1) return NULL;
-
- MachineInstr *NewMI = NULL;
-
- switch (MI->getOpcode())
- {
- case Mips::ADDu:
- if ((MI->getOperand(0).isRegister()) &&
- (MI->getOperand(1).isRegister()) &&
- (MI->getOperand(1).getReg() == Mips::ZERO) &&
- (MI->getOperand(2).isRegister()))
- {
- if (Ops[0] == 0) { // COPY -> STORE
- unsigned SrcReg = MI->getOperand(2).getReg();
- bool isKill = MI->getOperand(2).isKill();
- NewMI = BuildMI(get(Mips::SW)).addFrameIndex(FI)
- .addImm(0).addReg(SrcReg, false, false, isKill);
- } else { // COPY -> LOAD
- unsigned DstReg = MI->getOperand(0).getReg();
- bool isDead = MI->getOperand(0).isDead();
- NewMI = BuildMI(get(Mips::LW))
- .addReg(DstReg, true, false, false, isDead)
- .addImm(0).addFrameIndex(FI);
- }
- }
- break;
- }
-
- return NewMI;
-}
-
unsigned MipsInstrInfo::
RemoveBranch(MachineBasicBlock &MBB) const
{
@@ -456,5 +564,3 @@ ReverseBranchCondition(std::vector<MachineOperand> &Cond) const
Cond[0].setImm(GetOppositeBranchCondition((Mips::CondCode)Cond[0].getImm()));
return false;
}
-
-
diff --git a/lib/Target/Mips/MipsInstrInfo.h b/lib/Target/Mips/MipsInstrInfo.h
index 1c094a8..55a2249 100644
--- a/lib/Target/Mips/MipsInstrInfo.h
+++ b/lib/Target/Mips/MipsInstrInfo.h
@@ -24,6 +24,45 @@ namespace Mips {
// Mips Condition Codes
enum CondCode {
+ // To be used with float branch True
+ FCOND_F,
+ FCOND_UN,
+ FCOND_EQ,
+ FCOND_UEQ,
+ FCOND_OLT,
+ FCOND_ULT,
+ FCOND_OLE,
+ FCOND_ULE,
+ FCOND_SF,
+ FCOND_NGLE,
+ FCOND_SEQ,
+ FCOND_NGL,
+ FCOND_LT,
+ FCOND_NGE,
+ FCOND_LE,
+ FCOND_NGT,
+
+ // To be used with float branch False
+ // This conditions have the same mnemonic as the
+ // above ones, but are used with a branch False;
+ FCOND_T,
+ FCOND_OR,
+ FCOND_NEQ,
+ FCOND_OGL,
+ FCOND_UGE,
+ FCOND_OGE,
+ FCOND_UGT,
+ FCOND_OGT,
+ FCOND_ST,
+ FCOND_GLE,
+ FCOND_SNE,
+ FCOND_GL,
+ FCOND_NLT,
+ FCOND_GE,
+ FCOND_NLE,
+ FCOND_GT,
+
+ // Only integer conditions
COND_E,
COND_GZ,
COND_GEZ,
@@ -40,6 +79,45 @@ namespace Mips {
/// e.g. turning COND_E to COND_NE.
CondCode GetOppositeBranchCondition(Mips::CondCode CC);
+ /// MipsCCToString - Map each FP condition code to its string
+ inline static const char *MipsFCCToString(Mips::CondCode CC)
+ {
+ switch (CC) {
+ default: assert(0 && "Unknown condition code");
+ case FCOND_F:
+ case FCOND_T: return "f";
+ case FCOND_UN:
+ case FCOND_OR: return "un";
+ case FCOND_EQ:
+ case FCOND_NEQ: return "eq";
+ case FCOND_UEQ:
+ case FCOND_OGL: return "ueq";
+ case FCOND_OLT:
+ case FCOND_UGE: return "olt";
+ case FCOND_ULT:
+ case FCOND_OGE: return "ult";
+ case FCOND_OLE:
+ case FCOND_UGT: return "ole";
+ case FCOND_ULE:
+ case FCOND_OGT: return "ule";
+ case FCOND_SF:
+ case FCOND_ST: return "sf";
+ case FCOND_NGLE:
+ case FCOND_GLE: return "ngle";
+ case FCOND_SEQ:
+ case FCOND_SNE: return "seq";
+ case FCOND_NGL:
+ case FCOND_GL: return "ngl";
+ case FCOND_LT:
+ case FCOND_NLT: return "lt";
+ case FCOND_NGE:
+ case FCOND_GE: return "ge";
+ case FCOND_LE:
+ case FCOND_NLE: return "nle";
+ case FCOND_NGT:
+ case FCOND_GT: return "gt";
+ }
+ }
}
class MipsInstrInfo : public TargetInstrInfoImpl {
diff --git a/lib/Target/Mips/MipsInstrInfo.td b/lib/Target/Mips/MipsInstrInfo.td
index 57f24ad..f78fd5d 100644
--- a/lib/Target/Mips/MipsInstrInfo.td
+++ b/lib/Target/Mips/MipsInstrInfo.td
@@ -17,10 +17,16 @@ include "MipsInstrFormats.td"
// Mips profiles and nodes
//===----------------------------------------------------------------------===//
+def SDT_MipsRet : SDTypeProfile<0, 1, [SDTCisInt<0>]>;
+def SDT_MipsJmpLink : SDTypeProfile<0, 1, [SDTCisVT<0, iPTR>]>;
+def SDT_MipsSelectCC : SDTypeProfile<1, 3, [SDTCisSameAs<0, 1>,
+ SDTCisSameAs<1, 2>, SDTCisInt<3>]>;
+def SDT_MipsCallSeqStart : SDCallSeqStart<[SDTCisVT<0, i32>]>;
+def SDT_MipsCallSeqEnd : SDCallSeqEnd<[SDTCisVT<0, i32>, SDTCisVT<1, i32>]>;
+
// Call
-def SDT_MipsJmpLink : SDTypeProfile<0, 1, [SDTCisVT<0, iPTR>]>;
-def MipsJmpLink : SDNode<"MipsISD::JmpLink",SDT_MipsJmpLink, [SDNPHasChain,
- SDNPOutFlag]>;
+def MipsJmpLink : SDNode<"MipsISD::JmpLink",SDT_MipsJmpLink, [SDNPHasChain,
+ SDNPOutFlag]>;
// Hi and Lo nodes are used to handle global addresses. Used on
// MipsISelLowering to lower stuff like GlobalAddress, ExternalSymbol
@@ -29,29 +35,22 @@ def MipsHi : SDNode<"MipsISD::Hi", SDTIntUnaryOp, [SDNPOutFlag]>;
def MipsLo : SDNode<"MipsISD::Lo", SDTIntUnaryOp>;
// Return
-def SDT_MipsRet : SDTypeProfile<0, 1, [SDTCisInt<0>]>;
-def MipsRet : SDNode<"MipsISD::Ret", SDT_MipsRet, [SDNPHasChain,
- SDNPOptInFlag]>;
+def MipsRet : SDNode<"MipsISD::Ret", SDT_MipsRet, [SDNPHasChain,
+ SDNPOptInFlag]>;
// These are target-independent nodes, but have target-specific formats.
-def SDT_MipsCallSeqStart : SDCallSeqStart<[SDTCisVT<0, i32>]>;
-def SDT_MipsCallSeqEnd : SDCallSeqEnd<[SDTCisVT<0, i32>,
- SDTCisVT<1, i32>]>;
+def callseq_start : SDNode<"ISD::CALLSEQ_START", SDT_MipsCallSeqStart,
+ [SDNPHasChain, SDNPOutFlag]>;
+def callseq_end : SDNode<"ISD::CALLSEQ_END", SDT_MipsCallSeqEnd,
+ [SDNPHasChain, SDNPOptInFlag, SDNPOutFlag]>;
-def callseq_start : SDNode<"ISD::CALLSEQ_START", SDT_MipsCallSeqStart,
- [SDNPHasChain, SDNPOutFlag]>;
-def callseq_end : SDNode<"ISD::CALLSEQ_END", SDT_MipsCallSeqEnd,
- [SDNPHasChain, SDNPOptInFlag, SDNPOutFlag]>;
-
-// Select CC
-def SDT_MipsSelectCC : SDTypeProfile<1, 3, [SDTCisSameAs<0, 1>,
- SDTCisSameAs<1, 2>, SDTCisInt<3>]>;
-def MipsSelectCC : SDNode<"MipsISD::SelectCC", SDT_MipsSelectCC>;
+// Select Condition Code
+def MipsSelectCC : SDNode<"MipsISD::SelectCC", SDT_MipsSelectCC>;
//===----------------------------------------------------------------------===//
// Mips Instruction Predicate Definitions.
//===----------------------------------------------------------------------===//
-def IsStatic : Predicate<"TM.getRelocationModel() == Reloc::Static">;
+def IsAllegrex : Predicate<"Subtarget.isAllegrex()">;
//===----------------------------------------------------------------------===//
// Mips Operand, Complex Patterns and Transformations Definitions.
@@ -63,7 +62,6 @@ def calltarget : Operand<i32>;
def uimm16 : Operand<i32>;
def simm16 : Operand<i32>;
def shamt : Operand<i32>;
-def addrlabel : Operand<i32>;
// Address operand
def mem : Operand<i32> {
@@ -345,6 +343,12 @@ class EffectiveAddress<string instr_asm> :
instr_asm,
[(set CPURegs:$dst, addr:$addr)], IIAlu>;
+class SignExtInReg<bits<6> func, string instr_asm, ValueType vt>:
+ FR< 0x3f, func, (outs CPURegs:$dst), (ins CPURegs:$src),
+ !strconcat(instr_asm, " $dst, $src"),
+ [(set CPURegs:$dst, (sext_inreg CPURegs:$src, vt))], NoItinerary>;
+
+
//===----------------------------------------------------------------------===//
// Pseudo instructions
//===----------------------------------------------------------------------===//
@@ -352,11 +356,11 @@ class EffectiveAddress<string instr_asm> :
// As stack alignment is always done with addiu, we need a 16-bit immediate
let Defs = [SP], Uses = [SP] in {
def ADJCALLSTACKDOWN : MipsPseudo<(outs), (ins uimm16:$amt),
- "!ADJCALLSTACKDOWN $amt",
- [(callseq_start imm:$amt)]>;
+ "!ADJCALLSTACKDOWN $amt",
+ [(callseq_start imm:$amt)]>;
def ADJCALLSTACKUP : MipsPseudo<(outs), (ins uimm16:$amt1, uimm16:$amt2),
- "!ADJCALLSTACKUP $amt1",
- [(callseq_end imm:$amt1, imm:$amt2)]>;
+ "!ADJCALLSTACKUP $amt1",
+ [(callseq_end imm:$amt1, imm:$amt2)]>;
}
// When handling PIC code the assembler needs .cpload and .cprestore
@@ -364,10 +368,10 @@ def ADJCALLSTACKUP : MipsPseudo<(outs), (ins uimm16:$amt1, uimm16:$amt2),
// are used, we have the same behavior, but get also a bunch of warnings
// from the assembler.
def CPLOAD : MipsPseudo<(outs), (ins CPURegs:$reg),
- ".set noreorder\n\t.cpload $reg\n\t.set reorder\n",
- []>;
+ ".set noreorder\n\t.cpload $reg\n\t.set reorder\n",
+ []>;
def CPRESTORE : MipsPseudo<(outs), (ins uimm16:$loc),
- ".cprestore $loc\n", []>;
+ ".cprestore $loc\n", []>;
// The supported Mips ISAs dont have any instruction close to the SELECT_CC
// operation. The solution is to create a Mips pseudo SELECT_CC instruction
@@ -474,19 +478,6 @@ def MFLO : MoveFromTo<0x12, "mflo">;
def MTHI : MoveFromTo<0x11, "mthi">;
def MTLO : MoveFromTo<0x13, "mtlo">;
-// Count Leading
-// CLO/CLZ are part of the newer MIPS32(tm) instruction
-// set and not older Mips I keep this for future use
-// though.
-//def CLO : CountLeading<0x21, "clo">;
-//def CLZ : CountLeading<0x20, "clz">;
-
-// MADD*/MSUB* are not part of MipsI either.
-//def MADD : MArithR<0x00, "madd">;
-//def MADDU : MArithR<0x01, "maddu">;
-//def MSUB : MArithR<0x04, "msub">;
-//def MSUBU : MArithR<0x05, "msubu">;
-
// No operation
let addr=0 in
def NOP : FJ<0, (outs), (ins), "nop", [], IIAlu>;
@@ -506,6 +497,27 @@ let isReturn=1, isTerminator=1, hasDelaySlot=1,
// can be matched. It's similar to Sparc LEA_ADDRi
def LEA_ADDiu : EffectiveAddress<"addiu $dst, ${addr:stackloc}">;
+// Count Leading
+// CLO/CLZ are part of the newer MIPS32(tm) instruction
+// set and not older Mips I keep this for future use
+// though.
+//def CLO : CountLeading<0x21, "clo">;
+//def CLZ : CountLeading<0x20, "clz">;
+
+// MADD*/MSUB* are not part of MipsI either.
+//def MADD : MArithR<0x00, "madd">;
+//def MADDU : MArithR<0x01, "maddu">;
+//def MSUB : MArithR<0x04, "msub">;
+//def MSUBU : MArithR<0x05, "msubu">;
+
+let Predicates = [IsAllegrex] in {
+ let shamt = 0x10, rs = 0 in
+ def SEB : SignExtInReg<0x21, "seb", i8>;
+
+ let shamt = 0x18, rs = 0 in
+ def SEH : SignExtInReg<0x20, "seh", i16>;
+}
+
//===----------------------------------------------------------------------===//
// Arbitrary patterns that map to one or more instructions
//===----------------------------------------------------------------------===//
@@ -546,7 +558,7 @@ def : Pat<(MipsLo tjumptable:$in), (ADDiu ZERO, tjumptable:$in)>;
def : Pat<(add CPURegs:$hi, (MipsLo tjumptable:$lo)),
(ADDiu CPURegs:$hi, tjumptable:$lo)>;
-// Mips does not have not, so we increase the operation
+// Mips does not have "not", so we expand our way
def : Pat<(not CPURegs:$in),
(NOR CPURegs:$in, ZERO)>;
@@ -558,10 +570,7 @@ def : Pat<(i32 (extloadi16 addr:$src)), (LHu addr:$src)>;
// peepholes
def : Pat<(store (i32 0), addr:$dst), (SW ZERO, addr:$dst)>;
-///
-/// brcond patterns
-///
-
+// brcond patterns
// direct match equal/notequal zero branches
def : Pat<(brcond (setne CPURegs:$lhs, 0), bb:$dst),
(BNE CPURegs:$lhs, ZERO, bb:$dst)>;
@@ -601,12 +610,8 @@ def : Pat<(brcond (setult CPURegs:$lhs, CPURegs:$rhs), bb:$dst),
def : Pat<(brcond CPURegs:$cond, bb:$dst),
(BNE CPURegs:$cond, ZERO, bb:$dst)>;
-///
/// setcc patterns, only matched when there
/// is no brcond following a setcc operation
-///
-
-// setcc 2 register operands
def : Pat<(setle CPURegs:$lhs, CPURegs:$rhs),
(XORi (SLT CPURegs:$rhs, CPURegs:$lhs), 1)>;
def : Pat<(setule CPURegs:$lhs, CPURegs:$rhs),
@@ -630,8 +635,14 @@ def : Pat<(seteq CPURegs:$lhs, CPURegs:$rhs),
(XORi (OR (SLT CPURegs:$lhs, CPURegs:$rhs),
(SLT CPURegs:$rhs, CPURegs:$lhs)), 1)>;
-// setcc reg/imm operands
def : Pat<(setge CPURegs:$lhs, immSExt16:$rhs),
(XORi (SLTi CPURegs:$lhs, immSExt16:$rhs), 1)>;
def : Pat<(setuge CPURegs:$lhs, immZExt16:$rhs),
(XORi (SLTiu CPURegs:$lhs, immZExt16:$rhs), 1)>;
+
+//===----------------------------------------------------------------------===//
+// Floating Point Support
+//===----------------------------------------------------------------------===//
+
+include "MipsInstrFPU.td"
+
diff --git a/lib/Target/Mips/MipsMachineFunction.h b/lib/Target/Mips/MipsMachineFunction.h
index e0ecdd9..4c53fcb 100644
--- a/lib/Target/Mips/MipsMachineFunction.h
+++ b/lib/Target/Mips/MipsMachineFunction.h
@@ -25,12 +25,12 @@ namespace llvm {
class MipsFunctionInfo : public MachineFunctionInfo {
private:
- /// Holds for each function where on the stack
- /// the Frame Pointer must be saved
+ /// Holds for each function where on the stack the Frame Pointer must be
+ /// saved.
int FPStackOffset;
- /// Holds for each function where on the stack
- /// the Return Address must be saved
+ /// Holds for each function where on the stack the Return Address must be
+ /// saved.
int RAStackOffset;
/// MipsFIHolder - Holds a FrameIndex and it's Stack Pointer Offset
@@ -43,31 +43,34 @@ private:
: FI(FrameIndex), SPOffset(StackPointerOffset) {}
};
- /// When PIC is used the GP must be saved on the stack
- /// on the function prologue and must be reloaded from this
- /// stack location after every call. A reference to its stack
- /// location and frame index must be kept to be used on
- /// emitPrologue and processFunctionBeforeFrameFinalized.
+ /// When PIC is used the GP must be saved on the stack on the function
+ /// prologue and must be reloaded from this stack location after every
+ /// call. A reference to its stack location and frame index must be kept
+ /// to be used on emitPrologue and processFunctionBeforeFrameFinalized.
MipsFIHolder GPHolder;
- // On LowerFORMAL_ARGUMENTS the stack size is unknown,
- // so the Stack Pointer Offset calculation of "not in
- // register arguments" must be postponed to emitPrologue.
+ // On LowerFORMAL_ARGUMENTS the stack size is unknown, so the Stack
+ // Pointer Offset calculation of "not in register arguments" must be
+ // postponed to emitPrologue.
SmallVector<MipsFIHolder, 16> FnLoadArgs;
bool HasLoadArgs;
- // When VarArgs, we must write registers back to caller
- // stack, preserving on register arguments. Since the
- // stack size is unknown on LowerFORMAL_ARGUMENTS,
- // the Stack Pointer Offset calculation must be
+ // When VarArgs, we must write registers back to caller stack, preserving
+ // on register arguments. Since the stack size is unknown on
+ // LowerFORMAL_ARGUMENTS, the Stack Pointer Offset calculation must be
// postponed to emitPrologue.
SmallVector<MipsFIHolder, 4> FnStoreVarArgs;
bool HasStoreVarArgs;
+ /// SRetReturnReg - Some subtargets require that sret lowering includes
+ /// returning the value of the returned struct in a register. This field
+ /// holds the virtual register into which the sret argument is passed.
+ unsigned SRetReturnReg;
+
public:
MipsFunctionInfo(MachineFunction& MF)
- : FPStackOffset(0), RAStackOffset(0), GPHolder(-1,-1),
- HasLoadArgs(false), HasStoreVarArgs(false)
+ : FPStackOffset(0), RAStackOffset(0), GPHolder(-1,-1), HasLoadArgs(false),
+ HasStoreVarArgs(false), SRetReturnReg(0)
{}
int getFPStackOffset() const { return FPStackOffset; }
@@ -109,6 +112,8 @@ public:
MFI->setObjectOffset( FnStoreVarArgs[i].FI, FnStoreVarArgs[i].SPOffset );
}
+ unsigned getSRetReturnReg() const { return SRetReturnReg; }
+ void setSRetReturnReg(unsigned Reg) { SRetReturnReg = Reg; }
};
} // end of namespace llvm
diff --git a/lib/Target/Mips/MipsRegisterInfo.cpp b/lib/Target/Mips/MipsRegisterInfo.cpp
index 0186f1e..75d9b24 100644
--- a/lib/Target/Mips/MipsRegisterInfo.cpp
+++ b/lib/Target/Mips/MipsRegisterInfo.cpp
@@ -32,14 +32,12 @@
#include "llvm/Support/Debug.h"
#include "llvm/ADT/BitVector.h"
#include "llvm/ADT/STLExtras.h"
-//#include "MipsSubtarget.h"
using namespace llvm;
-// TODO: add subtarget support
MipsRegisterInfo::MipsRegisterInfo(const TargetInstrInfo &tii)
: MipsGenRegisterInfo(Mips::ADJCALLSTACKDOWN, Mips::ADJCALLSTACKUP),
- TII(tii) {}
+ TII(tii) {}
/// getRegisterNumbering - Given the enum value for some register, e.g.
/// Mips::RA, return the number that it corresponds to (e.g. 31).
@@ -47,38 +45,38 @@ unsigned MipsRegisterInfo::
getRegisterNumbering(unsigned RegEnum)
{
switch (RegEnum) {
- case Mips::ZERO : return 0;
- case Mips::AT : return 1;
- case Mips::V0 : return 2;
- case Mips::V1 : return 3;
- case Mips::A0 : return 4;
- case Mips::A1 : return 5;
- case Mips::A2 : return 6;
- case Mips::A3 : return 7;
- case Mips::T0 : return 8;
- case Mips::T1 : return 9;
- case Mips::T2 : return 10;
- case Mips::T3 : return 11;
- case Mips::T4 : return 12;
- case Mips::T5 : return 13;
- case Mips::T6 : return 14;
- case Mips::T7 : return 15;
- case Mips::T8 : return 16;
- case Mips::T9 : return 17;
- case Mips::S0 : return 18;
- case Mips::S1 : return 19;
- case Mips::S2 : return 20;
- case Mips::S3 : return 21;
- case Mips::S4 : return 22;
- case Mips::S5 : return 23;
- case Mips::S6 : return 24;
- case Mips::S7 : return 25;
- case Mips::K0 : return 26;
- case Mips::K1 : return 27;
- case Mips::GP : return 28;
- case Mips::SP : return 29;
- case Mips::FP : return 30;
- case Mips::RA : return 31;
+ case Mips::ZERO : case Mips::F0 : return 0;
+ case Mips::AT : case Mips::F1 : return 1;
+ case Mips::V0 : case Mips::F2 : return 2;
+ case Mips::V1 : case Mips::F3 : return 3;
+ case Mips::A0 : case Mips::F4 : return 4;
+ case Mips::A1 : case Mips::F5 : return 5;
+ case Mips::A2 : case Mips::F6 : return 6;
+ case Mips::A3 : case Mips::F7 : return 7;
+ case Mips::T0 : case Mips::F8 : return 8;
+ case Mips::T1 : case Mips::F9 : return 9;
+ case Mips::T2 : case Mips::F10: return 10;
+ case Mips::T3 : case Mips::F11: return 11;
+ case Mips::T4 : case Mips::F12: return 12;
+ case Mips::T5 : case Mips::F13: return 13;
+ case Mips::T6 : case Mips::F14: return 14;
+ case Mips::T7 : case Mips::F15: return 15;
+ case Mips::T8 : case Mips::F16: return 16;
+ case Mips::T9 : case Mips::F17: return 17;
+ case Mips::S0 : case Mips::F18: return 18;
+ case Mips::S1 : case Mips::F19: return 19;
+ case Mips::S2 : case Mips::F20: return 20;
+ case Mips::S3 : case Mips::F21: return 21;
+ case Mips::S4 : case Mips::F22: return 22;
+ case Mips::S5 : case Mips::F23: return 23;
+ case Mips::S6 : case Mips::F24: return 24;
+ case Mips::S7 : case Mips::F25: return 25;
+ case Mips::K0 : case Mips::F26: return 26;
+ case Mips::K1 : case Mips::F27: return 27;
+ case Mips::GP : case Mips::F28: return 28;
+ case Mips::SP : case Mips::F29: return 29;
+ case Mips::FP : case Mips::F30: return 30;
+ case Mips::RA : case Mips::F31: return 31;
default: assert(0 && "Unknown register number!");
}
return 0; // Not reached
@@ -94,11 +92,12 @@ getRegisterNumbering(unsigned RegEnum)
const unsigned* MipsRegisterInfo::
getCalleeSavedRegs(const MachineFunction *MF) const
{
- // Mips calle-save register range is $16-$26(s0-s7)
+ // Mips callee-save register range is $16-$23(s0-s7)
static const unsigned CalleeSavedRegs[] = {
Mips::S0, Mips::S1, Mips::S2, Mips::S3,
Mips::S4, Mips::S5, Mips::S6, Mips::S7, 0
};
+
return CalleeSavedRegs;
}
@@ -271,6 +270,8 @@ emitPrologue(MachineFunction &MF) const
int FPOffset, RAOffset;
// Allocate space for saved RA and FP when needed
+ // FIXME: within 64-bit registers, change hardcoded
+ // sizes for RA and FP offsets.
if ((hasFP(MF)) && (MFI->hasCalls())) {
FPOffset = NumBytes;
RAOffset = (NumBytes+4);
@@ -283,8 +284,7 @@ emitPrologue(MachineFunction &MF) const
FPOffset = NumBytes;
RAOffset = 0;
NumBytes += 4;
- } else {
- // No calls and no fp.
+ } else { // No calls and no fp.
RAOffset = FPOffset = 0;
}
diff --git a/lib/Target/Mips/MipsRegisterInfo.td b/lib/Target/Mips/MipsRegisterInfo.td
index 2712bb7..0a7a69e 100644
--- a/lib/Target/Mips/MipsRegisterInfo.td
+++ b/lib/Target/Mips/MipsRegisterInfo.td
@@ -17,50 +17,123 @@ class MipsReg<string n> : Register<n> {
let Namespace = "Mips";
}
-//===----------------------------------------------------------------------===//
-// General Purpose Registers
-//===----------------------------------------------------------------------===//
-
// Mips CPU Registers
class MipsGPRReg<bits<5> num, string n> : MipsReg<n> {
let Num = num;
}
-// CPU GPR Registers
-def ZERO : MipsGPRReg< 0, "ZERO">, DwarfRegNum<[0]>;
-def AT : MipsGPRReg< 1, "AT">, DwarfRegNum<[1]>;
-def V0 : MipsGPRReg< 2, "2">, DwarfRegNum<[2]>;
-def V1 : MipsGPRReg< 3, "3">, DwarfRegNum<[3]>;
-def A0 : MipsGPRReg< 4, "4">, DwarfRegNum<[5]>;
-def A1 : MipsGPRReg< 5, "5">, DwarfRegNum<[5]>;
-def A2 : MipsGPRReg< 6, "6">, DwarfRegNum<[6]>;
-def A3 : MipsGPRReg< 7, "7">, DwarfRegNum<[7]>;
-def T0 : MipsGPRReg< 8, "8">, DwarfRegNum<[8]>;
-def T1 : MipsGPRReg< 9, "9">, DwarfRegNum<[9]>;
-def T2 : MipsGPRReg< 10, "10">, DwarfRegNum<[10]>;
-def T3 : MipsGPRReg< 11, "11">, DwarfRegNum<[11]>;
-def T4 : MipsGPRReg< 12, "12">, DwarfRegNum<[12]>;
-def T5 : MipsGPRReg< 13, "13">, DwarfRegNum<[13]>;
-def T6 : MipsGPRReg< 14, "14">, DwarfRegNum<[14]>;
-def T7 : MipsGPRReg< 15, "15">, DwarfRegNum<[15]>;
-def S0 : MipsGPRReg< 16, "16">, DwarfRegNum<[16]>;
-def S1 : MipsGPRReg< 17, "17">, DwarfRegNum<[17]>;
-def S2 : MipsGPRReg< 18, "18">, DwarfRegNum<[18]>;
-def S3 : MipsGPRReg< 19, "19">, DwarfRegNum<[19]>;
-def S4 : MipsGPRReg< 20, "20">, DwarfRegNum<[20]>;
-def S5 : MipsGPRReg< 21, "21">, DwarfRegNum<[21]>;
-def S6 : MipsGPRReg< 22, "22">, DwarfRegNum<[22]>;
-def S7 : MipsGPRReg< 23, "23">, DwarfRegNum<[23]>;
-def T8 : MipsGPRReg< 24, "24">, DwarfRegNum<[24]>;
-def T9 : MipsGPRReg< 25, "25">, DwarfRegNum<[25]>;
-def K0 : MipsGPRReg< 26, "26">, DwarfRegNum<[26]>;
-def K1 : MipsGPRReg< 27, "27">, DwarfRegNum<[27]>;
-def GP : MipsGPRReg< 28, "GP">, DwarfRegNum<[28]>;
-def SP : MipsGPRReg< 29, "SP">, DwarfRegNum<[29]>;
-def FP : MipsGPRReg< 30, "FP">, DwarfRegNum<[30]>;
-def RA : MipsGPRReg< 31, "RA">, DwarfRegNum<[31]>;
-
-// CPU Registers Class
+// Mips 32-bit FPU Registers
+class FPR<bits<5> num, string n> : MipsReg<n> {
+ let Num = num;
+}
+
+// Mips 64-bit (aliased) FPU Registers
+class AFPR<bits<5> num, string n, list<Register> aliases> : MipsReg<n> {
+ let Num = num;
+ let Aliases = aliases;
+}
+
+//===----------------------------------------------------------------------===//
+// Registers
+//===----------------------------------------------------------------------===//
+
+let Namespace = "Mips" in {
+
+ // General Purpose Registers
+ def ZERO : MipsGPRReg< 0, "ZERO">, DwarfRegNum<[0]>;
+ def AT : MipsGPRReg< 1, "AT">, DwarfRegNum<[1]>;
+ def V0 : MipsGPRReg< 2, "2">, DwarfRegNum<[2]>;
+ def V1 : MipsGPRReg< 3, "3">, DwarfRegNum<[3]>;
+ def A0 : MipsGPRReg< 4, "4">, DwarfRegNum<[5]>;
+ def A1 : MipsGPRReg< 5, "5">, DwarfRegNum<[5]>;
+ def A2 : MipsGPRReg< 6, "6">, DwarfRegNum<[6]>;
+ def A3 : MipsGPRReg< 7, "7">, DwarfRegNum<[7]>;
+ def T0 : MipsGPRReg< 8, "8">, DwarfRegNum<[8]>;
+ def T1 : MipsGPRReg< 9, "9">, DwarfRegNum<[9]>;
+ def T2 : MipsGPRReg< 10, "10">, DwarfRegNum<[10]>;
+ def T3 : MipsGPRReg< 11, "11">, DwarfRegNum<[11]>;
+ def T4 : MipsGPRReg< 12, "12">, DwarfRegNum<[12]>;
+ def T5 : MipsGPRReg< 13, "13">, DwarfRegNum<[13]>;
+ def T6 : MipsGPRReg< 14, "14">, DwarfRegNum<[14]>;
+ def T7 : MipsGPRReg< 15, "15">, DwarfRegNum<[15]>;
+ def S0 : MipsGPRReg< 16, "16">, DwarfRegNum<[16]>;
+ def S1 : MipsGPRReg< 17, "17">, DwarfRegNum<[17]>;
+ def S2 : MipsGPRReg< 18, "18">, DwarfRegNum<[18]>;
+ def S3 : MipsGPRReg< 19, "19">, DwarfRegNum<[19]>;
+ def S4 : MipsGPRReg< 20, "20">, DwarfRegNum<[20]>;
+ def S5 : MipsGPRReg< 21, "21">, DwarfRegNum<[21]>;
+ def S6 : MipsGPRReg< 22, "22">, DwarfRegNum<[22]>;
+ def S7 : MipsGPRReg< 23, "23">, DwarfRegNum<[23]>;
+ def T8 : MipsGPRReg< 24, "24">, DwarfRegNum<[24]>;
+ def T9 : MipsGPRReg< 25, "25">, DwarfRegNum<[25]>;
+ def K0 : MipsGPRReg< 26, "26">, DwarfRegNum<[26]>;
+ def K1 : MipsGPRReg< 27, "27">, DwarfRegNum<[27]>;
+ def GP : MipsGPRReg< 28, "GP">, DwarfRegNum<[28]>;
+ def SP : MipsGPRReg< 29, "SP">, DwarfRegNum<[29]>;
+ def FP : MipsGPRReg< 30, "FP">, DwarfRegNum<[30]>;
+ def RA : MipsGPRReg< 31, "RA">, DwarfRegNum<[31]>;
+
+ /// Mips Single point precision FPU Registers
+ def F0 : FPR< 0, "F0">, DwarfRegNum<[32]>;
+ def F1 : FPR< 1, "F1">, DwarfRegNum<[33]>;
+ def F2 : FPR< 2, "F2">, DwarfRegNum<[34]>;
+ def F3 : FPR< 3, "F3">, DwarfRegNum<[35]>;
+ def F4 : FPR< 4, "F4">, DwarfRegNum<[36]>;
+ def F5 : FPR< 5, "F5">, DwarfRegNum<[37]>;
+ def F6 : FPR< 6, "F6">, DwarfRegNum<[38]>;
+ def F7 : FPR< 7, "F7">, DwarfRegNum<[39]>;
+ def F8 : FPR< 8, "F8">, DwarfRegNum<[40]>;
+ def F9 : FPR< 9, "F9">, DwarfRegNum<[41]>;
+ def F10 : FPR<10, "F10">, DwarfRegNum<[42]>;
+ def F11 : FPR<11, "F11">, DwarfRegNum<[43]>;
+ def F12 : FPR<12, "F12">, DwarfRegNum<[44]>;
+ def F13 : FPR<13, "F13">, DwarfRegNum<[45]>;
+ def F14 : FPR<14, "F14">, DwarfRegNum<[46]>;
+ def F15 : FPR<15, "F15">, DwarfRegNum<[47]>;
+ def F16 : FPR<16, "F16">, DwarfRegNum<[48]>;
+ def F17 : FPR<17, "F17">, DwarfRegNum<[49]>;
+ def F18 : FPR<18, "F18">, DwarfRegNum<[50]>;
+ def F19 : FPR<19, "F19">, DwarfRegNum<[51]>;
+ def F20 : FPR<20, "F20">, DwarfRegNum<[52]>;
+ def F21 : FPR<21, "F21">, DwarfRegNum<[53]>;
+ def F22 : FPR<22, "F22">, DwarfRegNum<[54]>;
+ def F23 : FPR<23, "F23">, DwarfRegNum<[55]>;
+ def F24 : FPR<24, "F24">, DwarfRegNum<[56]>;
+ def F25 : FPR<25, "F25">, DwarfRegNum<[57]>;
+ def F26 : FPR<26, "F26">, DwarfRegNum<[58]>;
+ def F27 : FPR<27, "F27">, DwarfRegNum<[59]>;
+ def F28 : FPR<28, "F28">, DwarfRegNum<[60]>;
+ def F29 : FPR<29, "F29">, DwarfRegNum<[61]>;
+ def F30 : FPR<30, "F30">, DwarfRegNum<[62]>;
+ def F31 : FPR<31, "F31">, DwarfRegNum<[63]>;
+
+ /// Mips Double point precision FPU Registers (aliased
+ /// with the single precision to hold 64 bit values)
+ def D0 : AFPR< 0, "F0", [F0, F1]>, DwarfRegNum<[32]>;
+ def D1 : AFPR< 2, "F2", [F2, F3]>, DwarfRegNum<[34]>;
+ def D2 : AFPR< 4, "F4", [F4, F5]>, DwarfRegNum<[36]>;
+ def D3 : AFPR< 6, "F6", [F6, F7]>, DwarfRegNum<[38]>;
+ def D4 : AFPR< 8, "F8", [F8, F9]>, DwarfRegNum<[40]>;
+ def D5 : AFPR<10, "F10", [F10, F11]>, DwarfRegNum<[42]>;
+ def D6 : AFPR<12, "F12", [F12, F13]>, DwarfRegNum<[44]>;
+ def D7 : AFPR<14, "F14", [F14, F15]>, DwarfRegNum<[46]>;
+ def D8 : AFPR<16, "F16", [F16, F17]>, DwarfRegNum<[48]>;
+ def D9 : AFPR<18, "F18", [F18, F19]>, DwarfRegNum<[50]>;
+ def D10 : AFPR<20, "F20", [F20, F21]>, DwarfRegNum<[52]>;
+ def D11 : AFPR<22, "F22", [F22, F23]>, DwarfRegNum<[54]>;
+ def D12 : AFPR<24, "F24", [F24, F25]>, DwarfRegNum<[56]>;
+ def D13 : AFPR<26, "F26", [F26, F27]>, DwarfRegNum<[58]>;
+ def D14 : AFPR<28, "F28", [F28, F29]>, DwarfRegNum<[60]>;
+ def D15 : AFPR<30, "F30", [F30, F31]>, DwarfRegNum<[62]>;
+
+ // Status flags register
+ def FCR31 : Register<"FCR31">;
+}
+
+//===----------------------------------------------------------------------===//
+// Register Classes
+//===----------------------------------------------------------------------===//
+
def CPURegs : RegisterClass<"Mips", [i32], 32,
// Return Values and Arguments
[V0, V1, A0, A1, A2, A3,
@@ -83,51 +156,14 @@ def CPURegs : RegisterClass<"Mips", [i32], 32,
}];
}
-//===----------------------------------------------------------------------===//
-// Floating Point Unit Registers (Single Precision)
-//===----------------------------------------------------------------------===//
-
-/// Mips Single point precision FPU Register Format
-class MipsFPUReg<bits<5> num, string n> : MipsReg<n> {
- let Num = num;
-}
-
-/// Mips Single point precision FPU Registers
-def F0 : MipsFPUReg< 0, "F0">, DwarfRegNum<[32]>;
-def F1 : MipsFPUReg< 1, "F1">, DwarfRegNum<[33]>;
-def F2 : MipsFPUReg< 2, "F2">, DwarfRegNum<[34]>;
-def F3 : MipsFPUReg< 3, "F3">, DwarfRegNum<[35]>;
-def F4 : MipsFPUReg< 4, "F4">, DwarfRegNum<[36]>;
-def F5 : MipsFPUReg< 5, "F5">, DwarfRegNum<[37]>;
-def F6 : MipsFPUReg< 6, "F6">, DwarfRegNum<[38]>;
-def F7 : MipsFPUReg< 7, "F7">, DwarfRegNum<[39]>;
-def F8 : MipsFPUReg< 8, "F8">, DwarfRegNum<[40]>;
-def F9 : MipsFPUReg< 9, "F9">, DwarfRegNum<[41]>;
-def F10 : MipsFPUReg<10, "F10">, DwarfRegNum<[42]>;
-def F11 : MipsFPUReg<11, "F11">, DwarfRegNum<[43]>;
-def F12 : MipsFPUReg<12, "F12">, DwarfRegNum<[44]>;
-def F13 : MipsFPUReg<13, "F13">, DwarfRegNum<[45]>;
-def F14 : MipsFPUReg<14, "F14">, DwarfRegNum<[46]>;
-def F15 : MipsFPUReg<15, "F15">, DwarfRegNum<[47]>;
-def F16 : MipsFPUReg<16, "F16">, DwarfRegNum<[48]>;
-def F17 : MipsFPUReg<17, "F17">, DwarfRegNum<[49]>;
-def F18 : MipsFPUReg<18, "F18">, DwarfRegNum<[50]>;
-def F19 : MipsFPUReg<19, "F19">, DwarfRegNum<[51]>;
-def F20 : MipsFPUReg<20, "F20">, DwarfRegNum<[52]>;
-def F21 : MipsFPUReg<21, "F21">, DwarfRegNum<[53]>;
-def F22 : MipsFPUReg<22, "F22">, DwarfRegNum<[54]>;
-def F23 : MipsFPUReg<23, "F23">, DwarfRegNum<[55]>;
-def F24 : MipsFPUReg<24, "F24">, DwarfRegNum<[56]>;
-def F25 : MipsFPUReg<25, "F25">, DwarfRegNum<[57]>;
-def F26 : MipsFPUReg<26, "F26">, DwarfRegNum<[58]>;
-def F27 : MipsFPUReg<27, "F27">, DwarfRegNum<[59]>;
-def F28 : MipsFPUReg<28, "F28">, DwarfRegNum<[60]>;
-def F29 : MipsFPUReg<29, "F29">, DwarfRegNum<[61]>;
-def F30 : MipsFPUReg<30, "F30">, DwarfRegNum<[62]>;
-def F31 : MipsFPUReg<31, "F31">, DwarfRegNum<[63]>;
-
-/// FPU Single Point Precision Registers Class
-def FPUDRegs : RegisterClass<"Mips", [f32], 32,
+// * 64bit fp:
+// - FGR64 = 32 64-bit registers (default mode)
+// - AFGR32/AFGR64 = 16 even 32-bit registers (32-bit compatible mode) for
+// single and double access.
+// * 32bit fp:
+// - AFGR32/AFGR64 = 16 even 32-bit registers - single and double
+// - FGR32 = 32 32-bit registers (within single-only mode)
+def FGR32 : RegisterClass<"Mips", [f32], 32,
// Return Values and Arguments
[F0, F1, F2, F3, F12, F13, F14, F15,
// Not preserved across procedure calls
@@ -141,45 +177,37 @@ def FPUDRegs : RegisterClass<"Mips", [f32], 32,
iterator allocation_order_end(const MachineFunction &MF) const;
}];
let MethodBodies = [{
- FPUDRegsClass::iterator
- FPUDRegsClass::allocation_order_end(const MachineFunction &MF) const {
+ FGR32Class::iterator
+ FGR32Class::allocation_order_end(const MachineFunction &MF) const {
// The last register on the list above is reserved
return end()-1;
}
}];
}
-//===----------------------------------------------------------------------===//
-// Floating Point Unit Registers (Double Precision)
-//===----------------------------------------------------------------------===//
-
-/// Mips Double point precision FPU Register Format
-class MipsFPUDReg<bits<5> num, string n, list<Register> aliases> : MipsReg<n> {
- let Num = num;
- let Aliases = aliases;
+def AFGR32 : RegisterClass<"Mips", [f32], 32,
+ // Return Values and Arguments
+ [F0, F2, F12, F14,
+ // Not preserved across procedure calls
+ F4, F6, F8, F10, F16, F18,
+ // Callee save
+ F20, F22, F24, F26, F28, F30,
+ // Reserved
+ F31]>
+{
+ let MethodProtos = [{
+ iterator allocation_order_end(const MachineFunction &MF) const;
+ }];
+ let MethodBodies = [{
+ AFGR32Class::iterator
+ AFGR32Class::allocation_order_end(const MachineFunction &MF) const {
+ // The last register on the list above is reserved
+ return end()-1;
+ }
+ }];
}
-/// Mips Double point precision FPU Registers (aliased
-/// with the single precision to hold 64 bit values)
-def D0 : MipsFPUDReg< 0, "F0", [F0, F1]>, DwarfRegNum<[32]>;
-def D1 : MipsFPUDReg< 2, "F2", [F2, F3]>, DwarfRegNum<[34]>;
-def D2 : MipsFPUDReg< 4, "F4", [F4, F5]>, DwarfRegNum<[36]>;
-def D3 : MipsFPUDReg< 6, "F6", [F6, F7]>, DwarfRegNum<[38]>;
-def D4 : MipsFPUDReg< 8, "F8", [F8, F9]>, DwarfRegNum<[40]>;
-def D5 : MipsFPUDReg<10, "F10", [F10, F11]>, DwarfRegNum<[42]>;
-def D6 : MipsFPUDReg<12, "F12", [F12, F13]>, DwarfRegNum<[44]>;
-def D7 : MipsFPUDReg<14, "F14", [F14, F15]>, DwarfRegNum<[46]>;
-def D8 : MipsFPUDReg<16, "F16", [F16, F17]>, DwarfRegNum<[48]>;
-def D9 : MipsFPUDReg<18, "F18", [F18, F19]>, DwarfRegNum<[50]>;
-def D10 : MipsFPUDReg<20, "F20", [F20, F21]>, DwarfRegNum<[52]>;
-def D11 : MipsFPUDReg<22, "F22", [F22, F23]>, DwarfRegNum<[54]>;
-def D12 : MipsFPUDReg<24, "F24", [F24, F25]>, DwarfRegNum<[56]>;
-def D13 : MipsFPUDReg<26, "F26", [F26, F27]>, DwarfRegNum<[58]>;
-def D14 : MipsFPUDReg<28, "F28", [F28, F29]>, DwarfRegNum<[60]>;
-def D15 : MipsFPUDReg<30, "F30", [F30, F31]>, DwarfRegNum<[62]>;
-
-/// FPU Single Point Precision Registers Class
-def FPURegs : RegisterClass<"Mips", [f32], 32,
+def AFGR64 : RegisterClass<"Mips", [f64], 64,
// Return Values and Arguments
[D0, D1, D6, D7,
// Not preserved across procedure calls
@@ -193,10 +221,15 @@ def FPURegs : RegisterClass<"Mips", [f32], 32,
iterator allocation_order_end(const MachineFunction &MF) const;
}];
let MethodBodies = [{
- FPURegsClass::iterator
- FPURegsClass::allocation_order_end(const MachineFunction &MF) const {
+ AFGR64Class::iterator
+ AFGR64Class::allocation_order_end(const MachineFunction &MF) const {
// The last register on the list above is reserved
return end()-1;
}
}];
}
+
+def CCR : RegisterClass<"Mips", [i32], 32, [FCR31]> {
+ let CopyCost = -1; // Don't allow copying of status registers.
+}
+
diff --git a/lib/Target/Mips/MipsSubtarget.cpp b/lib/Target/Mips/MipsSubtarget.cpp
index 2bfb82a..31e777d 100644
--- a/lib/Target/Mips/MipsSubtarget.cpp
+++ b/lib/Target/Mips/MipsSubtarget.cpp
@@ -14,15 +14,29 @@
#include "MipsSubtarget.h"
#include "Mips.h"
#include "MipsGenSubtarget.inc"
+#include "llvm/Module.h"
using namespace llvm;
MipsSubtarget::MipsSubtarget(const TargetMachine &TM, const Module &M,
const std::string &FS, bool little) :
- IsMipsIII(false),
- IsLittle(little)
+ MipsArchVersion(Mips1), MipsABI(O32), IsLittle(little), IsSingleFloat(false),
+ IsFP64bit(false), IsGP64bit(false), HasAllegrexVFPU(false), IsAllegrex(false)
{
std::string CPU = "mips1";
// Parse features string.
ParseSubtargetFeatures(FS, CPU);
+
+ // When only the target triple is specified and is
+ // a allegrex target, set the features. We also match
+ // big and little endian allegrex cores (dont really
+ // know if a big one exists)
+ const std::string& TT = M.getTargetTriple();
+ if (TT.find("mipsallegrex") != std::string::npos) {
+ MipsABI = EABI;
+ IsSingleFloat = true;
+ MipsArchVersion = Mips2;
+ HasAllegrexVFPU = true; // Enables Allegrex Vector FPU (not supported yet)
+ IsAllegrex = true;
+ }
}
diff --git a/lib/Target/Mips/MipsSubtarget.h b/lib/Target/Mips/MipsSubtarget.h
index f106823..5300a81 100644
--- a/lib/Target/Mips/MipsSubtarget.h
+++ b/lib/Target/Mips/MipsSubtarget.h
@@ -26,11 +26,48 @@ class MipsSubtarget : public TargetSubtarget {
protected:
- bool IsMipsIII;
+ enum MipsArchEnum {
+ Mips1, Mips2, Mips3, Mips4, Mips32, Mips32r2
+ };
+
+ enum MipsABIEnum {
+ O32, EABI
+ };
+
+ // Mips architecture version
+ MipsArchEnum MipsArchVersion;
+
+ // Mips supported ABIs
+ MipsABIEnum MipsABI;
+
+ // IsLittle - The target is Little Endian
bool IsLittle;
+
+ // IsSingleFloat - The target only supports single precision float
+ // point operations. This enable the target to use all 32 32-bit
+ // float point registers instead of only using even ones.
+ bool IsSingleFloat;
+
+ // IsFP64bit - The target processor has 64-bit float point registers.
+ bool IsFP64bit;
+
+ // IsFP64bit - General-purpose registers are 64 bits wide
+ bool IsGP64bit;
+
+ // HasAllegrexVFPU - Allegrex processor has a vector float point unit.
+ bool HasAllegrexVFPU;
+
+ // IsAllegrex - The target processor is a Allegrex core.
+ bool IsAllegrex;
+
InstrItineraryData InstrItins;
public:
+
+ /// Only O32 and EABI supported right now.
+ bool isABI_EABI() const { return MipsABI == EABI; }
+ bool isABI_O32() const { return MipsABI == O32; }
+
/// This constructor initializes the data members to match that
/// of the specified module.
MipsSubtarget(const TargetMachine &TM, const Module &M,
@@ -40,12 +77,17 @@ public:
/// subtarget options. Definition of function is auto generated by tblgen.
void ParseSubtargetFeatures(const std::string &FS, const std::string &CPU);
- /// isMipsIII - Return true if the selected CPU supports MipsIII ISA
- /// support.
- bool isMipsIII() const { return IsMipsIII; }
+ bool hasMips2Ops() const { return MipsArchVersion >= Mips2; }
- /// isMipsIII - Return true if the target is little endian.
bool isLittle() const { return IsLittle; }
+ bool isFP64bit() const { return IsFP64bit; };
+ bool isGP64bit() const { return IsGP64bit; };
+ bool isGP32bit() const { return !IsGP64bit; };
+ bool isSingleFloat() const { return IsSingleFloat; };
+ bool isNotSingleFloat() const { return !IsSingleFloat; };
+ bool hasAllegrexVFPU() const { return HasAllegrexVFPU; };
+ bool isAllegrex() const { return IsAllegrex; };
+
};
} // End llvm namespace
diff --git a/lib/Target/Mips/MipsTargetMachine.cpp b/lib/Target/Mips/MipsTargetMachine.cpp
index b4ca963..a170d6f 100644
--- a/lib/Target/Mips/MipsTargetMachine.cpp
+++ b/lib/Target/Mips/MipsTargetMachine.cpp
@@ -34,8 +34,7 @@ createTargetAsmInfo() const
// On function prologue, the stack is created by decrementing
// its pointer. Once decremented, all references are done with positive
// offset from the stack/frame pointer, so StackGrowsUp is used.
-// When using CodeModel::Large the behaviour
-//
+// Using CodeModel::Large enables different CALL behavior.
MipsTargetMachine::
MipsTargetMachine(const Module &M, const std::string &FS, bool isLittle=false):
Subtarget(*this, M, FS, isLittle),
@@ -59,22 +58,33 @@ MipselTargetMachine(const Module &M, const std::string &FS) :
unsigned MipsTargetMachine::
getModuleMatchQuality(const Module &M)
{
- // We strongly match "mips-*".
+ // We strongly match "mips*-*".
std::string TT = M.getTargetTriple();
if (TT.size() >= 5 && std::string(TT.begin(), TT.begin()+5) == "mips-")
return 20;
+ if (TT.size() >= 13 && std::string(TT.begin(),
+ TT.begin()+13) == "mipsallegrex-")
+ return 20;
+
return 0;
}
-// return 0 and must specify -march to gen MIPSel code.
+// return 0 and must specify -march to gen MIPSEL code.
unsigned MipselTargetMachine::
getModuleMatchQuality(const Module &M)
{
- // We strongly match "mipsel-*".
+ // We strongly match "mips*el-*".
std::string TT = M.getTargetTriple();
if (TT.size() >= 7 && std::string(TT.begin(), TT.begin()+7) == "mipsel-")
return 20;
+
+ if (TT.size() >= 15 && std::string(TT.begin(),
+ TT.begin()+15) == "mipsallegrexel-")
+ return 20;
+
+ if (TT.size() == 3 && std::string(TT.begin(), TT.begin()+3) == "psp")
+ return 20;
return 0;
}