[llvm] 7bee944 - [InstCombine] form copysign from select of FP constants (PR44153)

Sanjay Patel via llvm-commits llvm-commits at lists.llvm.org
Mon Jan 20 07:53:41 PST 2020


Author: Sanjay Patel
Date: 2020-01-20T10:51:14-05:00
New Revision: 7bee94410ce265833695128dfad7fbd7a8eef6ba

URL: https://github.com/llvm/llvm-project/commit/7bee94410ce265833695128dfad7fbd7a8eef6ba
DIFF: https://github.com/llvm/llvm-project/commit/7bee94410ce265833695128dfad7fbd7a8eef6ba.diff

LOG: [InstCombine] form copysign from select of FP constants (PR44153)

This should be the last step needed to solve the problem in the
description of PR44153:
https://bugs.llvm.org/show_bug.cgi?id=44153

If we're casting an FP value to int, testing its signbit, and then
choosing between a value and its negated value, that's a
complicated way of saying "copysign":

(bitcast X) <  0 ? -TC :  TC --> copysign(TC,  X)

Differential Revision: https://reviews.llvm.org/D72643

Added: 
    

Modified: 
    llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
    llvm/test/Transforms/InstCombine/select.ll

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
index 05a624fde86b..2628e57deba5 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
@@ -2317,6 +2317,48 @@ static Instruction *foldSelectRotate(SelectInst &Sel) {
   return IntrinsicInst::Create(F, { TVal, TVal, ShAmt });
 }
 
+static Instruction *foldSelectToCopysign(SelectInst &Sel,
+                                         InstCombiner::BuilderTy &Builder) {
+  Value *Cond = Sel.getCondition();
+  Value *TVal = Sel.getTrueValue();
+  Value *FVal = Sel.getFalseValue();
+  Type *SelType = Sel.getType();
+
+  // Match select ?, TC, FC where the constants are equal but negated.
+  // TODO: Generalize to handle a negated variable operand?
+  const APFloat *TC, *FC;
+  if (!match(TVal, m_APFloat(TC)) || !match(FVal, m_APFloat(FC)) ||
+      !abs(*TC).bitwiseIsEqual(abs(*FC)))
+    return nullptr;
+
+  assert(TC != FC && "Expected equal select arms to simplify");
+
+  Value *X;
+  const APInt *C;
+  bool IsTrueIfSignSet;
+  ICmpInst::Predicate Pred;
+  if (!match(Cond, m_OneUse(m_ICmp(Pred, m_BitCast(m_Value(X)), m_APInt(C)))) ||
+      !isSignBitCheck(Pred, *C, IsTrueIfSignSet) || X->getType() != SelType)
+    return nullptr;
+
+  // If needed, negate the value that will be the sign argument of the copysign:
+  // (bitcast X) <  0 ? -TC :  TC --> copysign(TC,  X)
+  // (bitcast X) <  0 ?  TC : -TC --> copysign(TC, -X)
+  // (bitcast X) >= 0 ? -TC :  TC --> copysign(TC, -X)
+  // (bitcast X) >= 0 ?  TC : -TC --> copysign(TC,  X)
+  if (IsTrueIfSignSet ^ TC->isNegative())
+    X = Builder.CreateFNegFMF(X, &Sel);
+
+  // Canonicalize the magnitude argument as the positive constant since we do
+  // not care about its sign.
+  Value *MagArg = TC->isNegative() ? FVal : TVal;
+  Function *F = Intrinsic::getDeclaration(Sel.getModule(), Intrinsic::copysign,
+                                          Sel.getType());
+  Instruction *CopySign = IntrinsicInst::Create(F, { MagArg, X });
+  CopySign->setFastMathFlags(Sel.getFastMathFlags());
+  return CopySign;
+}
+
 Instruction *InstCombiner::visitSelectInst(SelectInst &SI) {
   Value *CondVal = SI.getCondition();
   Value *TrueVal = SI.getTrueValue();
@@ -2785,5 +2827,8 @@ Instruction *InstCombiner::visitSelectInst(SelectInst &SI) {
   if (Instruction *Rot = foldSelectRotate(SI))
     return Rot;
 
+  if (Instruction *Copysign = foldSelectToCopysign(SI, Builder))
+    return Copysign;
+
   return nullptr;
 }

diff  --git a/llvm/test/Transforms/InstCombine/select.ll b/llvm/test/Transforms/InstCombine/select.ll
index 2f04efe44b2a..0f26a93a7bae 100644
--- a/llvm/test/Transforms/InstCombine/select.ll
+++ b/llvm/test/Transforms/InstCombine/select.ll
@@ -1535,9 +1535,7 @@ define <2 x i32> @test_shl_zext_bool_vec(<2 x i1> %t) {
 
 define float @copysign1(float %x) {
 ; CHECK-LABEL: @copysign1(
-; CHECK-NEXT:    [[I:%.*]] = bitcast float [[X:%.*]] to i32
-; CHECK-NEXT:    [[ISPOS:%.*]] = icmp sgt i32 [[I]], -1
-; CHECK-NEXT:    [[R:%.*]] = select i1 [[ISPOS]], float 1.000000e+00, float -1.000000e+00
+; CHECK-NEXT:    [[R:%.*]] = call float @llvm.copysign.f32(float 1.000000e+00, float [[X:%.*]])
 ; CHECK-NEXT:    ret float [[R]]
 ;
   %i = bitcast float %x to i32
@@ -1548,9 +1546,8 @@ define float @copysign1(float %x) {
 
 define <2 x float> @copysign2(<2 x float> %x) {
 ; CHECK-LABEL: @copysign2(
-; CHECK-NEXT:    [[I:%.*]] = bitcast <2 x float> [[X:%.*]] to <2 x i32>
-; CHECK-NEXT:    [[ISNEG:%.*]] = icmp slt <2 x i32> [[I]], zeroinitializer
-; CHECK-NEXT:    [[R:%.*]] = select nsz <2 x i1> [[ISNEG]], <2 x float> <float 4.200000e+01, float 4.200000e+01>, <2 x float> <float -4.200000e+01, float -4.200000e+01>
+; CHECK-NEXT:    [[TMP1:%.*]] = fneg nsz <2 x float> [[X:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = call nsz <2 x float> @llvm.copysign.v2f32(<2 x float> <float 4.200000e+01, float 4.200000e+01>, <2 x float> [[TMP1]])
 ; CHECK-NEXT:    ret <2 x float> [[R]]
 ;
   %i = bitcast <2 x float> %x to <2 x i32>
@@ -1561,9 +1558,8 @@ define <2 x float> @copysign2(<2 x float> %x) {
 
 define float @copysign3(float %x) {
 ; CHECK-LABEL: @copysign3(
-; CHECK-NEXT:    [[I:%.*]] = bitcast float [[X:%.*]] to i32
-; CHECK-NEXT:    [[ISPOS:%.*]] = icmp sgt i32 [[I]], -1
-; CHECK-NEXT:    [[R:%.*]] = select fast i1 [[ISPOS]], float -4.300000e+01, float 4.300000e+01
+; CHECK-NEXT:    [[TMP1:%.*]] = fneg fast float [[X:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = call fast float @llvm.copysign.f32(float 4.300000e+01, float [[TMP1]])
 ; CHECK-NEXT:    ret float [[R]]
 ;
   %i = bitcast float %x to i32
@@ -1572,6 +1568,8 @@ define float @copysign3(float %x) {
   ret float %r
 }
 
+; TODO: Allow undefs when matching vectors.
+
 define <2 x float> @copysign4(<2 x float> %x) {
 ; CHECK-LABEL: @copysign4(
 ; CHECK-NEXT:    [[I:%.*]] = bitcast <2 x float> [[X:%.*]] to <2 x i32>
@@ -1587,6 +1585,8 @@ define <2 x float> @copysign4(<2 x float> %x) {
 
 declare void @use1(i1)
 
+; Negative test
+
 define float @copysign_extra_use(float %x) {
 ; CHECK-LABEL: @copysign_extra_use(
 ; CHECK-NEXT:    [[I:%.*]] = bitcast float [[X:%.*]] to i32
@@ -1602,6 +1602,8 @@ define float @copysign_extra_use(float %x) {
   ret float %r
 }
 
+; Negative test
+
 define float @copysign_type_mismatch(double %x) {
 ; CHECK-LABEL: @copysign_type_mismatch(
 ; CHECK-NEXT:    [[I:%.*]] = bitcast double [[X:%.*]] to i64
@@ -1615,6 +1617,8 @@ define float @copysign_type_mismatch(double %x) {
   ret float %r
 }
 
+; Negative test
+
 define float @copysign_wrong_cmp(float %x) {
 ; CHECK-LABEL: @copysign_wrong_cmp(
 ; CHECK-NEXT:    [[I:%.*]] = bitcast float [[X:%.*]] to i32
@@ -1628,6 +1632,8 @@ define float @copysign_wrong_cmp(float %x) {
   ret float %r
 }
 
+; Negative test
+
 define float @copysign_wrong_const(float %x) {
 ; CHECK-LABEL: @copysign_wrong_const(
 ; CHECK-NEXT:    [[I:%.*]] = bitcast float [[X:%.*]] to i32


        


More information about the llvm-commits mailing list