[llvm-commits] Patch: Floating point optimizations for SimplifyInstruction

Duncan Sands baldrick at free.fr
Fri Dec 7 08:42:37 PST 2012


Hi Michael,

On 06/12/12 01:34, Michael Ilseman wrote:
> Here's a second round of patches, incorporating the review feedback Duncan had given me earlier but I had spaced. The biggest difference is an extension to PatternMatch.h for pattern matching ConstantFP values of interest.
>
> Patch1: Pattern matching for more floating point values: -0, +/-0, 1.0, and ConstantFPs
>
> Patch2: Added a slew of SimplifyInstruction floating-point optimizations, many of which take advantage of fast-math flags. Test cases included.
>    fsub X, 0 ==> X
>    fsub 0, (fsub 0, X) ==> X
>    fsub X, -0 ==> X
>      when X is known non-negative-zero, e.g. the fsub is nsz.
>    fsub nnan ninf x, x ==> 0.0
>    fadd X, -0 ==> X
>    fadd X, 0 ==> X
>      when X is known non-negative-zero, e.g. the fadd is nsz.
>    fadd [nnan ninf] X, (fsub [nnan ninf] 0, X) ==> 0
>      where nnan and ninf have to occur at least once somewhere in this expression
>    fmul X, 1.0 ==> X


> --- a/lib/Analysis/InstructionSimplify.cpp
> +++ b/lib/Analysis/InstructionSimplify.cpp
> @@ -887,6 +887,82 @@ Value *llvm::SimplifySubInst(Value *Op0, Value *Op1, bool isNSW, bool isNUW,
>                             RecursionLimit);
>  }
>
> +/// Given operands for an FAdd, see if we can fold the result.  If not, this
> +/// returns null.
> +static Value *SimplifyFAddInst(Value *Op0, Value *Op1, FastMathFlags FMF,
> +                              const Query &Q, unsigned MaxRecurse) {
> +  if (Constant *CLHS = dyn_cast<Constant>(Op0)) {
> +    if (Constant *CRHS = dyn_cast<Constant>(Op1)) {
> +      Constant *Ops[] = { CLHS, CRHS };
> +      return ConstantFoldInstOperands(Instruction::FAdd, CLHS->getType(),
> +                                      Ops, Q.TD, Q.TLI);
> +    }
> +
> +    // Canonicalize the constant to the RHS.
> +    std::swap(Op0, Op1);
> +  }
> +
> +  // fadd X, -0 ==> X
> +  if (match(Op1, m_NegZero()))
> +    return Op0;
> +
> +  // fadd X, 0 ==> X, when we know X is not -0
> +  if (match(Op1, m_Zero()) &&
> +      (FMF.NoSignedZeros || CannotBeNegativeZero(Op0)))
> +    return Op0;
> +
> +  // fadd [nnan ninf] X, (fsub [nnan ninf] 0, X) ==> 0
> +  //   where nnan and ninf have to occur at least once somewhere in this
> +  //   expression
> +  Value *X = 0;

(Bike shed) You don't need to initialize X.  Actually you don't need X at all
(see next comment).

> +  Value *SubOp = 0;
> +  if (match(Op1, m_FSub(m_AnyZero(), m_Value(X))) && X == Op0)

Rather than
   m_Value(X))) && X == Op0
you can do
   m_Specific(Op0)
Same comment applies below too.

> +    SubOp = Op1;
> +  else if (match(Op0, m_FSub(m_AnyZero(), m_Value(X))) && X == Op1)
> +    SubOp = Op0;
> +  if (SubOp) {
> +    Instruction *FSub = cast<Instruction>(SubOp);
> +    if ((FMF.NoNaNs || FSub->hasNoNaNs()) &&
> +        (FMF.NoInfs || FSub->hasNoInfs()))
> +      return Constant::getNullValue(Op0->getType());
> +  }
> +
> +  return 0;
> +}
> +
> +/// Given operands for an FSub, see if we can fold the result.  If not, this
> +/// returns null.
> +static Value *SimplifyFSubInst(Value *Op0, Value *Op1, FastMathFlags FMF,
> +                              const Query &Q, unsigned MaxRecurse) {
> +  if (Constant *CLHS = dyn_cast<Constant>(Op0)) {
> +    if (Constant *CRHS = dyn_cast<Constant>(Op1)) {
> +      Constant *Ops[] = { CLHS, CRHS };
> +      return ConstantFoldInstOperands(Instruction::FSub, CLHS->getType(),
> +                                      Ops, Q.TD, Q.TLI);
> +    }
> +  }
> +
> +  // fsub X, 0 ==> X
> +  if (match(Op1, m_Zero()))
> +    return Op0;
> +
> +  // fsub X, -0 ==> X, when we know X is not -0
> +  if (match(Op1, m_NegZero()) &&
> +      (FMF.NoSignedZeros || CannotBeNegativeZero(Op0)))
> +    return Op0;
> +
> +  // fsub 0, (fsub 0, X) ==> X
> +  Value *X = 0;
> +  if (match(Op0, m_Zero()) && match(Op1, m_FSub(m_Zero(), m_Value(X))))
> +    return X;

Does this also work for -0.0?  With fast-math it should work with mixes
of +0.0 and -0.0 too.


> --- a/include/llvm/Support/PatternMatch.h
> +++ b/include/llvm/Support/PatternMatch.h
> @@ -87,8 +87,36 @@ struct match_zero {
>  /// m_Zero() - Match an arbitrary zero/null constant.  This includes
>  /// zero_initializer for vectors and ConstantPointerNull for pointers.
>  inline match_zero m_Zero() { return match_zero(); }
> -
> -
> +
> +struct match_neg_zero {
> +  template<typename ITy>
> +  bool match(ITy *V) {
> +    if (const Constant *C = dyn_cast<Constant>(V))
> +      return C->isNegativeZeroValue();
> +    return false;
> +  }
> +};
> +
> +/// m_NegZero() - Match an arbitrary zero/null constant.  This includes
> +/// zero_initializer for vectors and ConstantPointerNull for pointers. For
> +/// floating point constants, this will match negative zero but not positive
> +/// zero
> +inline match_neg_zero m_NegZero() { return match_neg_zero(); }
> +
> +struct match_any_zero {
> +  template<typename ITy>
> +  bool match(ITy *V) {
> +    if (const Constant *C = dyn_cast<Constant>(V))
> +      return C->isNullValue() || C->isNegativeZeroValue();
> +    return false;
> +  }
> +};
> +
> +/// m_AnyZero() - Match an arbitrary zero/null constant.  This includes
> +/// zero_initializer for vectors and ConstantPointerNull for pointers. For
> +/// floating point constants, this will match negative zero and positive zero
> +inline match_any_zero m_AnyZero() { return match_any_zero(); }
> +

While I think m_AnyZero is OK as it is, it could probably have been implemented
as some kind of m_Or(m_Zero(...), m_NegZero(...)) thing.

>  struct apint_match {
>    const APInt *&Res;
>    apint_match(const APInt *&R) : Res(R) {}
> @@ -161,7 +189,27 @@ struct cst_pred_ty : public Predicate {
>      return false;
>    }
>  };
> -
> +
> +/// cst_fp_pred_ty - This helper class is used to match scalar and vector
> +/// floating point constants that satisfy a specified predicate.
> +template<typename Predicate>
> +struct cst_fp_pred_ty : public Predicate {
> +  template<typename ITy>
> +  bool match(ITy *V) {
> +    if (const ConstantFP *CFP = dyn_cast<ConstantFP>(V))
> +      return this->isValue(CFP->getValueAPF());
> +    // FIXME: Remove this.

Remove this?

> +    if (const ConstantVector *CV = dyn_cast<ConstantVector>(V))
> +      if (ConstantFP *CFP = dyn_cast_or_null<ConstantFP>(CV->getSplatValue()))
> +        return this->isValue(CFP->getValueAPF());
> +    if (const ConstantDataVector *CV = dyn_cast<ConstantDataVector>(V))
> +      if (ConstantFP *CFP = dyn_cast_or_null<ConstantFP>(CV->getSplatValue()))
> +        return this->isValue(CFP->getValueAPF());
> +    return false;
> +  }
> +};
> +
> +
>  /// api_pred_ty - This helper class is used to match scalar and vector constants
>  /// that satisfy a specified predicate, and bind them to an APInt.
>  template<typename Predicate>
> @@ -198,12 +246,22 @@ struct api_pred_ty : public Predicate {
>
>  struct is_one {
>    bool isValue(const APInt &C) { return C == 1; }
> +  bool isValue(const APFloat &C) {
> +    bool ignored;
> +    APFloat F(1.0);
> +    F.convert(C.getSemantics(), APFloat::rmNearestTiesToEven, &ignored);
> +    return C.bitwiseIsEqual(F);
> +  }

This seems to be doing some heavy operations, is there no cheaper trick?

Otherwise LGTM.

Ciao, Duncan.



More information about the llvm-commits mailing list