From 225ca9cdd70de3d12641b0aba7daf6cb568a7ebd Mon Sep 17 00:00:00 2001 From: Bruno Cardoso Lopes Date: Sat, 5 Jul 2008 19:05:21 +0000 Subject: [PATCH] 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 --- lib/Target/Mips/Mips.td | 39 ++- lib/Target/Mips/MipsAsmPrinter.cpp | 9 + lib/Target/Mips/MipsCallingConv.td | 66 ++++- lib/Target/Mips/MipsISelDAGToDAG.cpp | 9 +- lib/Target/Mips/MipsISelLowering.cpp | 180 +++++++++--- lib/Target/Mips/MipsISelLowering.h | 9 + lib/Target/Mips/MipsInstrFPU.td | 296 ++++++++++++++++++++ lib/Target/Mips/MipsInstrFormats.td | 37 ++- lib/Target/Mips/MipsInstrInfo.cpp | 382 ++++++++++++++++---------- lib/Target/Mips/MipsInstrInfo.h | 78 ++++++ lib/Target/Mips/MipsInstrInfo.td | 111 ++++---- lib/Target/Mips/MipsMachineFunction.h | 41 +-- lib/Target/Mips/MipsRegisterInfo.cpp | 76 ++--- lib/Target/Mips/MipsRegisterInfo.td | 267 ++++++++++-------- lib/Target/Mips/MipsSubtarget.cpp | 18 +- lib/Target/Mips/MipsSubtarget.h | 52 +++- lib/Target/Mips/MipsTargetMachine.cpp | 20 +- 17 files changed, 1247 insertions(+), 443 deletions(-) create mode 100644 lib/Target/Mips/MipsInstrFPU.td diff --git a/lib/Target/Mips/Mips.td b/lib/Target/Mips/Mips.td index 50a5f65e76b..1199cc47ace 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 Features> + : Processor; + +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 0587d9859c1..11f14e11555 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 85f019dcc61..c05e82d5b57 100644 --- a/lib/Target/Mips/MipsCallingConv.td +++ b/lib/Target/Mips/MipsCallingConv.td @@ -14,26 +14,76 @@ class CCIfSubtarget: CCIf().", 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>, + + // 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>, - // 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>, + CCDelegateTo +]>; + +def RetCC_Mips : CallingConv<[ + CCIfSubtarget<"isABI_EABI()", CCDelegateTo>, + CCDelegateTo +]>; diff --git a/lib/Target/Mips/MipsISelDAGToDAG.cpp b/lib/Target/Mips/MipsISelDAGToDAG.cpp index 0c967e2e8ab..4822e0159a0 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()) {} virtual void InstructionSelect(SelectionDAG &SD); diff --git a/lib/Target/Mips/MipsISelLowering.cpp b/lib/Target/Mips/MipsISelLowering.cpp index 18cedcf7579..7fb5390c90a 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(); + // 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, 8> RegsToPass; + // With EABI is it possible to have 16 args on registers. + SmallVector, 16> RegsToPass; SmallVector 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(); - 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 ArgValues; + SmallVector 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(); + 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 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 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(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(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(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(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(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(); } diff --git a/lib/Target/Mips/MipsISelLowering.h b/lib/Target/Mips/MipsISelLowering.h index 6f621b41b06..bd4b004a5cc 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 00000000000..a185a3562bc --- /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; + +//===----------------------------------------------------------------------===// +// 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 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 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 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 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 : FFI<0x11, (ops), + (ins brtarget:$dst), !strconcat(asmstr, " $dst"), + [(MipsFPBrcond op, bb:$dst, FCR31)]>; +} +def BC1F : FBRANCH; +def BC1T : FBRANCH; +def BC1FL : FBRANCH; +def BC1TL : FBRANCH; + +//===----------------------------------------------------------------------===// +// 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 + + 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 f82c3f575fa..226377f1480 100644 --- a/lib/Target/Mips/MipsInstrFormats.td +++ b/lib/Target/Mips/MipsInstrFormats.td @@ -120,8 +120,8 @@ class FJ op, dag outs, dag ins, string asmstr, list pattern, //===----------------------------------------------------------------------===// class FFR op, bits<6> _funct, bits<5> _fmt, dag outs, dag ins, - string asmstr, list pattern, InstrItinClass itin> : - MipsInst + string asmstr, list pattern> : + MipsInst { bits<5> fd; bits<5> fs; @@ -141,21 +141,42 @@ class FFR 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 op, bits<5> _fmt, dag outs, dag ins, string asmstr, - list pattern, InstrItinClass itin>: - MipsInst +class FFI op, dag outs, dag ins, string asmstr, list pattern>: + MipsInst { 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 _fmt, dag outs, dag ins, string asmstr, list pattern> : + MipsInst +{ + 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 c7bc1e9076b..cc29bae1417 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 &Addr, + const TargetRegisterClass *RC, SmallVectorImpl &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 &Addr, + const TargetRegisterClass *RC, + SmallVectorImpl &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 &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 &Addr, - const TargetRegisterClass *RC, - SmallVectorImpl &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 &Addr, - const TargetRegisterClass *RC, - SmallVectorImpl &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 &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 &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 1c094a8f3db..55a22490297 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 57f24ad395b..f78fd5dae87 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; def uimm16 : Operand; def simm16 : Operand; def shamt : Operand; -def addrlabel : Operand; // Address operand def mem : Operand { @@ -345,6 +343,12 @@ class EffectiveAddress : instr_asm, [(set CPURegs:$dst, addr:$addr)], IIAlu>; +class SignExtInReg 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 : // 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 e0ecdd91b94..4c53fcb609a 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 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 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 0186f1e424c..75d9b24d7db 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 2712bb766f3..0a7a69e8e07 100644 --- a/lib/Target/Mips/MipsRegisterInfo.td +++ b/lib/Target/Mips/MipsRegisterInfo.td @@ -17,50 +17,123 @@ class MipsReg : Register { let Namespace = "Mips"; } -//===----------------------------------------------------------------------===// -// General Purpose Registers -//===----------------------------------------------------------------------===// - // Mips CPU Registers class MipsGPRReg num, string n> : MipsReg { 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 num, string n> : MipsReg { + let Num = num; +} + +// Mips 64-bit (aliased) FPU Registers +class AFPR num, string n, list aliases> : MipsReg { + 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 num, string n> : MipsReg { - 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 num, string n, list aliases> : MipsReg { - 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 2bfb82a3100..31e777da95a 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 f1068231c2a..5300a81254a 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 b4ca963478f..a170d6fb36d 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; } -- 2.34.1