Skip to content

[InstCombine] Fold fneg/fabs patterns with ppc_f128 #130557

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Apr 14, 2025

Conversation

dtcxzyw
Copy link
Member

@dtcxzyw dtcxzyw commented Mar 10, 2025

This patch is needed by #130496.

@llvmbot
Copy link
Member

llvmbot commented Mar 10, 2025

@llvm/pr-subscribers-llvm-adt
@llvm/pr-subscribers-llvm-support

@llvm/pr-subscribers-llvm-transforms

Author: Yingwei Zheng (dtcxzyw)

Changes

This patch is needed by #130496.


Full diff: https://github.com/llvm/llvm-project/pull/130557.diff

4 Files Affected:

  • (modified) llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp (+13-22)
  • (modified) llvm/test/Transforms/InstCombine/fabs-as-int.ll (+2-2)
  • (modified) llvm/test/Transforms/InstCombine/fneg-as-int.ll (+2-2)
  • (modified) llvm/test/Transforms/InstCombine/fneg-fabs-as-int.ll (+3-2)
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

@arsenm arsenm added the floating-point Floating-point math label Mar 10, 2025
// 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()) &&
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might be worth wrapping this in a predicate with this explicit property

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about adding new matchers like m_IntValue/m_FPValue? They are very useful to work with the bitcast matcher.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@arsenm Do you mean the property "has sign bit in high bit"?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see.

fltNanEncoding::AllOnes,
false,
false,
false};

This comment was marked as outdated.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think so. All the bits are exponent bits (E8M0). It ranges from 2^-127 to 2^127 (255 values). The remaining one is NaN (all ones).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ooops, it looks like I looked at a different entry, not sure how I ended up there. This one is:

    // 8-bit floating point number with (all the) 8 bits for the exponent
    // like in FP32. There are no zeroes, no infinities, and no denormal values.
    // This format has unsigned representation only. (U -> Unsigned only).
    // NaN is represented with all bits set to 1. Bias is 127.
    // This format represents the scale data type in the MX specification from:
    // https://www.opencompute.org/documents/ocp-microscaling-formats-mx-v1-0-spec-final-pdf

Okay, that makes sense.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This makes me wonder though whether we need a separate flag. Can we use hasSignedRepr instead, and specify that hasSignedRepr must have the sign bit in the MSB?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IIUC hasSignedRepr is weaker. It just indicates that the semantics doesn't have negative numbers.

@dtcxzyw dtcxzyw force-pushed the remove-is-ieee-pre branch from 29eaf37 to dde7d59 Compare March 12, 2025 06:22
@dtcxzyw
Copy link
Member Author

dtcxzyw commented Apr 13, 2025

Ping.

Copy link
Contributor

@nikic nikic left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@dtcxzyw dtcxzyw merged commit e710a5a into llvm:main Apr 14, 2025
11 checks passed
@dtcxzyw dtcxzyw deleted the remove-is-ieee-pre branch April 14, 2025 06:30
var-const pushed a commit to ldionne/llvm-project that referenced this pull request Apr 17, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants