From e87cadc49a9f6e327d09add0b2ab81d9c062cdc8 Mon Sep 17 00:00:00 2001 From: Tim Northover Date: Sat, 10 May 2014 07:37:50 +0000 Subject: [PATCH] ARM64: fix SELECT_CC lowering in absence of NaNs. We were swapping the true & false results while testing for FMAX/FMIN, but not putting them back to the original state if the later checks failed. Should fix PR19700. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@208469 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Target/ARM64/ARM64ISelLowering.cpp | 17 +++++++++-------- test/CodeGen/ARM64/fmax.ll | 17 +++++++++++++++-- 2 files changed, 24 insertions(+), 10 deletions(-) diff --git a/lib/Target/ARM64/ARM64ISelLowering.cpp b/lib/Target/ARM64/ARM64ISelLowering.cpp index bff6ba060fb..b422ddcb43d 100644 --- a/lib/Target/ARM64/ARM64ISelLowering.cpp +++ b/lib/Target/ARM64/ARM64ISelLowering.cpp @@ -3121,17 +3121,18 @@ SDValue ARM64TargetLowering::LowerSELECT_CC(SDValue Op, // Try to match this select into a max/min operation, which have dedicated // opcode in the instruction set. - // NOTE: This is not correct in the presence of NaNs, so we only enable this + // FIXME: This is not correct in the presence of NaNs, so we only enable this // in no-NaNs mode. if (getTargetMachine().Options.NoNaNsFPMath) { - if (selectCCOpsAreFMaxCompatible(LHS, FVal) && - selectCCOpsAreFMaxCompatible(RHS, TVal)) { + SDValue MinMaxLHS = TVal, MinMaxRHS = FVal; + if (selectCCOpsAreFMaxCompatible(LHS, MinMaxRHS) && + selectCCOpsAreFMaxCompatible(RHS, MinMaxLHS)) { CC = ISD::getSetCCSwappedOperands(CC); - std::swap(TVal, FVal); + std::swap(MinMaxLHS, MinMaxRHS); } - if (selectCCOpsAreFMaxCompatible(LHS, TVal) && - selectCCOpsAreFMaxCompatible(RHS, FVal)) { + if (selectCCOpsAreFMaxCompatible(LHS, MinMaxLHS) && + selectCCOpsAreFMaxCompatible(RHS, MinMaxRHS)) { switch (CC) { default: break; @@ -3141,7 +3142,7 @@ SDValue ARM64TargetLowering::LowerSELECT_CC(SDValue Op, case ISD::SETUGE: case ISD::SETOGT: case ISD::SETOGE: - return DAG.getNode(ARM64ISD::FMAX, dl, VT, TVal, FVal); + return DAG.getNode(ARM64ISD::FMAX, dl, VT, MinMaxLHS, MinMaxRHS); break; case ISD::SETLT: case ISD::SETLE: @@ -3149,7 +3150,7 @@ SDValue ARM64TargetLowering::LowerSELECT_CC(SDValue Op, case ISD::SETULE: case ISD::SETOLT: case ISD::SETOLE: - return DAG.getNode(ARM64ISD::FMIN, dl, VT, TVal, FVal); + return DAG.getNode(ARM64ISD::FMIN, dl, VT, MinMaxLHS, MinMaxRHS); break; } } diff --git a/test/CodeGen/ARM64/fmax.ll b/test/CodeGen/ARM64/fmax.ll index 53ecf86a022..94b745437bd 100644 --- a/test/CodeGen/ARM64/fmax.ll +++ b/test/CodeGen/ARM64/fmax.ll @@ -1,7 +1,7 @@ ; RUN: llc -march=arm64 -enable-no-nans-fp-math < %s | FileCheck %s define double @test_direct(float %in) #1 { -entry: +; CHECK-LABEL: test_direct: %cmp = fcmp olt float %in, 0.000000e+00 %longer = fpext float %in to double %val = select i1 %cmp, double 0.000000e+00, double %longer @@ -11,7 +11,7 @@ entry: } define double @test_cross(float %in) #1 { -entry: +; CHECK-LABEL: test_cross: %cmp = fcmp olt float %in, 0.000000e+00 %longer = fpext float %in to double %val = select i1 %cmp, double %longer, double 0.000000e+00 @@ -19,3 +19,16 @@ entry: ; CHECK: fmin } + +; This isn't a min or a max, but passes the first condition for swapping the +; results. Make sure they're put back before we resort to the normal fcsel. +define float @test_cross_fail(float %lhs, float %rhs) { +; CHECK-LABEL: test_cross_fail: + %tst = fcmp une float %lhs, %rhs + %res = select i1 %tst, float %rhs, float %lhs + ret float %res + + ; The register allocator would have to decide to be deliberately obtuse before + ; other register were used. +; CHECK: fcsel s0, s1, s0, ne +} \ No newline at end of file -- 2.34.1