addRegisterClass(MVT::i32, &SP::IntRegsRegClass);
addRegisterClass(MVT::f32, &SP::FPRegsRegClass);
addRegisterClass(MVT::f64, &SP::DFPRegsRegClass);
+ addRegisterClass(MVT::f128, &SP::QFPRegsRegClass);
if (Subtarget->is64Bit())
addRegisterClass(MVT::i64, &SP::I64RegsRegClass);
// Turn FP extload into load/fextend
setLoadExtAction(ISD::EXTLOAD, MVT::f32, Expand);
+ setLoadExtAction(ISD::EXTLOAD, MVT::f64, Expand);
+
// Sparc doesn't have i1 sign extending load
setLoadExtAction(ISD::SEXTLOAD, MVT::i1, Promote);
+
// Turn FP truncstore into trunc + store.
setTruncStoreAction(MVT::f64, MVT::f32, Expand);
+ setTruncStoreAction(MVT::f128, MVT::f32, Expand);
+ setTruncStoreAction(MVT::f128, MVT::f64, Expand);
// Custom legalize GlobalAddress nodes into LO/HI parts.
setOperationAction(ISD::GlobalAddress, getPointerTy(), Custom);
setOperationAction(ISD::SELECT, MVT::i32, Expand);
setOperationAction(ISD::SELECT, MVT::f32, Expand);
setOperationAction(ISD::SELECT, MVT::f64, Expand);
+ setOperationAction(ISD::SELECT, MVT::f128, Expand);
+
setOperationAction(ISD::SETCC, MVT::i32, Expand);
setOperationAction(ISD::SETCC, MVT::f32, Expand);
setOperationAction(ISD::SETCC, MVT::f64, Expand);
+ setOperationAction(ISD::SETCC, MVT::f128, Expand);
// Sparc doesn't have BRCOND either, it has BR_CC.
setOperationAction(ISD::BRCOND, MVT::Other, Expand);
setOperationAction(ISD::BR_CC, MVT::i32, Custom);
setOperationAction(ISD::BR_CC, MVT::f32, Custom);
setOperationAction(ISD::BR_CC, MVT::f64, Custom);
+ setOperationAction(ISD::BR_CC, MVT::f128, Custom);
setOperationAction(ISD::SELECT_CC, MVT::i32, Custom);
setOperationAction(ISD::SELECT_CC, MVT::f32, Custom);
setOperationAction(ISD::SELECT_CC, MVT::f64, Custom);
+ setOperationAction(ISD::SELECT_CC, MVT::f128, Custom);
if (Subtarget->is64Bit()) {
setOperationAction(ISD::BITCAST, MVT::f64, Expand);
setOperationAction(ISD::FABS, MVT::f64, Custom);
}
+ setOperationAction(ISD::FSIN , MVT::f128, Expand);
+ setOperationAction(ISD::FCOS , MVT::f128, Expand);
+ setOperationAction(ISD::FSINCOS, MVT::f128, Expand);
+ setOperationAction(ISD::FREM , MVT::f128, Expand);
+ setOperationAction(ISD::FMA , MVT::f128, Expand);
setOperationAction(ISD::FSIN , MVT::f64, Expand);
setOperationAction(ISD::FCOS , MVT::f64, Expand);
setOperationAction(ISD::FSINCOS, MVT::f64, Expand);
setOperationAction(ISD::ROTL , MVT::i32, Expand);
setOperationAction(ISD::ROTR , MVT::i32, Expand);
setOperationAction(ISD::BSWAP, MVT::i32, Expand);
+ setOperationAction(ISD::FCOPYSIGN, MVT::f128, Expand);
setOperationAction(ISD::FCOPYSIGN, MVT::f64, Expand);
setOperationAction(ISD::FCOPYSIGN, MVT::f32, Expand);
+ setOperationAction(ISD::FPOW , MVT::f128, Expand);
setOperationAction(ISD::FPOW , MVT::f64, Expand);
setOperationAction(ISD::FPOW , MVT::f32, Expand);
if (Subtarget->isV9())
setOperationAction(ISD::CTPOP, MVT::i32, Legal);
+ if (Subtarget->isV9() && Subtarget->hasHardQuad()) {
+ setOperationAction(ISD::LOAD, MVT::f128, Legal);
+ setOperationAction(ISD::STORE, MVT::f128, Legal);
+ } else {
+ setOperationAction(ISD::LOAD, MVT::f128, Custom);
+ setOperationAction(ISD::STORE, MVT::f128, Custom);
+ }
+
+ if (Subtarget->hasHardQuad()) {
+ setOperationAction(ISD::FADD, MVT::f128, Legal);
+ setOperationAction(ISD::FSUB, MVT::f128, Legal);
+ setOperationAction(ISD::FMUL, MVT::f128, Legal);
+ setOperationAction(ISD::FDIV, MVT::f128, Legal);
+ setOperationAction(ISD::FSQRT, MVT::f128, Legal);
+ setOperationAction(ISD::FP_EXTEND, MVT::f128, Legal);
+ setOperationAction(ISD::FP_ROUND, MVT::f64, Legal);
+ if (Subtarget->isV9()) {
+ setOperationAction(ISD::FNEG, MVT::f128, Legal);
+ setOperationAction(ISD::FABS, MVT::f128, Legal);
+ } else {
+ setOperationAction(ISD::FNEG, MVT::f128, Custom);
+ setOperationAction(ISD::FABS, MVT::f128, Custom);
+ }
+ }
+
setMinFunctionAlignment(2);
computeRegisterProperties();
return DstReg64;
}
+// Lower a f128 load into two f64 loads.
+static SDValue LowerF128Load(SDValue Op, SelectionDAG &DAG)
+{
+ SDLoc dl(Op);
+ LoadSDNode *LdNode = dyn_cast<LoadSDNode>(Op.getNode());
+ assert(LdNode && LdNode->getOffset().getOpcode() == ISD::UNDEF
+ && "Unexpected node type");
+
+ SDValue Hi64 = DAG.getLoad(MVT::f64,
+ dl,
+ LdNode->getChain(),
+ LdNode->getBasePtr(),
+ LdNode->getPointerInfo(),
+ false, false, false, 8);
+ EVT addrVT = LdNode->getBasePtr().getValueType();
+ SDValue LoPtr = DAG.getNode(ISD::ADD, dl, addrVT,
+ LdNode->getBasePtr(),
+ DAG.getConstant(8, addrVT));
+ SDValue Lo64 = DAG.getLoad(MVT::f64,
+ dl,
+ LdNode->getChain(),
+ LoPtr,
+ LdNode->getPointerInfo(),
+ false, false, false, 8);
+
+ SDValue SubRegEven = DAG.getTargetConstant(SP::sub_even64, MVT::i32);
+ SDValue SubRegOdd = DAG.getTargetConstant(SP::sub_odd64, MVT::i32);
+
+ SDNode *InFP128 = DAG.getMachineNode(TargetOpcode::IMPLICIT_DEF,
+ dl, MVT::f128);
+ InFP128 = DAG.getMachineNode(TargetOpcode::INSERT_SUBREG, dl,
+ MVT::f128,
+ SDValue(InFP128, 0),
+ Hi64,
+ SubRegEven);
+ InFP128 = DAG.getMachineNode(TargetOpcode::INSERT_SUBREG, dl,
+ MVT::f128,
+ SDValue(InFP128, 0),
+ Lo64,
+ SubRegOdd);
+ SDValue OutChains[2] = { SDValue(Hi64.getNode(), 1),
+ SDValue(Lo64.getNode(), 1) };
+ SDValue OutChain = DAG.getNode(ISD::TokenFactor, dl, MVT::Other,
+ &OutChains[0], 2);
+ SDValue Ops[2] = {SDValue(InFP128,0), OutChain};
+ return DAG.getMergeValues(Ops, 2, dl);
+}
+
+// Lower a f128 store into two f64 stores.
+static SDValue LowerF128Store(SDValue Op, SelectionDAG &DAG) {
+ SDLoc dl(Op);
+ StoreSDNode *StNode = dyn_cast<StoreSDNode>(Op.getNode());
+ assert(StNode && StNode->getOffset().getOpcode() == ISD::UNDEF
+ && "Unexpected node type");
+ SDValue SubRegEven = DAG.getTargetConstant(SP::sub_even64, MVT::i32);
+ SDValue SubRegOdd = DAG.getTargetConstant(SP::sub_odd64, MVT::i32);
+
+ SDNode *Hi64 = DAG.getMachineNode(TargetOpcode::EXTRACT_SUBREG,
+ dl,
+ MVT::f64,
+ StNode->getValue(),
+ SubRegEven);
+ SDNode *Lo64 = DAG.getMachineNode(TargetOpcode::EXTRACT_SUBREG,
+ dl,
+ MVT::f64,
+ StNode->getValue(),
+ SubRegOdd);
+ SDValue OutChains[2];
+ OutChains[0] = DAG.getStore(StNode->getChain(),
+ dl,
+ SDValue(Hi64, 0),
+ StNode->getBasePtr(),
+ MachinePointerInfo(),
+ false, false, 8);
+ EVT addrVT = StNode->getBasePtr().getValueType();
+ SDValue LoPtr = DAG.getNode(ISD::ADD, dl, addrVT,
+ StNode->getBasePtr(),
+ DAG.getConstant(8, addrVT));
+ OutChains[1] = DAG.getStore(StNode->getChain(),
+ dl,
+ SDValue(Lo64, 0),
+ LoPtr,
+ MachinePointerInfo(),
+ false, false, 8);
+ return DAG.getNode(ISD::TokenFactor, dl, MVT::Other,
+ &OutChains[0], 2);
+}
+
SDValue SparcTargetLowering::
LowerOperation(SDValue Op, SelectionDAG &DAG) const {
switch (Op.getOpcode()) {
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 ISD::LOAD: return LowerF128Load(Op, DAG);
+ case ISD::STORE: return LowerF128Store(Op, DAG);
}
}
// HasVIS - This is true when the target processor has VIS extensions.
def HasVIS : Predicate<"Subtarget.isVIS()">;
+// HasHardQuad - This is true when the target processor supports quad floating
+// point instructions.
+def HasHardQuad : Predicate<"Subtarget.hasHardQuad()">;
+
// UseDeprecatedInsts - This predicate is true when the target processor is a
// V8, or when it is V9 but the V8 deprecated instructions are efficient enough
// to use when appropriate. In either of these cases, the instruction selector
(outs DFPRegs:$dst), (ins MEMri:$addr),
"ldd [$addr], $dst",
[(set f64:$dst, (load ADDRri:$addr))]>;
+def LDQFrr : F3_1<3, 0b100010,
+ (outs QFPRegs:$dst), (ins MEMrr:$addr),
+ "ldq [$addr], $dst",
+ [(set f128:$dst, (load ADDRrr:$addr))]>,
+ Requires<[HasV9, HasHardQuad]>;
+def LDQFri : F3_2<3, 0b100010,
+ (outs QFPRegs:$dst), (ins MEMri:$addr),
+ "ldq [$addr], $dst",
+ [(set f128:$dst, (load ADDRri:$addr))]>,
+ Requires<[HasV9, HasHardQuad]>;
// Section B.4 - Store Integer Instructions, p. 95
def STBrr : F3_1<3, 0b000101,
(outs), (ins MEMri:$addr, DFPRegs:$src),
"std $src, [$addr]",
[(store f64:$src, ADDRri:$addr)]>;
+def STQFrr : F3_1<3, 0b100110,
+ (outs), (ins MEMrr:$addr, QFPRegs:$src),
+ "stq $src, [$addr]",
+ [(store f128:$src, ADDRrr:$addr)]>,
+ Requires<[HasV9, HasHardQuad]>;
+def STQFri : F3_2<3, 0b100110,
+ (outs), (ins MEMri:$addr, QFPRegs:$src),
+ "stq $src, [$addr]",
+ [(store f128:$src, ADDRri:$addr)]>,
+ Requires<[HasV9, HasHardQuad]>;
// Section B.9 - SETHI Instruction, p. 104
def SETHIi: F2_1<0b100,
(outs DFPRegs:$dst), (ins FPRegs:$src),
"fitod $src, $dst",
[(set DFPRegs:$dst, (SPitof FPRegs:$src))]>;
+def FITOQ : F3_3<2, 0b110100, 0b011001100,
+ (outs QFPRegs:$dst), (ins FPRegs:$src),
+ "fitoq $src, $dst",
+ [(set QFPRegs:$dst, (SPitof FPRegs:$src))]>,
+ Requires<[HasHardQuad]>;
// Convert Floating-point to Integer Instructions, p. 142
def FSTOI : F3_3<2, 0b110100, 0b011010001,
(outs FPRegs:$dst), (ins DFPRegs:$src),
"fdtoi $src, $dst",
[(set FPRegs:$dst, (SPftoi DFPRegs:$src))]>;
+def FQTOI : F3_3<2, 0b110100, 0b011010011,
+ (outs FPRegs:$dst), (ins QFPRegs:$src),
+ "fqtoi $src, $dst",
+ [(set FPRegs:$dst, (SPftoi QFPRegs:$src))]>,
+ Requires<[HasHardQuad]>;
// Convert between Floating-point Formats Instructions, p. 143
def FSTOD : F3_3<2, 0b110100, 0b011001001,
(outs DFPRegs:$dst), (ins FPRegs:$src),
"fstod $src, $dst",
[(set f64:$dst, (fextend f32:$src))]>;
+def FSTOQ : F3_3<2, 0b110100, 0b011001101,
+ (outs QFPRegs:$dst), (ins FPRegs:$src),
+ "fstoq $src, $dst",
+ [(set f128:$dst, (fextend f32:$src))]>,
+ Requires<[HasHardQuad]>;
def FDTOS : F3_3<2, 0b110100, 0b011000110,
(outs FPRegs:$dst), (ins DFPRegs:$src),
"fdtos $src, $dst",
[(set f32:$dst, (fround f64:$src))]>;
+def FDTOQ : F3_3<2, 0b110100, 0b01101110,
+ (outs QFPRegs:$dst), (ins DFPRegs:$src),
+ "fdtoq $src, $dst",
+ [(set f128:$dst, (fextend f64:$src))]>,
+ Requires<[HasHardQuad]>;
+def FQTOS : F3_3<2, 0b110100, 0b011000111,
+ (outs FPRegs:$dst), (ins QFPRegs:$src),
+ "fqtos $src, $dst",
+ [(set f32:$dst, (fround f128:$src))]>,
+ Requires<[HasHardQuad]>;
+def FQTOD : F3_3<2, 0b110100, 0b011001011,
+ (outs DFPRegs:$dst), (ins QFPRegs:$src),
+ "fqtod $src, $dst",
+ [(set f64:$dst, (fround f128:$src))]>,
+ Requires<[HasHardQuad]>;
// Floating-point Move Instructions, p. 144
def FMOVS : F3_3<2, 0b110100, 0b000000001,
(outs DFPRegs:$dst), (ins DFPRegs:$src),
"fsqrtd $src, $dst",
[(set f64:$dst, (fsqrt f64:$src))]>;
+def FSQRTQ : F3_3<2, 0b110100, 0b000101011,
+ (outs QFPRegs:$dst), (ins QFPRegs:$src),
+ "fsqrtq $src, $dst",
+ [(set f128:$dst, (fsqrt f128:$src))]>,
+ Requires<[HasHardQuad]>;
(outs DFPRegs:$dst), (ins DFPRegs:$src1, DFPRegs:$src2),
"faddd $src1, $src2, $dst",
[(set f64:$dst, (fadd f64:$src1, f64:$src2))]>;
+def FADDQ : F3_3<2, 0b110100, 0b001000011,
+ (outs QFPRegs:$dst), (ins QFPRegs:$src1, QFPRegs:$src2),
+ "faddq $src1, $src2, $dst",
+ [(set f128:$dst, (fadd f128:$src1, f128:$src2))]>,
+ Requires<[HasHardQuad]>;
+
def FSUBS : F3_3<2, 0b110100, 0b001000101,
(outs FPRegs:$dst), (ins FPRegs:$src1, FPRegs:$src2),
"fsubs $src1, $src2, $dst",
(outs DFPRegs:$dst), (ins DFPRegs:$src1, DFPRegs:$src2),
"fsubd $src1, $src2, $dst",
[(set f64:$dst, (fsub f64:$src1, f64:$src2))]>;
+def FSUBQ : F3_3<2, 0b110100, 0b001000111,
+ (outs QFPRegs:$dst), (ins QFPRegs:$src1, QFPRegs:$src2),
+ "fsubq $src1, $src2, $dst",
+ [(set f128:$dst, (fsub f128:$src1, f128:$src2))]>,
+ Requires<[HasHardQuad]>;
+
// Floating-point Multiply and Divide Instructions, p. 147
def FMULS : F3_3<2, 0b110100, 0b001001001,
(outs DFPRegs:$dst), (ins DFPRegs:$src1, DFPRegs:$src2),
"fmuld $src1, $src2, $dst",
[(set f64:$dst, (fmul f64:$src1, f64:$src2))]>;
+def FMULQ : F3_3<2, 0b110100, 0b001001011,
+ (outs QFPRegs:$dst), (ins QFPRegs:$src1, QFPRegs:$src2),
+ "fmulq $src1, $src2, $dst",
+ [(set f128:$dst, (fmul f128:$src1, f128:$src2))]>,
+ Requires<[HasHardQuad]>;
+
def FSMULD : F3_3<2, 0b110100, 0b001101001,
(outs DFPRegs:$dst), (ins FPRegs:$src1, FPRegs:$src2),
"fsmuld $src1, $src2, $dst",
[(set f64:$dst, (fmul (fextend f32:$src1),
(fextend f32:$src2)))]>;
+def FDMULQ : F3_3<2, 0b110100, 0b001101110,
+ (outs QFPRegs:$dst), (ins DFPRegs:$src1, DFPRegs:$src2),
+ "fdmulq $src1, $src2, $dst",
+ [(set f128:$dst, (fmul (fextend f64:$src1),
+ (fextend f64:$src2)))]>,
+ Requires<[HasHardQuad]>;
+
def FDIVS : F3_3<2, 0b110100, 0b001001101,
(outs FPRegs:$dst), (ins FPRegs:$src1, FPRegs:$src2),
"fdivs $src1, $src2, $dst",
(outs DFPRegs:$dst), (ins DFPRegs:$src1, DFPRegs:$src2),
"fdivd $src1, $src2, $dst",
[(set f64:$dst, (fdiv f64:$src1, f64:$src2))]>;
+def FDIVQ : F3_3<2, 0b110100, 0b001001111,
+ (outs QFPRegs:$dst), (ins QFPRegs:$src1, QFPRegs:$src2),
+ "fdivq $src1, $src2, $dst",
+ [(set f128:$dst, (fdiv f128:$src1, f128:$src2))]>,
+ Requires<[HasHardQuad]>;
// Floating-point Compare Instructions, p. 148
// Note: the 2nd template arg is different for these guys.
(outs), (ins DFPRegs:$src1, DFPRegs:$src2),
"fcmpd $src1, $src2\n\tnop",
[(SPcmpfcc f64:$src1, f64:$src2)]>;
+ def FCMPQ : F3_3<2, 0b110101, 0b001010011,
+ (outs), (ins QFPRegs:$src1, QFPRegs:$src2),
+ "fcmpq $src1, $src2\n\tnop",
+ [(SPcmpfcc f128:$src1, f128:$src2)]>,
+ Requires<[HasHardQuad]>;
}
//===----------------------------------------------------------------------===//
def FMOVD : F3_3<2, 0b110100, 0b000000010,
(outs DFPRegs:$dst), (ins DFPRegs:$src),
"fmovd $src, $dst", []>;
+ def FMOVQ : F3_3<2, 0b110100, 0b000000011,
+ (outs QFPRegs:$dst), (ins QFPRegs:$src),
+ "fmovq $src, $dst", []>,
+ Requires<[HasHardQuad]>;
def FNEGD : F3_3<2, 0b110100, 0b000000110,
(outs DFPRegs:$dst), (ins DFPRegs:$src),
"fnegd $src, $dst",
[(set f64:$dst, (fneg f64:$src))]>;
+ def FNEGQ : F3_3<2, 0b110100, 0b000000111,
+ (outs QFPRegs:$dst), (ins QFPRegs:$src),
+ "fnegq $src, $dst",
+ [(set f128:$dst, (fneg f128:$src))]>,
+ Requires<[HasHardQuad]>;
def FABSD : F3_3<2, 0b110100, 0b000001010,
(outs DFPRegs:$dst), (ins DFPRegs:$src),
"fabsd $src, $dst",
[(set f64:$dst, (fabs f64:$src))]>;
+ def FABSQ : F3_3<2, 0b110100, 0b000001011,
+ (outs QFPRegs:$dst), (ins QFPRegs:$src),
+ "fabsq $src, $dst",
+ [(set f128:$dst, (fabs f128:$src))]>,
+ Requires<[HasHardQuad]>;
}
// POPCrr - This does a ctpop of a 64-bit register. As such, we have to clear