/* Tests for powerpc GLIBC_TUNABLES=glibc.cpu.hwcaps filter.
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
. */
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
/* Nonzero if the program gets called via `exec'. */
#define CMDLINE_OPTIONS \
{ "restart", no_argument, &restart, 1 },
static int restart;
/* Hold the four initial argument used to respawn the process, plus the extra
'--direct', '--restart', and the function to check */
static char *spargs[8];
static int fc;
/* Called on process re-execution. */
_Noreturn static void
handle_restart (int argc, char *argv[])
{
TEST_VERIFY_EXIT (argc == 1);
const char *funcname = argv[0];
struct libc_ifunc_impl impls[32];
int cnt = __libc_ifunc_impl_list ("memcpy", impls, array_length (impls));
if (cnt == 0)
_exit (EXIT_SUCCESS);
TEST_VERIFY_EXIT (cnt >= 1);
for (int i = 0; i < cnt; i++) {
if (strcmp (impls[i].name, funcname) == 0)
{
TEST_COMPARE (impls[i].usable, false);
break;
}
}
_exit (EXIT_SUCCESS);
}
static void
run_test (const char *filter, const char *funcname)
{
printf ("info: checking filter %s (expect %s ifunc selection to be removed)\n",
filter, funcname);
char *tunable = xasprintf ("GLIBC_TUNABLES=glibc.cpu.hwcaps=%s", filter);
char *const newenvs[] = { (char*) tunable, NULL };
spargs[fc] = (char *) funcname;
pid_t pid;
TEST_COMPARE (posix_spawn (&pid, spargs[0], NULL, NULL, spargs, newenvs), 0);
int status;
TEST_COMPARE (xwaitpid (pid, &status, 0), pid);
TEST_VERIFY (WIFEXITED (status));
TEST_VERIFY (!WIFSIGNALED (status));
TEST_COMPARE (WEXITSTATUS (status), 0);
free (tunable);
}
static int
do_test (int argc, char *argv[])
{
if (restart)
handle_restart (argc - 1, &argv[1]);
TEST_VERIFY_EXIT (argc == 2 || argc == 5);
int i;
for (i = 0; i < argc - 1; i++)
spargs[i] = argv[i + 1];
spargs[i++] = (char *) "--direct";
spargs[i++] = (char *) "--restart";
fc = i++;
spargs[i] = NULL;
unsigned long int hwcap = getauxval (AT_HWCAP);
unsigned long int hwcap2 = getauxval (AT_HWCAP2);
if (__WORDSIZE == 64)
{
if (hwcap2 & PPC_FEATURE2_ARCH_3_1)
run_test ("-arch_3_1", "__memcpy_power10");
if (hwcap2 & PPC_FEATURE2_ARCH_2_07)
run_test ("-arch_2_07", "__memcpy_power8_cached");
if (hwcap & PPC_FEATURE_ARCH_2_06)
run_test ("-arch_2_06", "__memcpy_power7");
if (hwcap & PPC_FEATURE_ARCH_2_05)
run_test ("-arch_2_06,-arch_2_05","__memcpy_power6");
run_test ("-arch_2_06,-arch_2_05,-power5+,-power5,-power4",
"__memcpy_power4");
/* Also run with valid, but empty settings. */
run_test (",-,-arch_2_06,-arch_2_05,-power5+,-power5,,-power4,-",
"__memcpy_power4");
}
else
{
if (hwcap & PPC_FEATURE_HAS_VSX)
run_test ("-vsx", "__memcpy_power7");
if (hwcap & PPC_FEATURE_ARCH_2_06)
run_test ("-arch_2_06", "__memcpy_a2");
if (hwcap & PPC_FEATURE_ARCH_2_05)
run_test ("-arch_2_05", "__memcpy_power6");
}
return 0;
}
#define TEST_FUNCTION_ARGV do_test
#include