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";
// 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<ConstantSDNode>(LHS.getOperand(2))->getZExtValue();
LHS = CMPCC.getOperand(0);
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 CmpOpc = isV9 ? SPISD::CMPFCC_V9 : SPISD::CMPFCC;
+ CompareFlag = DAG.getNode(CmpOpc, dl, MVT::Glue, 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,
}
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<CondCodeSDNode>(Op.getOperand(4))->get();
CompareFlag = TLI.LowerF128Compare(LHS, RHS, SPCC, dl, DAG);
Opc = SPISD::SELECT_ICC;
} else {
- CompareFlag = DAG.getNode(SPISD::CMPFCC, dl, MVT::Glue, LHS, RHS);
+ unsigned CmpOpc = isV9 ? SPISD::CMPFCC_V9 : SPISD::CMPFCC;
+ CompareFlag = DAG.getNode(CmpOpc, dl, MVT::Glue, LHS, RHS);
Opc = SPISD::SELECT_FCC;
if (SPCC == ~0U) SPCC = FPCondCCodeToFCC(CC);
}
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,
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::FBCOND_V9);
return expandSelectCC(MI, BB, SP::FBCOND);
}
}
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
+ 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.
def SPcmpicc : SDNode<"SPISD::CMPICC", SDTSPcmpicc, [SDNPOutGlue]>;
def SPcmpfcc : SDNode<"SPISD::CMPFCC", SDTSPcmpfcc, [SDNPOutGlue]>;
+def SPcmpfccv9 : SDNode<"SPISD::CMPFCC_V9", SDTSPcmpfcc, [SDNPOutGlue]>;
def SPbricc : SDNode<"SPISD::BRICC", SDTSPbrcc, [SDNPHasChain, SDNPInGlue]>;
def SPbpicc : SDNode<"SPISD::BPICC", SDTSPbrcc, [SDNPHasChain, SDNPInGlue]>;
def SPbpxcc : SDNode<"SPISD::BPXCC", SDTSPbrcc, [SDNPHasChain, SDNPInGlue]>;
def SPbrfcc : SDNode<"SPISD::BRFCC", SDTSPbrcc, [SDNPHasChain, SDNPInGlue]>;
+def SPbrfccv9 : SDNode<"SPISD::BRFCC_V9", SDTSPbrcc, [SDNPHasChain, SDNPInGlue]>;
def SPhi : SDNode<"SPISD::Hi", SDTIntUnaryOp>;
def SPlo : SDNode<"SPISD::Lo", SDTIntUnaryOp>;
"fb$cond,a $imm22", []>;
}
+// Variants of FBCOND that uses V9 opcode
+let Predicates = [HasV9], Uses = [FCC0], cc = 0,
+ isBranch = 1, isTerminator = 1, hasDelaySlot = 1 in {
+ def FBCOND_V9 : F2_3<0b101, 0, 1, (outs),
+ (ins bprtarget:$imm19, CCOp:$cond),
+ "fb$cond %fcc0, $imm19",
+ [(SPbrfccv9 bb:$imm19, imm:$cond)], IIC_fpu_normal_instr>;
+ def FBCONDA_V9 : F2_3<0b101, 1, 1, (outs),
+ (ins bprtarget:$imm19, CCOp:$cond),
+ "fb$cond,a %fcc0, $imm19",
+ [(SPbrfccv9 bb:$imm19, imm:$cond)], IIC_fpu_normal_instr>;
+}
+
let Predicates = [HasV9] in
defm BPF : FPredBranch;
Requires<[HasHardQuad]>;
}
+// A.13 Floating-Point Compare (SPARC v9)
+// Note that these always write to %fcc0 instead of having its destination
+// allocated automatically.
+// This avoids complications with the scheduler sometimes wanting to spill
+// the contents of an FCC, since SPARC v9 doesn't have facilities to spill
+// an individual FCC.
+
+let Predicates = [HasV9], Defs = [FCC0], rd = 0, isCodeGenOnly = 1 in {
+ def FCMPS_V9 : F3_3c<2, 0b110101, 0b001010001,
+ (outs), (ins FPRegs:$rs1, FPRegs:$rs2),
+ "fcmps %fcc0, $rs1, $rs2",
+ [(SPcmpfccv9 f32:$rs1, f32:$rs2)],
+ IIC_fpu_fast_instr>;
+ def FCMPD_V9 : F3_3c<2, 0b110101, 0b001010010,
+ (outs), (ins DFPRegs:$rs1, DFPRegs:$rs2),
+ "fcmpd %fcc0, $rs1, $rs2",
+ [(SPcmpfccv9 f64:$rs1, f64:$rs2)],
+ IIC_fpu_fast_instr>;
+ def FCMPQ_V9 : F3_3c<2, 0b110101, 0b001010011,
+ (outs), (ins QFPRegs:$rs1, QFPRegs:$rs2),
+ "fcmpq %fcc0, $rs1, $rs2",
+ [(SPcmpfccv9 f128:$rs1, f128:$rs2)]>,
+ Requires<[HasHardQuad]>;
+}
+
//===----------------------------------------------------------------------===//
// Instructions for Thread Local Storage(TLS).
//===----------------------------------------------------------------------===//
; V8: {{fbule|fbg}} .LBB
; V9-LABEL: test_float_cc
-; V9: fcmpd
-; V9: {{fbl|fbuge}} .LBB
-; V9: fcmpd
-; V9: {{fbule|fbg}} .LBB
+; V9: fcmpd %fcc0
+; V9: {{fbl|fbuge}} %fcc0, .LBB
+; V9: fcmpd %fcc0
+; V9: {{fbule|fbg}} %fcc0, .LBB
%0 = fcmp uge double %a, 0.000000e+00
br i1 %0, label %loop, label %loop.2
; CHECK: selecti64_fcc
; CHECK: mov %i3, %i0
-; CHECK: fcmps %f1, %f3
+; CHECK: fcmps %fcc0, %f1, %f3
; CHECK: movul %fcc0, %i2, %i0
; CHECK: restore
define i64 @selecti64_fcc(float %x, float %y, i64 %a, i64 %b) {