diff options
author | Bruno Cardoso Lopes <bruno.cardoso@gmail.com> | 2008-07-05 19:05:21 +0000 |
---|---|---|
committer | Bruno Cardoso Lopes <bruno.cardoso@gmail.com> | 2008-07-05 19:05:21 +0000 |
commit | 225ca9cdd70de3d12641b0aba7daf6cb568a7ebd (patch) | |
tree | 4e9448b1e96f4e7792d2dcb85781c53ddef8dd39 | |
parent | 126d90770bdb17e6925b2fe26de99aa079b7b9b3 (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.td | 39 | ||||
-rw-r--r-- | lib/Target/Mips/MipsAsmPrinter.cpp | 9 | ||||
-rw-r--r-- | lib/Target/Mips/MipsCallingConv.td | 66 | ||||
-rw-r--r-- | lib/Target/Mips/MipsISelDAGToDAG.cpp | 9 | ||||
-rw-r--r-- | lib/Target/Mips/MipsISelLowering.cpp | 180 | ||||
-rw-r--r-- | lib/Target/Mips/MipsISelLowering.h | 9 | ||||
-rw-r--r-- | lib/Target/Mips/MipsInstrFPU.td | 296 | ||||
-rw-r--r-- | lib/Target/Mips/MipsInstrFormats.td | 37 | ||||
-rw-r--r-- | lib/Target/Mips/MipsInstrInfo.cpp | 382 | ||||
-rw-r--r-- | lib/Target/Mips/MipsInstrInfo.h | 78 | ||||
-rw-r--r-- | lib/Target/Mips/MipsInstrInfo.td | 111 | ||||
-rw-r--r-- | lib/Target/Mips/MipsMachineFunction.h | 41 | ||||
-rw-r--r-- | lib/Target/Mips/MipsRegisterInfo.cpp | 76 | ||||
-rw-r--r-- | lib/Target/Mips/MipsRegisterInfo.td | 267 | ||||
-rw-r--r-- | lib/Target/Mips/MipsSubtarget.cpp | 18 | ||||
-rw-r--r-- | lib/Target/Mips/MipsSubtarget.h | 52 | ||||
-rw-r--r-- | lib/Target/Mips/MipsTargetMachine.cpp | 20 |
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 |