return LowerCallTo(CLI);
}
-
/// SoftenSetCCOperands - Soften the operands of a comparison. This code is
/// shared among BR_CC, SELECT_CC, and SETCC handlers.
void TargetLowering::softenSetCCOperands(SelectionDAG &DAG, EVT VT,
// Expand into one or more soft-fp libcall(s).
RTLIB::Libcall LC1 = RTLIB::UNKNOWN_LIBCALL, LC2 = RTLIB::UNKNOWN_LIBCALL;
+ bool ShouldInvertCC = false;
switch (CCCode) {
case ISD::SETEQ:
case ISD::SETOEQ:
LC1 = (VT == MVT::f32) ? RTLIB::O_F32 :
(VT == MVT::f64) ? RTLIB::O_F64 : RTLIB::O_F128;
break;
- default:
+ case ISD::SETONE:
+ // SETONE = SETOLT | SETOGT
+ LC1 = (VT == MVT::f32) ? RTLIB::OLT_F32 :
+ (VT == MVT::f64) ? RTLIB::OLT_F64 : RTLIB::OLT_F128;
+ LC2 = (VT == MVT::f32) ? RTLIB::OGT_F32 :
+ (VT == MVT::f64) ? RTLIB::OGT_F64 : RTLIB::OGT_F128;
+ break;
+ case ISD::SETUEQ:
LC1 = (VT == MVT::f32) ? RTLIB::UO_F32 :
(VT == MVT::f64) ? RTLIB::UO_F64 : RTLIB::UO_F128;
+ LC2 = (VT == MVT::f32) ? RTLIB::OEQ_F32 :
+ (VT == MVT::f64) ? RTLIB::OEQ_F64 : RTLIB::OEQ_F128;
+ break;
+ default:
+ // Invert CC for unordered comparisons
+ ShouldInvertCC = true;
switch (CCCode) {
- case ISD::SETONE:
- // SETONE = SETOLT | SETOGT
- LC1 = (VT == MVT::f32) ? RTLIB::OLT_F32 :
- (VT == MVT::f64) ? RTLIB::OLT_F64 : RTLIB::OLT_F128;
- // Fallthrough
- case ISD::SETUGT:
- LC2 = (VT == MVT::f32) ? RTLIB::OGT_F32 :
- (VT == MVT::f64) ? RTLIB::OGT_F64 : RTLIB::OGT_F128;
- break;
- case ISD::SETUGE:
- LC2 = (VT == MVT::f32) ? RTLIB::OGE_F32 :
- (VT == MVT::f64) ? RTLIB::OGE_F64 : RTLIB::OGE_F128;
- break;
case ISD::SETULT:
- LC2 = (VT == MVT::f32) ? RTLIB::OLT_F32 :
- (VT == MVT::f64) ? RTLIB::OLT_F64 : RTLIB::OLT_F128;
+ LC1 = (VT == MVT::f32) ? RTLIB::OGE_F32 :
+ (VT == MVT::f64) ? RTLIB::OGE_F64 : RTLIB::OGE_F128;
break;
case ISD::SETULE:
- LC2 = (VT == MVT::f32) ? RTLIB::OLE_F32 :
+ LC1 = (VT == MVT::f32) ? RTLIB::OGT_F32 :
+ (VT == MVT::f64) ? RTLIB::OGT_F64 : RTLIB::OGT_F128;
+ break;
+ case ISD::SETUGT:
+ LC1 = (VT == MVT::f32) ? RTLIB::OLE_F32 :
(VT == MVT::f64) ? RTLIB::OLE_F64 : RTLIB::OLE_F128;
break;
- case ISD::SETUEQ:
- LC2 = (VT == MVT::f32) ? RTLIB::OEQ_F32 :
- (VT == MVT::f64) ? RTLIB::OEQ_F64 : RTLIB::OEQ_F128;
+ case ISD::SETUGE:
+ LC1 = (VT == MVT::f32) ? RTLIB::OLT_F32 :
+ (VT == MVT::f64) ? RTLIB::OLT_F64 : RTLIB::OLT_F128;
break;
default: llvm_unreachable("Do not know how to soften this setcc!");
}
EVT RetVT = getCmpLibcallReturnType();
SDValue Ops[2] = { NewLHS, NewRHS };
NewLHS = makeLibCall(DAG, LC1, RetVT, Ops, 2, false/*sign irrelevant*/,
- dl).first;
+ dl).first;
NewRHS = DAG.getConstant(0, dl, RetVT);
+
CCCode = getCmpLibcallCC(LC1);
+ if (ShouldInvertCC)
+ CCCode = getSetCCInverse(CCCode, /*isInteger=*/true);
+
if (LC2 != RTLIB::UNKNOWN_LIBCALL) {
SDValue Tmp = DAG.getNode(
ISD::SETCC, dl,
getSetCCResultType(DAG.getDataLayout(), *DAG.getContext(), RetVT),
NewLHS, NewRHS, DAG.getCondCode(CCCode));
NewLHS = makeLibCall(DAG, LC2, RetVT, Ops, 2, false/*sign irrelevant*/,
- dl).first;
+ dl).first;
NewLHS = DAG.getNode(
ISD::SETCC, dl,
getSetCCResultType(DAG.getDataLayout(), *DAG.getContext(), RetVT),
; CHECK: ldr q1, [{{x[0-9]+}}, :lo12:rhs]
%val = fcmp ugt fp128 %lhs, %rhs
-; CHECK: bl __gttf2
+; CHECK: bl __letf2
; CHECK: cmp w0, #0
-; CHECK: cset [[GT:w[0-9]+]], gt
-
-; CHECK: bl __unordtf2
-; CHECK: cmp w0, #0
-; CHECK: cset [[UNORDERED:w[0-9]+]], ne
-; CHECK: orr w0, [[UNORDERED]], [[GT]]
+; CHECK: cset w0, gt
ret i1 %val
; CHECK: ret
; CHECK: ldr q0, [{{x[0-9]+}}, :lo12:lhs]
; CHECK: ldr q1, [{{x[0-9]+}}, :lo12:rhs]
- ; olt == !uge, which LLVM unfortunately "optimizes" this to.
+ ; olt == !uge, which LLVM optimizes this to.
%cond = fcmp olt fp128 %lhs, %rhs
-; CHECK: bl __getf2
-; CHECK: cmp w0, #0
-; CHECK: cset [[OGE:w[0-9]+]], ge
-
-; CHECK: bl __unordtf2
-; CHECK: cmp w0, #0
-; CHECK: cset [[UNORDERED:w[0-9]+]], ne
-
-; CHECK: orr [[UGE:w[0-9]+]], [[UNORDERED]], [[OGE]]
-; CHECK: cbnz [[UGE]], [[RET29:.LBB[0-9]+_[0-9]+]]
+; CHECK: bl __lttf2
+; CHECK-NEXT: cmp w0, #0
+; CHECK-NEXT: b.ge {{.LBB[0-9]+_[0-9]+}}
br i1 %cond, label %iftrue, label %iffalse
iftrue:
ret i32 42
; CHECK-NEXT: BB#
; CHECK-NEXT: movz w0, #0x2a
-; CHECK-NEXT: b [[REALRET:.LBB[0-9]+_[0-9]+]]
-
+; CHECK: ret
iffalse:
ret i32 29
-; CHECK: [[RET29]]:
-; CHECK-NEXT: movz w0, #0x1d
-; CHECK-NEXT: [[REALRET]]:
+; CHECK: movz w0, #0x1d
; CHECK: ret
}
%and2 = and i1 %lnot, %cmp1
%and = zext i1 %and2 to i32
store i32 %and, i32* @ltsf2_result, align 4
-;16hf: lw ${{[0-9]+}}, %call16(__mips16_unordsf2)(${{[0-9]+}})
+;16hf: lw ${{[0-9]+}}, %call16(__mips16_ltsf2)(${{[0-9]+}})
;16hf: lw ${{[0-9]+}}, %call16(__mips16_ltsf2)(${{[0-9]+}})
ret void
}
%and2 = and i1 %lnot, %cmp1
%and = zext i1 %and2 to i32
store i32 %and, i32* @ltdf2_result, align 4
-;16hf: lw ${{[0-9]+}}, %call16(__mips16_unorddf2)(${{[0-9]+}})
+;16hf: lw ${{[0-9]+}}, %call16(__mips16_ltdf2)(${{[0-9]+}})
;16hf: lw ${{[0-9]+}}, %call16(__mips16_ltdf2)(${{[0-9]+}})
ret void
}
}
define i1 @cmp_f_ugt(float %a, float %b) {
; CHECK-LABEL: cmp_f_ugt:
-; NONE: bl __aeabi_fcmpgt
-; NONE: bl __aeabi_fcmpun
+; NONE: bl __aeabi_fcmple
+; NONE: cmp r0, #0
+; NONE-NEXT: it eq
; HARD: vcmpe.f32
; HARD: movhi r0, #1
%1 = fcmp ugt float %a, %b
}
define i1 @cmp_f_uge(float %a, float %b) {
; CHECK-LABEL: cmp_f_uge:
-; NONE: bl __aeabi_fcmpge
-; NONE: bl __aeabi_fcmpun
+; NONE: bl __aeabi_fcmplt
+; NONE: cmp r0, #0
+; NONE-NEXT: it eq
; HARD: vcmpe.f32
; HARD: movpl r0, #1
%1 = fcmp uge float %a, %b
}
define i1 @cmp_f_ult(float %a, float %b) {
; CHECK-LABEL: cmp_f_ult:
-; NONE: bl __aeabi_fcmplt
-; NONE: bl __aeabi_fcmpun
+; NONE: bl __aeabi_fcmpge
+; NONE: cmp r0, #0
+; NONE-NEXT: it eq
; HARD: vcmpe.f32
; HARD: movlt r0, #1
%1 = fcmp ult float %a, %b
}
define i1 @cmp_f_ule(float %a, float %b) {
; CHECK-LABEL: cmp_f_ule:
-; NONE: bl __aeabi_fcmple
-; NONE: bl __aeabi_fcmpun
+; NONE: bl __aeabi_fcmpgt
+; NONE: cmp r0, #0
+; NONE-NEXT: it eq
; HARD: vcmpe.f32
; HARD: movle r0, #1
%1 = fcmp ule float %a, %b
}
define i1 @cmp_d_ugt(double %a, double %b) {
; CHECK-LABEL: cmp_d_ugt:
-; NONE: bl __aeabi_dcmpgt
-; NONE: bl __aeabi_dcmpun
-; SP: bl __aeabi_dcmpgt
-; SP: bl __aeabi_dcmpun
+; NONE: bl __aeabi_dcmple
+; SP: bl __aeabi_dcmple
; DP: vcmpe.f64
; DP: movhi r0, #1
%1 = fcmp ugt double %a, %b
define i1 @cmp_d_ult(double %a, double %b) {
; CHECK-LABEL: cmp_d_ult:
-; NONE: bl __aeabi_dcmplt
-; NONE: bl __aeabi_dcmpun
-; SP: bl __aeabi_dcmplt
-; SP: bl __aeabi_dcmpun
+; NONE: bl __aeabi_dcmpge
+; SP: bl __aeabi_dcmpge
; DP: vcmpe.f64
; DP: movlt r0, #1
%1 = fcmp ult double %a, %b
define i1 @cmp_d_uge(double %a, double %b) {
; CHECK-LABEL: cmp_d_uge:
-; NONE: bl __aeabi_dcmpge
-; NONE: bl __aeabi_dcmpun
-; SP: bl __aeabi_dcmpge
-; SP: bl __aeabi_dcmpun
+; NONE: bl __aeabi_dcmplt
+; SP: bl __aeabi_dcmplt
; DP: vcmpe.f64
; DP: movpl r0, #1
%1 = fcmp uge double %a, %b
define i1 @cmp_d_ule(double %a, double %b) {
; CHECK-LABEL: cmp_d_ule:
-; NONE: bl __aeabi_dcmple
-; NONE: bl __aeabi_dcmpun
-; SP: bl __aeabi_dcmple
-; SP: bl __aeabi_dcmpun
+; NONE: bl __aeabi_dcmpgt
+; SP: bl __aeabi_dcmpgt
; DP: vcmpe.f64
; DP: movle r0, #1
%1 = fcmp ule double %a, %b
define double @abs_d(double %a) {
; CHECK-LABEL: abs_d:
; NONE: bic r1, r1, #-2147483648
-; SP: bl __aeabi_dcmpgt
-; SP: bl __aeabi_dcmpun
; SP: bl __aeabi_dsub
+; SP: bl __aeabi_dcmple
; DP: vabs.f64 d0, d0
%1 = call double @llvm.fabs.f64(double %a)
ret double %1
--- /dev/null
+; RUN: llc < %s -march=x86 -mcpu=pentium -mtriple=x86-linux-gnu -float-abi=soft | FileCheck %s \r
+\r
+define i1 @test1(double %d) #0 {\r
+entry:\r
+ %cmp = fcmp ule double %d, 0.000000e+00\r
+ ret i1 %cmp\r
+}\r
+; CHECK-LABEL: test1:\r
+; CHECK: calll __gtdf2\r
+; CHECK: setle\r
+; CHECK: retl\r
+ \r
+define i1 @test2(double %d) #0 {\r
+entry:\r
+ %cmp = fcmp ult double %d, 0.000000e+00\r
+ ret i1 %cmp\r
+}\r
+; CHECK-LABEL: test2:\r
+; CHECK: calll __gedf2\r
+; CHECK: sets\r
+; CHECK: retl\r
+\r
+define i1 @test3(double %d) #0 {\r
+entry:\r
+ %cmp = fcmp ugt double %d, 0.000000e+00\r
+ ret i1 %cmp\r
+}\r
+; CHECK-LABEL: test3:\r
+; CHECK: calll __ledf2\r
+; CHECK: setg\r
+; CHECK: retl\r
+\r
+define i1 @test4(double %d) #0 {\r
+entry:\r
+ %cmp = fcmp uge double %d, 0.000000e+00\r
+ ret i1 %cmp\r
+}\r
+; CHECK-LABEL: test4:\r
+; CHECK: calll __ltdf2\r
+; CHECK: setns\r
+; CHECK: retl\r
+\r
+define i1 @test5(double %d) #0 {\r
+entry:\r
+ %cmp = fcmp ole double %d, 0.000000e+00\r
+ ret i1 %cmp\r
+}\r
+; CHECK-LABEL: test5: \r
+; CHECK: calll __ledf2\r
+; CHECK: setle\r
+; CHECK: retl\r
+\r
+define i1 @test6(double %d) #0 {\r
+entry:\r
+ %cmp = fcmp olt double %d, 0.000000e+00\r
+ ret i1 %cmp\r
+}\r
+; CHECK-LABEL: test6:\r
+; CHECK: calll __ltdf2\r
+; CHECK: sets\r
+; CHECK: retl\r
+\r
+define i1 @test7(double %d) #0 {\r
+entry:\r
+ %cmp = fcmp ogt double %d, 0.000000e+00\r
+ ret i1 %cmp\r
+}\r
+; CHECK-LABEL: test7:\r
+; CHECK: calll __gtdf2\r
+; CHECK: setg\r
+; CHECK: retl\r
+\r
+define i1 @test8(double %d) #0 {\r
+entry:\r
+ %cmp = fcmp oge double %d, 0.000000e+00\r
+ ret i1 %cmp\r
+}\r
+; CHECK-LABEL: test8:\r
+; CHECK: calll __gedf2\r
+; CHECK: setns\r
+; CHECK: retl\r
+\r
+define i1 @test9(double %d) #0 {\r
+entry:\r
+ %cmp = fcmp oeq double %d, 0.000000e+00\r
+ ret i1 %cmp\r
+}\r
+; CHECK-LABEL: test9:\r
+; CHECK: calll __eqdf2\r
+; CHECK: sete\r
+; CHECK: retl\r
+\r
+define i1 @test10(double %d) #0 {\r
+entry:\r
+ %cmp = fcmp ueq double %d, 0.000000e+00\r
+ ret i1 %cmp\r
+}\r
+; CHECK-LABEL: test10:\r
+; CHECK: calll __eqdf2\r
+; CHECK: sete\r
+; CHECK: calll __unorddf2\r
+; CHECK: setne\r
+; CHECK: retl\r
+\r
+define i1 @test11(double %d) #0 {\r
+entry:\r
+ %cmp = fcmp one double %d, 0.000000e+00\r
+ ret i1 %cmp\r
+}\r
+; CHECK-LABEL: test11:\r
+; CHECK: calll __gtdf2\r
+; CHECK: setg\r
+; CHECK: calll __ltdf2\r
+; CHECK: sets\r
+; CHECK: retl\r
+\r
+define i1 @test12(double %d) #0 {\r
+entry:\r
+ %cmp = fcmp une double %d, 0.000000e+00\r
+ ret i1 %cmp\r
+}\r
+; CHECK-LABEL: test12:\r
+; CHECK: calll __nedf2\r
+; CHECK: setne\r
+; CHECK: retl\r
+\r
+attributes #0 = { "use-soft-float"="true" }\r