1/* Tests for powerpc GLIBC_TUNABLES=glibc.cpu.hwcaps filter.
2 Copyright (C) 2023-2024 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
4
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, see
17 <http://www.gnu.org/licenses/>. */
18
19#include <array_length.h>
20#include <getopt.h>
21#include <ifunc-impl-list.h>
22#include <spawn.h>
23#include <stdio.h>
24#include <stdlib.h>
25#include <string.h>
26#include <support/check.h>
27#include <support/support.h>
28#include <support/xunistd.h>
29#include <sys/auxv.h>
30#include <sys/wait.h>
31
32/* Nonzero if the program gets called via `exec'. */
33#define CMDLINE_OPTIONS \
34 { "restart", no_argument, &restart, 1 },
35static int restart;
36
37/* Hold the four initial argument used to respawn the process, plus the extra
38 '--direct', '--restart', and the function to check */
39static char *spargs[8];
40static int fc;
41
42/* Called on process re-execution. */
43_Noreturn static void
44handle_restart (int argc, char *argv[])
45{
46 TEST_VERIFY_EXIT (argc == 1);
47 const char *funcname = argv[0];
48
49 struct libc_ifunc_impl impls[32];
50 int cnt = __libc_ifunc_impl_list (name: "memcpy", array: impls, array_length (impls));
51 if (cnt == 0)
52 _exit (EXIT_SUCCESS);
53 TEST_VERIFY_EXIT (cnt >= 1);
54 for (int i = 0; i < cnt; i++) {
55 if (strcmp (impls[i].name, funcname) == 0)
56 {
57 TEST_COMPARE (impls[i].usable, false);
58 break;
59 }
60 }
61
62 _exit (EXIT_SUCCESS);
63}
64
65static void
66run_test (const char *filter, const char *funcname)
67{
68 printf (format: "info: checking filter %s (expect %s ifunc selection to be removed)\n",
69 filter, funcname);
70 char *tunable = xasprintf (format: "GLIBC_TUNABLES=glibc.cpu.hwcaps=%s", filter);
71 char *const newenvs[] = { (char*) tunable, NULL };
72 spargs[fc] = (char *) funcname;
73
74 pid_t pid;
75 TEST_COMPARE (posix_spawn (&pid, spargs[0], NULL, NULL, spargs, newenvs), 0);
76 int status;
77 TEST_COMPARE (xwaitpid (pid, &status, 0), pid);
78 TEST_VERIFY (WIFEXITED (status));
79 TEST_VERIFY (!WIFSIGNALED (status));
80 TEST_COMPARE (WEXITSTATUS (status), 0);
81
82 free (ptr: tunable);
83}
84
85static int
86do_test (int argc, char *argv[])
87{
88 if (restart)
89 handle_restart (argc: argc - 1, argv: &argv[1]);
90
91 TEST_VERIFY_EXIT (argc == 2 || argc == 5);
92
93 int i;
94 for (i = 0; i < argc - 1; i++)
95 spargs[i] = argv[i + 1];
96 spargs[i++] = (char *) "--direct";
97 spargs[i++] = (char *) "--restart";
98 fc = i++;
99 spargs[i] = NULL;
100
101 unsigned long int hwcap = getauxval (AT_HWCAP);
102 unsigned long int hwcap2 = getauxval (AT_HWCAP2);
103 if (__WORDSIZE == 64)
104 {
105 if (hwcap2 & PPC_FEATURE2_ARCH_3_1)
106 run_test (filter: "-arch_3_1", funcname: "__memcpy_power10");
107 if (hwcap2 & PPC_FEATURE2_ARCH_2_07)
108 run_test (filter: "-arch_2_07", funcname: "__memcpy_power8_cached");
109 if (hwcap & PPC_FEATURE_ARCH_2_06)
110 run_test (filter: "-arch_2_06", funcname: "__memcpy_power7");
111 if (hwcap & PPC_FEATURE_ARCH_2_05)
112 run_test (filter: "-arch_2_06,-arch_2_05",funcname: "__memcpy_power6");
113 run_test (filter: "-arch_2_06,-arch_2_05,-power5+,-power5,-power4",
114 funcname: "__memcpy_power4");
115 /* Also run with valid, but empty settings. */
116 run_test (filter: ",-,-arch_2_06,-arch_2_05,-power5+,-power5,,-power4,-",
117 funcname: "__memcpy_power4");
118 }
119 else
120 {
121 if (hwcap & PPC_FEATURE_HAS_VSX)
122 run_test (filter: "-vsx", funcname: "__memcpy_power7");
123 if (hwcap & PPC_FEATURE_ARCH_2_06)
124 run_test (filter: "-arch_2_06", funcname: "__memcpy_a2");
125 if (hwcap & PPC_FEATURE_ARCH_2_05)
126 run_test (filter: "-arch_2_05", funcname: "__memcpy_power6");
127 }
128 return 0;
129}
130
131#define TEST_FUNCTION_ARGV do_test
132#include <support/test-driver.c>
133

source code of glibc/sysdeps/unix/sysv/linux/powerpc/tst-hwcap-tunables.c