[PATCH] D12096: [InstCombineAddSub opportunities]: More opportunities to factorize FAdd/FSub when unsafeAlgebra is present for Inst

Justin Bogner via llvm-commits llvm-commits at lists.llvm.org
Thu Aug 20 17:53:05 PDT 2015


Aditya Nandakumar <aditya_nandakumar at apple.com> writes:
> This change in signature for performFactorization is required.
> Previously it accepted Instruction and would extract the two operands to see
> if it could be factorized but now we try to factorize values across different
> instructions.
> Also the opcode and the operand order for factorization can change. For eg
> (a - b) + c -> a + (c - b) which would roughly translate to factorize(c , b,
> FSub).

My bad - I didn't notice the calls in performFactorizationAssociative.
This makes sense.

Aditya Nandakumar via llvm-commits <llvm-commits at lists.llvm.org> writes:
> +// If I is either FAdd or FSub, see if we can ...
> +// -> Transform (A op1 B) op2 C -> A op3 (B op4 C) if (B op C) factorizes
> +//    Eg. (A + X * C1) + X * C2 -> A + X * (C1 + C2)
> +// -> Transform A op1 (B op2 C) -> (A op3 B) op4 C) if (A op3 B) factorizes
> +//    Eg. (A + X * C1) - X * C2 -> A + X * (C1-C2)
> +// -> Transform ( A op1 B) op2 C -> (A op3 C) op4 B if (A op3 C) factorizes
> +//    Eg. (X * C1 - B) + X * C2 -> X * (C1 - C2) - B
> +// -> Transform A op1 (B op2 C) -> (A op3 C) op4 B
> +//    Eg. X * C1 - (B + X * C2) -> X * (C1 - C2) - B
> +// This method should only be called when unsafeAlgebra is set for the inst
> +Value *FAddCombine::performFactorizationAssociative(Instruction *I) {
> +  assert(I->hasUnsafeAlgebra() &&
> +         "This method can't be called without unsafe algebra");
> +  if (I->getOpcode() != Instruction::FAdd &&
> +      I->getOpcode() != Instruction::FSub)
> +    return nullptr;
> +  // TODO: Overly conservative?
> +  if (I->getNumUses() != 1)
> +    return nullptr;
> +
> +  BinaryOperator *Op0 = dyn_cast<BinaryOperator>(I->getOperand(0));
> +  BinaryOperator *Op1 = dyn_cast<BinaryOperator>(I->getOperand(1));
> +  {
> +    // (A op B) op C -> Simplify?

These extra {} scopes aren't doing anything anymore.

> +    if (Op0 && (Op0->getOpcode() == Instruction::FAdd ||
> +                Op0->getOpcode() == Instruction::FSub)) {
> +      unsigned FactorizeOpcode, FinalOpcode;
> +      Value *OpFactor0, *OpFactor1;
> +      bool IsOp0OpcodeAdd = (Op0->getOpcode() == Instruction::FAdd);
> +      bool IsIOpcodeAdd = (I->getOpcode() == Instruction::FAdd);
> +      Value *A = Op0->getOperand(0);
> +      Value *B = Op0->getOperand(1);
> +      Value *C = I->getOperand(1);
> +      // (a + b) + c -> a + ( b + c ) ?
> +      // (a + b) - c -> a + ( b - c ) ?
> +      if (IsOp0OpcodeAdd) {
> +        OpFactor0 = B;
> +        OpFactor1 = C;
> +        FactorizeOpcode = I->getOpcode();
> +        FinalOpcode = Instruction::FAdd;
> +      }
> +      // (a - b) + c -> a + (c - b) ?
> +      else if (!IsOp0OpcodeAdd && IsIOpcodeAdd) {
> +        OpFactor0 = C;
> +        OpFactor1 = B;
> +        FactorizeOpcode = Instruction::FSub;
> +        FinalOpcode = Instruction::FAdd;
> +      }
> +      // (a - b) - c -> a - (b + c) ?
> +      else {
> +        OpFactor0 = B;
> +        OpFactor1 = C;
> +        FactorizeOpcode = Instruction::FAdd;
> +        FinalOpcode = Instruction::FSub;
> +      }
> +      if (Value *V = performFactorization(OpFactor0, OpFactor1, FactorizeOpcode,
> +                                          I->getFastMathFlags())) {
> +        Value *NewV = (FinalOpcode == Instruction::FAdd) ? createFAdd(A, V)
> +                                                         : createFSub(A, V);
> +        FastMathFlags Flags;
> +        Flags.setUnsafeAlgebra();
> +        Flags &= I->getFastMathFlags();
> +        Instruction *NewI = cast<Instruction>(NewV);
> +        NewI->setFastMathFlags(Flags);
> +        return NewI;
> +      }
> +    }
> +  }
> +  {
> +    // Transform: "A op (B op C)" ==> "(A op B) op C" if "A op B" factorizes.
> +    if (Op1 && (Op1->getOpcode() == Instruction::FAdd ||
> +                Op1->getOpcode() == Instruction::FSub)) {
> +      unsigned FactorizeOpcode, FinalOpcode;
> +      bool IsOp1OpcodeAdd = (Op1->getOpcode() == Instruction::FAdd);
> +      bool IsIOpcodeAdd = (I->getOpcode() == Instruction::FAdd);
> +      Value *A = I->getOperand(0);
> +      Value *B = Op1->getOperand(0);
> +      Value *C = Op1->getOperand(1);
> +      // A + (B+C) -> (A + B) + C factorizes?
> +      if (IsIOpcodeAdd && IsOp1OpcodeAdd) {
> +        FactorizeOpcode = FinalOpcode = Instruction::FAdd;
> +      }
> +      // A + (B - C) -> (A + B) - C factorizes?
> +      if (IsIOpcodeAdd && !IsOp1OpcodeAdd) {
> +        FactorizeOpcode = Instruction::FAdd;
> +        FinalOpcode = Instruction::FSub;
> +      }
> +      // A - (B + C) -> (A - B) - C factorizes?
> +      if (!IsIOpcodeAdd && IsOp1OpcodeAdd) {
> +        FactorizeOpcode = FinalOpcode = Instruction::FSub;
> +      }
> +      // A - (B - C) -> (A - B) + C factorizes?
> +      if (!IsIOpcodeAdd && !IsOp1OpcodeAdd) {
> +        FactorizeOpcode = Instruction::FSub;
> +        FinalOpcode = Instruction::FAdd;
> +      }
> +      if (Value *V = performFactorization(A, B, FactorizeOpcode,
> +                                          I->getFastMathFlags())) {
> +        Value *NewV = (FinalOpcode == Instruction::FAdd) ? createFAdd(V, C)
> +                                                         : createFSub(V, C);
> +        FastMathFlags Flags;
> +        Flags.setUnsafeAlgebra();
> +        Flags &= I->getFastMathFlags();
> +        Instruction *NewI = cast<Instruction>(NewV);
> +        NewI->setFastMathFlags(Flags);
> +        return NewI;
> +      }
> +    }
> +  }
> +  {
> +    // We know that op1 and op2 can only be FAdd or FSub
> +    // (A op1 B) op2 C -> (A op2 C) op1 B factorizes?
> +    if (Op0 && (Op0->getOpcode() == Instruction::FAdd ||
> +                Op0->getOpcode() == Instruction::FSub)) {
> +      Value *A = Op0->getOperand(0);
> +      Value *B = Op0->getOperand(1);
> +      Value *C = I->getOperand(1);
> +      if (Value *V = performFactorization(A, C, I->getOpcode(),
> +                                          I->getFastMathFlags())) {
> +        Value *NewV = (Op0->getOpcode() == Instruction::FAdd)
> +                          ? createFAdd(V, B)
> +                          : createFSub(V, B);
> +        FastMathFlags Flags;
> +        Flags.setUnsafeAlgebra();
> +        Flags &= I->getFastMathFlags();
> +        Instruction *NewI = cast<Instruction>(NewV);
> +        NewI->setFastMathFlags(Flags);
> +        return NewI;
> +      }
> +    }
> +  }
> +  {
> +    // A op1 (B op2 C) -> (A op2 C) op1 B factorizes?
> +    if (Op1 && (Op1->getOpcode() == Instruction::FAdd ||
> +                Op1->getOpcode() == Instruction::FSub)) {
> +      Value *A = I->getOperand(0);
> +      Value *B = Op1->getOperand(0);
> +      Value *C = Op1->getOperand(1);
> +      unsigned FactorizeOpcode, FinalOpcode;
> +      bool IsOp1OpcodeAdd = (Op1->getOpcode() == Instruction::FAdd);
> +      bool IsIOpcodeAdd = (I->getOpcode() == Instruction::FAdd);
> +      // A + (B + C) -> (A + C) + B simplifies?
> +      // A + (B - C) -> (A - C) + B simplifies?
> +      if (IsIOpcodeAdd) {
> +        FactorizeOpcode = Op1->getOpcode();
> +        FinalOpcode = Instruction::FAdd;
> +      }
> +      // A - (B + C) -> (A - C) - B
> +      else if (IsOp1OpcodeAdd) {
> +        FactorizeOpcode = FinalOpcode = Instruction::FSub;
> +      } else {
> +        // A - (B - C) -> (A + C) - B
> +        FactorizeOpcode = Instruction::FAdd;
> +        FinalOpcode = Instruction::FSub;
> +      }
> +      if (Value *V = performFactorization(A, C, FactorizeOpcode,
> +                                          I->getFastMathFlags())) {
> +        Value *NewV = (FinalOpcode == Instruction::FAdd) ? createFAdd(V, B)
> +                                                         : createFSub(V, B);
> +        FastMathFlags Flags;
> +        Flags.setUnsafeAlgebra();
> +        Flags &= I->getFastMathFlags();
> +        Instruction *NewI = cast<Instruction>(NewV);
> +        NewI->setFastMathFlags(Flags);
> +        return NewI;
> +      }
> +    }
> +  }
> +  return nullptr;
> +}


More information about the llvm-commits mailing list