From a3fc2b00ccd339f52e3b4efe0aa9a10bbca7c102 Mon Sep 17 00:00:00 2001 From: Venkatraman Govindaraju Date: Sun, 25 Aug 2013 18:30:06 +0000 Subject: [PATCH] [Sparc] Add long double (f128) instructions to sparc backend. llvm-svn: 189198 --- lib/Target/Sparc/Sparc.td | 4 + lib/Target/Sparc/SparcISelLowering.cpp | 134 +++++++++++++++++++++++++ lib/Target/Sparc/SparcInstrInfo.td | 108 ++++++++++++++++++++ lib/Target/Sparc/SparcSubtarget.cpp | 3 +- lib/Target/Sparc/SparcSubtarget.h | 2 + test/CodeGen/SPARC/fp128.ll | 27 +++++ 6 files changed, 277 insertions(+), 1 deletion(-) create mode 100644 test/CodeGen/SPARC/fp128.ll diff --git a/lib/Target/Sparc/Sparc.td b/lib/Target/Sparc/Sparc.td index d42c40faa15..0df48f60e8f 100644 --- a/lib/Target/Sparc/Sparc.td +++ b/lib/Target/Sparc/Sparc.td @@ -30,6 +30,10 @@ def FeatureVIS : SubtargetFeature<"vis", "IsVIS", "true", "Enable UltraSPARC Visual Instruction Set extensions">; +def FeatureHardQuad + : SubtargetFeature<"hard-quad-float", "HasHardQuad", "true", + "Enable quad-word floating point instructions">; + //===----------------------------------------------------------------------===// // Register File, Calling Conv, Instruction Descriptions //===----------------------------------------------------------------------===// diff --git a/lib/Target/Sparc/SparcISelLowering.cpp b/lib/Target/Sparc/SparcISelLowering.cpp index ce9cd9470ea..654a03a95e1 100644 --- a/lib/Target/Sparc/SparcISelLowering.cpp +++ b/lib/Target/Sparc/SparcISelLowering.cpp @@ -1257,15 +1257,21 @@ SparcTargetLowering::SparcTargetLowering(TargetMachine &TM) 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); @@ -1299,9 +1305,12 @@ SparcTargetLowering::SparcTargetLowering(TargetMachine &TM) 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); @@ -1310,10 +1319,12 @@ SparcTargetLowering::SparcTargetLowering(TargetMachine &TM) 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); @@ -1334,6 +1345,11 @@ SparcTargetLowering::SparcTargetLowering(TargetMachine &TM) 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); @@ -1352,8 +1368,10 @@ SparcTargetLowering::SparcTargetLowering(TargetMachine &TM) 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); @@ -1387,6 +1405,31 @@ SparcTargetLowering::SparcTargetLowering(TargetMachine &TM) 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(); @@ -1800,6 +1843,94 @@ static SDValue LowerF64Op(SDValue Op, SelectionDAG &DAG) return DstReg64; } +// Lower a f128 load into two f64 loads. +static SDValue LowerF128Load(SDValue Op, SelectionDAG &DAG) +{ + SDLoc dl(Op); + LoadSDNode *LdNode = dyn_cast(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(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()) { @@ -1822,6 +1953,9 @@ LowerOperation(SDValue Op, SelectionDAG &DAG) const { 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); } } diff --git a/lib/Target/Sparc/SparcInstrInfo.td b/lib/Target/Sparc/SparcInstrInfo.td index f5aa581ed8c..a08d1cb6d54 100644 --- a/lib/Target/Sparc/SparcInstrInfo.td +++ b/lib/Target/Sparc/SparcInstrInfo.td @@ -39,6 +39,10 @@ def HasNoV9 : Predicate<"!Subtarget.isV9()">; // 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 @@ -354,6 +358,16 @@ def LDDFri : F3_2<3, 0b100011, (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, @@ -398,6 +412,16 @@ def STDFri : F3_2<3, 0b100111, (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, @@ -599,6 +623,11 @@ def FITOD : F3_3<2, 0b110100, 0b011001000, (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, @@ -609,16 +638,41 @@ def FDTOI : F3_3<2, 0b110100, 0b011010010, (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, @@ -643,6 +697,11 @@ def FSQRTD : F3_3<2, 0b110100, 0b000101010, (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]>; @@ -655,6 +714,12 @@ def FADDD : F3_3<2, 0b110100, 0b001000010, (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", @@ -663,6 +728,12 @@ def FSUBD : F3_3<2, 0b110100, 0b001000110, (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, @@ -673,11 +744,24 @@ def FMULD : F3_3<2, 0b110100, 0b001001010, (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", @@ -686,6 +770,11 @@ def FDIVD : F3_3<2, 0b110100, 0b001001110, (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. @@ -701,6 +790,11 @@ let Defs = [FCC] in { (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]>; } //===----------------------------------------------------------------------===// @@ -762,14 +856,28 @@ let Predicates = [HasV9] in { 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 diff --git a/lib/Target/Sparc/SparcSubtarget.cpp b/lib/Target/Sparc/SparcSubtarget.cpp index f9ce0984f45..7d09d0e3f7d 100644 --- a/lib/Target/Sparc/SparcSubtarget.cpp +++ b/lib/Target/Sparc/SparcSubtarget.cpp @@ -30,7 +30,8 @@ SparcSubtarget::SparcSubtarget(const std::string &TT, const std::string &CPU, IsV9(false), V8DeprecatedInsts(false), IsVIS(false), - Is64Bit(is64Bit) { + Is64Bit(is64Bit), + HasHardQuad(false) { // Determine default and user specified characteristics std::string CPUName = CPU; diff --git a/lib/Target/Sparc/SparcSubtarget.h b/lib/Target/Sparc/SparcSubtarget.h index 2bf599d9122..0f81cc960f8 100644 --- a/lib/Target/Sparc/SparcSubtarget.h +++ b/lib/Target/Sparc/SparcSubtarget.h @@ -29,6 +29,7 @@ class SparcSubtarget : public SparcGenSubtargetInfo { bool V8DeprecatedInsts; bool IsVIS; bool Is64Bit; + bool HasHardQuad; public: SparcSubtarget(const std::string &TT, const std::string &CPU, @@ -37,6 +38,7 @@ public: bool isV9() const { return IsV9; } bool isVIS() const { return IsVIS; } bool useDeprecatedV8Instructions() const { return V8DeprecatedInsts; } + bool hasHardQuad() const { return HasHardQuad; } /// ParseSubtargetFeatures - Parses features string setting specified /// subtarget options. Definition of function is auto generated by tblgen. diff --git a/test/CodeGen/SPARC/fp128.ll b/test/CodeGen/SPARC/fp128.ll new file mode 100644 index 00000000000..a3a8bfa4899 --- /dev/null +++ b/test/CodeGen/SPARC/fp128.ll @@ -0,0 +1,27 @@ +; RUN: llc < %s -march=sparc -mattr=hard-quad-float | FileCheck %s + +; CHECK-LABEL: f128_ops +; CHECK: ldd +; CHECK: ldd +; CHECK: ldd +; CHECK: ldd +; CHECK: faddq [[R0:.+]], [[R1:.+]], [[R2:.+]] +; CHECK: fsubq [[R2]], [[R3:.+]], [[R4:.+]] +; CHECK: fmulq [[R4]], [[R5:.+]], [[R6:.+]] +; CHECK: fdivq [[R6]], [[R2]] +; CHECK: std +; CHECK: std + +define void @f128_ops(fp128* noalias sret %scalar.result, fp128* byval %a, fp128* byval %b, fp128* byval %c, fp128* byval %d) { +entry: + %0 = load fp128* %a, align 8 + %1 = load fp128* %b, align 8 + %2 = load fp128* %c, align 8 + %3 = load fp128* %d, align 8 + %4 = fadd fp128 %0, %1 + %5 = fsub fp128 %4, %2 + %6 = fmul fp128 %5, %3 + %7 = fdiv fp128 %6, %4 + store fp128 %7, fp128* %scalar.result, align 8 + ret void +}