[InstCombine] Optimise x / sqrt(y / z) with fast-math pattern. (#76737)

Replace the pattern with
x * sqrt(z/y)

---------

Co-authored-by: Matt Arsenault <arsenm2@gmail.com>
This commit is contained in:
Zain Jaffal 2024-02-09 17:24:41 +00:00 committed by GitHub
parent 2884d04839
commit bb5c3899d1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 39 additions and 9 deletions

View File

@ -1709,6 +1709,33 @@ static Instruction *foldFDivPowDivisor(BinaryOperator &I,
return BinaryOperator::CreateFMulFMF(Op0, Pow, &I);
}
/// Convert div to mul if we have an sqrt divisor iff sqrt's operand is a fdiv
/// instruction.
static Instruction *foldFDivSqrtDivisor(BinaryOperator &I,
InstCombiner::BuilderTy &Builder) {
// X / sqrt(Y / Z) --> X * sqrt(Z / Y)
if (!I.hasAllowReassoc() || !I.hasAllowReciprocal())
return nullptr;
Value *Op0 = I.getOperand(0), *Op1 = I.getOperand(1);
auto *II = dyn_cast<IntrinsicInst>(Op1);
if (!II || II->getIntrinsicID() != Intrinsic::sqrt || !II->hasOneUse() ||
!II->hasAllowReassoc() || !II->hasAllowReciprocal())
return nullptr;
Value *Y, *Z;
auto *DivOp = dyn_cast<Instruction>(II->getOperand(0));
if (!DivOp || !DivOp->hasAllowReassoc() || !I.hasAllowReciprocal() ||
!DivOp->hasOneUse())
return nullptr;
if (match(DivOp, m_FDiv(m_Value(Y), m_Value(Z)))) {
Value *SwapDiv = Builder.CreateFDivFMF(Z, Y, DivOp);
Value *NewSqrt =
Builder.CreateUnaryIntrinsic(II->getIntrinsicID(), SwapDiv, II);
return BinaryOperator::CreateFMulFMF(Op0, NewSqrt, &I);
}
return nullptr;
}
Instruction *InstCombinerImpl::visitFDiv(BinaryOperator &I) {
Module *M = I.getModule();
@ -1816,6 +1843,9 @@ Instruction *InstCombinerImpl::visitFDiv(BinaryOperator &I) {
if (Instruction *Mul = foldFDivPowDivisor(I, Builder))
return Mul;
if (Instruction *Mul = foldFDivSqrtDivisor(I, Builder))
return Mul;
// pow(X, Y) / X --> pow(X, Y-1)
if (I.hasAllowReassoc() &&
match(Op0, m_OneUse(m_Intrinsic<Intrinsic::pow>(m_Specific(Op1),

View File

@ -6,9 +6,9 @@ declare double @llvm.sqrt.f64(double)
define double @sqrt_div_fast(double %x, double %y, double %z) {
; CHECK-LABEL: @sqrt_div_fast(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[DIV:%.*]] = fdiv fast double [[Y:%.*]], [[Z:%.*]]
; CHECK-NEXT: [[SQRT:%.*]] = call fast double @llvm.sqrt.f64(double [[DIV]])
; CHECK-NEXT: [[DIV1:%.*]] = fdiv fast double [[X:%.*]], [[SQRT]]
; CHECK-NEXT: [[TMP0:%.*]] = fdiv fast double [[Z:%.*]], [[Y:%.*]]
; CHECK-NEXT: [[TMP1:%.*]] = call fast double @llvm.sqrt.f64(double [[TMP0]])
; CHECK-NEXT: [[DIV1:%.*]] = fmul fast double [[TMP1]], [[X:%.*]]
; CHECK-NEXT: ret double [[DIV1]]
;
entry:
@ -36,9 +36,9 @@ entry:
define double @sqrt_div_reassoc_arcp(double %x, double %y, double %z) {
; CHECK-LABEL: @sqrt_div_reassoc_arcp(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[DIV:%.*]] = fdiv reassoc arcp double [[Y:%.*]], [[Z:%.*]]
; CHECK-NEXT: [[SQRT:%.*]] = call reassoc arcp double @llvm.sqrt.f64(double [[DIV]])
; CHECK-NEXT: [[DIV1:%.*]] = fdiv reassoc arcp double [[X:%.*]], [[SQRT]]
; CHECK-NEXT: [[TMP0:%.*]] = fdiv reassoc arcp double [[Z:%.*]], [[Y:%.*]]
; CHECK-NEXT: [[TMP1:%.*]] = call reassoc arcp double @llvm.sqrt.f64(double [[TMP0]])
; CHECK-NEXT: [[DIV1:%.*]] = fmul reassoc arcp double [[TMP1]], [[X:%.*]]
; CHECK-NEXT: ret double [[DIV1]]
;
entry:
@ -96,9 +96,9 @@ entry:
define double @sqrt_div_arcp_missing(double %x, double %y, double %z) {
; CHECK-LABEL: @sqrt_div_arcp_missing(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[DIV:%.*]] = fdiv reassoc double [[Y:%.*]], [[Z:%.*]]
; CHECK-NEXT: [[SQRT:%.*]] = call reassoc arcp double @llvm.sqrt.f64(double [[DIV]])
; CHECK-NEXT: [[DIV1:%.*]] = fdiv reassoc arcp double [[X:%.*]], [[SQRT]]
; CHECK-NEXT: [[TMP0:%.*]] = fdiv reassoc double [[Z:%.*]], [[Y:%.*]]
; CHECK-NEXT: [[TMP1:%.*]] = call reassoc arcp double @llvm.sqrt.f64(double [[TMP0]])
; CHECK-NEXT: [[DIV1:%.*]] = fmul reassoc arcp double [[TMP1]], [[X:%.*]]
; CHECK-NEXT: ret double [[DIV1]]
;
entry: