Index: llvm/lib/Target/Sparc/MCTargetDesc/SparcInstPrinter.cpp =================================================================== --- llvm/lib/Target/Sparc/MCTargetDesc/SparcInstPrinter.cpp +++ llvm/lib/Target/Sparc/MCTargetDesc/SparcInstPrinter.cpp @@ -183,11 +183,11 @@ case SP::BPFCCA: case SP::BPFCCNT: case SP::BPFCCANT: - case SP::MOVFCCrr: case SP::V9MOVFCCrr: - case SP::MOVFCCri: case SP::V9MOVFCCri: - case SP::FMOVS_FCC: case SP::V9FMOVS_FCC: - case SP::FMOVD_FCC: case SP::V9FMOVD_FCC: - case SP::FMOVQ_FCC: case SP::V9FMOVQ_FCC: + case SP::V9MOVFCCrr: + case SP::V9MOVFCCri: + case SP::V9FMOVS_FCC: + case SP::V9FMOVD_FCC: + case SP::V9FMOVQ_FCC: // Make sure CC is a fp conditional flag. CC = (CC < 16) ? (CC + 16) : CC; break; Index: llvm/lib/Target/Sparc/SparcISelLowering.h =================================================================== --- llvm/lib/Target/Sparc/SparcISelLowering.h +++ llvm/lib/Target/Sparc/SparcISelLowering.h @@ -23,15 +23,19 @@ namespace SPISD { enum NodeType : unsigned { FIRST_NUMBER = ISD::BUILTIN_OP_END, - CMPICC, // Compare two GPR operands, set icc+xcc. - CMPFCC, // Compare two FP operands, set fcc. - BRICC, // Branch to dest on icc condition - BPICC, // Branch to dest on icc condition, with prediction (64-bit only). - BPXCC, // Branch to dest on xcc condition, with prediction (64-bit only). - BRFCC, // Branch to dest on fcc condition - SELECT_ICC, // Select between two values using the current ICC flags. - SELECT_XCC, // Select between two values using the current XCC flags. - SELECT_FCC, // Select between two values using the current FCC flags. + CMPICC, // Compare two GPR operands, set icc+xcc. + CMPFCC, // Compare two FP operands, set fcc. + CMPFCC_V9, // Compare two FP operands, set fcc (v9 variant). + BRICC, // Branch to dest on icc condition + BPICC, // Branch to dest on icc condition, with prediction (64-bit only). + BPXCC, // Branch to dest on xcc condition, with prediction (64-bit only). + BRFCC, // Branch to dest on fcc condition + BRFCC_V9, // Branch to dest on fcc condition (v9 variant). + SELECT_ICC, // Select between two values using the current ICC flags. + SELECT_XCC, // Select between two values using the current XCC flags. + SELECT_FCC, // Select between two values using the current FCC flags. + SELECT_FCC_V9, // Select between two values using the current FCC flags (v9 + // variant). Hi, Lo, // Hi/Lo operations, typically on a global address. Index: llvm/lib/Target/Sparc/SparcISelLowering.cpp =================================================================== --- llvm/lib/Target/Sparc/SparcISelLowering.cpp +++ llvm/lib/Target/Sparc/SparcISelLowering.cpp @@ -1862,6 +1862,10 @@ if (Subtarget->hasLeonCycleCounter()) setOperationAction(ISD::READCYCLECOUNTER, MVT::i64, Custom); + // SPARC v9 has multiple FCC registers. + if (Subtarget->isV9()) + setHasMultipleConditionRegisters(); + setOperationAction(ISD::INTRINSIC_WO_CHAIN, MVT::Other, Custom); setMinFunctionAlignment(Align(4)); @@ -1878,15 +1882,21 @@ case SPISD::FIRST_NUMBER: break; case SPISD::CMPICC: return "SPISD::CMPICC"; case SPISD::CMPFCC: return "SPISD::CMPFCC"; + case SPISD::CMPFCC_V9: + return "SPISD::CMPFCC_V9"; case SPISD::BRICC: return "SPISD::BRICC"; case SPISD::BPICC: return "SPISD::BPICC"; case SPISD::BPXCC: return "SPISD::BPXCC"; case SPISD::BRFCC: return "SPISD::BRFCC"; + case SPISD::BRFCC_V9: + return "SPISD::BRFCC_V9"; case SPISD::SELECT_ICC: return "SPISD::SELECT_ICC"; case SPISD::SELECT_XCC: return "SPISD::SELECT_XCC"; case SPISD::SELECT_FCC: return "SPISD::SELECT_FCC"; + case SPISD::SELECT_FCC_V9: + return "SPISD::SELECT_FCC_V9"; case SPISD::Hi: return "SPISD::Hi"; case SPISD::Lo: return "SPISD::Lo"; case SPISD::FTOI: return "SPISD::FTOI"; @@ -1943,15 +1953,14 @@ // set LHS/RHS and SPCC to the LHS/RHS of the setcc and SPCC to the condition. static void LookThroughSetCC(SDValue &LHS, SDValue &RHS, ISD::CondCode CC, unsigned &SPCC) { - if (isNullConstant(RHS) && - CC == ISD::SETNE && + if (isNullConstant(RHS) && CC == ISD::SETNE && (((LHS.getOpcode() == SPISD::SELECT_ICC || LHS.getOpcode() == SPISD::SELECT_XCC) && LHS.getOperand(3).getOpcode() == SPISD::CMPICC) || (LHS.getOpcode() == SPISD::SELECT_FCC && - LHS.getOperand(3).getOpcode() == SPISD::CMPFCC)) && - isOneConstant(LHS.getOperand(0)) && - isNullConstant(LHS.getOperand(1))) { + (LHS.getOperand(3).getOpcode() == SPISD::CMPFCC || + LHS.getOperand(3).getOpcode() == SPISD::CMPFCC_V9))) && + isOneConstant(LHS.getOperand(0)) && isNullConstant(LHS.getOperand(1))) { SDValue CMPCC = LHS.getOperand(3); SPCC = cast(LHS.getOperand(2))->getZExtValue(); LHS = CMPCC.getOperand(0); @@ -2518,9 +2527,11 @@ CompareFlag = TLI.LowerF128Compare(LHS, RHS, SPCC, dl, DAG); Opc = isV9 ? SPISD::BPICC : SPISD::BRICC; } else { - CompareFlag = DAG.getNode(SPISD::CMPFCC, dl, MVT::Glue, LHS, RHS); + unsigned CmpOp = isV9 ? SPISD::CMPFCC_V9 : SPISD::CMPFCC; + MVT::SimpleValueType CmpRet = isV9 ? MVT::i32 : MVT::Glue; + CompareFlag = DAG.getNode(CmpOp, dl, CmpRet, LHS, RHS); if (SPCC == ~0U) SPCC = FPCondCCodeToFCC(CC); - Opc = SPISD::BRFCC; + Opc = isV9 ? SPISD::BRFCC_V9 : SPISD::BRFCC; } } return DAG.getNode(Opc, dl, MVT::Other, Chain, Dest, @@ -2528,8 +2539,8 @@ } static SDValue LowerSELECT_CC(SDValue Op, SelectionDAG &DAG, - const SparcTargetLowering &TLI, - bool hasHardQuad) { + const SparcTargetLowering &TLI, bool hasHardQuad, + bool isV9) { SDValue LHS = Op.getOperand(0); SDValue RHS = Op.getOperand(1); ISD::CondCode CC = cast(Op.getOperand(4))->get(); @@ -2554,8 +2565,10 @@ CompareFlag = TLI.LowerF128Compare(LHS, RHS, SPCC, dl, DAG); Opc = SPISD::SELECT_ICC; } else { - CompareFlag = DAG.getNode(SPISD::CMPFCC, dl, MVT::Glue, LHS, RHS); - Opc = SPISD::SELECT_FCC; + unsigned CmpOp = isV9 ? SPISD::CMPFCC_V9 : SPISD::CMPFCC; + MVT::SimpleValueType CmpRet = isV9 ? MVT::i32 : MVT::Glue; + CompareFlag = DAG.getNode(CmpOp, dl, CmpRet, LHS, RHS); + Opc = isV9 ? SPISD::SELECT_FCC_V9 : SPISD::SELECT_FCC; if (SPCC == ~0U) SPCC = FPCondCCodeToFCC(CC); } } @@ -3101,8 +3114,8 @@ hasHardQuad); case ISD::BR_CC: return LowerBR_CC(Op, DAG, *this, hasHardQuad, isV9); - case ISD::SELECT_CC: return LowerSELECT_CC(Op, DAG, *this, - hasHardQuad); + case ISD::SELECT_CC: + return LowerSELECT_CC(Op, DAG, *this, hasHardQuad, isV9); case ISD::VASTART: return LowerVASTART(Op, DAG, *this); case ISD::VAARG: return LowerVAARG(Op, DAG); case ISD::DYNAMIC_STACKALLOC: return LowerDYNAMIC_STACKALLOC(Op, DAG, @@ -3191,6 +3204,8 @@ case SP::SELECT_CC_FP_FCC: case SP::SELECT_CC_DFP_FCC: case SP::SELECT_CC_QFP_FCC: + if (Subtarget->isV9()) + return expandSelectCC(MI, BB, SP::BPFCC); return expandSelectCC(MI, BB, SP::FBCOND); } } Index: llvm/lib/Target/Sparc/SparcInstr64Bit.td =================================================================== --- llvm/lib/Target/Sparc/SparcInstr64Bit.td +++ llvm/lib/Target/Sparc/SparcInstr64Bit.td @@ -477,10 +477,10 @@ def : Pat<(SPselecticc (i64 simm11:$t), i64:$f, imm:$cond), (MOVICCri (as_i32imm $t), $f, imm:$cond)>; -def : Pat<(SPselectfcc i64:$t, i64:$f, imm:$cond), - (MOVFCCrr $t, $f, imm:$cond)>; -def : Pat<(SPselectfcc (i64 simm11:$t), i64:$f, imm:$cond), - (MOVFCCri (as_i32imm $t), $f, imm:$cond)>; +def : Pat<(SPv9selectfcc i64:$t, i64:$f, imm:$cond, i32:$cc), + (V9MOVFCCrr i32:$cc, $t, $f, imm:$cond)>; +def : Pat<(SPv9selectfcc (i64 simm11:$t), i64:$f, imm:$cond, i32:$cc), + (V9MOVFCCri i32:$cc, (as_i32imm $t), $f, imm:$cond)>; } // Predicates = [Is64Bit] Index: llvm/lib/Target/Sparc/SparcInstrInfo.cpp =================================================================== --- llvm/lib/Target/Sparc/SparcInstrInfo.cpp +++ llvm/lib/Target/Sparc/SparcInstrInfo.cpp @@ -19,6 +19,7 @@ #include "llvm/CodeGen/MachineFrameInfo.h" #include "llvm/CodeGen/MachineInstrBuilder.h" #include "llvm/CodeGen/MachineMemOperand.h" +#include "llvm/CodeGen/MachineOperand.h" #include "llvm/CodeGen/MachineRegisterInfo.h" #include "llvm/MC/TargetRegistry.h" #include "llvm/Support/ErrorHandling.h" @@ -154,7 +155,16 @@ Opc == SP::BPXCCANT; } -static bool isFCondBranchOpcode(int Opc) { return Opc == SP::FBCOND; } +// V9 FP branches need special treatment since it takes an +// additional register parameter. +static bool isV9FCondBranchOpcode(int Opc) { + return Opc == SP::BPFCC || Opc == SP::BPFCCA || Opc == SP::BPFCCNT || + Opc == SP::BPFCCANT; +} + +static bool isFCondBranchOpcode(int Opc) { + return Opc == SP::FBCOND || isV9FCondBranchOpcode(Opc); +} static bool isCondBranchOpcode(int Opc) { return isI32CondBranchOpcode(Opc) || isI64CondBranchOpcode(Opc) || @@ -175,6 +185,12 @@ Cond.push_back(MachineOperand::CreateImm(Opc)); Cond.push_back(MachineOperand::CreateImm(CC)); + if (isV9FCondBranchOpcode(Opc)) { + // v9 FP branches need an additional operand + // to specify the CCR to branch on. + Cond.push_back(LastInst->getOperand(2)); + } + Target = LastInst->getOperand(0).getMBB(); } @@ -268,8 +284,8 @@ const DebugLoc &DL, int *BytesAdded) const { assert(TBB && "insertBranch must not be told to insert a fallthrough"); - assert((Cond.size() <= 2) && - "Sparc branch conditions should have at most two components!"); + assert((Cond.size() <= 3) && + "Sparc branch conditions should have at most three components!"); assert(!BytesAdded && "code size not handled"); if (Cond.empty()) { @@ -285,7 +301,13 @@ if (IsIntegerCC(CC)) { BuildMI(&MBB, DL, get(Opc)).addMBB(TBB).addImm(CC); } else { - BuildMI(&MBB, DL, get(SP::FBCOND)).addMBB(TBB).addImm(CC); + if (isV9FCondBranchOpcode(Opc)) { + // v9 FP branches explicitly select which CCR to branch on. + Register Reg = Cond[2].getReg(); + BuildMI(&MBB, DL, get(Opc)).addMBB(TBB).addImm(CC).addReg(Reg); + } else { + BuildMI(&MBB, DL, get(Opc)).addMBB(TBB).addImm(CC); + } } if (!FBB) return 1; @@ -319,7 +341,7 @@ bool SparcInstrInfo::reverseBranchCondition( SmallVectorImpl &Cond) const { - assert(Cond.size() <= 2); + assert(Cond.size() <= 3); SPCC::CondCodes CC = static_cast(Cond[1].getImm()); Cond[1].setImm(GetOppositeBranchCondition(CC)); return false; Index: llvm/lib/Target/Sparc/SparcInstrInfo.td =================================================================== --- llvm/lib/Target/Sparc/SparcInstrInfo.td +++ llvm/lib/Target/Sparc/SparcInstrInfo.td @@ -231,6 +231,14 @@ def SDTSPXTOF : SDTypeProfile<1, 1, [SDTCisFP<0>, SDTCisVT<1, f64>]>; +// V9 FP compare, branch, and select +def SDTSPv9cmpfcc : +SDTypeProfile<1, 2, [SDTCisVT<0, i32>, SDTCisFP<1>, SDTCisSameAs<1, 2>]>; +def SDTSPv9brfcc : +SDTypeProfile<0, 3, [SDTCisVT<0, OtherVT>, SDTCisVT<1, i32>, SDTCisVT<2, i32>]>; +def SDTSPv9selectcc : +SDTypeProfile<1, 4, [SDTCisSameAs<0, 1>, SDTCisSameAs<1, 2>, SDTCisVT<3, i32>, SDTCisVT<4, i32>]>; + def SDTSPtlsadd : SDTypeProfile<1, 3, [SDTCisInt<0>, SDTCisSameAs<0, 1>, SDTCisPtrTy<2>]>; def SDTSPtlsld : @@ -246,6 +254,10 @@ def SPbpxcc : SDNode<"SPISD::BPXCC", SDTSPbrcc, [SDNPHasChain, SDNPInGlue]>; def SPbrfcc : SDNode<"SPISD::BRFCC", SDTSPbrcc, [SDNPHasChain, SDNPInGlue]>; +// V9 FP compare and branch +def SPv9cmpfcc : SDNode<"SPISD::CMPFCC_V9", SDTSPv9cmpfcc, []>; +def SPv9brfcc : SDNode<"SPISD::BRFCC_V9", SDTSPv9brfcc, [SDNPHasChain]>; + def SPhi : SDNode<"SPISD::Hi", SDTIntUnaryOp>; def SPlo : SDNode<"SPISD::Lo", SDTIntUnaryOp>; @@ -257,6 +269,7 @@ def SPselecticc : SDNode<"SPISD::SELECT_ICC", SDTSPselectcc, [SDNPInGlue]>; def SPselectxcc : SDNode<"SPISD::SELECT_XCC", SDTSPselectcc, [SDNPInGlue]>; def SPselectfcc : SDNode<"SPISD::SELECT_FCC", SDTSPselectcc, [SDNPInGlue]>; +def SPv9selectfcc : SDNode<"SPISD::SELECT_FCC_V9", SDTSPv9selectcc, []>; // These are target-independent nodes, but have target-specific formats. def SDT_SPCallSeqStart : SDCallSeqStart<[ SDTCisVT<0, i32>, @@ -941,7 +954,9 @@ multiclass FPredBranch { def CC : F2_3<0b101, 0, 1, (outs), (ins bprtarget:$imm19, CCOp:$cond, FCCRegs:$cc), - "fb$cond $cc, $imm19", [], IIC_fpu_normal_instr>; + "fb$cond $cc, $imm19", + [(SPv9brfcc bb:$imm19, imm:$cond, i32:$cc)], + IIC_fpu_normal_instr>; def CCA : F2_3<0b101, 1, 1, (outs), (ins bprtarget:$imm19, CCOp:$cond, FCCRegs:$cc), "fb$cond,a $cc, $imm19", [], IIC_fpu_normal_instr>; @@ -1488,20 +1503,6 @@ (SPselecticc simm11:$simm11, i32:$f, imm:$cond))]>; } - let Uses = [FCC0], intcc = 0, cc = 0b00 in { - def MOVFCCrr - : F4_1<0b101100, (outs IntRegs:$rd), - (ins IntRegs:$rs2, IntRegs:$f, CCOp:$cond), - "mov$cond %fcc0, $rs2, $rd", - [(set i32:$rd, (SPselectfcc i32:$rs2, i32:$f, imm:$cond))]>; - def MOVFCCri - : F4_2<0b101100, (outs IntRegs:$rd), - (ins i32imm:$simm11, IntRegs:$f, CCOp:$cond), - "mov$cond %fcc0, $simm11, $rd", - [(set i32:$rd, - (SPselectfcc simm11:$simm11, i32:$f, imm:$cond))]>; - } - let Uses = [ICC], intcc = 1, opf_cc = 0b00 in { def FMOVS_ICC : F4_3<0b110101, 0b000001, (outs FPRegs:$rd), @@ -1520,26 +1521,6 @@ "fmovq$cond %icc, $rs2, $rd", [(set f128:$rd, (SPselecticc f128:$rs2, f128:$f, imm:$cond))]>; } - - let Uses = [FCC0], intcc = 0, opf_cc = 0b00 in { - def FMOVS_FCC - : F4_3<0b110101, 0b000001, (outs FPRegs:$rd), - (ins FPRegs:$rs2, FPRegs:$f, CCOp:$cond), - "fmovs$cond %fcc0, $rs2, $rd", - [(set f32:$rd, (SPselectfcc f32:$rs2, f32:$f, imm:$cond))]>; - def FMOVD_FCC - : F4_3<0b110101, 0b000010, (outs DFPRegs:$rd), - (ins DFPRegs:$rs2, DFPRegs:$f, CCOp:$cond), - "fmovd$cond %fcc0, $rs2, $rd", - [(set f64:$rd, (SPselectfcc f64:$rs2, f64:$f, imm:$cond))]>; - let Predicates = [HasV9, HasHardQuad] in - def FMOVQ_FCC - : F4_3<0b110101, 0b000011, (outs QFPRegs:$rd), - (ins QFPRegs:$rs2, QFPRegs:$f, CCOp:$cond), - "fmovq$cond %fcc0, $rs2, $rd", - [(set f128:$rd, (SPselectfcc f128:$rs2, f128:$f, imm:$cond))]>; - } - } // Floating-Point Move Instructions, p. 164 of the V9 manual. @@ -1573,15 +1554,18 @@ // Floating-point compare instruction with %fcc0-%fcc3. def V9FCMPS : F3_3c<2, 0b110101, 0b001010001, - (outs FCCRegs:$rd), (ins FPRegs:$rs1, FPRegs:$rs2), - "fcmps $rd, $rs1, $rs2", []>; + (outs FCCRegs:$rd), (ins FPRegs:$rs1, FPRegs:$rs2), + "fcmps $rd, $rs1, $rs2", + [(set i32:$rd, (SPv9cmpfcc f32:$rs1, f32:$rs2))]>; def V9FCMPD : F3_3c<2, 0b110101, 0b001010010, (outs FCCRegs:$rd), (ins DFPRegs:$rs1, DFPRegs:$rs2), - "fcmpd $rd, $rs1, $rs2", []>; + "fcmpd $rd, $rs1, $rs2", + [(set i32:$rd, (SPv9cmpfcc f64:$rs1, f64:$rs2))]>; def V9FCMPQ : F3_3c<2, 0b110101, 0b001010011, (outs FCCRegs:$rd), (ins QFPRegs:$rs1, QFPRegs:$rs2), - "fcmpq $rd, $rs1, $rs2", []>, - Requires<[HasHardQuad]>; + "fcmpq $rd, $rs1, $rs2", + [(set i32:$rd, (SPv9cmpfcc f128:$rs1, f128:$rs2))]>, + Requires<[HasHardQuad]>; let hasSideEffects = 1 in { def V9FCMPES : F3_3c<2, 0b110101, 0b001010101, @@ -1602,24 +1586,33 @@ def V9MOVFCCrr : F4_1<0b101100, (outs IntRegs:$rd), (ins FCCRegs:$cc, IntRegs:$rs2, IntRegs:$f, CCOp:$cond), - "mov$cond $cc, $rs2, $rd", []>; + "mov$cond $cc, $rs2, $rd", + [(set i32:$rd, (SPv9selectfcc i32:$rs2, i32:$f, imm:$cond, i32:$cc))]>; def V9MOVFCCri : F4_2<0b101100, (outs IntRegs:$rd), (ins FCCRegs:$cc, i32imm:$simm11, IntRegs:$f, CCOp:$cond), - "mov$cond $cc, $simm11, $rd", []>; + "mov$cond $cc, $simm11, $rd", + [(set i32:$rd, + (SPv9selectfcc simm11:$simm11, i32:$f, imm:$cond, i32:$cc))]>; def V9FMOVS_FCC : F4_3<0b110101, 0b000001, (outs FPRegs:$rd), (ins FCCRegs:$opf_cc, FPRegs:$rs2, FPRegs:$f, CCOp:$cond), - "fmovs$cond $opf_cc, $rs2, $rd", []>; + "fmovs$cond $opf_cc, $rs2, $rd", + [(set f32:$rd, + (SPv9selectfcc f32:$rs2, f32:$f, imm:$cond, i32:$opf_cc))]>; def V9FMOVD_FCC : F4_3<0b110101, 0b000010, (outs DFPRegs:$rd), (ins FCCRegs:$opf_cc, DFPRegs:$rs2, DFPRegs:$f, CCOp:$cond), - "fmovd$cond $opf_cc, $rs2, $rd", []>; + "fmovd$cond $opf_cc, $rs2, $rd", + [(set f64:$rd, + (SPv9selectfcc f64:$rs2, f64:$f, imm:$cond, i32:$opf_cc))]>; let Predicates = [HasV9, HasHardQuad] in def V9FMOVQ_FCC : F4_3<0b110101, 0b000011, (outs QFPRegs:$rd), (ins FCCRegs:$opf_cc, QFPRegs:$rs2, QFPRegs:$f, CCOp:$cond), - "fmovq$cond $opf_cc, $rs2, $rd", []>; + "fmovq$cond $opf_cc, $rs2, $rd", + [(set f128:$rd, + (SPv9selectfcc f128:$rs2, f128:$f, imm:$cond, i32:$opf_cc))]>; } // Constraints = "$f = $rd", ... } // let Predicates = [hasV9] Index: llvm/lib/Target/Sparc/SparcRegisterInfo.td =================================================================== --- llvm/lib/Target/Sparc/SparcRegisterInfo.td +++ llvm/lib/Target/Sparc/SparcRegisterInfo.td @@ -355,7 +355,7 @@ def LowQFPRegs : RegisterClass<"SP", [f128], 128, (sequence "Q%u", 0, 7)>; // Floating point control register classes. -def FCCRegs : RegisterClass<"SP", [i1], 1, (sequence "FCC%u", 0, 3)>; +def FCCRegs : RegisterClass<"SP", [i32], 1, (sequence "FCC%u", 0, 3)>; let isAllocatable = 0 in { // Ancillary state registers Index: llvm/test/CodeGen/SPARC/2011-01-11-CC.ll =================================================================== --- llvm/test/CodeGen/SPARC/2011-01-11-CC.ll +++ llvm/test/CodeGen/SPARC/2011-01-11-CC.ll @@ -119,9 +119,9 @@ ; V9-LABEL: test_float_cc ; V9: fcmpd -; V9: {{fbl|fbuge}} .LBB +; V9: {{fbl|fbuge}} %fcc0, .LBB ; V9: fcmpd -; V9: {{fbule|fbg}} .LBB +; V9: {{fbule|fbg}} %fcc0, .LBB %0 = fcmp uge double %a, 0.000000e+00 br i1 %0, label %loop, label %loop.2