Skip to content

Commit 56ca5ec

Browse files
committed
[InstCombine] Optimize powi(X, Y)/ (X * Z) with Ofast
foldFDivPowDivisor can address A / powi(x, y) to A * powi(x, -y), while for small const value y, for example y=2, the instcombine will transform powi(x, 2) to fmul x, x, so it is not optimal for A / powi(x, 2). Fix #77171
1 parent cb7cb83 commit 56ca5ec

File tree

2 files changed

+152
-17
lines changed

2 files changed

+152
-17
lines changed

llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp

Lines changed: 37 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -576,9 +576,10 @@ Instruction *InstCombinerImpl::foldPowiReassoc(BinaryOperator &I) {
576576
Value *Y, Value *Z) {
577577
InstCombiner::BuilderTy &Builder = IC.Builder;
578578
Value *YZ = Builder.CreateAdd(Y, Z);
579-
auto *NewPow = Builder.CreateIntrinsic(
579+
Instruction *NewPow = Builder.CreateIntrinsic(
580580
Intrinsic::powi, {X->getType(), YZ->getType()}, {X, YZ}, &I);
581-
return IC.replaceInstUsesWith(I, NewPow);
581+
582+
return NewPow;
582583
};
583584

584585
Value *X, *Y, *Z;
@@ -592,8 +593,10 @@ Instruction *InstCombinerImpl::foldPowiReassoc(BinaryOperator &I) {
592593
m_Value(X), m_Value(Y)))),
593594
m_Deferred(X)))) {
594595
Constant *One = ConstantInt::get(Y->getType(), 1);
595-
if (willNotOverflowSignedAdd(Y, One, I))
596-
return createPowiExpr(I, *this, X, Y, One);
596+
if (willNotOverflowSignedAdd(Y, One, I)) {
597+
Instruction *NewPow = createPowiExpr(I, *this, X, Y, One);
598+
return replaceInstUsesWith(I, NewPow);
599+
}
597600
}
598601

599602
// powi(x, y) * powi(x, z) -> powi(x, y + z)
@@ -604,19 +607,36 @@ Instruction *InstCombinerImpl::foldPowiReassoc(BinaryOperator &I) {
604607
m_Intrinsic<Intrinsic::powi>(m_Value(X), m_Value(Y)))) &&
605608
match(Op1, m_AllowReassoc(m_Intrinsic<Intrinsic::powi>(m_Specific(X),
606609
m_Value(Z)))) &&
607-
Y->getType() == Z->getType())
608-
return createPowiExpr(I, *this, X, Y, Z);
609-
610-
// powi(X, Y) / X --> powi(X, Y-1)
611-
// This is legal when (Y - 1) can't wraparound, in which case reassoc and nnan
612-
// are required.
613-
// TODO: Multi-use may be also better off creating Powi(x,y-1)
614-
if (Opcode == Instruction::FDiv && I.hasAllowReassoc() && I.hasNoNaNs() &&
615-
match(Op0, m_OneUse(m_AllowReassoc(m_Intrinsic<Intrinsic::powi>(
616-
m_Specific(Op1), m_Value(Y))))) &&
617-
willNotOverflowSignedSub(Y, ConstantInt::get(Y->getType(), 1), I)) {
618-
Constant *NegOne = ConstantInt::getAllOnesValue(Y->getType());
619-
return createPowiExpr(I, *this, Op1, Y, NegOne);
610+
Y->getType() == Z->getType()) {
611+
Instruction *NewPow = createPowiExpr(I, *this, X, Y, Z);
612+
return replaceInstUsesWith(I, NewPow);
613+
}
614+
615+
if (Opcode == Instruction::FDiv && I.hasAllowReassoc() && I.hasNoNaNs()) {
616+
// powi(X, Y) / X --> powi(X, Y-1)
617+
// This is legal when (Y - 1) can't wraparound, in which case reassoc and
618+
// nnan are required.
619+
// TODO: Multi-use may be also better off creating Powi(x,y-1)
620+
if (match(Op0, m_OneUse(m_AllowReassoc(m_Intrinsic<Intrinsic::powi>(
621+
m_Specific(Op1), m_Value(Y))))) &&
622+
willNotOverflowSignedSub(Y, ConstantInt::get(Y->getType(), 1), I)) {
623+
Constant *NegOne = ConstantInt::getAllOnesValue(Y->getType());
624+
Instruction *NewPow = createPowiExpr(I, *this, Op1, Y, NegOne);
625+
return replaceInstUsesWith(I, NewPow);
626+
}
627+
628+
// powi(X, Y) / (X * Z) --> powi(X, Y-1) / Z
629+
// This is legal when (Y - 1) can't wraparound, in which case reassoc and
630+
// nnan are required.
631+
// TODO: Multi-use may be also better off creating Powi(x,y-1)
632+
if (match(Op0, m_OneUse(m_AllowReassoc(m_Intrinsic<Intrinsic::powi>(
633+
m_Value(X), m_Value(Y))))) &&
634+
match(Op1, m_AllowReassoc(m_c_FMul(m_Specific(X), m_Value(Z)))) &&
635+
willNotOverflowSignedSub(Y, ConstantInt::get(Y->getType(), 1), I)) {
636+
Constant *NegOne = ConstantInt::getAllOnesValue(Y->getType());
637+
auto *NewPow = createPowiExpr(I, *this, X, Y, NegOne);
638+
return BinaryOperator::CreateFDivFMF(NewPow, Z, &I);
639+
}
620640
}
621641

622642
return nullptr;

llvm/test/Transforms/InstCombine/powi.ll

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -401,6 +401,121 @@ define double @fdiv_pow_powi_negative_variable(double %x, i32 %y) {
401401
ret double %div
402402
}
403403

404+
; powi(X,C1)/ (X * Z) --> powi(X,C1 - 1)/ Z
405+
define double @fdiv_fmul_powi(double %a, double %z) {
406+
; CHECK-LABEL: @fdiv_fmul_powi(
407+
; CHECK-NEXT: [[TMP1:%.*]] = call reassoc nnan double @llvm.powi.f64.i32(double [[A:%.*]], i32 4)
408+
; CHECK-NEXT: [[DIV:%.*]] = fdiv reassoc nnan double [[TMP1]], [[Z:%.*]]
409+
; CHECK-NEXT: ret double [[DIV]]
410+
;
411+
%pow = call reassoc double @llvm.powi.f64.i32(double %a, i32 5)
412+
%square = fmul reassoc double %z, %a
413+
%div = fdiv reassoc nnan double %pow, %square
414+
ret double %div
415+
}
416+
417+
; powi(X, 5)/ (X * X) --> powi(X, 4)/ X -> powi(X, 3)
418+
define double @fdiv_fmul_powi_2(double %a) {
419+
; CHECK-LABEL: @fdiv_fmul_powi_2(
420+
; CHECK-NEXT: [[DIV:%.*]] = call reassoc nnan double @llvm.powi.f64.i32(double [[A:%.*]], i32 3)
421+
; CHECK-NEXT: ret double [[DIV]]
422+
;
423+
%pow = call reassoc double @llvm.powi.f64.i32(double %a, i32 5)
424+
%square = fmul reassoc double %a, %a
425+
%div = fdiv reassoc nnan double %pow, %square
426+
ret double %div
427+
}
428+
429+
define <2 x float> @fdiv_fmul_powi_vector(<2 x float> %a) {
430+
; CHECK-LABEL: @fdiv_fmul_powi_vector(
431+
; CHECK-NEXT: [[DIV:%.*]] = call reassoc nnan <2 x float> @llvm.powi.v2f32.i32(<2 x float> [[A:%.*]], i32 3)
432+
; CHECK-NEXT: ret <2 x float> [[DIV]]
433+
;
434+
%pow = call reassoc <2 x float> @llvm.powi.v2f32.i32(<2 x float> %a, i32 5)
435+
%square = fmul reassoc <2 x float> %a, %a
436+
%div = fdiv reassoc nnan <2 x float> %pow, %square
437+
ret <2 x float> %div
438+
}
439+
440+
; Negative test
441+
define double @fdiv_fmul_powi_missing_reassoc1(double %a) {
442+
; CHECK-LABEL: @fdiv_fmul_powi_missing_reassoc1(
443+
; CHECK-NEXT: [[POW:%.*]] = call reassoc double @llvm.powi.f64.i32(double [[A:%.*]], i32 5)
444+
; CHECK-NEXT: [[SQUARE:%.*]] = fmul reassoc double [[A]], [[A]]
445+
; CHECK-NEXT: [[DIV:%.*]] = fdiv nnan double [[POW]], [[SQUARE]]
446+
; CHECK-NEXT: ret double [[DIV]]
447+
;
448+
%pow = call reassoc double @llvm.powi.f64.i32(double %a, i32 5)
449+
%square = fmul reassoc double %a, %a
450+
%div = fdiv nnan double %pow, %square
451+
ret double %div
452+
}
453+
454+
define double @fdiv_fmul_powi_missing_reassoc2(double %a) {
455+
; CHECK-LABEL: @fdiv_fmul_powi_missing_reassoc2(
456+
; CHECK-NEXT: [[POW:%.*]] = call reassoc double @llvm.powi.f64.i32(double [[A:%.*]], i32 5)
457+
; CHECK-NEXT: [[SQUARE:%.*]] = fmul double [[A]], [[A]]
458+
; CHECK-NEXT: [[DIV:%.*]] = fdiv reassoc nnan double [[POW]], [[SQUARE]]
459+
; CHECK-NEXT: ret double [[DIV]]
460+
;
461+
%pow = call reassoc double @llvm.powi.f64.i32(double %a, i32 5)
462+
%square = fmul double %a, %a
463+
%div = fdiv reassoc nnan double %pow, %square
464+
ret double %div
465+
}
466+
467+
define double @fdiv_fmul_powi_missing_reassoc3(double %a) {
468+
; CHECK-LABEL: @fdiv_fmul_powi_missing_reassoc3(
469+
; CHECK-NEXT: [[POW:%.*]] = call double @llvm.powi.f64.i32(double [[A:%.*]], i32 5)
470+
; CHECK-NEXT: [[SQUARE:%.*]] = fmul reassoc double [[A]], [[A]]
471+
; CHECK-NEXT: [[DIV:%.*]] = fdiv reassoc nnan double [[POW]], [[SQUARE]]
472+
; CHECK-NEXT: ret double [[DIV]]
473+
;
474+
%pow = call double @llvm.powi.f64.i32(double %a, i32 5)
475+
%square = fmul reassoc double %a, %a
476+
%div = fdiv reassoc nnan double %pow, %square
477+
ret double %div
478+
}
479+
480+
define double @fdiv_fmul_powi_missing_nnan(double %a) {
481+
; CHECK-LABEL: @fdiv_fmul_powi_missing_nnan(
482+
; CHECK-NEXT: [[POW:%.*]] = call reassoc double @llvm.powi.f64.i32(double [[A:%.*]], i32 5)
483+
; CHECK-NEXT: [[SQUARE:%.*]] = fmul reassoc double [[A]], [[A]]
484+
; CHECK-NEXT: [[DIV:%.*]] = fdiv reassoc double [[POW]], [[SQUARE]]
485+
; CHECK-NEXT: ret double [[DIV]]
486+
;
487+
%pow = call reassoc double @llvm.powi.f64.i32(double %a, i32 5)
488+
%square = fmul reassoc double %a, %a
489+
%div = fdiv reassoc double %pow, %square
490+
ret double %div
491+
}
492+
493+
define double @fdiv_fmul_powi_negative_wrap(double noundef %x) {
494+
; CHECK-LABEL: @fdiv_fmul_powi_negative_wrap(
495+
; CHECK-NEXT: [[P1:%.*]] = tail call double @llvm.powi.f64.i32(double [[X:%.*]], i32 -2147483648)
496+
; CHECK-NEXT: [[MUL:%.*]] = fmul reassoc double [[P1]], [[X]]
497+
; CHECK-NEXT: ret double [[MUL]]
498+
;
499+
%p1 = tail call double @llvm.powi.f64.i32(double %x, i32 -2147483648) ; INT_MIN
500+
%mul = fmul reassoc double %p1, %x
501+
ret double %mul
502+
}
503+
504+
define double @fdiv_fmul_powi_multi_use(double %a) {
505+
; CHECK-LABEL: @fdiv_fmul_powi_multi_use(
506+
; CHECK-NEXT: [[POW:%.*]] = call reassoc double @llvm.powi.f64.i32(double [[A:%.*]], i32 5)
507+
; CHECK-NEXT: tail call void @use(double [[POW]])
508+
; CHECK-NEXT: [[SQUARE:%.*]] = fmul reassoc double [[A]], [[A]]
509+
; CHECK-NEXT: [[DIV:%.*]] = fdiv reassoc nnan double [[POW]], [[SQUARE]]
510+
; CHECK-NEXT: ret double [[DIV]]
511+
;
512+
%pow = call reassoc double @llvm.powi.f64.i32(double %a, i32 5)
513+
tail call void @use(double %pow)
514+
%square = fmul reassoc double %a, %a
515+
%div = fdiv reassoc nnan double %pow, %square
516+
ret double %div
517+
}
518+
404519
; powi(X, Y) * X --> powi(X, Y+1)
405520
define double @powi_fmul_powi_x(double noundef %x) {
406521
; CHECK-LABEL: @powi_fmul_powi_x(

0 commit comments

Comments
 (0)