[llvm] [X86][SelectionDAG] - Extend dag combiner to handle pow(1.5f), pow(x,2/3f) (PR #214202)
Rohit Aggarwal via llvm-commits
llvm-commits at lists.llvm.org
Tue Aug 11 23:22:56 PDT 2026
https://github.com/rohitaggarwal007 updated https://github.com/llvm/llvm-project/pull/214202
>From 55942af10b8b14e57d2e52a489b2cc0f583271b8 Mon Sep 17 00:00:00 2001
From: Rohit Aggarwal <Rohit.Aggarwal at amd.com>
Date: Tue, 4 Aug 2026 18:34:06 +0530
Subject: [PATCH 1/3] [X86][SelectionDAG] - Extend dag combiner to handle
pow(x,0.25f), pow(1.5f), pow(x,2/3f)
Fold pow(X, 2/3) -> cbrt(X) * cbrt(X) and pow(X, 1.5) -> X * sqrt(X) in
addition to the existing cbrt and sqrt-based fractional exponent folds.
---
llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp | 26 +-
llvm/test/CodeGen/X86/pow-fold.ll | 239 ++++++++++++++++++
2 files changed, 259 insertions(+), 6 deletions(-)
create mode 100644 llvm/test/CodeGen/X86/pow-fold.ll
diff --git a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
index 418ef38daac29..978e92c1dbcfd 100644
--- a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
@@ -20329,10 +20329,15 @@ SDValue DAGCombiner::visitFPOW(SDNode *N) {
// Some range near 1/3 should be fine.
EVT VT = N->getValueType(0);
EVT ScalarVT = VT.getScalarType();
- if ((ScalarVT == MVT::f32 &&
- ExponentC->getValueAPF().isExactlyValue(1.0f / 3.0f)) ||
- (ScalarVT == MVT::f64 &&
- ExponentC->getValueAPF().isExactlyValue(1.0 / 3.0))) {
+ bool Exponent1by3 = (ScalarVT == MVT::f32 &&
+ ExponentC->getValueAPF().isExactlyValue(1.0f / 3.0f)) ||
+ (ScalarVT == MVT::f64 &&
+ ExponentC->getValueAPF().isExactlyValue(1.0 / 3.0));
+ bool Exponent2by3 = (ScalarVT == MVT::f32 &&
+ ExponentC->getValueAPF().isExactlyValue(2.0f / 3.0f)) ||
+ (ScalarVT == MVT::f64 &&
+ ExponentC->getValueAPF().isExactlyValue(2.0 / 3.0));
+ if (Exponent1by3 || Exponent2by3) {
// pow(-0.0, 1/3) = +0.0; cbrt(-0.0) = -0.0.
// pow(-inf, 1/3) = +inf; cbrt(-inf) = -inf.
// pow(-val, 1/3) = nan; cbrt(-val) = -num.
@@ -20354,7 +20359,12 @@ SDValue DAGCombiner::visitFPOW(SDNode *N) {
DAG.getTargetLoweringInfo().isOperationExpand(ISD::FCBRT, VT)))
return SDValue();
- return DAG.getNode(ISD::FCBRT, SDLoc(N), VT, N->getOperand(0));
+ SDLoc DL(N);
+ SDValue Cbrt = DAG.getNode(ISD::FCBRT, DL, VT, N->getOperand(0));
+ if (Exponent1by3)
+ return Cbrt;
+ // pow(X, 2/3) --> cbrt(X) * cbrt(X)
+ return DAG.getNode(ISD::FMUL, DL, VT, Cbrt, Cbrt);
}
// Try to convert x ** (1/4) and x ** (3/4) into square roots.
@@ -20363,7 +20373,8 @@ SDValue DAGCombiner::visitFPOW(SDNode *N) {
// power-of-2 fractional exponents.
bool ExponentIs025 = ExponentC->getValueAPF().isExactlyValue(0.25);
bool ExponentIs075 = ExponentC->getValueAPF().isExactlyValue(0.75);
- if (ExponentIs025 || ExponentIs075) {
+ bool ExponentIs150 = ExponentC->getValueAPF().isExactlyValue(1.50);
+ if (ExponentIs025 || ExponentIs075 || ExponentIs150) {
// pow(-0.0, 0.25) = +0.0; sqrt(sqrt(-0.0)) = -0.0.
// pow(-inf, 0.25) = +inf; sqrt(sqrt(-inf)) = NaN.
// pow(-0.0, 0.75) = +0.0; sqrt(-0.0) * sqrt(sqrt(-0.0)) = +0.0.
@@ -20390,6 +20401,9 @@ SDValue DAGCombiner::visitFPOW(SDNode *N) {
// pow(X, 0.25) --> sqrt(sqrt(X))
SDLoc DL(N);
SDValue Sqrt = DAG.getNode(ISD::FSQRT, DL, VT, N->getOperand(0));
+ // pow(X, 1.50) --> X * sqrt(X)
+ if (ExponentIs150)
+ return DAG.getNode(ISD::FMUL, DL, VT, N->getOperand(0), Sqrt);
SDValue SqrtSqrt = DAG.getNode(ISD::FSQRT, DL, VT, Sqrt);
if (ExponentIs025)
return SqrtSqrt;
diff --git a/llvm/test/CodeGen/X86/pow-fold.ll b/llvm/test/CodeGen/X86/pow-fold.ll
new file mode 100644
index 0000000000000..2bdac03d2b956
--- /dev/null
+++ b/llvm/test/CodeGen/X86/pow-fold.ll
@@ -0,0 +1,239 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: llc < %s -mtriple=x86_64-- -mcpu=x86-64 -mattr=+avx | FileCheck %s
+; RUN: FileCheck %s --check-prefix=IR < %s
+; RUN: opt -passes=instcombine -S %s | FileCheck %s --check-prefix=IR-OPT
+
+; Verify the fractional-exponent pow folds, including the cases added by this
+; change:
+; pow(X, 2/3) --> cbrt(X) * cbrt(X)
+; pow(X, 1.5) --> X * sqrt(X)
+; The pre-existing folds (1/3, 0.25, 0.75) are included to guard against
+; regressions.
+
+declare float @llvm.pow.f32(float, float)
+declare double @llvm.pow.f64(double, double)
+
+; pow(X, 1.5) with @llvm.pow.f64 still in IR: InstCombine rewrites this to
+; X * sqrt(X) when run through the IR optimizer (see IR-OPT checks below), but
+; when llc sees the unoptimized IR the DAG combiner performs the fold at
+; codegen. This is the path that matters for -O0 IR / llc-only
+; tests and complements the existing InstCombine rewrite used by clang -O3.
+define double @pow_f64_1_5_ir_pow(double %x) {
+; IR-LABEL: @pow_f64_1_5_ir_pow(
+; IR: call{{.*}}@llvm.pow.f64
+;
+; IR-OPT-LABEL: @pow_f64_1_5_ir_pow(
+; IR-OPT: call{{.*}}@llvm.sqrt.f64
+; IR-OPT: fmul
+; IR-OPT-NOT: call{{.*}}@llvm.pow.f64
+; IR-OPT-LABEL: @pow_f64_1_5(
+;
+; CHECK-LABEL: pow_f64_1_5_ir_pow:
+; CHECK: # %bb.0:
+; CHECK-NEXT: vsqrtsd %xmm0, %xmm0, %xmm1
+; CHECK-NEXT: vmulsd %xmm1, %xmm0, %xmm0
+; CHECK-NEXT: retq
+ %r = call afn ninf nsz nnan double @llvm.pow.f64(double %x, double 1.500000e+00)
+ ret double %r
+}
+
+; pow(X, 1.5) --> X * sqrt(X)
+define double @pow_f64_1_5(double %x) {
+; CHECK-LABEL: pow_f64_1_5:
+; CHECK: # %bb.0:
+; CHECK-NEXT: vsqrtsd %xmm0, %xmm0, %xmm1
+; CHECK-NEXT: vmulsd %xmm1, %xmm0, %xmm0
+; CHECK-NEXT: retq
+ %r = call afn ninf nsz nnan double @llvm.pow.f64(double %x, double 1.500000e+00)
+ ret double %r
+}
+
+define float @pow_f32_1_5(float %x) {
+; CHECK-LABEL: pow_f32_1_5:
+; CHECK: # %bb.0:
+; CHECK-NEXT: vsqrtss %xmm0, %xmm0, %xmm1
+; CHECK-NEXT: vmulss %xmm1, %xmm0, %xmm0
+; CHECK-NEXT: retq
+ %r = call afn ninf nsz nnan float @llvm.pow.f32(float %x, float 1.500000e+00)
+ ret float %r
+}
+
+; pow(X, 2/3) --> cbrt(X) * cbrt(X)
+define double @pow_f64_2_3(double %x) {
+; CHECK-LABEL: pow_f64_2_3:
+; CHECK: # %bb.0:
+; CHECK-NEXT: pushq %rax
+; CHECK-NEXT: .cfi_def_cfa_offset 16
+; CHECK-NEXT: callq cbrt at PLT
+; CHECK-NEXT: vmulsd %xmm0, %xmm0, %xmm0
+; CHECK-NEXT: popq %rax
+; CHECK-NEXT: .cfi_def_cfa_offset 8
+; CHECK-NEXT: retq
+ %r = call afn ninf nsz nnan double @llvm.pow.f64(double %x, double 0x3FE5555555555555)
+ ret double %r
+}
+
+define float @pow_f32_2_3(float %x) {
+; CHECK-LABEL: pow_f32_2_3:
+; CHECK: # %bb.0:
+; CHECK-NEXT: pushq %rax
+; CHECK-NEXT: .cfi_def_cfa_offset 16
+; CHECK-NEXT: callq cbrtf at PLT
+; CHECK-NEXT: vmulss %xmm0, %xmm0, %xmm0
+; CHECK-NEXT: popq %rax
+; CHECK-NEXT: .cfi_def_cfa_offset 8
+; CHECK-NEXT: retq
+ %r = call afn ninf nsz nnan float @llvm.pow.f32(float %x, float 0x3FE5555560000000)
+ ret float %r
+}
+
+; pow(X, 1/3) --> cbrt(X) (pre-existing)
+define double @pow_f64_1_3(double %x) {
+; CHECK-LABEL: pow_f64_1_3:
+; CHECK: # %bb.0:
+; CHECK-NEXT: jmp cbrt at PLT # TAILCALL
+ %r = call afn ninf nsz nnan double @llvm.pow.f64(double %x, double 0x3FD5555555555555)
+ ret double %r
+}
+
+; pow(X, 0.25) --> sqrt(sqrt(X)) (pre-existing)
+define double @pow_f64_0_25(double %x) {
+; CHECK-LABEL: pow_f64_0_25:
+; CHECK: # %bb.0:
+; CHECK-NEXT: vsqrtsd %xmm0, %xmm0, %xmm0
+; CHECK-NEXT: vsqrtsd %xmm0, %xmm0, %xmm0
+; CHECK-NEXT: retq
+ %r = call afn ninf nsz nnan double @llvm.pow.f64(double %x, double 2.500000e-01)
+ ret double %r
+}
+
+; pow(X, 0.75) --> sqrt(X) * sqrt(sqrt(X)) (pre-existing)
+define double @pow_f64_0_75(double %x) {
+; CHECK-LABEL: pow_f64_0_75:
+; CHECK: # %bb.0:
+; CHECK-NEXT: vsqrtsd %xmm0, %xmm0, %xmm0
+; CHECK-NEXT: vsqrtsd %xmm0, %xmm0, %xmm1
+; CHECK-NEXT: vmulsd %xmm1, %xmm0, %xmm0
+; CHECK-NEXT: retq
+ %r = call afn ninf nsz nnan double @llvm.pow.f64(double %x, double 7.500000e-01)
+ ret double %r
+}
+
+; Negative tests: without the required fast-math flags the fold must not happen
+; and we must retain a libm pow call.
+;
+; Cbrt path (1/3, 2/3): requires { afn, ninf, nsz, nnan }.
+; Sqrt path (0.25): requires { afn, ninf, nsz }.
+; Sqrt path (0.75, 1.5): requires { afn, ninf }.
+
+define double @pow_f64_1_5_no_afn(double %x) {
+; CHECK-LABEL: pow_f64_1_5_no_afn:
+; CHECK: jmp pow at PLT
+; CHECK-NOT: vsqrtsd
+ %r = call ninf nsz nnan double @llvm.pow.f64(double %x, double 1.500000e+00)
+ ret double %r
+}
+
+define double @pow_f64_1_5_no_ninf(double %x) {
+; CHECK-LABEL: pow_f64_1_5_no_ninf:
+; CHECK: jmp pow at PLT
+; CHECK-NOT: vsqrtsd
+ %r = call afn nsz nnan double @llvm.pow.f64(double %x, double 1.500000e+00)
+ ret double %r
+}
+
+define double @pow_f64_2_3_no_afn(double %x) {
+; CHECK-LABEL: pow_f64_2_3_no_afn:
+; CHECK: jmp pow at PLT
+; CHECK-NOT: cbrt
+ %r = call ninf nsz nnan double @llvm.pow.f64(double %x, double 0x3FE5555555555555)
+ ret double %r
+}
+
+define double @pow_f64_2_3_no_nnan(double %x) {
+; CHECK-LABEL: pow_f64_2_3_no_nnan:
+; CHECK: jmp pow at PLT
+; CHECK-NOT: cbrt
+ %r = call afn ninf nsz double @llvm.pow.f64(double %x, double 0x3FE5555555555555)
+ ret double %r
+}
+
+define double @pow_f64_1_3_no_nsz(double %x) {
+; CHECK-LABEL: pow_f64_1_3_no_nsz:
+; CHECK: jmp pow at PLT
+; CHECK-NOT: cbrt
+ %r = call afn ninf nnan double @llvm.pow.f64(double %x, double 0x3FD5555555555555)
+ ret double %r
+}
+
+define double @pow_f64_0_25_no_nsz(double %x) {
+; CHECK-LABEL: pow_f64_0_25_no_nsz:
+; CHECK: jmp pow at PLT
+; CHECK-NOT: vsqrtsd
+ %r = call afn ninf double @llvm.pow.f64(double %x, double 2.500000e-01)
+ ret double %r
+}
+
+define double @pow_f64_0_75_no_afn(double %x) {
+; CHECK-LABEL: pow_f64_0_75_no_afn:
+; CHECK: jmp pow at PLT
+; CHECK-NOT: vsqrtsd
+ %r = call ninf nsz nnan double @llvm.pow.f64(double %x, double 7.500000e-01)
+ ret double %r
+}
+
+define double @pow_f64_no_flags(double %x) {
+; CHECK-LABEL: pow_f64_no_flags:
+; CHECK: jmp pow at PLT
+; CHECK-NOT: vsqrtsd
+; CHECK-NOT: cbrt
+ %r = call double @llvm.pow.f64(double %x, double 1.500000e+00)
+ ret double %r
+}
+
+; Negative tests: all required fast-math flags are present, but the fold must
+; still not happen for other reasons:
+; - optsize/minimize size: sqrt-path folds are disabled (ForCodeSize).
+; - non-exact constant exponent: exponent does not match exactly.
+; - variable exponent: exponent is not a compile-time constant.
+
+define double @pow_f64_1_5_optsize(double %x) optsize {
+; CHECK-LABEL: pow_f64_1_5_optsize:
+; CHECK: jmp pow at PLT
+; CHECK-NOT: vsqrtsd
+ %r = call afn ninf nsz nnan double @llvm.pow.f64(double %x, double 1.500000e+00)
+ ret double %r
+}
+
+define double @pow_f64_0_25_optsize(double %x) optsize {
+; CHECK-LABEL: pow_f64_0_25_optsize:
+; CHECK: jmp pow at PLT
+; CHECK-NOT: vsqrtsd
+ %r = call afn ninf nsz nnan double @llvm.pow.f64(double %x, double 2.500000e-01)
+ ret double %r
+}
+
+define double @pow_f64_1_5_nonexact_exp(double %x) {
+; CHECK-LABEL: pow_f64_1_5_nonexact_exp:
+; CHECK: jmp pow at PLT
+; CHECK-NOT: vsqrtsd
+ %r = call afn ninf nsz nnan double @llvm.pow.f64(double %x, double 0x3FF8000000000001)
+ ret double %r
+}
+
+define double @pow_f64_2_3_nonexact_exp(double %x) {
+; CHECK-LABEL: pow_f64_2_3_nonexact_exp:
+; CHECK: jmp pow at PLT
+; CHECK-NOT: cbrt
+ %r = call afn ninf nsz nnan double @llvm.pow.f64(double %x, double 0x3FE5555555555556)
+ ret double %r
+}
+
+define double @pow_f64_var_exp(double %x, double %e) {
+; CHECK-LABEL: pow_f64_var_exp:
+; CHECK: jmp pow at PLT
+; CHECK-NOT: vsqrtsd
+; CHECK-NOT: cbrt
+ %r = call afn ninf nsz nnan double @llvm.pow.f64(double %x, double %e)
+ ret double %r
+}
>From 63cff8151d6f240b2e0af5fc6d2c15d6d512fdd7 Mon Sep 17 00:00:00 2001
From: Rohit Aggarwal <Rohit.Aggarwal at amd.com>
Date: Wed, 5 Aug 2026 18:37:38 +0530
Subject: [PATCH 2/3] Update pow-fold.ll
---
llvm/test/CodeGen/X86/pow-fold.ll | 4 ----
1 file changed, 4 deletions(-)
diff --git a/llvm/test/CodeGen/X86/pow-fold.ll b/llvm/test/CodeGen/X86/pow-fold.ll
index 2bdac03d2b956..21211551158be 100644
--- a/llvm/test/CodeGen/X86/pow-fold.ll
+++ b/llvm/test/CodeGen/X86/pow-fold.ll
@@ -1,6 +1,5 @@
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
; RUN: llc < %s -mtriple=x86_64-- -mcpu=x86-64 -mattr=+avx | FileCheck %s
-; RUN: FileCheck %s --check-prefix=IR < %s
; RUN: opt -passes=instcombine -S %s | FileCheck %s --check-prefix=IR-OPT
; Verify the fractional-exponent pow folds, including the cases added by this
@@ -19,9 +18,6 @@ declare double @llvm.pow.f64(double, double)
; codegen. This is the path that matters for -O0 IR / llc-only
; tests and complements the existing InstCombine rewrite used by clang -O3.
define double @pow_f64_1_5_ir_pow(double %x) {
-; IR-LABEL: @pow_f64_1_5_ir_pow(
-; IR: call{{.*}}@llvm.pow.f64
-;
; IR-OPT-LABEL: @pow_f64_1_5_ir_pow(
; IR-OPT: call{{.*}}@llvm.sqrt.f64
; IR-OPT: fmul
>From 4130f2f668a84b5b08f5db30519c19169eb910d0 Mon Sep 17 00:00:00 2001
From: Rohit Aggarwal <Rohit.Aggarwal at amd.com>
Date: Wed, 12 Aug 2026 11:52:15 +0530
Subject: [PATCH 3/3] [X86][SelectionDAG] - Implement review to update the
pow-fold.ll test case
---
llvm/test/CodeGen/X86/pow-fold.ll | 235 ------------------------------
llvm/test/CodeGen/X86/pow.ll | 142 ++++++++++++++++++
2 files changed, 142 insertions(+), 235 deletions(-)
delete mode 100644 llvm/test/CodeGen/X86/pow-fold.ll
diff --git a/llvm/test/CodeGen/X86/pow-fold.ll b/llvm/test/CodeGen/X86/pow-fold.ll
deleted file mode 100644
index 21211551158be..0000000000000
--- a/llvm/test/CodeGen/X86/pow-fold.ll
+++ /dev/null
@@ -1,235 +0,0 @@
-; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
-; RUN: llc < %s -mtriple=x86_64-- -mcpu=x86-64 -mattr=+avx | FileCheck %s
-; RUN: opt -passes=instcombine -S %s | FileCheck %s --check-prefix=IR-OPT
-
-; Verify the fractional-exponent pow folds, including the cases added by this
-; change:
-; pow(X, 2/3) --> cbrt(X) * cbrt(X)
-; pow(X, 1.5) --> X * sqrt(X)
-; The pre-existing folds (1/3, 0.25, 0.75) are included to guard against
-; regressions.
-
-declare float @llvm.pow.f32(float, float)
-declare double @llvm.pow.f64(double, double)
-
-; pow(X, 1.5) with @llvm.pow.f64 still in IR: InstCombine rewrites this to
-; X * sqrt(X) when run through the IR optimizer (see IR-OPT checks below), but
-; when llc sees the unoptimized IR the DAG combiner performs the fold at
-; codegen. This is the path that matters for -O0 IR / llc-only
-; tests and complements the existing InstCombine rewrite used by clang -O3.
-define double @pow_f64_1_5_ir_pow(double %x) {
-; IR-OPT-LABEL: @pow_f64_1_5_ir_pow(
-; IR-OPT: call{{.*}}@llvm.sqrt.f64
-; IR-OPT: fmul
-; IR-OPT-NOT: call{{.*}}@llvm.pow.f64
-; IR-OPT-LABEL: @pow_f64_1_5(
-;
-; CHECK-LABEL: pow_f64_1_5_ir_pow:
-; CHECK: # %bb.0:
-; CHECK-NEXT: vsqrtsd %xmm0, %xmm0, %xmm1
-; CHECK-NEXT: vmulsd %xmm1, %xmm0, %xmm0
-; CHECK-NEXT: retq
- %r = call afn ninf nsz nnan double @llvm.pow.f64(double %x, double 1.500000e+00)
- ret double %r
-}
-
-; pow(X, 1.5) --> X * sqrt(X)
-define double @pow_f64_1_5(double %x) {
-; CHECK-LABEL: pow_f64_1_5:
-; CHECK: # %bb.0:
-; CHECK-NEXT: vsqrtsd %xmm0, %xmm0, %xmm1
-; CHECK-NEXT: vmulsd %xmm1, %xmm0, %xmm0
-; CHECK-NEXT: retq
- %r = call afn ninf nsz nnan double @llvm.pow.f64(double %x, double 1.500000e+00)
- ret double %r
-}
-
-define float @pow_f32_1_5(float %x) {
-; CHECK-LABEL: pow_f32_1_5:
-; CHECK: # %bb.0:
-; CHECK-NEXT: vsqrtss %xmm0, %xmm0, %xmm1
-; CHECK-NEXT: vmulss %xmm1, %xmm0, %xmm0
-; CHECK-NEXT: retq
- %r = call afn ninf nsz nnan float @llvm.pow.f32(float %x, float 1.500000e+00)
- ret float %r
-}
-
-; pow(X, 2/3) --> cbrt(X) * cbrt(X)
-define double @pow_f64_2_3(double %x) {
-; CHECK-LABEL: pow_f64_2_3:
-; CHECK: # %bb.0:
-; CHECK-NEXT: pushq %rax
-; CHECK-NEXT: .cfi_def_cfa_offset 16
-; CHECK-NEXT: callq cbrt at PLT
-; CHECK-NEXT: vmulsd %xmm0, %xmm0, %xmm0
-; CHECK-NEXT: popq %rax
-; CHECK-NEXT: .cfi_def_cfa_offset 8
-; CHECK-NEXT: retq
- %r = call afn ninf nsz nnan double @llvm.pow.f64(double %x, double 0x3FE5555555555555)
- ret double %r
-}
-
-define float @pow_f32_2_3(float %x) {
-; CHECK-LABEL: pow_f32_2_3:
-; CHECK: # %bb.0:
-; CHECK-NEXT: pushq %rax
-; CHECK-NEXT: .cfi_def_cfa_offset 16
-; CHECK-NEXT: callq cbrtf at PLT
-; CHECK-NEXT: vmulss %xmm0, %xmm0, %xmm0
-; CHECK-NEXT: popq %rax
-; CHECK-NEXT: .cfi_def_cfa_offset 8
-; CHECK-NEXT: retq
- %r = call afn ninf nsz nnan float @llvm.pow.f32(float %x, float 0x3FE5555560000000)
- ret float %r
-}
-
-; pow(X, 1/3) --> cbrt(X) (pre-existing)
-define double @pow_f64_1_3(double %x) {
-; CHECK-LABEL: pow_f64_1_3:
-; CHECK: # %bb.0:
-; CHECK-NEXT: jmp cbrt at PLT # TAILCALL
- %r = call afn ninf nsz nnan double @llvm.pow.f64(double %x, double 0x3FD5555555555555)
- ret double %r
-}
-
-; pow(X, 0.25) --> sqrt(sqrt(X)) (pre-existing)
-define double @pow_f64_0_25(double %x) {
-; CHECK-LABEL: pow_f64_0_25:
-; CHECK: # %bb.0:
-; CHECK-NEXT: vsqrtsd %xmm0, %xmm0, %xmm0
-; CHECK-NEXT: vsqrtsd %xmm0, %xmm0, %xmm0
-; CHECK-NEXT: retq
- %r = call afn ninf nsz nnan double @llvm.pow.f64(double %x, double 2.500000e-01)
- ret double %r
-}
-
-; pow(X, 0.75) --> sqrt(X) * sqrt(sqrt(X)) (pre-existing)
-define double @pow_f64_0_75(double %x) {
-; CHECK-LABEL: pow_f64_0_75:
-; CHECK: # %bb.0:
-; CHECK-NEXT: vsqrtsd %xmm0, %xmm0, %xmm0
-; CHECK-NEXT: vsqrtsd %xmm0, %xmm0, %xmm1
-; CHECK-NEXT: vmulsd %xmm1, %xmm0, %xmm0
-; CHECK-NEXT: retq
- %r = call afn ninf nsz nnan double @llvm.pow.f64(double %x, double 7.500000e-01)
- ret double %r
-}
-
-; Negative tests: without the required fast-math flags the fold must not happen
-; and we must retain a libm pow call.
-;
-; Cbrt path (1/3, 2/3): requires { afn, ninf, nsz, nnan }.
-; Sqrt path (0.25): requires { afn, ninf, nsz }.
-; Sqrt path (0.75, 1.5): requires { afn, ninf }.
-
-define double @pow_f64_1_5_no_afn(double %x) {
-; CHECK-LABEL: pow_f64_1_5_no_afn:
-; CHECK: jmp pow at PLT
-; CHECK-NOT: vsqrtsd
- %r = call ninf nsz nnan double @llvm.pow.f64(double %x, double 1.500000e+00)
- ret double %r
-}
-
-define double @pow_f64_1_5_no_ninf(double %x) {
-; CHECK-LABEL: pow_f64_1_5_no_ninf:
-; CHECK: jmp pow at PLT
-; CHECK-NOT: vsqrtsd
- %r = call afn nsz nnan double @llvm.pow.f64(double %x, double 1.500000e+00)
- ret double %r
-}
-
-define double @pow_f64_2_3_no_afn(double %x) {
-; CHECK-LABEL: pow_f64_2_3_no_afn:
-; CHECK: jmp pow at PLT
-; CHECK-NOT: cbrt
- %r = call ninf nsz nnan double @llvm.pow.f64(double %x, double 0x3FE5555555555555)
- ret double %r
-}
-
-define double @pow_f64_2_3_no_nnan(double %x) {
-; CHECK-LABEL: pow_f64_2_3_no_nnan:
-; CHECK: jmp pow at PLT
-; CHECK-NOT: cbrt
- %r = call afn ninf nsz double @llvm.pow.f64(double %x, double 0x3FE5555555555555)
- ret double %r
-}
-
-define double @pow_f64_1_3_no_nsz(double %x) {
-; CHECK-LABEL: pow_f64_1_3_no_nsz:
-; CHECK: jmp pow at PLT
-; CHECK-NOT: cbrt
- %r = call afn ninf nnan double @llvm.pow.f64(double %x, double 0x3FD5555555555555)
- ret double %r
-}
-
-define double @pow_f64_0_25_no_nsz(double %x) {
-; CHECK-LABEL: pow_f64_0_25_no_nsz:
-; CHECK: jmp pow at PLT
-; CHECK-NOT: vsqrtsd
- %r = call afn ninf double @llvm.pow.f64(double %x, double 2.500000e-01)
- ret double %r
-}
-
-define double @pow_f64_0_75_no_afn(double %x) {
-; CHECK-LABEL: pow_f64_0_75_no_afn:
-; CHECK: jmp pow at PLT
-; CHECK-NOT: vsqrtsd
- %r = call ninf nsz nnan double @llvm.pow.f64(double %x, double 7.500000e-01)
- ret double %r
-}
-
-define double @pow_f64_no_flags(double %x) {
-; CHECK-LABEL: pow_f64_no_flags:
-; CHECK: jmp pow at PLT
-; CHECK-NOT: vsqrtsd
-; CHECK-NOT: cbrt
- %r = call double @llvm.pow.f64(double %x, double 1.500000e+00)
- ret double %r
-}
-
-; Negative tests: all required fast-math flags are present, but the fold must
-; still not happen for other reasons:
-; - optsize/minimize size: sqrt-path folds are disabled (ForCodeSize).
-; - non-exact constant exponent: exponent does not match exactly.
-; - variable exponent: exponent is not a compile-time constant.
-
-define double @pow_f64_1_5_optsize(double %x) optsize {
-; CHECK-LABEL: pow_f64_1_5_optsize:
-; CHECK: jmp pow at PLT
-; CHECK-NOT: vsqrtsd
- %r = call afn ninf nsz nnan double @llvm.pow.f64(double %x, double 1.500000e+00)
- ret double %r
-}
-
-define double @pow_f64_0_25_optsize(double %x) optsize {
-; CHECK-LABEL: pow_f64_0_25_optsize:
-; CHECK: jmp pow at PLT
-; CHECK-NOT: vsqrtsd
- %r = call afn ninf nsz nnan double @llvm.pow.f64(double %x, double 2.500000e-01)
- ret double %r
-}
-
-define double @pow_f64_1_5_nonexact_exp(double %x) {
-; CHECK-LABEL: pow_f64_1_5_nonexact_exp:
-; CHECK: jmp pow at PLT
-; CHECK-NOT: vsqrtsd
- %r = call afn ninf nsz nnan double @llvm.pow.f64(double %x, double 0x3FF8000000000001)
- ret double %r
-}
-
-define double @pow_f64_2_3_nonexact_exp(double %x) {
-; CHECK-LABEL: pow_f64_2_3_nonexact_exp:
-; CHECK: jmp pow at PLT
-; CHECK-NOT: cbrt
- %r = call afn ninf nsz nnan double @llvm.pow.f64(double %x, double 0x3FE5555555555556)
- ret double %r
-}
-
-define double @pow_f64_var_exp(double %x, double %e) {
-; CHECK-LABEL: pow_f64_var_exp:
-; CHECK: jmp pow at PLT
-; CHECK-NOT: vsqrtsd
-; CHECK-NOT: cbrt
- %r = call afn ninf nsz nnan double @llvm.pow.f64(double %x, double %e)
- ret double %r
-}
diff --git a/llvm/test/CodeGen/X86/pow.ll b/llvm/test/CodeGen/X86/pow.ll
index c2f7eb66ab01c..1f1d26e83e1ed 100644
--- a/llvm/test/CodeGen/X86/pow.ll
+++ b/llvm/test/CodeGen/X86/pow.ll
@@ -222,4 +222,146 @@ define double @pow_f64_not_enough_fmf(double %x) nounwind {
ret double %r
}
+; pow(X, 1.5) --> X * sqrt(X)
+define double @pow_f64_1_5(double %x) {
+; CHECK-LABEL: pow_f64_1_5:
+; CHECK: # %bb.0:
+; CHECK-NEXT: sqrtsd %xmm0, %xmm1
+; CHECK-NEXT: mulsd %xmm1, %xmm0
+; CHECK-NEXT: retq
+ %r = call afn ninf nsz nnan double @llvm.pow.f64(double %x, double 1.500000e+00)
+ ret double %r
+}
+
+define float @pow_f32_1_5(float %x) {
+; CHECK-LABEL: pow_f32_1_5:
+; CHECK: # %bb.0:
+; CHECK-NEXT: sqrtss %xmm0, %xmm1
+; CHECK-NEXT: mulss %xmm1, %xmm0
+; CHECK-NEXT: retq
+ %r = call afn ninf nsz nnan float @llvm.pow.f32(float %x, float 1.500000e+00)
+ ret float %r
+}
+
+; pow(X, 2/3) --> cbrt(X) * cbrt(X)
+define double @pow_f64_2_3(double %x) {
+; CHECK-LABEL: pow_f64_2_3:
+; CHECK: # %bb.0:
+; CHECK-NEXT: pushq %rax
+; CHECK-NEXT: .cfi_def_cfa_offset 16
+; CHECK-NEXT: callq cbrt at PLT
+; CHECK-NEXT: mulsd %xmm0, %xmm0
+; CHECK-NEXT: popq %rax
+; CHECK-NEXT: .cfi_def_cfa_offset 8
+; CHECK-NEXT: retq
+ %r = call afn ninf nsz nnan double @llvm.pow.f64(double %x, double 0x3FE5555555555555)
+ ret double %r
+}
+
+define float @pow_f32_2_3(float %x) {
+; CHECK-LABEL: pow_f32_2_3:
+; CHECK: # %bb.0:
+; CHECK-NEXT: pushq %rax
+; CHECK-NEXT: .cfi_def_cfa_offset 16
+; CHECK-NEXT: callq cbrtf at PLT
+; CHECK-NEXT: mulss %xmm0, %xmm0
+; CHECK-NEXT: popq %rax
+; CHECK-NEXT: .cfi_def_cfa_offset 8
+; CHECK-NEXT: retq
+ %r = call afn ninf nsz nnan float @llvm.pow.f32(float %x, float 0x3FE5555560000000)
+ ret float %r
+}
+
+; Negative tests: without the required fast-math flags the fold must not happen
+; and we must retain a libm pow call.
+;
+; Cbrt path (2/3): requires { afn, ninf, nsz, nnan }.
+; Sqrt path (1.5): requires { afn, ninf }.
+
+define double @pow_f64_1_5_no_afn(double %x) {
+; CHECK-LABEL: pow_f64_1_5_no_afn:
+; CHECK: # %bb.0:
+; CHECK-NEXT: movsd {{.*#+}} xmm1 = [1.5E+0,0.0E+0]
+; CHECK-NEXT: jmp pow at PLT # TAILCALL
+ %r = call ninf nsz nnan double @llvm.pow.f64(double %x, double 1.500000e+00)
+ ret double %r
+}
+
+define double @pow_f64_1_5_no_ninf(double %x) {
+; CHECK-LABEL: pow_f64_1_5_no_ninf:
+; CHECK: # %bb.0:
+; CHECK-NEXT: movsd {{.*#+}} xmm1 = [1.5E+0,0.0E+0]
+; CHECK-NEXT: jmp pow at PLT # TAILCALL
+ %r = call afn nsz nnan double @llvm.pow.f64(double %x, double 1.500000e+00)
+ ret double %r
+}
+
+define double @pow_f64_2_3_no_afn(double %x) {
+; CHECK-LABEL: pow_f64_2_3_no_afn:
+; CHECK: # %bb.0:
+; CHECK-NEXT: movsd {{.*#+}} xmm1 = [6.6666666666666663E-1,0.0E+0]
+; CHECK-NEXT: jmp pow at PLT # TAILCALL
+ %r = call ninf nsz nnan double @llvm.pow.f64(double %x, double 0x3FE5555555555555)
+ ret double %r
+}
+
+define double @pow_f64_2_3_no_nnan(double %x) {
+; CHECK-LABEL: pow_f64_2_3_no_nnan:
+; CHECK: # %bb.0:
+; CHECK-NEXT: movsd {{.*#+}} xmm1 = [6.6666666666666663E-1,0.0E+0]
+; CHECK-NEXT: jmp pow at PLT # TAILCALL
+ %r = call afn ninf nsz double @llvm.pow.f64(double %x, double 0x3FE5555555555555)
+ ret double %r
+}
+
+define double @pow_f64_no_flags(double %x) {
+; CHECK-LABEL: pow_f64_no_flags:
+; CHECK: # %bb.0:
+; CHECK-NEXT: movsd {{.*#+}} xmm1 = [1.5E+0,0.0E+0]
+; CHECK-NEXT: jmp pow at PLT # TAILCALL
+ %r = call double @llvm.pow.f64(double %x, double 1.500000e+00)
+ ret double %r
+}
+
+; Negative tests: all required fast-math flags are present, but the fold must
+; still not happen for other reasons:
+; - optsize/minimize size: sqrt-path folds are disabled (ForCodeSize).
+; - non-exact constant exponent: exponent does not match exactly.
+; - variable exponent: exponent is not a compile-time constant.
+
+define double @pow_f64_1_5_optsize(double %x) optsize {
+; CHECK-LABEL: pow_f64_1_5_optsize:
+; CHECK: # %bb.0:
+; CHECK-NEXT: movsd {{.*#+}} xmm1 = [1.5E+0,0.0E+0]
+; CHECK-NEXT: jmp pow at PLT # TAILCALL
+ %r = call afn ninf nsz nnan double @llvm.pow.f64(double %x, double 1.500000e+00)
+ ret double %r
+}
+
+define double @pow_f64_1_5_nonexact_exp(double %x) {
+; CHECK-LABEL: pow_f64_1_5_nonexact_exp:
+; CHECK: # %bb.0:
+; CHECK-NEXT: movsd {{.*#+}} xmm1 = [1.5000000000000002E+0,0.0E+0]
+; CHECK-NEXT: jmp pow at PLT # TAILCALL
+ %r = call afn ninf nsz nnan double @llvm.pow.f64(double %x, double 0x3FF8000000000001)
+ ret double %r
+}
+
+define double @pow_f64_2_3_nonexact_exp(double %x) {
+; CHECK-LABEL: pow_f64_2_3_nonexact_exp:
+; CHECK: # %bb.0:
+; CHECK-NEXT: movsd {{.*#+}} xmm1 = [6.6666666666666674E-1,0.0E+0]
+; CHECK-NEXT: jmp pow at PLT # TAILCALL
+ %r = call afn ninf nsz nnan double @llvm.pow.f64(double %x, double 0x3FE5555555555556)
+ ret double %r
+}
+
+define double @pow_f64_var_exp(double %x, double %e) {
+; CHECK-LABEL: pow_f64_var_exp:
+; CHECK: # %bb.0:
+; CHECK-NEXT: jmp pow at PLT # TAILCALL
+ %r = call afn ninf nsz nnan double @llvm.pow.f64(double %x, double %e)
+ ret double %r
+}
+
attributes #0 = { nounwind denormal_fpenv(ieee|preservesign) }
More information about the llvm-commits
mailing list