1//===----------------------------------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8///
9/// \file
10/// Common header for PolyEval implementations.
11///
12//===----------------------------------------------------------------------===//
13
14#ifndef LLVM_LIBC_SRC___SUPPORT_FPUTIL_POLYEVAL_H
15#define LLVM_LIBC_SRC___SUPPORT_FPUTIL_POLYEVAL_H
16
17#include "multiply_add.h"
18#include "src/__support/CPP/type_traits.h"
19#include "src/__support/common.h"
20#include "src/__support/macros/config.h"
21
22// Evaluate polynomial using Horner's Scheme:
23// With polyeval(x, a_0, a_1, ..., a_n) = a_n * x^n + ... + a_1 * x + a_0, we
24// evaluated it as: a_0 + x * (a_1 + x * ( ... (a_(n-1) + x * a_n) ... ) ) ).
25// We will use FMA instructions if available.
26// Example: to evaluate x^3 + 2*x^2 + 3*x + 4, call
27// polyeval( x, 4.0, 3.0, 2.0, 1.0 )
28
29namespace LIBC_NAMESPACE_DECL {
30namespace fputil {
31
32template <typename T>
33LIBC_INLINE constexpr cpp::enable_if_t<(sizeof(T) > sizeof(void *)), T>
34polyeval(const T &, const T &a0) {
35 return a0;
36}
37
38template <typename T>
39LIBC_INLINE constexpr cpp::enable_if_t<(sizeof(T) <= sizeof(void *)), T>
40polyeval(T, T a0) {
41 return a0;
42}
43
44template <typename T, typename... Ts>
45LIBC_INLINE static constexpr cpp::enable_if_t<(sizeof(T) > sizeof(void *)), T>
46polyeval(const T &x, const T &a0, const Ts &...a) {
47 return multiply_add(x, polyeval(x, a...), a0);
48}
49
50template <typename T, typename... Ts>
51LIBC_INLINE LIBC_CONSTEXPR cpp::enable_if_t<(sizeof(T) <= sizeof(void *)), T>
52polyeval(T x, T a0, Ts... a) {
53 return multiply_add(x, polyeval(x, a...), a0);
54}
55
56// Evaluating alternating polynomials using subtraction directly.
57// altpolyeval(x, a_0, a_1, ..., a_n) = a_0 - x * a_1 + x^2 * a_2 - ... +
58// + (-1)^n x_n * a_n.
59template <typename T>
60LIBC_INLINE constexpr cpp::enable_if_t<(sizeof(T) > sizeof(void *)), T>
61altpolyeval(const T &, const T &a0) {
62 return a0;
63}
64
65template <typename T>
66LIBC_INLINE constexpr cpp::enable_if_t<(sizeof(T) <= sizeof(void *)), T>
67altpolyeval(T, T a0) {
68 return a0;
69}
70
71// TODO: Make use of FMA instructions when using these for floating points.
72template <typename T, typename... Ts>
73LIBC_INLINE constexpr cpp::enable_if_t<(sizeof(T) > sizeof(void *)), T>
74altpolyeval(const T &x, const T &a0, const Ts &...a) {
75 T prod = x * altpolyeval(x, a...);
76 return a0 - prod;
77}
78
79template <typename T, typename... Ts>
80LIBC_INLINE constexpr cpp::enable_if_t<(sizeof(T) <= sizeof(void *)), T>
81altpolyeval(T x, T a0, Ts... a) {
82 T prod = x * altpolyeval(x, a...);
83 return a0 - prod;
84}
85
86} // namespace fputil
87} // namespace LIBC_NAMESPACE_DECL
88
89#endif // LLVM_LIBC_SRC___SUPPORT_FPUTIL_POLYEVAL_H
90