}
static SDValue visitFMinMax(SelectionDAG &DAG, SDNode *N,
- APFloat (*Op)(const APFloat &, const APFloat &)) {
+ APFloat (*Op)(const APFloat &, const APFloat &),
+ bool PropagatesNaN) {
SDValue N0 = N->getOperand(0);
SDValue N1 = N->getOperand(1);
EVT VT = N->getValueType(0);
!isConstantFPBuildVectorOrConstantFP(N1))
return DAG.getNode(N->getOpcode(), SDLoc(N), VT, N1, N0);
+ // minnum(X, nan) -> X
+ // maxnum(X, nan) -> X
+ // minimum(X, nan) -> nan
+ // maximum(X, nan) -> nan
+ if (N1CFP && N1CFP->isNaN())
+ return PropagatesNaN ? N->getOperand(1) : N->getOperand(0);
+
return SDValue();
}
SDValue DAGCombiner::visitFMINNUM(SDNode *N) {
- return visitFMinMax(DAG, N, minnum);
+ return visitFMinMax(DAG, N, minnum, /* PropagatesNaN */ false);
}
SDValue DAGCombiner::visitFMAXNUM(SDNode *N) {
- return visitFMinMax(DAG, N, maxnum);
+ return visitFMinMax(DAG, N, maxnum, /* PropagatesNaN */ false);
}
SDValue DAGCombiner::visitFMINIMUM(SDNode *N) {
- return visitFMinMax(DAG, N, minimum);
+ return visitFMinMax(DAG, N, minimum, /* PropagatesNaN */ true);
}
SDValue DAGCombiner::visitFMAXIMUM(SDNode *N) {
- return visitFMinMax(DAG, N, maximum);
+ return visitFMinMax(DAG, N, maximum, /* PropagatesNaN */ true);
}
SDValue DAGCombiner::visitFABS(SDNode *N) {
define float @test_minnum_const_nan(float %x) {
; CHECK-LABEL: test_minnum_const_nan:
; CHECK: @ %bb.0:
-; CHECK-NEXT: vldr s0, .LCPI0_0
-; CHECK-NEXT: vmov s2, r0
-; CHECK-NEXT: vminnm.f32 s0, s2, s0
-; CHECK-NEXT: vmov r0, s0
; CHECK-NEXT: bx lr
-; CHECK-NEXT: .p2align 2
-; CHECK-NEXT: @ %bb.1:
-; CHECK-NEXT: .LCPI0_0:
-; CHECK-NEXT: .long 0x7ff80000 @ float NaN
%r = call float @llvm.minnum.f32(float %x, float 0x7fff000000000000)
ret float %r
}
define float @test_maxnum_const_nan(float %x) {
; CHECK-LABEL: test_maxnum_const_nan:
; CHECK: @ %bb.0:
-; CHECK-NEXT: vldr s0, .LCPI1_0
-; CHECK-NEXT: vmov s2, r0
-; CHECK-NEXT: vmaxnm.f32 s0, s2, s0
-; CHECK-NEXT: vmov r0, s0
; CHECK-NEXT: bx lr
-; CHECK-NEXT: .p2align 2
-; CHECK-NEXT: @ %bb.1:
-; CHECK-NEXT: .LCPI1_0:
-; CHECK-NEXT: .long 0x7ff80000 @ float NaN
%r = call float @llvm.maxnum.f32(float %x, float 0x7fff000000000000)
ret float %r
}
define float @test_maximum_const_nan(float %x) {
; CHECK-LABEL: test_maximum_const_nan:
; CHECK: @ %bb.0:
-; CHECK-NEXT: vldr s0, .LCPI2_0
-; CHECK-NEXT: vmov s2, r0
-; CHECK-NEXT: vmax.f32 d0, d1, d0
-; CHECK-NEXT: vmov r0, s0
+; CHECK-NEXT: movw r0, #0
+; CHECK-NEXT: movt r0, #32760
; CHECK-NEXT: bx lr
-; CHECK-NEXT: .p2align 2
-; CHECK-NEXT: @ %bb.1:
-; CHECK-NEXT: .LCPI2_0:
-; CHECK-NEXT: .long 0x7ff80000 @ float NaN
%r = call float @llvm.maximum.f32(float %x, float 0x7fff000000000000)
ret float %r
}
define float @test_minimum_const_nan(float %x) {
; CHECK-LABEL: test_minimum_const_nan:
; CHECK: @ %bb.0:
-; CHECK-NEXT: vldr s0, .LCPI3_0
-; CHECK-NEXT: vmov s2, r0
-; CHECK-NEXT: vmin.f32 d0, d1, d0
-; CHECK-NEXT: vmov r0, s0
+; CHECK-NEXT: movw r0, #0
+; CHECK-NEXT: movt r0, #32760
; CHECK-NEXT: bx lr
-; CHECK-NEXT: .p2align 2
-; CHECK-NEXT: @ %bb.1:
-; CHECK-NEXT: .LCPI3_0:
-; CHECK-NEXT: .long 0x7ff80000 @ float NaN
%r = call float @llvm.minimum.f32(float %x, float 0x7fff000000000000)
ret float %r
}
}
define float @test_maxnum_const_nan(float %x) {
-; SSE-LABEL: test_maxnum_const_nan:
-; SSE: # %bb.0:
-; SSE-NEXT: movss {{.*#+}} xmm2 = mem[0],zero,zero,zero
-; SSE-NEXT: movaps %xmm0, %xmm1
-; SSE-NEXT: cmpunordss %xmm0, %xmm1
-; SSE-NEXT: movaps %xmm1, %xmm3
-; SSE-NEXT: andps %xmm2, %xmm3
-; SSE-NEXT: maxss %xmm0, %xmm2
-; SSE-NEXT: andnps %xmm2, %xmm1
-; SSE-NEXT: orps %xmm3, %xmm1
-; SSE-NEXT: movaps %xmm1, %xmm0
-; SSE-NEXT: retq
-;
-; AVX1-LABEL: test_maxnum_const_nan:
-; AVX1: # %bb.0:
-; AVX1-NEXT: vmovss {{.*#+}} xmm1 = mem[0],zero,zero,zero
-; AVX1-NEXT: vmaxss %xmm0, %xmm1, %xmm2
-; AVX1-NEXT: vcmpunordss %xmm0, %xmm0, %xmm0
-; AVX1-NEXT: vblendvps %xmm0, %xmm1, %xmm2, %xmm0
-; AVX1-NEXT: retq
-;
-; AVX512-LABEL: test_maxnum_const_nan:
-; AVX512: # %bb.0:
-; AVX512-NEXT: vmovss {{.*#+}} xmm2 = mem[0],zero,zero,zero
-; AVX512-NEXT: vmaxss %xmm0, %xmm2, %xmm1
-; AVX512-NEXT: vcmpunordss %xmm0, %xmm0, %k1
-; AVX512-NEXT: vmovss %xmm2, %xmm1, %xmm1 {%k1}
-; AVX512-NEXT: vmovaps %xmm1, %xmm0
-; AVX512-NEXT: retq
+; CHECK-LABEL: test_maxnum_const_nan:
+; CHECK: # %bb.0:
+; CHECK-NEXT: retq
%r = call float @llvm.maxnum.f32(float %x, float 0x7fff000000000000)
ret float %r
}
}
define float @test_minnum_const_nan(float %x) {
-; SSE-LABEL: test_minnum_const_nan:
-; SSE: # %bb.0:
-; SSE-NEXT: movss {{.*#+}} xmm2 = mem[0],zero,zero,zero
-; SSE-NEXT: movaps %xmm0, %xmm1
-; SSE-NEXT: cmpunordss %xmm0, %xmm1
-; SSE-NEXT: movaps %xmm1, %xmm3
-; SSE-NEXT: andps %xmm2, %xmm3
-; SSE-NEXT: minss %xmm0, %xmm2
-; SSE-NEXT: andnps %xmm2, %xmm1
-; SSE-NEXT: orps %xmm3, %xmm1
-; SSE-NEXT: movaps %xmm1, %xmm0
-; SSE-NEXT: retq
-;
-; AVX1-LABEL: test_minnum_const_nan:
-; AVX1: # %bb.0:
-; AVX1-NEXT: vmovss {{.*#+}} xmm1 = mem[0],zero,zero,zero
-; AVX1-NEXT: vminss %xmm0, %xmm1, %xmm2
-; AVX1-NEXT: vcmpunordss %xmm0, %xmm0, %xmm0
-; AVX1-NEXT: vblendvps %xmm0, %xmm1, %xmm2, %xmm0
-; AVX1-NEXT: retq
-;
-; AVX512-LABEL: test_minnum_const_nan:
-; AVX512: # %bb.0:
-; AVX512-NEXT: vmovss {{.*#+}} xmm2 = mem[0],zero,zero,zero
-; AVX512-NEXT: vminss %xmm0, %xmm2, %xmm1
-; AVX512-NEXT: vcmpunordss %xmm0, %xmm0, %k1
-; AVX512-NEXT: vmovss %xmm2, %xmm1, %xmm1 {%k1}
-; AVX512-NEXT: vmovaps %xmm1, %xmm0
-; AVX512-NEXT: retq
+; CHECK-LABEL: test_minnum_const_nan:
+; CHECK: # %bb.0:
+; CHECK-NEXT: retq
%r = call float @llvm.minnum.f32(float %x, float 0x7fff000000000000)
ret float %r
}