Index: lib/Target/Sparc/SparcISelLowering.h =================================================================== --- lib/Target/Sparc/SparcISelLowering.h +++ lib/Target/Sparc/SparcISelLowering.h @@ -192,6 +192,10 @@ SDValue LowerINTRINSIC_WO_CHAIN(SDValue Op, SelectionDAG &DAG) const; + SDValue LowerBITCAST(SDValue Op, SelectionDAG &DAG) const; + + SDValue LowerUINT_TO_FP(SDValue Op, SelectionDAG &DAG) const; + bool ShouldShrinkFPConstant(EVT VT) const override { // Do not shrink FP constpool if VT == MVT::f128. // (ldd, call _Q_fdtoq) is more expensive than two ldds. Index: lib/Target/Sparc/SparcISelLowering.cpp =================================================================== --- lib/Target/Sparc/SparcISelLowering.cpp +++ lib/Target/Sparc/SparcISelLowering.cpp @@ -1389,6 +1389,78 @@ return Chain; } +SDValue SparcTargetLowering::LowerBITCAST(SDValue Op, SelectionDAG &DAG) const { + SDLoc dl(Op); + EVT SrcVT = Op.getOperand(0).getValueType(); + + EVT DstVT = Op.getValueType(); + + if (Subtarget->isVIS3()) { + if (DstVT == MVT::f32 && SrcVT == MVT::i32) { + return Op; // Legal + } else if (DstVT == MVT::f64 && SrcVT == MVT::i64) { + return (Subtarget->is64Bit()) + ? Op + : SDValue(); // Legal on 64 bit, otherwise Expand + } else if (DstVT == MVT::i64 && SrcVT == MVT::f64) { + return (Subtarget->is64Bit()) + ? Op + : SDValue(); // Legal on 64 bit, otherwise Expand + } + } + + // Expand + return SDValue(); +} + +SDValue SparcTargetLowering::LowerUINT_TO_FP(SDValue Op, + SelectionDAG &DAG) const { + SDLoc dl(Op); + EVT OpVT = Op.getOperand(0).getValueType(); + assert(OpVT == MVT::i32 || OpVT == MVT::i64); + + // Expand f128 operations to fp128 ABI calls. + if (Op.getValueType() == MVT::f128 && + (!Subtarget->hasHardQuad() || !isTypeLegal(OpVT))) { + return LowerF128Op(Op, DAG, + getLibcallName(OpVT == MVT::i32 + ? RTLIB::UINTTOFP_I32_F128 + : RTLIB::UINTTOFP_I64_F128), + 1); + } + + // Since UINT_TO_FP is legal (it's marked custom), dag combiner won't + // optimize it to a SINT_TO_FP when the sign bit is known zero. Perform + // the optimization here. + if (DAG.SignBitIsZero(Op.getOperand(0))) { + + EVT floatVT = MVT::f32; + unsigned IntToFloatOpcode = SPISD::ITOF; + + if (OpVT == MVT::i64) { + floatVT = MVT::f64; + IntToFloatOpcode = SPISD::XTOF; + } + + // Convert the int value to FP in an FP register. + SDValue FloatTmp = DAG.getNode(ISD::BITCAST, dl, floatVT, Op.getOperand(0)); + + return DAG.getNode(IntToFloatOpcode, dl, Op.getValueType(), FloatTmp); + } + + if (OpVT == MVT::i32 && Subtarget->is64Bit()) { + + SDValue Int64Tmp = + DAG.getNode(ISD::ZERO_EXTEND, dl, MVT::i64, Op.getOperand(0)); + + SDValue Float64Tmp = DAG.getNode(ISD::BITCAST, dl, MVT::f64, Int64Tmp); + + return DAG.getNode(SPISD::XTOF, dl, Op.getValueType(), Float64Tmp); + } + + return SDValue(); +} + //===----------------------------------------------------------------------===// // TargetLowering Implementation //===----------------------------------------------------------------------===// @@ -1559,9 +1631,6 @@ setOperationAction(ISD::FP_TO_UINT, MVT::i64, Custom); setOperationAction(ISD::UINT_TO_FP, MVT::i64, Custom); - setOperationAction(ISD::BITCAST, MVT::f32, Expand); - setOperationAction(ISD::BITCAST, MVT::i32, Expand); - // Sparc has no select or setcc: expand to SELECT_CC. setOperationAction(ISD::SELECT, MVT::i32, Expand); setOperationAction(ISD::SELECT, MVT::f32, Expand); @@ -1590,13 +1659,14 @@ setOperationAction(ISD::EH_SJLJ_SETJMP, MVT::i32, Custom); setOperationAction(ISD::EH_SJLJ_LONGJMP, MVT::Other, Custom); + setOperationAction(ISD::BITCAST, MVT::i32, Custom); + setOperationAction(ISD::BITCAST, MVT::f32, Custom); + if (Subtarget->is64Bit()) { setOperationAction(ISD::ADDC, MVT::i64, Custom); setOperationAction(ISD::ADDE, MVT::i64, Custom); setOperationAction(ISD::SUBC, MVT::i64, Custom); setOperationAction(ISD::SUBE, MVT::i64, Custom); - setOperationAction(ISD::BITCAST, MVT::f64, Expand); - setOperationAction(ISD::BITCAST, MVT::i64, Expand); setOperationAction(ISD::SELECT, MVT::i64, Expand); setOperationAction(ISD::SETCC, MVT::i64, Expand); setOperationAction(ISD::BR_CC, MVT::i64, Custom); @@ -1610,6 +1680,9 @@ setOperationAction(ISD::ROTL , MVT::i64, Expand); setOperationAction(ISD::ROTR , MVT::i64, Expand); setOperationAction(ISD::DYNAMIC_STACKALLOC, MVT::i64, Custom); + + setOperationAction(ISD::BITCAST, MVT::i64, Custom); + setOperationAction(ISD::BITCAST, MVT::f64, Custom); } // ATOMICs. @@ -2425,25 +2498,6 @@ 1); } -static SDValue LowerUINT_TO_FP(SDValue Op, SelectionDAG &DAG, - const SparcTargetLowering &TLI, - bool hasHardQuad) { - SDLoc dl(Op); - EVT OpVT = Op.getOperand(0).getValueType(); - assert(OpVT == MVT::i32 || OpVT == MVT::i64); - - // Expand if it does not involve f128 or the target has support for - // quad floating point instructions and the operand type is legal. - if (Op.getValueType() != MVT::f128 || (hasHardQuad && TLI.isTypeLegal(OpVT))) - return SDValue(); - - return TLI.LowerF128Op(Op, DAG, - TLI.getLibcallName(OpVT == MVT::i32 - ? RTLIB::UINTTOFP_I32_F128 - : RTLIB::UINTTOFP_I64_F128), - 1); -} - static SDValue LowerBR_CC(SDValue Op, SelectionDAG &DAG, const SparcTargetLowering &TLI, bool hasHardQuad) { @@ -3059,8 +3113,7 @@ hasHardQuad); case ISD::FP_TO_UINT: return LowerFP_TO_UINT(Op, DAG, *this, hasHardQuad); - case ISD::UINT_TO_FP: return LowerUINT_TO_FP(Op, DAG, *this, - hasHardQuad); + case ISD::UINT_TO_FP: return LowerUINT_TO_FP(Op, DAG); case ISD::BR_CC: return LowerBR_CC(Op, DAG, *this, hasHardQuad); case ISD::SELECT_CC: return LowerSELECT_CC(Op, DAG, *this, @@ -3097,6 +3150,7 @@ case ISD::ATOMIC_LOAD: case ISD::ATOMIC_STORE: return LowerATOMIC_LOAD_STORE(Op, DAG); case ISD::INTRINSIC_WO_CHAIN: return LowerINTRINSIC_WO_CHAIN(Op, DAG); + case ISD::BITCAST: return LowerBITCAST(Op, DAG); } } Index: lib/Target/Sparc/SparcInstrVIS.td =================================================================== --- lib/Target/Sparc/SparcInstrVIS.td +++ lib/Target/Sparc/SparcInstrVIS.td @@ -243,16 +243,21 @@ (ins I64Regs:$rs2), "lzcnt $rs2, $rd", []>; let rs1 = 0 in { -def MOVSTOSW : VISInstFormat<0b100010011, (outs I64Regs:$rd), - (ins DFPRegs:$rs2), "movstosw $rs2, $rd", []>; -def MOVSTOUW : VISInstFormat<0b100010001, (outs I64Regs:$rd), - (ins DFPRegs:$rs2), "movstouw $rs2, $rd", []>; -def MOVDTOX : VISInstFormat<0b100010000, (outs I64Regs:$rd), - (ins DFPRegs:$rs2), "movdtox $rs2, $rd", []>; -def MOVWTOS : VISInstFormat<0b100011001, (outs DFPRegs:$rd), - (ins I64Regs:$rs2), "movdtox $rs2, $rd", []>; -def MOVXTOD : VISInstFormat<0b100011000, (outs DFPRegs:$rd), - (ins I64Regs:$rs2), "movdtox $rs2, $rd", []>; +def MOVSTOSW : VISInstFormat<0b100010011, (outs I64Regs:$rd), (ins FPRegs:$rs2), + "movstosw $rs2, $rd", + [(set I64Regs:$rd, (sext (i32 (bitconvert FPRegs:$rs2))))]>; +def MOVSTOUW : VISInstFormat<0b100010001, (outs I64Regs:$rd), (ins FPRegs:$rs2), + "movstouw $rs2, $rd", + [(set I64Regs:$rd, (zext (i32 (bitconvert FPRegs:$rs2))))]>; +def MOVDTOX : VISInstFormat<0b100010000, (outs I64Regs:$rd), (ins DFPRegs:$rs2), + "movdtox $rs2, $rd", + [(set I64Regs:$rd, (bitconvert DFPRegs:$rs2))]>; +def MOVWTOS : VISInstFormat<0b100011001, (outs FPRegs:$rd), (ins IntRegs:$rs2), + "movwtos $rs2, $rd", + [(set FPRegs:$rd, (bitconvert i32:$rs2))]>; +def MOVXTOD : VISInstFormat<0b100011000, (outs DFPRegs:$rd), (ins I64Regs:$rs2), + "movxtod $rs2, $rd", + [(set DFPRegs:$rd, (bitconvert I64Regs:$rs2))]>; } def PDISTN : VISInst<0b000111111, "pdistn">; Index: test/CodeGen/SPARC/float.ll =================================================================== --- test/CodeGen/SPARC/float.ll +++ test/CodeGen/SPARC/float.ll @@ -194,7 +194,7 @@ ; V9: fstoi ; SPARC64-LABEL: test_utos_stou -; SPARC64: fdtos +; SPARC64: fxtos ; SPARC64: fstoi define void @test_utos_stou(i32 %a, i32* %ptr0, float* %ptr1) { Index: test/CodeGen/SPARC/uint_to_fp.ll =================================================================== --- /dev/null +++ test/CodeGen/SPARC/uint_to_fp.ll @@ -0,0 +1,28 @@ + +; +; RUN: llc -march=sparc < %s 2>&1 | FileCheck %s +; RUN: llc -march=sparcv9 < %s 2>&1 | FileCheck --check-prefix=CHECK --check-prefix=CHECK64 %s + +; check that fitod used for SPISD::ITOF +; +; CHECK-LABEL: Primitive_us +; CHECK:fitod + +; Function Attrs: norecurse nounwind readnone +define double @Primitive_us(i16 zeroext) local_unnamed_addr #0 { + %2 = uitofp i16 %0 to double + ret double %2 +} + +; check that fxtod used for SPISD::XTOF +; +; CHECK-LABEL: Primitive_ui +; CHECK64:fxtod + +; Function Attrs: norecurse nounwind readnone +define double @Primitive_ui(i32 zeroext) local_unnamed_addr #0 { + %2 = uitofp i32 %0 to double + ret double %2 +} + + Index: test/CodeGen/SPARC/vis3.ll =================================================================== --- /dev/null +++ test/CodeGen/SPARC/vis3.ll @@ -0,0 +1,28 @@ + +; +; RUN: llc -march=sparc -mcpu=niagara4 < %s 2>&1 | FileCheck %s +; RUN: llc -march=sparcv9 -mcpu=niagara4 < %s 2>&1 | FileCheck --check-prefix=CHECK --check-prefix=CHECK64 %s + +; check that movwtos used for bitcast +; +; CHECK-LABEL: Primitive_us +; CHECK:movwtos + +; Function Attrs: norecurse nounwind readnone +define double @Primitive_us(i16 zeroext) local_unnamed_addr #0 { + %2 = uitofp i16 %0 to double + ret double %2 +} + +; check for movxtod used for bitcast +; +; CHECK-LABEL: Primitive_ui +; CHECK64:movxtod + +; Function Attrs: norecurse nounwind readnone +define double @Primitive_ui(i32 zeroext) local_unnamed_addr #0 { + %2 = uitofp i32 %0 to double + ret double %2 +} + +