#!/usr/bin/python3
# Copyright (C) 2023-2024 Free Software Foundation, Inc.
# This file is part of the GNU C Library.
#
# The GNU C Library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# The GNU C Library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with the GNU C Library; if not, see
# .
import sys
TEMPLATE = """
#include
#include
#define STRIDE {stride}
#define PTRUE svptrue_b{prec_short}
#define SV_LOAD svld1_f{prec_short}
#define SV_STORE svst1_f{prec_short}
#define REQUIRE_SVE
#define CALL_BENCH_FUNC_1(v, i) (__extension__ ({{ \\
{rtype} mx0 = {fname}(SV_LOAD (PTRUE(), &variants[v].in->arg0[i * STRIDE]), PTRUE()); \\
mx0; }}))
#define CALL_BENCH_FUNC_2(v, i) (__extension__ ({{ \\
{rtype} mx0 = {fname}(SV_LOAD (PTRUE(), &variants[v].in->arg0[i * STRIDE]), \\
SV_LOAD (PTRUE(), &variants[v].in->arg1[i * STRIDE]), \\
PTRUE()); \\
mx0; }}))
struct args_1
{{
{stype} arg0[{nelems}];
}};
struct args_2
{{
{stype} arg0[{nelems}];
{stype} arg1[{nelems}];
}};
struct _variants
{{
const char *name;
const struct args_{arity} *in;
}};
static const struct args_{arity} in0 = {{
{in_data}
}};
static const struct _variants variants[1] = {{
{{"", &in0}},
}};
#define NUM_VARIANTS 1
#define NUM_SAMPLES(i) ({nelems} / STRIDE)
#define VARIANT(i) (variants[i].name)
// Cannot pass volatile pointer to svst1. This still does not appear to get optimised out.
static {stype} /*volatile*/ ret[{rowlen}];
#define BENCH_FUNC(i, j) ({{ SV_STORE(PTRUE(), ret, CALL_BENCH_FUNC_{arity}(i, j)); }})
#define FUNCNAME "{fname}"
#include
"""
def main(name):
_, prec, _, func = name.split("-")
scalar_to_sve_type = {"double": "svfloat64_t", "float": "svfloat32_t"}
stride = {"double": "svcntd()", "float": "svcntw()"}[prec]
rtype = scalar_to_sve_type[prec]
atype = scalar_to_sve_type[prec]
prec_short = {"double": 64, "float": 32}[prec]
# Max SVE vector length is 2048 bits. To ensure benchmarks are
# vector-length-agnostic, but still use as wide vectors as
# possible on any given target, divide input data into 2048-bit
# rows, then load/store as many elements as the target will allow.
rowlen = {"double": 32, "float": 64}[prec]
input_filename = {"double": f"{func}-inputs", "float": f"{func}f-inputs"}[prec]
with open(f"../benchtests/libmvec/{input_filename}") as f:
input_file = f.readlines()
in_vals = (l.strip() for l in input_file if l and not l.startswith("#"))
# Split in case of multivariate signature
in_vals = (l.split(", ") for l in in_vals)
# Transpose
in_vals = list(zip(*in_vals))
in_data = ",\n".join("{" + (", ".join(val for val in col) + "}")
for col in in_vals)
arity = [l for l in input_file if l.startswith("## args: ")][0].count(prec)
fname = f"_ZGVsMx{'v' * arity}_{func}{'f' if prec == 'float' else ''}"
print(TEMPLATE.format(stride=stride,
rtype=rtype,
atype=atype,
fname=fname,
prec_short=prec_short,
in_data=in_data,
stype=prec,
rowlen=rowlen,
arity=arity,
nelems=len(in_vals[0])))
if __name__ == "__main__":
main(sys.argv[1])