1#ifndef RDKIT_NUMERICS_OPTIMIZER_BFGSOPT_SVE_H
2#define RDKIT_NUMERICS_OPTIMIZER_BFGSOPT_SVE_H
4#if defined(__linux__) && defined(__aarch64__)
7#if defined(__has_include)
8#if __has_include(<arm_sve.h>)
10#define RDK_SVE_AVAILABLE 1
17#if defined(__linux__) && defined(__aarch64__) && defined(RDK_SVE_AVAILABLE)
18 static const bool result = (getauxval(AT_HWCAP) & HWCAP_SVE) != 0;
25#ifdef RDK_SVE_AVAILABLE
30__attribute__((target(
"+sve"))) static
void sveInitXiAndSum(
unsigned int dim,
35 svfloat64_t acc = svdup_f64(0.0);
38 svbool_t pg = svwhilelt_b64(i, (uint64_t)dim);
39 svfloat64_t g = svld1_f64(pg, grad + i);
40 svfloat64_t p = svld1_f64(pg, pos + i);
42 svst1_f64(pg, xi + i, svneg_f64_m(svdup_f64(0.0), pg, g));
44 acc = svmla_f64_m(pg, acc, p, p);
48 *outSum = svaddv_f64(svptrue_b64(), acc);
63__attribute__((target(
"+sve"))) static
void sveHessianVecMul(
64 unsigned int dim, const
double *invHessian, const
double *dGrad,
65 double *hessDGrad, const
double *xi,
double *outFac,
double *outFae,
66 double *outSumDGrad,
double *outSumXi) {
69 for (
unsigned int i = 0; i < dim; i++) {
70 const double *row = invHessian + i * dim;
71 svfloat64_t acc = svdup_f64(0.0);
74 svbool_t pg = svwhilelt_b64(j, (uint64_t)dim);
75 acc = svmla_f64_m(pg, acc, svld1_f64(pg, row + j),
76 svld1_f64(pg, dGrad + j));
79 hessDGrad[i] = svaddv_f64(svptrue_b64(), acc);
82 svfloat64_t vFac = svdup_f64(0.0), vFae = svdup_f64(0.0);
83 svfloat64_t vSDG = svdup_f64(0.0), vSXi = svdup_f64(0.0);
86 svbool_t pg = svwhilelt_b64(i, (uint64_t)dim);
87 svfloat64_t vdg = svld1_f64(pg, dGrad + i);
88 svfloat64_t vxi = svld1_f64(pg, xi + i);
89 svfloat64_t vhd = svld1_f64(pg, hessDGrad + i);
91 vFac = svmla_f64_m(pg, vFac, vdg, vxi);
92 vFae = svmla_f64_m(pg, vFae, vdg, vhd);
93 vSDG = svmla_f64_m(pg, vSDG, vdg, vdg);
94 vSXi = svmla_f64_m(pg, vSXi, vxi, vxi);
97 *outFac = svaddv_f64(svptrue_b64(), vFac);
98 *outFae = svaddv_f64(svptrue_b64(), vFae);
99 *outSumDGrad = svaddv_f64(svptrue_b64(), vSDG);
100 *outSumXi = svaddv_f64(svptrue_b64(), vSXi);
113__attribute__((target(
"+sve"))) static
void sveHessianRank1Update(
114 unsigned int dim,
double *invHessian, const
double *xi,
115 const
double *hessDGrad, const
double *dGrad,
double fac,
double fad,
117 for (
unsigned int i = 0; i < dim; i++) {
119 svfloat64_t vpxi = svdup_f64(fac * xi[i]);
120 svfloat64_t vhdgi = svdup_f64(fad * hessDGrad[i]);
121 svfloat64_t vdgi = svdup_f64(fae * dGrad[i]);
122 double *row = invHessian + i * dim;
126 svbool_t pg = svwhilelt_b64(j, (uint64_t)dim);
127 svfloat64_t vxj = svld1_f64(pg, xi + j);
128 svfloat64_t vhdgj = svld1_f64(pg, hessDGrad + j);
129 svfloat64_t vdgj = svld1_f64(pg, dGrad + j);
130 svfloat64_t vh = svld1_f64(pg, row + j);
132 vh = svmla_f64_m(pg, vh, vpxi, vxj);
133 vh = svmls_f64_m(pg, vh, vhdgi, vhdgj);
134 vh = svmla_f64_m(pg, vh, vdgi, vdgj);
135 svst1_f64(pg, row + j, vh);
140 for (
unsigned int j2 = i + 1; j2 < dim; j2++) {
141 invHessian[j2 * dim + i] = invHessian[i * dim + j2];
155__attribute__((target(
"+sve"))) static
void sveHessianVecMulNeg(
156 unsigned int dim, const
double *invHessian, const
double *grad,
158 for (
unsigned int i = 0; i < dim; i++) {
159 const double *row = invHessian + i * dim;
160 svfloat64_t acc = svdup_f64(0.0);
163 svbool_t pg = svwhilelt_b64(j, (uint64_t)dim);
164 svfloat64_t h = svld1_f64(pg, row + j);
165 svfloat64_t g = svld1_f64(pg, grad + j);
166 acc = svmla_f64_m(pg, acc, h, g);
171 xi[i] = -svaddv_f64(svptrue_b64(), acc);