Commit f7f5d348 authored by Matt Arsenault's avatar Matt Arsenault
Browse files

InstCombine: Fold fneg (ldexp x, n) -> ldexp (fneg x), n

parent 5e6a2044
Loading
Loading
Loading
Loading
+29 −11
Original line number Diff line number Diff line
@@ -2557,17 +2557,35 @@ static Instruction *foldFNegIntoConstant(Instruction &I, const DataLayout &DL) {
  return nullptr;
}

static Instruction *hoistFNegAboveFMulFDiv(Value *FNegOp,
                                           Instruction &FMFSource,
                                           InstCombiner::BuilderTy &Builder) {
Instruction *InstCombinerImpl::hoistFNegAboveFMulFDiv(Value *FNegOp,
                                                      Instruction &FMFSource) {
  Value *X, *Y;
  if (match(FNegOp, m_FMul(m_Value(X), m_Value(Y))))
    return BinaryOperator::CreateFMulFMF(Builder.CreateFNegFMF(X, &FMFSource),
                                         Y, &FMFSource);
  if (match(FNegOp, m_FMul(m_Value(X), m_Value(Y)))) {
    return cast<Instruction>(Builder.CreateFMulFMF(
        Builder.CreateFNegFMF(X, &FMFSource), Y, &FMFSource));
  }

  if (match(FNegOp, m_FDiv(m_Value(X), m_Value(Y)))) {
    return cast<Instruction>(Builder.CreateFDivFMF(
        Builder.CreateFNegFMF(X, &FMFSource), Y, &FMFSource));
  }

  if (match(FNegOp, m_FDiv(m_Value(X), m_Value(Y))))
    return BinaryOperator::CreateFDivFMF(Builder.CreateFNegFMF(X, &FMFSource),
                                         Y, &FMFSource);
  if (IntrinsicInst *II = dyn_cast<IntrinsicInst>(FNegOp)) {
    // Make sure to preserve flags and metadata on the call.
    if (II->getIntrinsicID() == Intrinsic::ldexp) {
      FastMathFlags FMF = FMFSource.getFastMathFlags();
      FMF |= II->getFastMathFlags();

      IRBuilder<>::FastMathFlagGuard FMFGuard(Builder);
      Builder.setFastMathFlags(FMF);

      CallInst *New = Builder.CreateCall(
          II->getCalledFunction(),
          {Builder.CreateFNeg(II->getArgOperand(0)), II->getArgOperand(1)});
      New->copyMetadata(*II);
      return New;
    }
  }

  return nullptr;
}
@@ -2593,8 +2611,8 @@ Instruction *InstCombinerImpl::visitFNeg(UnaryOperator &I) {
  if (!match(Op, m_OneUse(m_Value(OneUse))))
    return nullptr;

  if (Instruction *R = hoistFNegAboveFMulFDiv(OneUse, I, Builder))
    return R;
  if (Instruction *R = hoistFNegAboveFMulFDiv(OneUse, I))
    return replaceInstUsesWith(I, R);

  // Try to eliminate fneg if at least 1 arm of the select is negated.
  Value *Cond;
+2 −0
Original line number Diff line number Diff line
@@ -392,6 +392,8 @@ private:
  Instruction *foldAndOrOfSelectUsingImpliedCond(Value *Op, SelectInst &SI,
                                                 bool IsAnd);

  Instruction *hoistFNegAboveFMulFDiv(Value *FNegOp, Instruction &FMFSource);

public:
  /// Create and insert the idiom we use to indicate a block is unreachable
  /// without having to rewrite the CFG from within InstCombine.
+24 −24
Original line number Diff line number Diff line
@@ -834,8 +834,8 @@ define float @select_fneg_use3(float %x, float %y, i1 %b) {

define float @fneg_ldexp(float %x, i32 %n) {
; CHECK-LABEL: @fneg_ldexp(
; CHECK-NEXT:    [[LDEXP:%.*]] = call float @llvm.ldexp.f32.i32(float [[X:%.*]], i32 [[N:%.*]])
; CHECK-NEXT:    [[NEG:%.*]] = fneg float [[LDEXP]]
; CHECK-NEXT:    [[TMP1:%.*]] = fneg float [[X:%.*]]
; CHECK-NEXT:    [[NEG:%.*]] = call float @llvm.ldexp.f32.i32(float [[TMP1]], i32 [[N:%.*]])
; CHECK-NEXT:    ret float [[NEG]]
;
  %ldexp = call float @llvm.ldexp.f32.i32(float %x, i32 %n)
@@ -845,8 +845,8 @@ define float @fneg_ldexp(float %x, i32 %n) {

define float @fsub_fneg_ldexp(float %x, i32 %n) {
; CHECK-LABEL: @fsub_fneg_ldexp(
; CHECK-NEXT:    [[LDEXP:%.*]] = call float @llvm.ldexp.f32.i32(float [[X:%.*]], i32 [[N:%.*]])
; CHECK-NEXT:    [[NEG:%.*]] = fneg float [[LDEXP]]
; CHECK-NEXT:    [[TMP1:%.*]] = fneg float [[X:%.*]]
; CHECK-NEXT:    [[NEG:%.*]] = call float @llvm.ldexp.f32.i32(float [[TMP1]], i32 [[N:%.*]])
; CHECK-NEXT:    ret float [[NEG]]
;
  %ldexp = call float @llvm.ldexp.f32.i32(float %x, i32 %n)
@@ -856,8 +856,8 @@ define float @fsub_fneg_ldexp(float %x, i32 %n) {

define float @fsub_fneg_ldexp_nsz(float %x, i32 %n) {
; CHECK-LABEL: @fsub_fneg_ldexp_nsz(
; CHECK-NEXT:    [[LDEXP:%.*]] = call float @llvm.ldexp.f32.i32(float [[X:%.*]], i32 [[N:%.*]])
; CHECK-NEXT:    [[NEG:%.*]] = fneg nsz float [[LDEXP]]
; CHECK-NEXT:    [[TMP1:%.*]] = fneg nsz float [[X:%.*]]
; CHECK-NEXT:    [[NEG:%.*]] = call nsz float @llvm.ldexp.f32.i32(float [[TMP1]], i32 [[N:%.*]])
; CHECK-NEXT:    ret float [[NEG]]
;
  %ldexp = call float @llvm.ldexp.f32.i32(float %x, i32 %n)
@@ -867,8 +867,8 @@ define float @fsub_fneg_ldexp_nsz(float %x, i32 %n) {

define float @fsub_fneg_ldexp_p0_nsz(float %x, i32 %n) {
; CHECK-LABEL: @fsub_fneg_ldexp_p0_nsz(
; CHECK-NEXT:    [[LDEXP:%.*]] = call float @llvm.ldexp.f32.i32(float [[X:%.*]], i32 [[N:%.*]])
; CHECK-NEXT:    [[NEG:%.*]] = fneg nsz float [[LDEXP]]
; CHECK-NEXT:    [[TMP1:%.*]] = fneg nsz float [[X:%.*]]
; CHECK-NEXT:    [[NEG:%.*]] = call nsz float @llvm.ldexp.f32.i32(float [[TMP1]], i32 [[N:%.*]])
; CHECK-NEXT:    ret float [[NEG]]
;
  %ldexp = call float @llvm.ldexp.f32.i32(float %x, i32 %n)
@@ -889,8 +889,8 @@ define float @fsub_fneg_ldexp_p0(float %x, i32 %n) {

define <2 x float> @fneg_ldexp_vector(<2 x float> %x, <2 x i32> %n) {
; CHECK-LABEL: @fneg_ldexp_vector(
; CHECK-NEXT:    [[LDEXP:%.*]] = call <2 x float> @llvm.ldexp.v2f32.v2i32(<2 x float> [[X:%.*]], <2 x i32> [[N:%.*]])
; CHECK-NEXT:    [[NEG:%.*]] = fneg <2 x float> [[LDEXP]]
; CHECK-NEXT:    [[TMP1:%.*]] = fneg <2 x float> [[X:%.*]]
; CHECK-NEXT:    [[NEG:%.*]] = call <2 x float> @llvm.ldexp.v2f32.v2i32(<2 x float> [[TMP1]], <2 x i32> [[N:%.*]])
; CHECK-NEXT:    ret <2 x float> [[NEG]]
;
  %ldexp = call <2 x float> @llvm.ldexp.v2f32.v2i32(<2 x float> %x, <2 x i32> %n)
@@ -913,8 +913,8 @@ define float @fneg_ldexp_multiuse(float %x, i32 %n, ptr %ptr) {

define float @fneg_ldexp_fmf_ldexp(float %x, i32 %n) {
; CHECK-LABEL: @fneg_ldexp_fmf_ldexp(
; CHECK-NEXT:    [[LDEXP:%.*]] = call nnan float @llvm.ldexp.f32.i32(float [[X:%.*]], i32 [[N:%.*]])
; CHECK-NEXT:    [[NEG:%.*]] = fneg float [[LDEXP]]
; CHECK-NEXT:    [[TMP1:%.*]] = fneg nnan float [[X:%.*]]
; CHECK-NEXT:    [[NEG:%.*]] = call nnan float @llvm.ldexp.f32.i32(float [[TMP1]], i32 [[N:%.*]])
; CHECK-NEXT:    ret float [[NEG]]
;
  %ldexp = call nnan float @llvm.ldexp.f32.i32(float %x, i32 %n)
@@ -924,8 +924,8 @@ define float @fneg_ldexp_fmf_ldexp(float %x, i32 %n) {

define float @fneg_ldexp_fmf_neg(float %x, i32 %n) {
; CHECK-LABEL: @fneg_ldexp_fmf_neg(
; CHECK-NEXT:    [[LDEXP:%.*]] = call float @llvm.ldexp.f32.i32(float [[X:%.*]], i32 [[N:%.*]])
; CHECK-NEXT:    [[NEG:%.*]] = fneg nnan float [[LDEXP]]
; CHECK-NEXT:    [[TMP1:%.*]] = fneg nnan float [[X:%.*]]
; CHECK-NEXT:    [[NEG:%.*]] = call nnan float @llvm.ldexp.f32.i32(float [[TMP1]], i32 [[N:%.*]])
; CHECK-NEXT:    ret float [[NEG]]
;
  %ldexp = call float @llvm.ldexp.f32.i32(float %x, i32 %n)
@@ -935,8 +935,8 @@ define float @fneg_ldexp_fmf_neg(float %x, i32 %n) {

define float @fneg_ldexp_fmf(float %x, i32 %n) {
; CHECK-LABEL: @fneg_ldexp_fmf(
; CHECK-NEXT:    [[LDEXP:%.*]] = call ninf float @llvm.ldexp.f32.i32(float [[X:%.*]], i32 [[N:%.*]])
; CHECK-NEXT:    [[NEG:%.*]] = fneg nnan float [[LDEXP]]
; CHECK-NEXT:    [[TMP1:%.*]] = fneg nnan ninf float [[X:%.*]]
; CHECK-NEXT:    [[NEG:%.*]] = call nnan ninf float @llvm.ldexp.f32.i32(float [[TMP1]], i32 [[N:%.*]])
; CHECK-NEXT:    ret float [[NEG]]
;
  %ldexp = call ninf float @llvm.ldexp.f32.i32(float %x, i32 %n)
@@ -946,8 +946,8 @@ define float @fneg_ldexp_fmf(float %x, i32 %n) {

define float @fneg_ldexp_contract0(float %x, i32 %n) {
; CHECK-LABEL: @fneg_ldexp_contract0(
; CHECK-NEXT:    [[LDEXP:%.*]] = call contract float @llvm.ldexp.f32.i32(float [[X:%.*]], i32 [[N:%.*]])
; CHECK-NEXT:    [[NEG:%.*]] = fneg float [[LDEXP]]
; CHECK-NEXT:    [[TMP1:%.*]] = fneg contract float [[X:%.*]]
; CHECK-NEXT:    [[NEG:%.*]] = call contract float @llvm.ldexp.f32.i32(float [[TMP1]], i32 [[N:%.*]])
; CHECK-NEXT:    ret float [[NEG]]
;
  %ldexp = call contract float @llvm.ldexp.f32.i32(float %x, i32 %n)
@@ -957,8 +957,8 @@ define float @fneg_ldexp_contract0(float %x, i32 %n) {

define float @fneg_ldexp_contract1(float %x, i32 %n) {
; CHECK-LABEL: @fneg_ldexp_contract1(
; CHECK-NEXT:    [[LDEXP:%.*]] = call float @llvm.ldexp.f32.i32(float [[X:%.*]], i32 [[N:%.*]])
; CHECK-NEXT:    [[NEG:%.*]] = fneg contract float [[LDEXP]]
; CHECK-NEXT:    [[TMP1:%.*]] = fneg contract float [[X:%.*]]
; CHECK-NEXT:    [[NEG:%.*]] = call contract float @llvm.ldexp.f32.i32(float [[TMP1]], i32 [[N:%.*]])
; CHECK-NEXT:    ret float [[NEG]]
;
  %ldexp = call float @llvm.ldexp.f32.i32(float %x, i32 %n)
@@ -968,8 +968,8 @@ define float @fneg_ldexp_contract1(float %x, i32 %n) {

define float @fneg_ldexp_contract(float %x, i32 %n) {
; CHECK-LABEL: @fneg_ldexp_contract(
; CHECK-NEXT:    [[LDEXP:%.*]] = call contract float @llvm.ldexp.f32.i32(float [[X:%.*]], i32 [[N:%.*]])
; CHECK-NEXT:    [[NEG:%.*]] = fneg contract float [[LDEXP]]
; CHECK-NEXT:    [[TMP1:%.*]] = fneg contract float [[X:%.*]]
; CHECK-NEXT:    [[NEG:%.*]] = call contract float @llvm.ldexp.f32.i32(float [[TMP1]], i32 [[N:%.*]])
; CHECK-NEXT:    ret float [[NEG]]
;
  %ldexp = call contract float @llvm.ldexp.f32.i32(float %x, i32 %n)
@@ -979,8 +979,8 @@ define float @fneg_ldexp_contract(float %x, i32 %n) {

define float @fneg_ldexp_metadata(float %x, i32 %n) {
; CHECK-LABEL: @fneg_ldexp_metadata(
; CHECK-NEXT:    [[LDEXP:%.*]] = call float @llvm.ldexp.f32.i32(float [[X:%.*]], i32 [[N:%.*]]), !arst !0
; CHECK-NEXT:    [[NEG:%.*]] = fneg float [[LDEXP]]
; CHECK-NEXT:    [[TMP1:%.*]] = fneg float [[X:%.*]]
; CHECK-NEXT:    [[NEG:%.*]] = call float @llvm.ldexp.f32.i32(float [[TMP1]], i32 [[N:%.*]]), !arst !0
; CHECK-NEXT:    ret float [[NEG]]
;
  %ldexp = call float @llvm.ldexp.f32.i32(float %x, i32 %n), !arst !0