about summary refs log tree commit diff
path: root/sysdeps/loongarch/tst-hwcap-tunables.c
diff options
context:
space:
mode:
Diffstat (limited to 'sysdeps/loongarch/tst-hwcap-tunables.c')
-rw-r--r--sysdeps/loongarch/tst-hwcap-tunables.c136
1 files changed, 136 insertions, 0 deletions
diff --git a/sysdeps/loongarch/tst-hwcap-tunables.c b/sysdeps/loongarch/tst-hwcap-tunables.c
new file mode 100644
index 0000000000..fe1b95a8bf
--- /dev/null
+++ b/sysdeps/loongarch/tst-hwcap-tunables.c
@@ -0,0 +1,136 @@
+/* Tests for LoongArch GLIBC_TUNABLES=glibc.cpu.hwcaps filter.
+   Copyright (C) 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
+   <http://www.gnu.org/licenses/>.  */
+
+#include <array_length.h>
+#include <getopt.h>
+#include <ifunc-impl-list.h>
+#include <spawn.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <support/check.h>
+#include <support/support.h>
+#include <support/xunistd.h>
+#include <sys/auxv.h>
+#include <sys/wait.h>
+
+/* Nonzero if the program gets called via `exec'.  */
+#define CMDLINE_OPTIONS \
+  { "restart", no_argument, &restart, 1 }, \
+  { "enable", no_argument, &enable, 1 },
+static int restart;
+static int enable;
+
+/* Hold the four initial argument used to respawn the process, plus the extra
+   '--direct', '--restart', and the function to check.  */
+static char *spargs[9];
+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)
+      {
+	if (enable && impls[i].usable != true)
+	  FAIL_EXIT1 ("FAIL: %s ifunc selection is not enabled.\n", funcname);
+	else if (!enable && impls[i].usable != false)
+	  FAIL_EXIT1 ("FAIL: %s ifunc selection is not disabled.\n", funcname);
+	break;
+      }
+  }
+
+  _exit (EXIT_SUCCESS);
+}
+
+static void
+run_test (const char *filter, const char *funcname, int disable)
+{
+  if (disable)
+    printf ("info: checking filter %s (expect %s ifunc "
+	    "selection to be disabled)\n", filter, funcname);
+  else
+    {
+      printf ("info: checking filter %s (expect %s ifunc "
+	      "selection to be enabled)\n", filter, funcname);
+      spargs[fc++] = (char *) "--enable";
+    }
+
+  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);
+
+  if (!disable)
+    fc--;
+  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);
+
+  if (hwcap & HWCAP_LOONGARCH_LASX)
+    run_test ("-LASX", "__memcpy_lasx", 1);
+  if (hwcap & HWCAP_LOONGARCH_LSX)
+    run_test ("-LSX", "__memcpy_lsx", 1);
+  if (hwcap & HWCAP_LOONGARCH_UAL)
+    run_test ("-UAL", "__memcpy_unaligned", 1);
+
+  /* __memcpy_aligned is the default ifunc selection and will be
+   * always enabled.  */
+  run_test ("-LASX,-LSX,-UAL", "__memcpy_aligned", 0);
+  run_test ("-LASX,-LSX", "__memcpy_aligned", 0);
+  run_test ("-LASX", "__memcpy_aligned", 0);
+
+  return 0;
+}
+
+#define TEST_FUNCTION_ARGV do_test
+#include <support/test-driver.c>