From 616b03c67b568c3fdf387b504d97a0a844f351a4 Mon Sep 17 00:00:00 2001 From: Yingwei Zheng Date: Mon, 10 Mar 2025 00:19:58 +0800 Subject: [PATCH 1/5] [InstCombine] Fold fneg/fabs patterns with ppc_f128 --- .../InstCombine/InstCombineAndOrXor.cpp | 35 +++++++------------ .../Transforms/InstCombine/fabs-as-int.ll | 4 +-- .../Transforms/InstCombine/fneg-as-int.ll | 4 +-- .../InstCombine/fneg-fabs-as-int.ll | 5 +-- 4 files changed, 20 insertions(+), 28 deletions(-) diff --git a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp index 6cc241781d112..8394cbb5e3183 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp @@ -2637,18 +2637,15 @@ Instruction *InstCombinerImpl::visitAnd(BinaryOperator &I) { // This is a generous interpretation for noimplicitfloat, this is not a true // floating-point operation. // - // Assumes any IEEE-represented type has the sign bit in the high bit. + // Assumes any floating point type has the sign bit in the high bit. // TODO: Unify with APInt matcher. This version allows undef unlike m_APInt Value *CastOp; if (match(Op0, m_ElementWiseBitCast(m_Value(CastOp))) && - match(Op1, m_MaxSignedValue()) && + CastOp->getType()->isFPOrFPVectorTy() && match(Op1, m_MaxSignedValue()) && !Builder.GetInsertBlock()->getParent()->hasFnAttribute( Attribute::NoImplicitFloat)) { - Type *EltTy = CastOp->getType()->getScalarType(); - if (EltTy->isFloatingPointTy() && EltTy->isIEEE()) { - Value *FAbs = Builder.CreateUnaryIntrinsic(Intrinsic::fabs, CastOp); - return new BitCastInst(FAbs, I.getType()); - } + Value *FAbs = Builder.CreateUnaryIntrinsic(Intrinsic::fabs, CastOp); + return new BitCastInst(FAbs, I.getType()); } // and(shl(zext(X), Y), SignMask) -> and(sext(X), SignMask) @@ -4047,21 +4044,18 @@ Instruction *InstCombinerImpl::visitOr(BinaryOperator &I) { // the number of instructions. This is still probably a better canonical form // as it enables FP value tracking. // - // Assumes any IEEE-represented type has the sign bit in the high bit. + // Assumes any floating point type has the sign bit in the high bit. // // This is generous interpretation of noimplicitfloat, this is not a true // floating-point operation. Value *CastOp; if (match(Op0, m_ElementWiseBitCast(m_Value(CastOp))) && - match(Op1, m_SignMask()) && + CastOp->getType()->isFPOrFPVectorTy() && match(Op1, m_SignMask()) && !Builder.GetInsertBlock()->getParent()->hasFnAttribute( Attribute::NoImplicitFloat)) { - Type *EltTy = CastOp->getType()->getScalarType(); - if (EltTy->isFloatingPointTy() && EltTy->isIEEE()) { - Value *FAbs = Builder.CreateUnaryIntrinsic(Intrinsic::fabs, CastOp); - Value *FNegFAbs = Builder.CreateFNeg(FAbs); - return new BitCastInst(FNegFAbs, I.getType()); - } + Value *FAbs = Builder.CreateUnaryIntrinsic(Intrinsic::fabs, CastOp); + Value *FNegFAbs = Builder.CreateFNeg(FAbs); + return new BitCastInst(FNegFAbs, I.getType()); } // (X & C1) | C2 -> X & (C1 | C2) iff (X & C2) == C2 @@ -4851,18 +4845,15 @@ Instruction *InstCombinerImpl::visitXor(BinaryOperator &I) { // This is generous interpretation of noimplicitfloat, this is not a true // floating-point operation. // - // Assumes any IEEE-represented type has the sign bit in the high bit. + // Assumes any floating point type has the sign bit in the high bit. // TODO: Unify with APInt matcher. This version allows undef unlike m_APInt Value *CastOp; if (match(Op0, m_ElementWiseBitCast(m_Value(CastOp))) && - match(Op1, m_SignMask()) && + CastOp->getType()->isFPOrFPVectorTy() && match(Op1, m_SignMask()) && !Builder.GetInsertBlock()->getParent()->hasFnAttribute( Attribute::NoImplicitFloat)) { - Type *EltTy = CastOp->getType()->getScalarType(); - if (EltTy->isFloatingPointTy() && EltTy->isIEEE()) { - Value *FNeg = Builder.CreateFNeg(CastOp); - return new BitCastInst(FNeg, I.getType()); - } + Value *FNeg = Builder.CreateFNeg(CastOp); + return new BitCastInst(FNeg, I.getType()); } } diff --git a/llvm/test/Transforms/InstCombine/fabs-as-int.ll b/llvm/test/Transforms/InstCombine/fabs-as-int.ll index 9d28cae8f04d6..f0e83ca6302fe 100644 --- a/llvm/test/Transforms/InstCombine/fabs-as-int.ll +++ b/llvm/test/Transforms/InstCombine/fabs-as-int.ll @@ -289,8 +289,8 @@ define i128 @fabs_as_int_ppc_fp128_f64_mask(ppc_fp128 %x) { define i128 @fabs_as_int_ppc_fp128_f128_mask(ppc_fp128 %x) { ; CHECK-LABEL: define i128 @fabs_as_int_ppc_fp128_f128_mask ; CHECK-SAME: (ppc_fp128 [[X:%.*]]) { -; CHECK-NEXT: [[BC:%.*]] = bitcast ppc_fp128 [[X]] to i128 -; CHECK-NEXT: [[AND:%.*]] = and i128 [[BC]], 170141183460469231731687303715884105727 +; 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]] ; %bc = bitcast ppc_fp128 %x to i128 diff --git a/llvm/test/Transforms/InstCombine/fneg-as-int.ll b/llvm/test/Transforms/InstCombine/fneg-as-int.ll index f8d88b4f238f2..590aca687e5b5 100644 --- a/llvm/test/Transforms/InstCombine/fneg-as-int.ll +++ b/llvm/test/Transforms/InstCombine/fneg-as-int.ll @@ -291,8 +291,8 @@ define i128 @fneg_as_int_ppc_fp128_f64_mask(ppc_fp128 %x) { define i128 @fneg_as_int_ppc_fp128_f128_mask(ppc_fp128 %x) { ; CHECK-LABEL: define i128 @fneg_as_int_ppc_fp128_f128_mask ; CHECK-SAME: (ppc_fp128 [[X:%.*]]) { -; CHECK-NEXT: [[BC:%.*]] = bitcast ppc_fp128 [[X]] to i128 -; CHECK-NEXT: [[XOR:%.*]] = xor i128 [[BC]], -170141183460469231731687303715884105728 +; CHECK-NEXT: [[TMP1:%.*]] = fneg ppc_fp128 [[X]] +; CHECK-NEXT: [[XOR:%.*]] = bitcast ppc_fp128 [[TMP1]] to i128 ; CHECK-NEXT: ret i128 [[XOR]] ; %bc = bitcast ppc_fp128 %x to i128 diff --git a/llvm/test/Transforms/InstCombine/fneg-fabs-as-int.ll b/llvm/test/Transforms/InstCombine/fneg-fabs-as-int.ll index 8b245bdd79299..a0894c3febc94 100644 --- a/llvm/test/Transforms/InstCombine/fneg-fabs-as-int.ll +++ b/llvm/test/Transforms/InstCombine/fneg-fabs-as-int.ll @@ -317,8 +317,9 @@ define i128 @fneg_fabs_as_int_ppc_fp128_f64_mask(ppc_fp128 %x) { define i128 @fneg_fabs_as_int_ppc_fp128_f128_mask(ppc_fp128 %x) { ; CHECK-LABEL: define i128 @fneg_fabs_as_int_ppc_fp128_f128_mask ; CHECK-SAME: (ppc_fp128 [[X:%.*]]) { -; CHECK-NEXT: [[BC:%.*]] = bitcast ppc_fp128 [[X]] to i128 -; CHECK-NEXT: [[OR:%.*]] = or i128 [[BC]], -170141183460469231731687303715884105728 +; CHECK-NEXT: [[TMP1:%.*]] = call ppc_fp128 @llvm.fabs.ppcf128(ppc_fp128 [[X]]) +; CHECK-NEXT: [[TMP2:%.*]] = fneg ppc_fp128 [[TMP1]] +; CHECK-NEXT: [[OR:%.*]] = bitcast ppc_fp128 [[TMP2]] to i128 ; CHECK-NEXT: ret i128 [[OR]] ; %bc = bitcast ppc_fp128 %x to i128 From 925dfd0de6d83f89a71ae8ca529174a0af65ed7f Mon Sep 17 00:00:00 2001 From: Yingwei Zheng Date: Mon, 10 Mar 2025 21:04:58 +0800 Subject: [PATCH 2/5] [ADT] Add `hasSignBitInMSB` helper --- llvm/include/llvm/ADT/APFloat.h | 1 + llvm/lib/Support/APFloat.cpp | 19 ++++++++++++++++--- .../InstCombine/InstCombineAndOrXor.cpp | 15 ++++++++++++--- llvm/unittests/ADT/APFloatTest.cpp | 6 ++++++ 4 files changed, 35 insertions(+), 6 deletions(-) diff --git a/llvm/include/llvm/ADT/APFloat.h b/llvm/include/llvm/ADT/APFloat.h index 25fc8a00f7ddd..01e51accec9df 100644 --- a/llvm/include/llvm/ADT/APFloat.h +++ b/llvm/include/llvm/ADT/APFloat.h @@ -354,6 +354,7 @@ struct APFloatBase { static bool semanticsHasInf(const fltSemantics &); static bool semanticsHasNaN(const fltSemantics &); static bool isIEEELikeFP(const fltSemantics &); + static bool hasSignBitInMSB(const fltSemantics &); // Returns true if any number described by \p Src can be precisely represented // by a normal (not subnormal) value in \p Dst. diff --git a/llvm/lib/Support/APFloat.cpp b/llvm/lib/Support/APFloat.cpp index e058010f9d267..a7b9f259bfed5 100644 --- a/llvm/lib/Support/APFloat.cpp +++ b/llvm/lib/Support/APFloat.cpp @@ -125,6 +125,9 @@ struct fltSemantics { /* Whether this semantics can represent signed values */ bool hasSignedRepr = true; + + /* Whether the sign bit of this semantics is the most significant bit */ + bool hasSignBitInMSB = true; }; static constexpr fltSemantics semIEEEhalf = {15, -14, 11, 16}; @@ -144,9 +147,15 @@ static constexpr fltSemantics semFloat8E4M3B11FNUZ = { 4, -10, 4, 8, fltNonfiniteBehavior::NanOnly, fltNanEncoding::NegativeZero}; static constexpr fltSemantics semFloat8E3M4 = {3, -2, 5, 8}; static constexpr fltSemantics semFloatTF32 = {127, -126, 11, 19}; -static constexpr fltSemantics semFloat8E8M0FNU = { - 127, -127, 1, 8, fltNonfiniteBehavior::NanOnly, fltNanEncoding::AllOnes, - false, false}; +static constexpr fltSemantics semFloat8E8M0FNU = {127, + -127, + 1, + 8, + fltNonfiniteBehavior::NanOnly, + fltNanEncoding::AllOnes, + false, + false, + false}; static constexpr fltSemantics semFloat6E3M2FN = { 4, -2, 3, 6, fltNonfiniteBehavior::FiniteOnly}; @@ -358,6 +367,10 @@ bool APFloatBase::isIEEELikeFP(const fltSemantics &semantics) { return SemanticsToEnum(semantics) <= S_IEEEquad; } +bool APFloatBase::hasSignBitInMSB(const fltSemantics &semantics) { + return semantics.hasSignBitInMSB; +} + bool APFloatBase::isRepresentableAsNormalIn(const fltSemantics &Src, const fltSemantics &Dst) { // Exponent range must be larger. diff --git a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp index 8394cbb5e3183..ee888eaaf7c2b 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp @@ -2641,7 +2641,10 @@ Instruction *InstCombinerImpl::visitAnd(BinaryOperator &I) { // TODO: Unify with APInt matcher. This version allows undef unlike m_APInt Value *CastOp; if (match(Op0, m_ElementWiseBitCast(m_Value(CastOp))) && - CastOp->getType()->isFPOrFPVectorTy() && match(Op1, m_MaxSignedValue()) && + CastOp->getType()->isFPOrFPVectorTy() && + APFloat::hasSignBitInMSB( + CastOp->getType()->getScalarType()->getFltSemantics()) && + match(Op1, m_MaxSignedValue()) && !Builder.GetInsertBlock()->getParent()->hasFnAttribute( Attribute::NoImplicitFloat)) { Value *FAbs = Builder.CreateUnaryIntrinsic(Intrinsic::fabs, CastOp); @@ -4050,7 +4053,10 @@ Instruction *InstCombinerImpl::visitOr(BinaryOperator &I) { // floating-point operation. Value *CastOp; if (match(Op0, m_ElementWiseBitCast(m_Value(CastOp))) && - CastOp->getType()->isFPOrFPVectorTy() && match(Op1, m_SignMask()) && + CastOp->getType()->isFPOrFPVectorTy() && + APFloat::hasSignBitInMSB( + CastOp->getType()->getScalarType()->getFltSemantics()) && + match(Op1, m_SignMask()) && !Builder.GetInsertBlock()->getParent()->hasFnAttribute( Attribute::NoImplicitFloat)) { Value *FAbs = Builder.CreateUnaryIntrinsic(Intrinsic::fabs, CastOp); @@ -4849,7 +4855,10 @@ Instruction *InstCombinerImpl::visitXor(BinaryOperator &I) { // TODO: Unify with APInt matcher. This version allows undef unlike m_APInt Value *CastOp; if (match(Op0, m_ElementWiseBitCast(m_Value(CastOp))) && - CastOp->getType()->isFPOrFPVectorTy() && match(Op1, m_SignMask()) && + CastOp->getType()->isFPOrFPVectorTy() && + APFloat::hasSignBitInMSB( + CastOp->getType()->getScalarType()->getFltSemantics()) && + match(Op1, m_SignMask()) && !Builder.GetInsertBlock()->getParent()->hasFnAttribute( Attribute::NoImplicitFloat)) { Value *FNeg = Builder.CreateFNeg(CastOp); diff --git a/llvm/unittests/ADT/APFloatTest.cpp b/llvm/unittests/ADT/APFloatTest.cpp index 09356191345f5..f9ed8aacbb849 100644 --- a/llvm/unittests/ADT/APFloatTest.cpp +++ b/llvm/unittests/ADT/APFloatTest.cpp @@ -8347,4 +8347,10 @@ TEST(APFloatTest, AddOrSubtractSignificand) { Helper::runTest(true, false, 3, 0x10001, false, 7, 0x100, false, 6, 0x1e00, lfLessThanHalf); } + +TEST(APFloatTest, hasSignBitInMSB) { + EXPECT_TRUE(APFloat::hasSignBitInMSB(APFloat::IEEEsingle())); + EXPECT_FALSE(APFloat::hasSignBitInMSB(APFloat::Float8E8M0FNU())); +} + } // namespace From fff348414e4f4fc0d269437c6eab61e52506a803 Mon Sep 17 00:00:00 2001 From: Yingwei Zheng Date: Mon, 10 Mar 2025 22:47:12 +0800 Subject: [PATCH 3/5] [InstCombine] Reduce changes --- .../InstCombine/InstCombineAndOrXor.cpp | 39 +++++++++---------- 1 file changed, 19 insertions(+), 20 deletions(-) diff --git a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp index ee888eaaf7c2b..ba079e4c2d4fa 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp @@ -2637,18 +2637,18 @@ Instruction *InstCombinerImpl::visitAnd(BinaryOperator &I) { // This is a generous interpretation for noimplicitfloat, this is not a true // floating-point operation. // - // Assumes any floating point type has the sign bit in the high bit. // TODO: Unify with APInt matcher. This version allows undef unlike m_APInt Value *CastOp; if (match(Op0, m_ElementWiseBitCast(m_Value(CastOp))) && - CastOp->getType()->isFPOrFPVectorTy() && - APFloat::hasSignBitInMSB( - CastOp->getType()->getScalarType()->getFltSemantics()) && match(Op1, m_MaxSignedValue()) && !Builder.GetInsertBlock()->getParent()->hasFnAttribute( Attribute::NoImplicitFloat)) { - Value *FAbs = Builder.CreateUnaryIntrinsic(Intrinsic::fabs, CastOp); - return new BitCastInst(FAbs, I.getType()); + Type *EltTy = CastOp->getType()->getScalarType(); + if (EltTy->isFloatingPointTy() && + APFloat::hasSignBitInMSB(EltTy->getFltSemantics())) { + Value *FAbs = Builder.CreateUnaryIntrinsic(Intrinsic::fabs, CastOp); + return new BitCastInst(FAbs, I.getType()); + } } // and(shl(zext(X), Y), SignMask) -> and(sext(X), SignMask) @@ -4047,21 +4047,20 @@ Instruction *InstCombinerImpl::visitOr(BinaryOperator &I) { // the number of instructions. This is still probably a better canonical form // as it enables FP value tracking. // - // Assumes any floating point type has the sign bit in the high bit. - // // This is generous interpretation of noimplicitfloat, this is not a true // floating-point operation. Value *CastOp; if (match(Op0, m_ElementWiseBitCast(m_Value(CastOp))) && - CastOp->getType()->isFPOrFPVectorTy() && - APFloat::hasSignBitInMSB( - CastOp->getType()->getScalarType()->getFltSemantics()) && match(Op1, m_SignMask()) && !Builder.GetInsertBlock()->getParent()->hasFnAttribute( Attribute::NoImplicitFloat)) { - Value *FAbs = Builder.CreateUnaryIntrinsic(Intrinsic::fabs, CastOp); - Value *FNegFAbs = Builder.CreateFNeg(FAbs); - return new BitCastInst(FNegFAbs, I.getType()); + Type *EltTy = CastOp->getType()->getScalarType(); + if (EltTy->isFloatingPointTy() && + APFloat::hasSignBitInMSB(EltTy->getFltSemantics())) { + Value *FAbs = Builder.CreateUnaryIntrinsic(Intrinsic::fabs, CastOp); + Value *FNegFAbs = Builder.CreateFNeg(FAbs); + return new BitCastInst(FNegFAbs, I.getType()); + } } // (X & C1) | C2 -> X & (C1 | C2) iff (X & C2) == C2 @@ -4851,18 +4850,18 @@ Instruction *InstCombinerImpl::visitXor(BinaryOperator &I) { // This is generous interpretation of noimplicitfloat, this is not a true // floating-point operation. // - // Assumes any floating point type has the sign bit in the high bit. // TODO: Unify with APInt matcher. This version allows undef unlike m_APInt Value *CastOp; if (match(Op0, m_ElementWiseBitCast(m_Value(CastOp))) && - CastOp->getType()->isFPOrFPVectorTy() && - APFloat::hasSignBitInMSB( - CastOp->getType()->getScalarType()->getFltSemantics()) && match(Op1, m_SignMask()) && !Builder.GetInsertBlock()->getParent()->hasFnAttribute( Attribute::NoImplicitFloat)) { - Value *FNeg = Builder.CreateFNeg(CastOp); - return new BitCastInst(FNeg, I.getType()); + Type *EltTy = CastOp->getType()->getScalarType(); + if (EltTy->isFloatingPointTy() && + APFloat::hasSignBitInMSB(EltTy->getFltSemantics())) { + Value *FNeg = Builder.CreateFNeg(CastOp); + return new BitCastInst(FNeg, I.getType()); + } } } From dde7d59cf32c2fe0c3575639d59f35515e4c1e0a Mon Sep 17 00:00:00 2001 From: Yingwei Zheng Date: Wed, 12 Mar 2025 14:21:53 +0800 Subject: [PATCH 4/5] [InstCombine] Add back comments. NFC. --- llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp index ba079e4c2d4fa..61c72293dd314 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp @@ -2637,6 +2637,7 @@ Instruction *InstCombinerImpl::visitAnd(BinaryOperator &I) { // This is a generous interpretation for noimplicitfloat, this is not a true // floating-point operation. // + // Assumes any IEEE-represented type has the sign bit in the high bit. // TODO: Unify with APInt matcher. This version allows undef unlike m_APInt Value *CastOp; if (match(Op0, m_ElementWiseBitCast(m_Value(CastOp))) && @@ -4047,6 +4048,8 @@ Instruction *InstCombinerImpl::visitOr(BinaryOperator &I) { // the number of instructions. This is still probably a better canonical form // as it enables FP value tracking. // + // Assumes any IEEE-represented type has the sign bit in the high bit. + // // This is generous interpretation of noimplicitfloat, this is not a true // floating-point operation. Value *CastOp; @@ -4850,6 +4853,7 @@ Instruction *InstCombinerImpl::visitXor(BinaryOperator &I) { // This is generous interpretation of noimplicitfloat, this is not a true // floating-point operation. // + // Assumes any IEEE-represented type has the sign bit in the high bit. // TODO: Unify with APInt matcher. This version allows undef unlike m_APInt Value *CastOp; if (match(Op0, m_ElementWiseBitCast(m_Value(CastOp))) && From 67b69549ea8d5aa6ccca4ab33684bc6e08eab762 Mon Sep 17 00:00:00 2001 From: Yingwei Zheng Date: Wed, 12 Mar 2025 16:04:52 +0800 Subject: [PATCH 5/5] [ADT][UnitTest] Test more fp types. NFC. --- llvm/unittests/ADT/APFloatTest.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/llvm/unittests/ADT/APFloatTest.cpp b/llvm/unittests/ADT/APFloatTest.cpp index f9ed8aacbb849..7a5fd83cd9581 100644 --- a/llvm/unittests/ADT/APFloatTest.cpp +++ b/llvm/unittests/ADT/APFloatTest.cpp @@ -8350,6 +8350,9 @@ TEST(APFloatTest, AddOrSubtractSignificand) { TEST(APFloatTest, hasSignBitInMSB) { EXPECT_TRUE(APFloat::hasSignBitInMSB(APFloat::IEEEsingle())); + EXPECT_TRUE(APFloat::hasSignBitInMSB(APFloat::x87DoubleExtended())); + EXPECT_TRUE(APFloat::hasSignBitInMSB(APFloat::PPCDoubleDouble())); + EXPECT_TRUE(APFloat::hasSignBitInMSB(APFloat::IEEEquad())); EXPECT_FALSE(APFloat::hasSignBitInMSB(APFloat::Float8E8M0FNU())); }