mirror of
https://github.com/RPCS3/llvm.git
synced 2024-12-13 23:18:58 +00:00
Implement a correct ui64->f32 conversion. The old
one was subject to double rounding in extreme cases. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@103744 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
b9c0e332b3
commit
a5afa1cb21
@ -2026,6 +2026,7 @@ SDValue SelectionDAGLegalize::ExpandLegalINT_TO_FP(bool isSigned,
|
||||
return Result;
|
||||
}
|
||||
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
|
||||
// __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);
|
||||
}
|
||||
|
||||
// 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 SignSet = DAG.getSetCC(dl, TLI.getSetCCResultType(Op0.getValueType()),
|
||||
|
Loading…
Reference in New Issue
Block a user