diff --git a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp index a9db383ede385..9a248879e301b 100644 --- a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp @@ -20346,6 +20346,11 @@ SDValue DAGCombiner::visitFCOPYSIGN(SDNode *N) { if (VT != N1.getValueType()) return SDValue(); + // ppcf128 has two sign bits (in bits 127 and 63), the logic below is invalid. + EVT SVT = VT.getScalarType(); + if (!APFloat::hasSignBitInMSB(SVT.getFltSemantics()) || SVT == MVT::ppcf128) + return SDValue(); + // If this is equivalent to a disjoint or, replace it with one. This can // happen if the sign operand is a sign mask (i.e., x << sign_bit_position). if (DAG.SignBitIsZeroFP(N0) && diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp index 07d7636e6cb3b..00fa2a1ce46a6 100644 --- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp @@ -4146,25 +4146,50 @@ KnownBits SelectionDAG::computeKnownBits(SDValue Op, const APInt &DemandedElts, FPClassTest NoFPClass = static_cast(Op.getConstantOperandVal(1)); + + EVT SVT = Op.getValueType().getScalarType(); + unsigned SignBitPos; + if (SVT == MVT::ppcf128) + // The sign bit position depends on endianness: ppc_fp128 is two doubles + // in a trenchcoat, and it is the high-order double that carries the sign. + SignBitPos = getDataLayout().isBigEndian() ? 127 : 63; + else if (APFloat::hasSignBitInMSB(SVT.getFltSemantics())) + // IEEE-like formats, bf16, x86_fp80: the sign bit is the integer MSB. + SignBitPos = BitWidth - 1; + else + break; + const FPClassTest NegativeTestMask = fcNan | fcNegative; if ((NoFPClass & NegativeTestMask) == NegativeTestMask) { // Cannot be negative. - Known.makeNonNegative(); + Known.Zero.setBit(SignBitPos); } const FPClassTest PositiveTestMask = fcNan | fcPositive; if ((NoFPClass & PositiveTestMask) == PositiveTestMask) { // Cannot be positive. - Known.makeNegative(); + Known.One.setBit(SignBitPos); } break; } - case ISD::FABS: - // fabs clears the sign bit + case ISD::FABS: { Known = computeKnownBits(Op.getOperand(0), DemandedElts, Depth + 1); - Known.makeNonNegative(); + EVT SVT = Op.getValueType().getScalarType(); + if (SVT == MVT::ppcf128) { + // The sign bit position depends on endianness: ppc_fp128 is two doubles + // in a trenchcoat, fabs only clears the sign bit of the high-order + // double. + Known.resetAll(); + Known.Zero.setBit(getDataLayout().isBigEndian() ? 127 : 63); + } else if (APFloat::hasSignBitInMSB(SVT.getFltSemantics())) { + // IEEE-like formats, bf16, x86_fp80: the sign bit is the integer MSB, + // fabs clears that sign bit. + Known.makeNonNegative(); + } + break; + } case ISD::FGETSIGN: // All bits are zero except the low bit. Known.Zero.setBitsFrom(1); diff --git a/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp b/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp index 673ecf1b62dea..66f06e4c5ec39 100644 --- a/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp @@ -3080,8 +3080,13 @@ bool TargetLowering::SimplifyDemandedBits( } case ISD::FABS: { SDValue Op0 = Op.getOperand(0); - APInt SignMask = APInt::getSignMask(BitWidth); + EVT SVT = Op0.getValueType(); + + // The position of the sign bit for ppc_fp128 is endian-dependent. + if (!APFloat::hasSignBitInMSB(SVT.getFltSemantics()) || SVT == MVT::ppcf128) + break; + APInt SignMask = APInt::getSignMask(BitWidth); if (!DemandedBits.intersects(SignMask)) return TLO.CombineTo(Op, Op0); @@ -3133,6 +3138,13 @@ bool TargetLowering::SimplifyDemandedBits( } case ISD::FNEG: { SDValue Op0 = Op.getOperand(0); + EVT SVT = Op0.getValueType(); + + // The logic below assumes the sign bit is in the MSB. + // ppc_fp128 has two sign bits (at bits 127 and 63). + if (!APFloat::hasSignBitInMSB(SVT.getFltSemantics()) || SVT == MVT::ppcf128) + break; + APInt SignMask = APInt::getSignMask(BitWidth); if (!DemandedBits.intersects(SignMask)) diff --git a/llvm/lib/Support/KnownFPClass.cpp b/llvm/lib/Support/KnownFPClass.cpp index 09bb9c5538a34..ec88c946cf201 100644 --- a/llvm/lib/Support/KnownFPClass.cpp +++ b/llvm/lib/Support/KnownFPClass.cpp @@ -290,6 +290,11 @@ KnownBits KnownFPClass::toKnownBits(const fltSemantics &FltSemantics) const { if (FPClasses == fcNone) return Known; + // The code below assumes the sign bit is the MSB. + if (!APFloat::hasSignBitInMSB(FltSemantics) || + &FltSemantics == &APFloat::PPCDoubleDouble()) + return Known; + if (isKnownNever(fcNormal | fcSubnormal | fcNan)) { Known.setAllConflict(); diff --git a/llvm/test/CodeGen/PowerPC/copysignl.ll b/llvm/test/CodeGen/PowerPC/copysignl.ll index e78038ab183c6..5261c27e5ca15 100644 --- a/llvm/test/CodeGen/PowerPC/copysignl.ll +++ b/llvm/test/CodeGen/PowerPC/copysignl.ll @@ -383,6 +383,13 @@ entry: define ppc_fp128 @copysign_signmask(ppc_fp128 %x, i1 %s) { ; LE-LABEL: copysign_signmask: ; LE: # %bb.0: # %entry +; LE-NEXT: fmr 0, 1 +; LE-NEXT: xsabsdp 1, 1 +; LE-NEXT: xscmpudp 0, 0, 1 +; LE-NEXT: beq 0, .LBB6_2 +; LE-NEXT: # %bb.1: # %entry +; LE-NEXT: xsnegdp 2, 2 +; LE-NEXT: .LBB6_2: # %entry ; LE-NEXT: mflr 0 ; LE-NEXT: stdu 1, -32(1) ; LE-NEXT: std 0, 48(1) @@ -400,6 +407,13 @@ define ppc_fp128 @copysign_signmask(ppc_fp128 %x, i1 %s) { ; ; BE-LABEL: copysign_signmask: ; BE: # %bb.0: # %entry +; BE-NEXT: fmr 0, 1 +; BE-NEXT: fabs 1, 1 +; BE-NEXT: fcmpu 0, 0, 1 +; BE-NEXT: beq 0, .LBB6_2 +; BE-NEXT: # %bb.1: # %entry +; BE-NEXT: fneg 2, 2 +; BE-NEXT: .LBB6_2: # %entry ; BE-NEXT: mflr 0 ; BE-NEXT: stdu 1, -128(1) ; BE-NEXT: std 0, 144(1) @@ -419,6 +433,13 @@ define ppc_fp128 @copysign_signmask(ppc_fp128 %x, i1 %s) { ; ; BE-VSX-LABEL: copysign_signmask: ; BE-VSX: # %bb.0: # %entry +; BE-VSX-NEXT: fmr 0, 1 +; BE-VSX-NEXT: xsabsdp 1, 1 +; BE-VSX-NEXT: xscmpudp 0, 0, 1 +; BE-VSX-NEXT: beq 0, .LBB6_2 +; BE-VSX-NEXT: # %bb.1: # %entry +; BE-VSX-NEXT: xsnegdp 2, 2 +; BE-VSX-NEXT: .LBB6_2: # %entry ; BE-VSX-NEXT: mflr 0 ; BE-VSX-NEXT: stdu 1, -128(1) ; BE-VSX-NEXT: std 0, 144(1) @@ -442,7 +463,13 @@ define ppc_fp128 @copysign_signmask(ppc_fp128 %x, i1 %s) { ; BE32-NEXT: stw 0, 100(1) ; BE32-NEXT: .cfi_def_cfa_offset 96 ; BE32-NEXT: .cfi_offset lr, 4 -; BE32-NEXT: stfd 1, 40(1) +; BE32-NEXT: fabs 0, 1 +; BE32-NEXT: fcmpu 0, 1, 0 +; BE32-NEXT: beq 0, .LBB6_2 +; BE32-NEXT: # %bb.1: # %entry +; BE32-NEXT: fneg 2, 2 +; BE32-NEXT: .LBB6_2: # %entry +; BE32-NEXT: stfd 0, 40(1) ; BE32-NEXT: slwi 3, 3, 31 ; BE32-NEXT: stw 3, 64(1) ; BE32-NEXT: li 4, 0 diff --git a/llvm/test/CodeGen/PowerPC/fneg.ll b/llvm/test/CodeGen/PowerPC/fneg.ll index 191594ab72316..a16df9122a321 100644 --- a/llvm/test/CodeGen/PowerPC/fneg.ll +++ b/llvm/test/CodeGen/PowerPC/fneg.ll @@ -145,7 +145,9 @@ entry: define i1 @fneg_msb(ppc_fp128 nofpclass(nan ninf nsub nnorm nzero) %x) { ; LE-LABEL: fneg_msb: ; LE: # %bb.0: # %entry -; LE-NEXT: li 3, 1 +; LE-NEXT: mffprd 3, 2 +; LE-NEXT: not 3, 3 +; LE-NEXT: rldicl 3, 3, 1, 63 ; LE-NEXT: blr ; ; BE-LABEL: fneg_msb: @@ -167,8 +169,7 @@ entry: define i1 @fneg_bit63(ppc_fp128 nofpclass(nan ninf nsub nnorm nzero) %x) { ; LE-LABEL: fneg_bit63: ; LE: # %bb.0: # %entry -; LE-NEXT: mffprd 3, 1 -; LE-NEXT: rldicl 3, 3, 1, 63 +; LE-NEXT: li 3, 1 ; LE-NEXT: blr ; ; BE-LABEL: fneg_bit63: @@ -200,8 +201,7 @@ entry: define i1 @fneg_fneg_msb(ppc_fp128 nofpclass(nan ninf nsub nnorm nzero) %x) { ; LE-LABEL: fneg_fneg_msb: ; LE: # %bb.0: # %entry -; LE-NEXT: mffprd 3, 1 -; LE-NEXT: rldicl 3, 3, 1, 63 +; LE-NEXT: li 3, 0 ; LE-NEXT: blr ; ; BE-LABEL: fneg_fneg_msb: diff --git a/llvm/test/CodeGen/PowerPC/fp128-fabs.ll b/llvm/test/CodeGen/PowerPC/fp128-fabs.ll new file mode 100644 index 0000000000000..49a14bd7c0015 --- /dev/null +++ b/llvm/test/CodeGen/PowerPC/fp128-fabs.ll @@ -0,0 +1,101 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -verify-machineinstrs -mtriple=powerpc64le-unknown-linux-gnu < %s | FileCheck %s -check-prefix=LE +; RUN: llc -verify-machineinstrs -mtriple=powerpc64-unknown-linux-gnu < %s | FileCheck %s -check-prefix=BE +; RUN: llc -verify-machineinstrs -mtriple=powerpc-unknown-linux-gnu < %s | FileCheck %s -check-prefix=BE32 + +; On little-endian powerpc the bit position of the sign bit is bit 63, not +; bit 127. However, APFloat reports that the sign bit is the MSB. Ensure +; that we do not incorrectly optimize based on the (false!) assumption that +; fabs just clears the MSB. + +define i1 @msb_set(ppc_fp128 %x) { +; LE-LABEL: msb_set: +; LE: # %bb.0: # %entry +; LE-NEXT: mffprd 3, 1 +; LE-NEXT: mffprd 4, 2 +; LE-NEXT: xor 3, 4, 3 +; LE-NEXT: rldicl 3, 3, 1, 63 +; LE-NEXT: blr +; +; BE-LABEL: msb_set: +; BE: # %bb.0: # %entry +; BE-NEXT: li 3, 0 +; BE-NEXT: blr +; +; BE32-LABEL: msb_set: +; BE32: # %bb.0: # %entry +; BE32-NEXT: li 3, 0 +; BE32-NEXT: blr +entry: + %a = call ppc_fp128 @llvm.fabs.ppcf128(ppc_fp128 %x) + %v = bitcast ppc_fp128 %a to i128 + %cmp = icmp slt i128 %v, 0 + ret i1 %cmp +} + +; On BE the ppc_fp128 sign bit is stored in bit 127, this information +; makes the function return a constant there. +define i1 @fabs_clears_sign_be(ppc_fp128 %x) { +; LE-LABEL: fabs_clears_sign_be: +; LE: # %bb.0: # %entry +; LE-NEXT: mffprd 3, 1 +; LE-NEXT: mffprd 4, 2 +; LE-NEXT: xor 3, 4, 3 +; LE-NEXT: rldicl 3, 3, 1, 63 +; LE-NEXT: blr +; +; BE-LABEL: fabs_clears_sign_be: +; BE: # %bb.0: # %entry +; BE-NEXT: li 3, 0 +; BE-NEXT: blr +; +; BE32-LABEL: fabs_clears_sign_be: +; BE32: # %bb.0: # %entry +; BE32-NEXT: li 3, 0 +; BE32-NEXT: blr +entry: + %neg = fneg ppc_fp128 %x + %a = call ppc_fp128 @llvm.fabs.ppcf128(ppc_fp128 %neg) + %v = bitcast ppc_fp128 %a to i128 + %cmp = icmp slt i128 %v, 0 + ret i1 %cmp +} + +; On LE the ppc_fp128 sign bit is stored in bit 63, this information +; makes the function return a constant there. +define i1 @fabs_clears_sign_le(ppc_fp128 %x) { +; LE-LABEL: fabs_clears_sign_le: +; LE: # %bb.0: # %entry +; LE-NEXT: li 3, 0 +; LE-NEXT: blr +; +; BE-LABEL: fabs_clears_sign_le: +; BE: # %bb.0: # %entry +; BE-NEXT: stfd 1, -16(1) +; BE-NEXT: stfd 2, -8(1) +; BE-NEXT: ld 3, -16(1) +; BE-NEXT: ld 4, -8(1) +; BE-NEXT: xor 3, 4, 3 +; BE-NEXT: rldicl 3, 3, 1, 63 +; BE-NEXT: blr +; +; BE32-LABEL: fabs_clears_sign_le: +; BE32: # %bb.0: # %entry +; BE32-NEXT: stwu 1, -32(1) +; BE32-NEXT: .cfi_def_cfa_offset 32 +; BE32-NEXT: stfd 1, 24(1) +; BE32-NEXT: stfd 2, 16(1) +; BE32-NEXT: lwz 3, 24(1) +; BE32-NEXT: lwz 4, 16(1) +; BE32-NEXT: xor 3, 4, 3 +; BE32-NEXT: srwi 3, 3, 31 +; BE32-NEXT: addi 1, 1, 32 +; BE32-NEXT: blr +entry: + %neg = fneg ppc_fp128 %x + %a = call ppc_fp128 @llvm.fabs.ppcf128(ppc_fp128 %neg) + %v = bitcast ppc_fp128 %a to i128 + %masked = and i128 %v, 9223372036854775808 ; 1 << 63 + %cmp = icmp ne i128 %masked, 0 + ret i1 %cmp +} diff --git a/llvm/test/CodeGen/PowerPC/nofpclass.ll b/llvm/test/CodeGen/PowerPC/nofpclass.ll index 6d447f09b1b3e..03482127ff7f1 100644 --- a/llvm/test/CodeGen/PowerPC/nofpclass.ll +++ b/llvm/test/CodeGen/PowerPC/nofpclass.ll @@ -7,7 +7,8 @@ define i1 @negative(ppc_fp128 nofpclass(nan pinf psub pnorm pzero) %x) { ; LE-LABEL: negative: ; LE: # %bb.0: # %entry -; LE-NEXT: li 3, 1 +; LE-NEXT: mffprd 3, 2 +; LE-NEXT: rldicl 3, 3, 1, 63 ; LE-NEXT: blr ; ; BE-LABEL: negative: @@ -33,7 +34,8 @@ entry: define i1 @nonnegative(ppc_fp128 nofpclass(nan ninf nsub nnorm nzero) %x) { ; LE-LABEL: nonnegative: ; LE: # %bb.0: # %entry -; LE-NEXT: li 3, 0 +; LE-NEXT: mffprd 3, 2 +; LE-NEXT: rldicl 3, 3, 1, 63 ; LE-NEXT: blr ; ; BE-LABEL: nonnegative: diff --git a/llvm/test/Transforms/InstCombine/known-bits.ll b/llvm/test/Transforms/InstCombine/known-bits.ll index d6b6232e92a49..23066e3bbe8ed 100644 --- a/llvm/test/Transforms/InstCombine/known-bits.ll +++ b/llvm/test/Transforms/InstCombine/known-bits.ll @@ -1537,9 +1537,12 @@ define i16 @test_inf_only_bfloat(bfloat nofpclass(nan sub norm zero) %x) { ret i16 %and } +; A bitcast from ppc_fp128 to i128 is endian-dependent. define i128 @test_inf_only_ppc_fp128(ppc_fp128 nofpclass(nan sub norm zero) %x) { ; CHECK-LABEL: @test_inf_only_ppc_fp128( -; CHECK-NEXT: ret i128 9218868437227405312 +; CHECK-NEXT: [[TMP1:%.*]] = call ppc_fp128 @llvm.fabs.ppcf128(ppc_fp128 [[X:%.*]]) +; CHECK-NEXT: [[AND:%.*]] = bitcast ppc_fp128 [[TMP1]] to i128 +; CHECK-NEXT: ret i128 [[AND]] ; %y = bitcast ppc_fp128 %x to i128 %and = and i128 %y, 170141183460469231731687303715884105727