mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-10-19 11:02:59 +02:00
[X86] Adding fp128 support for strict fcmp
Summary: Adding fp128 support for strict fcmp Reviewers: craig.topper, LiuChen3, andrew.w.kaylor, RKSimon, uweigand Subscribers: hiraditya, llvm-commits, LuoYuanke Tags: #llvm Differential Revision: https://reviews.llvm.org/D71897
This commit is contained in:
parent
0e3b53e64e
commit
424f235504
@ -3032,6 +3032,12 @@ public:
|
||||
const SDLoc &DL, const SDValue OldLHS,
|
||||
const SDValue OldRHS) const;
|
||||
|
||||
void softenSetCCOperands(SelectionDAG &DAG, EVT VT, SDValue &NewLHS,
|
||||
SDValue &NewRHS, ISD::CondCode &CCCode,
|
||||
const SDLoc &DL, const SDValue OldLHS,
|
||||
const SDValue OldRHS, SDValue &Chain,
|
||||
bool IsSignaling = false) const;
|
||||
|
||||
/// Returns a pair of (return value, chain).
|
||||
/// It is an error to pass RTLIB::UNKNOWN_LIBCALL as \p LC.
|
||||
std::pair<SDValue, SDValue> makeLibCall(SelectionDAG &DAG, RTLIB::Libcall LC,
|
||||
|
@ -782,6 +782,8 @@ bool DAGTypeLegalizer::SoftenFloatOperand(SDNode *N, unsigned OpNo) {
|
||||
case ISD::STRICT_LLRINT:
|
||||
case ISD::LLRINT: Res = SoftenFloatOp_LLRINT(N); break;
|
||||
case ISD::SELECT_CC: Res = SoftenFloatOp_SELECT_CC(N); break;
|
||||
case ISD::STRICT_FSETCC:
|
||||
case ISD::STRICT_FSETCCS:
|
||||
case ISD::SETCC: Res = SoftenFloatOp_SETCC(N); break;
|
||||
case ISD::STORE: Res = SoftenFloatOp_STORE(N, OpNo); break;
|
||||
case ISD::FCOPYSIGN: Res = SoftenFloatOp_FCOPYSIGN(N); break;
|
||||
@ -931,26 +933,39 @@ SDValue DAGTypeLegalizer::SoftenFloatOp_SELECT_CC(SDNode *N) {
|
||||
}
|
||||
|
||||
SDValue DAGTypeLegalizer::SoftenFloatOp_SETCC(SDNode *N) {
|
||||
SDValue NewLHS = N->getOperand(0), NewRHS = N->getOperand(1);
|
||||
ISD::CondCode CCCode = cast<CondCodeSDNode>(N->getOperand(2))->get();
|
||||
bool IsStrict = N->isStrictFPOpcode();
|
||||
SDValue Op0 = N->getOperand(IsStrict ? 1 : 0);
|
||||
SDValue Op1 = N->getOperand(IsStrict ? 2 : 1);
|
||||
SDValue Chain = IsStrict ? N->getOperand(0) : SDValue();
|
||||
ISD::CondCode CCCode =
|
||||
cast<CondCodeSDNode>(N->getOperand(IsStrict ? 3 : 2))->get();
|
||||
|
||||
EVT VT = NewLHS.getValueType();
|
||||
NewLHS = GetSoftenedFloat(NewLHS);
|
||||
NewRHS = GetSoftenedFloat(NewRHS);
|
||||
TLI.softenSetCCOperands(DAG, VT, NewLHS, NewRHS, CCCode, SDLoc(N),
|
||||
N->getOperand(0), N->getOperand(1));
|
||||
EVT VT = Op0.getValueType();
|
||||
SDValue NewLHS = GetSoftenedFloat(Op0);
|
||||
SDValue NewRHS = GetSoftenedFloat(Op1);
|
||||
TLI.softenSetCCOperands(DAG, VT, NewLHS, NewRHS, CCCode, SDLoc(N), Op0, Op1,
|
||||
Chain, N->getOpcode() == ISD::STRICT_FSETCCS);
|
||||
|
||||
// If softenSetCCOperands returned a scalar, use it.
|
||||
if (!NewRHS.getNode()) {
|
||||
assert(NewLHS.getValueType() == N->getValueType(0) &&
|
||||
"Unexpected setcc expansion!");
|
||||
return NewLHS;
|
||||
// Update N to have the operands specified.
|
||||
if (NewRHS.getNode()) {
|
||||
if (IsStrict)
|
||||
NewLHS = DAG.getNode(ISD::SETCC, SDLoc(N), N->getValueType(0), NewLHS,
|
||||
NewRHS, DAG.getCondCode(CCCode));
|
||||
else
|
||||
return SDValue(DAG.UpdateNodeOperands(N, NewLHS, NewRHS,
|
||||
DAG.getCondCode(CCCode)), 0);
|
||||
}
|
||||
|
||||
// Otherwise, update N to have the operands specified.
|
||||
return SDValue(DAG.UpdateNodeOperands(N, NewLHS, NewRHS,
|
||||
DAG.getCondCode(CCCode)),
|
||||
0);
|
||||
// Otherwise, softenSetCCOperands returned a scalar, use it.
|
||||
assert((NewRHS.getNode() || NewLHS.getValueType() == N->getValueType(0)) &&
|
||||
"Unexpected setcc expansion!");
|
||||
|
||||
if (IsStrict) {
|
||||
ReplaceValueWith(SDValue(N, 0), NewLHS);
|
||||
ReplaceValueWith(SDValue(N, 1), Chain);
|
||||
return SDValue();
|
||||
}
|
||||
return NewLHS;
|
||||
}
|
||||
|
||||
SDValue DAGTypeLegalizer::SoftenFloatOp_STORE(SDNode *N, unsigned OpNo) {
|
||||
|
@ -285,6 +285,22 @@ void TargetLowering::softenSetCCOperands(SelectionDAG &DAG, EVT VT,
|
||||
ISD::CondCode &CCCode,
|
||||
const SDLoc &dl, const SDValue OldLHS,
|
||||
const SDValue OldRHS) const {
|
||||
SDValue Chain;
|
||||
return softenSetCCOperands(DAG, VT, NewLHS, NewRHS, CCCode, dl, OldLHS,
|
||||
OldRHS, Chain);
|
||||
}
|
||||
|
||||
void TargetLowering::softenSetCCOperands(SelectionDAG &DAG, EVT VT,
|
||||
SDValue &NewLHS, SDValue &NewRHS,
|
||||
ISD::CondCode &CCCode,
|
||||
const SDLoc &dl, const SDValue OldLHS,
|
||||
const SDValue OldRHS,
|
||||
SDValue &Chain,
|
||||
bool IsSignaling) const {
|
||||
// FIXME: Currently we cannot really respect all IEEE predicates due to libgcc
|
||||
// not supporting it. We can update this code when libgcc provides such
|
||||
// functions.
|
||||
|
||||
assert((VT == MVT::f32 || VT == MVT::f64 || VT == MVT::f128 || VT == MVT::ppcf128)
|
||||
&& "Unsupported setcc type!");
|
||||
|
||||
@ -390,7 +406,8 @@ void TargetLowering::softenSetCCOperands(SelectionDAG &DAG, EVT VT,
|
||||
EVT OpsVT[2] = { OldLHS.getValueType(),
|
||||
OldRHS.getValueType() };
|
||||
CallOptions.setTypeListBeforeSoften(OpsVT, RetVT, true);
|
||||
NewLHS = makeLibCall(DAG, LC1, RetVT, Ops, CallOptions, dl).first;
|
||||
auto Call = makeLibCall(DAG, LC1, RetVT, Ops, CallOptions, dl, Chain);
|
||||
NewLHS = Call.first;
|
||||
NewRHS = DAG.getConstant(0, dl, RetVT);
|
||||
|
||||
CCCode = getCmpLibcallCC(LC1);
|
||||
@ -399,16 +416,22 @@ void TargetLowering::softenSetCCOperands(SelectionDAG &DAG, EVT VT,
|
||||
CCCode = getSetCCInverse(CCCode, RetVT);
|
||||
}
|
||||
|
||||
if (LC2 != RTLIB::UNKNOWN_LIBCALL) {
|
||||
if (LC2 == RTLIB::UNKNOWN_LIBCALL) {
|
||||
// Update Chain.
|
||||
Chain = Call.second;
|
||||
} else {
|
||||
SDValue Tmp = DAG.getNode(
|
||||
ISD::SETCC, dl,
|
||||
getSetCCResultType(DAG.getDataLayout(), *DAG.getContext(), RetVT),
|
||||
NewLHS, NewRHS, DAG.getCondCode(CCCode));
|
||||
NewLHS = makeLibCall(DAG, LC2, RetVT, Ops, CallOptions, dl).first;
|
||||
auto Call2 = makeLibCall(DAG, LC2, RetVT, Ops, CallOptions, dl, Chain);
|
||||
NewLHS = DAG.getNode(
|
||||
ISD::SETCC, dl,
|
||||
getSetCCResultType(DAG.getDataLayout(), *DAG.getContext(), RetVT),
|
||||
NewLHS, NewRHS, DAG.getCondCode(getCmpLibcallCC(LC2)));
|
||||
Call2.first, NewRHS, DAG.getCondCode(getCmpLibcallCC(LC2)));
|
||||
if (Chain)
|
||||
Chain = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, Call.second,
|
||||
Call2.second);
|
||||
NewLHS = DAG.getNode(ISD::OR, dl, Tmp.getValueType(), Tmp, NewLHS);
|
||||
NewRHS = SDValue();
|
||||
}
|
||||
|
@ -20755,7 +20755,7 @@ static std::pair<SDValue, SDValue> EmitCmp(SDValue Op0, SDValue Op1,
|
||||
const X86Subtarget &Subtarget,
|
||||
SDValue Chain, bool IsSignaling) {
|
||||
if (isNullConstant(Op1))
|
||||
return std::make_pair(EmitTest(Op0, X86CC, dl, DAG, Subtarget), SDValue());
|
||||
return std::make_pair(EmitTest(Op0, X86CC, dl, DAG, Subtarget), Chain);
|
||||
|
||||
EVT CmpVT = Op0.getValueType();
|
||||
|
||||
@ -21842,15 +21842,15 @@ SDValue X86TargetLowering::LowerSETCC(SDValue Op, SelectionDAG &DAG) const {
|
||||
// Handle f128 first, since one possible outcome is a normal integer
|
||||
// comparison which gets handled by emitFlagsForSetcc.
|
||||
if (Op0.getValueType() == MVT::f128) {
|
||||
// FIXME: We may need a strict version of softenSetCCOperands before
|
||||
// supporting f128.
|
||||
assert(!IsStrict && "Unhandled strict operation!");
|
||||
softenSetCCOperands(DAG, MVT::f128, Op0, Op1, CC, dl, Op0, Op1);
|
||||
softenSetCCOperands(DAG, MVT::f128, Op0, Op1, CC, dl, Op0, Op1, Chain,
|
||||
Op.getOpcode() == ISD::STRICT_FSETCCS);
|
||||
|
||||
// If softenSetCCOperands returned a scalar, use it.
|
||||
if (!Op1.getNode()) {
|
||||
assert(Op0.getValueType() == Op.getValueType() &&
|
||||
"Unexpected setcc expansion!");
|
||||
if (IsStrict)
|
||||
return DAG.getMergeValues({Op0, Chain}, dl);
|
||||
return Op0;
|
||||
}
|
||||
}
|
||||
|
@ -1128,7 +1128,99 @@ entry:
|
||||
ret i64 %round
|
||||
}
|
||||
|
||||
attributes #0 = { strictfp }
|
||||
define i64 @cmp(i64 %a, i64 %b, fp128 %x, fp128 %y) #0 {
|
||||
; CHECK-LABEL: cmp:
|
||||
; CHECK: # %bb.0:
|
||||
; CHECK-NEXT: pushq %r14
|
||||
; CHECK-NEXT: pushq %rbx
|
||||
; CHECK-NEXT: pushq %rax
|
||||
; CHECK-NEXT: movq %rsi, %r14
|
||||
; CHECK-NEXT: movq %rdi, %rbx
|
||||
; CHECK-NEXT: callq __eqtf2
|
||||
; CHECK-NEXT: testl %eax, %eax
|
||||
; CHECK-NEXT: cmovneq %r14, %rbx
|
||||
; CHECK-NEXT: movq %rbx, %rax
|
||||
; CHECK-NEXT: addq $8, %rsp
|
||||
; CHECK-NEXT: popq %rbx
|
||||
; CHECK-NEXT: popq %r14
|
||||
; CHECK-NEXT: retq
|
||||
;
|
||||
; X86-LABEL: cmp:
|
||||
; X86: # %bb.0:
|
||||
; X86-NEXT: subl $12, %esp
|
||||
; X86-NEXT: pushl {{[0-9]+}}(%esp)
|
||||
; X86-NEXT: pushl {{[0-9]+}}(%esp)
|
||||
; X86-NEXT: pushl {{[0-9]+}}(%esp)
|
||||
; X86-NEXT: pushl {{[0-9]+}}(%esp)
|
||||
; X86-NEXT: pushl {{[0-9]+}}(%esp)
|
||||
; X86-NEXT: pushl {{[0-9]+}}(%esp)
|
||||
; X86-NEXT: pushl {{[0-9]+}}(%esp)
|
||||
; X86-NEXT: pushl {{[0-9]+}}(%esp)
|
||||
; X86-NEXT: calll __eqtf2
|
||||
; X86-NEXT: addl $32, %esp
|
||||
; X86-NEXT: testl %eax, %eax
|
||||
; X86-NEXT: leal {{[0-9]+}}(%esp), %eax
|
||||
; X86-NEXT: leal {{[0-9]+}}(%esp), %ecx
|
||||
; X86-NEXT: cmovel %eax, %ecx
|
||||
; X86-NEXT: movl (%ecx), %eax
|
||||
; X86-NEXT: movl 4(%ecx), %edx
|
||||
; X86-NEXT: addl $12, %esp
|
||||
; X86-NEXT: retl
|
||||
%cond = call i1 @llvm.experimental.constrained.fcmp.f128(
|
||||
fp128 %x, fp128 %y,
|
||||
metadata !"oeq",
|
||||
metadata !"fpexcept.strict") #0
|
||||
%res = select i1 %cond, i64 %a, i64 %b
|
||||
ret i64 %res
|
||||
}
|
||||
|
||||
define i64 @cmps(i64 %a, i64 %b, fp128 %x, fp128 %y) #0 {
|
||||
; CHECK-LABEL: cmps:
|
||||
; CHECK: # %bb.0:
|
||||
; CHECK-NEXT: pushq %r14
|
||||
; CHECK-NEXT: pushq %rbx
|
||||
; CHECK-NEXT: pushq %rax
|
||||
; CHECK-NEXT: movq %rsi, %r14
|
||||
; CHECK-NEXT: movq %rdi, %rbx
|
||||
; CHECK-NEXT: callq __eqtf2
|
||||
; CHECK-NEXT: testl %eax, %eax
|
||||
; CHECK-NEXT: cmovneq %r14, %rbx
|
||||
; CHECK-NEXT: movq %rbx, %rax
|
||||
; CHECK-NEXT: addq $8, %rsp
|
||||
; CHECK-NEXT: popq %rbx
|
||||
; CHECK-NEXT: popq %r14
|
||||
; CHECK-NEXT: retq
|
||||
;
|
||||
; X86-LABEL: cmps:
|
||||
; X86: # %bb.0:
|
||||
; X86-NEXT: subl $12, %esp
|
||||
; X86-NEXT: pushl {{[0-9]+}}(%esp)
|
||||
; X86-NEXT: pushl {{[0-9]+}}(%esp)
|
||||
; X86-NEXT: pushl {{[0-9]+}}(%esp)
|
||||
; X86-NEXT: pushl {{[0-9]+}}(%esp)
|
||||
; X86-NEXT: pushl {{[0-9]+}}(%esp)
|
||||
; X86-NEXT: pushl {{[0-9]+}}(%esp)
|
||||
; X86-NEXT: pushl {{[0-9]+}}(%esp)
|
||||
; X86-NEXT: pushl {{[0-9]+}}(%esp)
|
||||
; X86-NEXT: calll __eqtf2
|
||||
; X86-NEXT: addl $32, %esp
|
||||
; X86-NEXT: testl %eax, %eax
|
||||
; X86-NEXT: leal {{[0-9]+}}(%esp), %eax
|
||||
; X86-NEXT: leal {{[0-9]+}}(%esp), %ecx
|
||||
; X86-NEXT: cmovel %eax, %ecx
|
||||
; X86-NEXT: movl (%ecx), %eax
|
||||
; X86-NEXT: movl 4(%ecx), %edx
|
||||
; X86-NEXT: addl $12, %esp
|
||||
; X86-NEXT: retl
|
||||
%cond = call i1 @llvm.experimental.constrained.fcmps.f128(
|
||||
fp128 %x, fp128 %y,
|
||||
metadata !"oeq",
|
||||
metadata !"fpexcept.strict") #0
|
||||
%res = select i1 %cond, i64 %a, i64 %b
|
||||
ret i64 %res
|
||||
}
|
||||
|
||||
attributes #0 = { nounwind strictfp }
|
||||
|
||||
declare fp128 @llvm.experimental.constrained.fadd.f128(fp128, fp128, metadata, metadata)
|
||||
declare fp128 @llvm.experimental.constrained.fsub.f128(fp128, fp128, metadata, metadata)
|
||||
@ -1158,3 +1250,5 @@ declare i32 @llvm.experimental.constrained.lrint.i32.f128(fp128, metadata, metad
|
||||
declare i64 @llvm.experimental.constrained.llrint.i64.f128(fp128, metadata, metadata)
|
||||
declare i32 @llvm.experimental.constrained.lround.i32.f128(fp128, metadata)
|
||||
declare i64 @llvm.experimental.constrained.llround.i64.f128(fp128, metadata)
|
||||
declare i1 @llvm.experimental.constrained.fcmp.f128(fp128, fp128, metadata, metadata)
|
||||
declare i1 @llvm.experimental.constrained.fcmps.f128(fp128, fp128, metadata, metadata)
|
||||
|
Loading…
Reference in New Issue
Block a user