mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-12-17 00:27:31 +00:00
Implement a correct ui64->f32 conversion. The old
one was subject to double rounding in extreme cases. llvm-svn: 103744
This commit is contained in:
parent
5e115a09ec
commit
9f19b6a761
@ -2026,6 +2026,7 @@ SDValue SelectionDAGLegalize::ExpandLegalINT_TO_FP(bool isSigned,
|
|||||||
return Result;
|
return Result;
|
||||||
}
|
}
|
||||||
assert(!isSigned && "Legalize cannot Expand SINT_TO_FP for i64 yet");
|
assert(!isSigned && "Legalize cannot Expand SINT_TO_FP for i64 yet");
|
||||||
|
// Code below here assumes !isSigned without checking again.
|
||||||
|
|
||||||
// Implementation of unsigned i64 to f64 following the algorithm in
|
// Implementation of unsigned i64 to f64 following the algorithm in
|
||||||
// __floatundidf in compiler_rt. This implementation has the advantage
|
// __floatundidf in compiler_rt. This implementation has the advantage
|
||||||
@ -2051,6 +2052,41 @@ SDValue SelectionDAGLegalize::ExpandLegalINT_TO_FP(bool isSigned,
|
|||||||
return DAG.getNode(ISD::FADD, dl, MVT::f64, LoFlt, HiSub);
|
return DAG.getNode(ISD::FADD, dl, MVT::f64, LoFlt, HiSub);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Implementation of unsigned i64 to f32. This implementation has the
|
||||||
|
// advantage of performing rounding correctly.
|
||||||
|
// TODO: Generalize this for use with other types.
|
||||||
|
if (Op0.getValueType() == MVT::i64 && DestVT == MVT::f32) {
|
||||||
|
EVT SHVT = TLI.getShiftAmountTy();
|
||||||
|
|
||||||
|
SDValue And = DAG.getNode(ISD::AND, dl, MVT::i64, Op0,
|
||||||
|
DAG.getConstant(UINT64_C(0xfffffffffffff800), MVT::i64));
|
||||||
|
SDValue Or = DAG.getNode(ISD::OR, dl, MVT::i64, And,
|
||||||
|
DAG.getConstant(UINT64_C(0x800), MVT::i64));
|
||||||
|
SDValue And2 = DAG.getNode(ISD::AND, dl, MVT::i64, Op0,
|
||||||
|
DAG.getConstant(UINT64_C(0x7ff), MVT::i64));
|
||||||
|
SDValue Ne = DAG.getSetCC(dl, TLI.getSetCCResultType(MVT::i64),
|
||||||
|
And2, DAG.getConstant(UINT64_C(0), MVT::i64), ISD::SETNE);
|
||||||
|
SDValue Sel = DAG.getNode(ISD::SELECT, dl, MVT::i64, Ne, Or, Op0);
|
||||||
|
SDValue Ge = DAG.getSetCC(dl, TLI.getSetCCResultType(MVT::i64),
|
||||||
|
Op0, DAG.getConstant(UINT64_C(0x0020000000000000), MVT::i64),
|
||||||
|
ISD::SETUGE);
|
||||||
|
SDValue Sel2 = DAG.getNode(ISD::SELECT, dl, MVT::i64, Ge, Sel, Op0);
|
||||||
|
|
||||||
|
SDValue Sh = DAG.getNode(ISD::SRL, dl, MVT::i64, Sel2,
|
||||||
|
DAG.getConstant(32, SHVT));
|
||||||
|
SDValue Trunc = DAG.getNode(ISD::TRUNCATE, dl, MVT::i32, Sh);
|
||||||
|
SDValue Fcvt = DAG.getNode(ISD::UINT_TO_FP, dl, MVT::f64, Trunc);
|
||||||
|
SDValue TwoP32 =
|
||||||
|
DAG.getConstantFP(BitsToDouble(UINT64_C(0x41f0000000000000)), MVT::f64);
|
||||||
|
SDValue Fmul = DAG.getNode(ISD::FMUL, dl, MVT::f64, TwoP32, Fcvt);
|
||||||
|
SDValue Lo = DAG.getNode(ISD::TRUNCATE, dl, MVT::i32, Sel2);
|
||||||
|
SDValue Fcvt2 = DAG.getNode(ISD::UINT_TO_FP, dl, MVT::f64, Lo);
|
||||||
|
SDValue Fadd = DAG.getNode(ISD::FADD, dl, MVT::f64, Fmul, Fcvt2);
|
||||||
|
return DAG.getNode(ISD::FP_ROUND, dl, MVT::f32, Fadd,
|
||||||
|
DAG.getIntPtrConstant(0));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
SDValue Tmp1 = DAG.getNode(ISD::SINT_TO_FP, dl, DestVT, Op0);
|
SDValue Tmp1 = DAG.getNode(ISD::SINT_TO_FP, dl, DestVT, Op0);
|
||||||
|
|
||||||
SDValue SignSet = DAG.getSetCC(dl, TLI.getSetCCResultType(Op0.getValueType()),
|
SDValue SignSet = DAG.getSetCC(dl, TLI.getSetCCResultType(Op0.getValueType()),
|
||||||
|
Loading…
Reference in New Issue
Block a user