diff options
author | Ulrich Weigand <ulrich.weigand@de.ibm.com> | 2019-12-04 10:27:02 +0100 |
---|---|---|
committer | Ulrich Weigand <ulrich.weigand@de.ibm.com> | 2019-12-04 10:32:35 +0100 |
commit | c3d05c1b5209122dbb18e2d7126c14359b6dfa90 (patch) | |
tree | 648d30876dbf910ecc47ba21f2fe49faf8f6e446 | |
parent | 4d37f18b29cc3fd1abd336ec10baca17694d035f (diff) | |
download | bcm5719-llvm-c3d05c1b5209122dbb18e2d7126c14359b6dfa90.tar.gz bcm5719-llvm-c3d05c1b5209122dbb18e2d7126c14359b6dfa90.zip |
[SelectionDAG] Expand nnan FMINNUM/FMAXNUM to select sequence
InstCombine may synthesize FMINNUM/FMAXNUM nodes from fcmp+select
sequences (where the fcmp is marked nnan). Currently, if the
target does not otherwise handle these nodes, they'll get expanded
to libcalls to fmin/fmax. However, these functions may reside in
libm, which may introduce a library dependency that was not originally
present in the source code, potentially resulting in link failures.
To fix this problem, add code to TargetLowering::expandFMINNUM_FMAXNUM
to expand FMINNUM/FMAXNUM to a compare+select sequence instead of the
libcall. This is done only if the node is marked as "nnan"; in this case,
the expansion to compare+select is always correct. This also suffices to
catch all cases where FMINNUM/FMAXNUM was synthesized as above.
Differential Revision: https://reviews.llvm.org/D70965
-rw-r--r-- | llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp | 20 | ||||
-rw-r--r-- | llvm/test/CodeGen/SystemZ/fp-libcall.ll | 62 |
2 files changed, 82 insertions, 0 deletions
diff --git a/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp b/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp index c24a3670c98..1e51ec2d6a2 100644 --- a/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp @@ -6225,6 +6225,26 @@ SDValue TargetLowering::expandFMINNUM_FMAXNUM(SDNode *Node, } } + // If none of the above worked, but there are no NaNs, then expand to + // a compare/select sequence. This is required for correctness since + // InstCombine might have canonicalized a fcmp+select sequence to a + // FMINNUM/FMAXNUM node. If we were to fall through to the default + // expansion to libcall, we might introduce a link-time dependency + // on libm into a file that originally did not have one. + if (Node->getFlags().hasNoNaNs()) { + ISD::CondCode Pred = + Node->getOpcode() == ISD::FMINNUM ? ISD::SETLT : ISD::SETGT; + SDValue Op1 = Node->getOperand(0); + SDValue Op2 = Node->getOperand(1); + SDValue SelCC = DAG.getSelectCC(dl, Op1, Op2, Op1, Op2, Pred); + // Copy FMF flags, but always set the no-signed-zeros flag + // as this is implied by the FMINNUM/FMAXNUM semantics. + SDNodeFlags Flags = Node->getFlags(); + Flags.setNoSignedZeros(true); + SelCC->setFlags(Flags); + return SelCC; + } + return SDValue(); } diff --git a/llvm/test/CodeGen/SystemZ/fp-libcall.ll b/llvm/test/CodeGen/SystemZ/fp-libcall.ll index 75250b811cb..2df25aaf814 100644 --- a/llvm/test/CodeGen/SystemZ/fp-libcall.ll +++ b/llvm/test/CodeGen/SystemZ/fp-libcall.ll @@ -233,6 +233,68 @@ define fp128 @f33(fp128 %x, fp128 %y) { ret fp128 %tmp } +; Verify that "nnan" minnum/maxnum calls are transformed to +; compare+select sequences instead of libcalls. +define float @f34(float %x, float %y) { +; CHECK-LABEL: f34: +; CHECK: cebr %f0, %f2 +; CHECK: blr %r14 +; CHECK: ler %f0, %f2 +; CHECK: br %r14 + %tmp = call nnan float @llvm.minnum.f32(float %x, float %y) + ret float %tmp +} + +define double @f35(double %x, double %y) { +; CHECK-LABEL: f35: +; CHECK: cdbr %f0, %f2 +; CHECK: blr %r14 +; CHECK: ldr %f0, %f2 +; CHECK: br %r14 + %tmp = call nnan double @llvm.minnum.f64(double %x, double %y) + ret double %tmp +} + +define fp128 @f36(fp128 %x, fp128 %y) { +; CHECK-LABEL: f36: +; CHECK: cxbr +; CHECK: jl +; CHECK: lxr +; CHECK: br %r14 + %tmp = call nnan fp128 @llvm.minnum.f128(fp128 %x, fp128 %y) + ret fp128 %tmp +} + +define float @f37(float %x, float %y) { +; CHECK-LABEL: f37: +; CHECK: cebr %f0, %f2 +; CHECK: bhr %r14 +; CHECK: ler %f0, %f2 +; CHECK: br %r14 + %tmp = call nnan float @llvm.maxnum.f32(float %x, float %y) + ret float %tmp +} + +define double @f38(double %x, double %y) { +; CHECK-LABEL: f38: +; CHECK: cdbr %f0, %f2 +; CHECK: bhr %r14 +; CHECK: ldr %f0, %f2 +; CHECK: br %r14 + %tmp = call nnan double @llvm.maxnum.f64(double %x, double %y) + ret double %tmp +} + +define fp128 @f39(fp128 %x, fp128 %y) { +; CHECK-LABEL: f39: +; CHECK: cxbr +; CHECK: jh +; CHECK: lxr +; CHECK: br %r14 + %tmp = call nnan fp128 @llvm.maxnum.f128(fp128 %x, fp128 %y) + ret fp128 %tmp +} + declare float @llvm.powi.f32(float, i32) declare double @llvm.powi.f64(double, i32) declare fp128 @llvm.powi.f128(fp128, i32) |