[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