[InstCombine] fold test of equality to 0.0 with bitcast operand
authorSanjay Patel <spatel@rotateright.com>
Fri, 26 Aug 2022 15:15:09 +0000 (11:15 -0400)
committerSanjay Patel <spatel@rotateright.com>
Fri, 26 Aug 2022 17:46:11 +0000 (13:46 -0400)
fcmp oeq/une (bitcast X), 0.0 --> (and X, SignMaskC) ==/!= 0
https://alive2.llvm.org/ce/z/ZKATGN

llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
llvm/test/Transforms/InstCombine/fcmp.ll

index fd45257..4a0ba31 100644 (file)
@@ -6888,6 +6888,25 @@ Instruction *InstCombinerImpl::visitFCmpInst(FCmpInst &I) {
   if (match(Op1, m_AnyZeroFP()) && !match(Op1, m_PosZeroFP()))
     return replaceOperand(I, 1, ConstantFP::getNullValue(OpType));
 
+  // Ignore signbit of bitcasted int when comparing equality to FP 0.0:
+  // fcmp oeq/une (bitcast X), 0.0 --> (and X, SignMaskC) ==/!= 0
+  if (match(Op1, m_PosZeroFP()) &&
+      match(Op0, m_OneUse(m_BitCast(m_Value(X)))) &&
+      X->getType()->getScalarSizeInBits() == OpType->getScalarSizeInBits()) {
+    ICmpInst::Predicate IntPred = ICmpInst::BAD_ICMP_PREDICATE;
+    if (Pred == FCmpInst::FCMP_OEQ)
+      IntPred = ICmpInst::ICMP_EQ;
+    else if (Pred == FCmpInst::FCMP_UNE)
+      IntPred = ICmpInst::ICMP_NE;
+
+    if (IntPred != ICmpInst::BAD_ICMP_PREDICATE) {
+      Type *IntTy = X->getType();
+      const APInt &SignMask = ~APInt::getSignMask(IntTy->getScalarSizeInBits());
+      Value *MaskX = Builder.CreateAnd(X, ConstantInt::get(IntTy, SignMask));
+      return new ICmpInst(IntPred, MaskX, ConstantInt::getNullValue(IntTy));
+    }
+  }
+
   // Handle fcmp with instruction LHS and constant RHS.
   Instruction *LHSI;
   Constant *RHSC;
index 1d4a2c1..198a715 100644 (file)
@@ -1215,8 +1215,8 @@ define i1 @fneg_une_swap(float %p) {
 
 define i1 @bitcast_eq0(i32 %x) {
 ; CHECK-LABEL: @bitcast_eq0(
-; CHECK-NEXT:    [[F:%.*]] = bitcast i32 [[X:%.*]] to float
-; CHECK-NEXT:    [[R:%.*]] = fcmp oeq float [[F]], 0.000000e+00
+; CHECK-NEXT:    [[TMP1:%.*]] = and i32 [[X:%.*]], 2147483647
+; CHECK-NEXT:    [[R:%.*]] = icmp eq i32 [[TMP1]], 0
 ; CHECK-NEXT:    ret i1 [[R]]
 ;
   %f = bitcast i32 %x to float
@@ -1226,8 +1226,8 @@ define i1 @bitcast_eq0(i32 %x) {
 
 define <2 x i1> @bitcast_ne0(<2 x i32> %x) {
 ; CHECK-LABEL: @bitcast_ne0(
-; CHECK-NEXT:    [[F:%.*]] = bitcast <2 x i32> [[X:%.*]] to <2 x float>
-; CHECK-NEXT:    [[R:%.*]] = fcmp une <2 x float> [[F]], zeroinitializer
+; CHECK-NEXT:    [[TMP1:%.*]] = and <2 x i32> [[X:%.*]], <i32 2147483647, i32 2147483647>
+; CHECK-NEXT:    [[R:%.*]] = icmp ne <2 x i32> [[TMP1]], zeroinitializer
 ; CHECK-NEXT:    ret <2 x i1> [[R]]
 ;
   %f = bitcast <2 x i32> %x to <2 x float>
@@ -1235,6 +1235,8 @@ define <2 x i1> @bitcast_ne0(<2 x i32> %x) {
   ret <2 x i1> %r
 }
 
+; negative test - extra use
+
 define i1 @bitcast_eq0_use(i32 %x) {
 ; CHECK-LABEL: @bitcast_eq0_use(
 ; CHECK-NEXT:    [[F:%.*]] = bitcast i32 [[X:%.*]] to float
@@ -1248,6 +1250,8 @@ define i1 @bitcast_eq0_use(i32 %x) {
   ret i1 %r
 }
 
+; negative test - this could be transformed, but requires a new bitcast
+
 define i1 @bitcast_nonint_eq0(<2 x i16> %x) {
 ; CHECK-LABEL: @bitcast_nonint_eq0(
 ; CHECK-NEXT:    [[F:%.*]] = bitcast <2 x i16> [[X:%.*]] to float
@@ -1259,6 +1263,8 @@ define i1 @bitcast_nonint_eq0(<2 x i16> %x) {
   ret i1 %r
 }
 
+; negative test - wrong predicate
+
 define i1 @bitcast_gt0(i32 %x) {
 ; CHECK-LABEL: @bitcast_gt0(
 ; CHECK-NEXT:    [[F:%.*]] = bitcast i32 [[X:%.*]] to float