aboutsummaryrefslogtreecommitdiff
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
parent126d90770bdb17e6925b2fe26de99aa079b7b9b3 (diff)
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
-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 50a5f65e76..1199cc47ac 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 0587d9859c..11f14e1155 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 85f019dcc6..c05e82d5b5 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 0c967e2e8a..4822e0159a 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 18cedcf757..7fb5390c90 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 6f621b41b0..bd4b004a5c 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 0000000000..a185a3562b
--- /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