This is the mail archive of the libc-alpha@sourceware.org mailing list for the glibc project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH] powerpc: New feature - HWCAP/HWCAP2 bits in the TCB


The proposed patch adds a new feature for powerpc. In order to get faster access to the HWCAP/HWCAP2 bits, we now store them in the TCB. This enables users to write versioned code based on the HWCAP bits without going through the overhead of reading them from the auxiliary vector.

A new API is published in ppc.h for get/set the bits in the aforementioned memory area (mainly for gcc to use to create builtins).

Testcases for the API functions were also created.

Tested on ppc32, ppc64 and ppc64le.

Okay to commit?

Thanks,

-- 
Carlos Eduardo Seo
Software Engineer - Linux on Power Toolchain
cseo@linux.vnet.ibm.com

2015-06-08  Carlos Eduardo Seo  <cseo@linux.vnet.ibm.com>

	This patch adds a new feature for powerpc. In order to get faster
	access to the HWCAP/HWCAP2 bits, we now store them in the TCB, so
	we don't have to deal with the overhead of reading them via the
	auxiliary vector. A new API is published in ppc.h for get/set the
	bits.

	* sysdeps/powerpc/nptl/tcb-offsets.sym: Added new offests
	for HWCAP and HWCAP2 in the TCB.
	* sysdeps/powerpc/nptl/tls.h: New functionality - stores
	the HWCAP and HWCAP2 in the TCB.
	(dtv): Added new fields for HWCAP and HWCAP2.
	(TLS_INIT_TP): Included calls to add the hwcap/hwcap2
	values in the TCB in TP initialization.
	(TLS_DEFINE_INIT_TP): Likewise.
	(THREAD_GET_HWCAP): New macro.
	(THREAD_SET_HWCAP): Likewise.
	(THREAD_GET_HWCAP2): Likewise.
	(THREAD_SET_HWCAP2): Likewise.
	* sysdeps/powerpc/sys/platform/ppc.h: Added new functions
	for get/set the HWCAP/HWCAP2 values in the TCB.
	(__ppc_get_hwcap): New function.
	(__ppc_get_hwcap2): Likewise.
	* sysdeps/powerpc/test-get_hwcap.c: Testcase for this
	functionality.
	* sysdeps/powerpc/test-set_hwcap.c: Testcase for this
	functionality.
	* sysdeps/powerpc/Makefile: Added testcases to the Makefile.
	

Index: glibc-working/sysdeps/powerpc/nptl/tcb-offsets.sym
===================================================================
--- glibc-working.orig/sysdeps/powerpc/nptl/tcb-offsets.sym
+++ glibc-working/sysdeps/powerpc/nptl/tcb-offsets.sym
@@ -20,6 +20,8 @@ TAR_SAVE			(offsetof (tcbhead_t, tar_sav
 DSO_SLOT1			(offsetof (tcbhead_t, dso_slot1) - TLS_TCB_OFFSET - sizeof (tcbhead_t))
 DSO_SLOT2			(offsetof (tcbhead_t, dso_slot2) - TLS_TCB_OFFSET - sizeof (tcbhead_t))
 TM_CAPABLE			(offsetof (tcbhead_t, tm_capable) - TLS_TCB_OFFSET - sizeof (tcbhead_t))
+TCB_HWCAP			(offsetof (tcbhead_t, hwcap) - TLS_TCB_OFFSET - sizeof (tcbhead_t))
+TCB_HWCAP2			(offsetof (tcbhead_t, hwcap2) - TLS_TCB_OFFSET - sizeof (tcbhead_t))
 #ifndef __ASSUME_PRIVATE_FUTEX
 PRIVATE_FUTEX_OFFSET		thread_offsetof (header.private_futex)
 #endif
Index: glibc-working/sysdeps/powerpc/nptl/tls.h
===================================================================
--- glibc-working.orig/sysdeps/powerpc/nptl/tls.h
+++ glibc-working/sysdeps/powerpc/nptl/tls.h
@@ -63,6 +63,9 @@ typedef union dtv
    are private.  */
 typedef struct
 {
+  /* Reservation for HWCAP data.  */
+  unsigned int hwcap2;
+  unsigned int hwcap;
   /* Indicate if HTM capable (ISA 2.07).  */
   int tm_capable;
   /* Reservation for Dynamic System Optimizer ABI.  */
@@ -134,7 +137,11 @@ register void *__thread_register __asm__
 # define TLS_INIT_TP(tcbp) \
   ({ 									      \
     __thread_register = (void *) (tcbp) + TLS_TCB_OFFSET;		      \
-    THREAD_SET_TM_CAPABLE (GLRO (dl_hwcap2) & PPC_FEATURE2_HAS_HTM ? 1 : 0);  \
+    unsigned int hwcap = GLRO(dl_hwcap);				      \
+    unsigned int hwcap2 = GLRO(dl_hwcap2);				      \
+    THREAD_SET_TM_CAPABLE (hwcap2 & PPC_FEATURE2_HAS_HTM ? 1 : 0);	      \
+    THREAD_SET_HWCAP (hwcap);						      \
+    THREAD_SET_HWCAP2 (hwcap2);						      \
     NULL;								      \
   })
 
@@ -142,7 +149,11 @@ register void *__thread_register __asm__
 # define TLS_DEFINE_INIT_TP(tp, pd) \
     void *tp = (void *) (pd) + TLS_TCB_OFFSET + TLS_PRE_TCB_SIZE;	      \
     (((tcbhead_t *) ((char *) tp - TLS_TCB_OFFSET))[-1].tm_capable) =	      \
-      THREAD_GET_TM_CAPABLE ();
+      THREAD_GET_TM_CAPABLE ();						      \
+    (((tcbhead_t *) ((char *) tp - TLS_TCB_OFFSET))[-1].hwcap) =	      \
+      THREAD_GET_HWCAP ();						      \
+    (((tcbhead_t *) ((char *) tp - TLS_TCB_OFFSET))[-1].hwcap2) =	      \
+      THREAD_GET_HWCAP2 ();
 
 /* Return the address of the dtv for the current thread.  */
 # define THREAD_DTV() \
@@ -203,6 +214,32 @@ register void *__thread_register __asm__
 # define THREAD_SET_TM_CAPABLE(value) \
     (THREAD_GET_TM_CAPABLE () = (value))
 
+/* hwcap & hwcap2 fields in TCB head.  */
+# define THREAD_GET_HWCAP() \
+    (((tcbhead_t *) ((char *) __thread_register				      \
+		     - TLS_TCB_OFFSET))[-1].hwcap)
+# define THREAD_SET_HWCAP(value) \
+    if (value & PPC_FEATURE_ARCH_2_06)					      \
+      value |= PPC_FEATURE_ARCH_2_05 |					      \
+	       PPC_FEATURE_POWER5_PLUS |				      \
+	       PPC_FEATURE_POWER5 |					      \
+	       PPC_FEATURE_POWER4;					      \
+    else if (value & PPC_FEATURE_ARCH_2_05)				      \
+      value |= PPC_FEATURE_POWER5_PLUS |				      \
+             PPC_FEATURE_POWER5 |					      \
+             PPC_FEATURE_POWER4;					      \
+    else if (value & PPC_FEATURE_POWER5_PLUS)				      \
+      value |= PPC_FEATURE_POWER5 |					      \
+             PPC_FEATURE_POWER4;					      \
+    else if (value & PPC_FEATURE_POWER5)				      \
+      value |= PPC_FEATURE_POWER4;					      \
+    (THREAD_GET_HWCAP () = (value))
+# define THREAD_GET_HWCAP2() \
+    (((tcbhead_t *) ((char *) __thread_register				      \
+                     - TLS_TCB_OFFSET))[-1].hwcap2)
+# define THREAD_SET_HWCAP2(value) \
+    (THREAD_GET_HWCAP2 () = (value))
+
 /* l_tls_offset == 0 is perfectly valid on PPC, so we have to use some
    different value to mean unset l_tls_offset.  */
 # define NO_TLS_OFFSET		-1
Index: glibc-working/sysdeps/powerpc/sys/platform/ppc.h
===================================================================
--- glibc-working.orig/sysdeps/powerpc/sys/platform/ppc.h
+++ glibc-working/sysdeps/powerpc/sys/platform/ppc.h
@@ -23,6 +23,86 @@
 #include <stdint.h>
 #include <bits/ppc.h>
 
+
+/* Get the hwcap/hwcap2 information from the TCB. Offsets taken
+   from tcb-offsets.h.  */
+static inline uint32_t
+__ppc_get_hwcap (void)
+{
+
+  uint32_t __tcb_hwcap;
+
+#ifdef __powerpc64__
+  register unsigned long __tp __asm__ ("r13");
+  __asm__ volatile ("lwz %0,-28772(%1)\n"
+		    : "=r" (__tcb_hwcap)
+		    : "r" (__tp));
+#else
+  register unsigned long __tp __asm__ ("r2");
+  __asm__ volatile ("lwz %0,-28724(%1)\n"
+		    : "=r" (__tcb_hwcap)
+		    : "r" (__tp));
+#endif
+
+  return __tcb_hwcap;
+}
+
+static inline uint32_t
+__ppc_get_hwcap2 (void)
+{
+
+  uint32_t __tcb_hwcap2;
+
+#ifdef __powerpc64__
+  register unsigned long __tp __asm__ ("r13");
+  __asm__ volatile ("lwz %0,-28776(%1)\n"
+		    : "=r" (__tcb_hwcap2)
+		    : "r" (__tp));
+#else
+  register unsigned long __tp __asm__ ("r2");
+  __asm__ volatile ("lwz %0,-28728(%1)\n"
+		    : "=r" (__tcb_hwcap2)
+		    : "r" (__tp));
+#endif
+
+  return __tcb_hwcap2;
+}
+
+/* Set the hwcap/hwcap2 bits into the designated area in the TCB. Offsets
+   taken from tcb-offsets.h.  */
+
+static inline void
+__ppc_set_hwcap (uint32_t __hwcap_mask)
+{
+#ifdef __powerpc64__
+  register unsigned long __tp __asm__ ("r13");
+  __asm__ volatile ("stw %1,-28772(%0)\n"
+		    :
+		    : "r" (__tp), "r" (__hwcap_mask));
+#else
+  register unsigned long __tp __asm__ ("r2");
+  __asm__ volatile ("stw %1,-28724(%0)\n"
+		    :
+		    : "r" (__tp), "r" (__hwcap_mask));
+#endif
+}
+
+static inline void
+__ppc_set_hwcap2 (uint32_t __hwcap2_mask)
+{
+#ifdef __powerpc64__
+  register unsigned long __tp __asm__ ("r13");
+  __asm__ volatile ("stw %1,-28776(%0)\n"
+		    :
+		    : "r" (__tp), "r" (__hwcap2_mask));
+#else
+  register unsigned long __tp __asm__ ("r2");
+  __asm__ volatile ("stw %1,-28728(%0)\n"
+		    :
+		    : "r" (__tp), "r" (__hwcap2_mask));
+#endif
+}
+
 /* Read the Time Base Register.   */
 static inline uint64_t
 __ppc_get_timebase (void)
Index: glibc-working/sysdeps/powerpc/Makefile
===================================================================
--- glibc-working.orig/sysdeps/powerpc/Makefile
+++ glibc-working/sysdeps/powerpc/Makefile
@@ -28,7 +28,7 @@ endif
 
 ifeq ($(subdir),misc)
 sysdep_headers += sys/platform/ppc.h
-tests += test-gettimebase
+tests += test-gettimebase test-get_hwcap test-set_hwcap
 endif
 
 ifneq (,$(filter %le,$(config-machine)))
Index: glibc-working/sysdeps/powerpc/test-get_hwcap.c
===================================================================
--- /dev/null
+++ glibc-working/sysdeps/powerpc/test-get_hwcap.c
@@ -0,0 +1,73 @@
+/* Check __ppc_get_hwcap() functionality
+   Copyright (C) 2015 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/>.  */
+
+/* Tests if the hwcap and hwcap2 data is stored in the TCB.  */
+
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdint.h>
+
+#include <sys/auxv.h>
+#include <sys/platform/ppc.h>
+
+static int
+do_test (void)
+{
+  uint32_t h1, h2, hwcap, hwcap2;
+
+  h1 = __ppc_get_hwcap ();
+  h2 = __ppc_get_hwcap2 ();
+  hwcap = getauxval(AT_HWCAP);
+  hwcap2 = getauxval(AT_HWCAP2);
+
+  /* hwcap contains only the latest supported ISA, the code checks which is
+     and fills the previous supported ones. This is necessary because the
+     same is done in tls.h when setting the values to the TCB.   */
+
+  if (hwcap & PPC_FEATURE_ARCH_2_06)
+    hwcap |= PPC_FEATURE_ARCH_2_05 | PPC_FEATURE_POWER5_PLUS |
+	     PPC_FEATURE_POWER5 | PPC_FEATURE_POWER4;
+  else if (hwcap & PPC_FEATURE_ARCH_2_05)
+    hwcap |= PPC_FEATURE_POWER5_PLUS | PPC_FEATURE_POWER5 | PPC_FEATURE_POWER4;
+  else if (hwcap & PPC_FEATURE_POWER5_PLUS)
+    hwcap |= PPC_FEATURE_POWER5 | PPC_FEATURE_POWER4;
+  else if (hwcap & PPC_FEATURE_POWER5)
+    hwcap |= PPC_FEATURE_POWER4;
+
+  if ( h1 != hwcap )
+    {
+      printf("Fail: HWCAP is %x. Should be %x\n", h1, hwcap);
+      return 1;
+    }
+
+  if ( h2 != hwcap2 )
+    {
+      printf("Fail: HWCAP2 is %x. Should be %x\n", h2, hwcap2);
+      return 1;
+    }
+
+    printf("Pass: HWCAP and HWCAP2 are correctly set in the TCB.\n");
+
+    return 0;
+
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
+
+
Index: glibc-working/sysdeps/powerpc/test-set_hwcap.c
===================================================================
--- /dev/null
+++ glibc-working/sysdeps/powerpc/test-set_hwcap.c
@@ -0,0 +1,63 @@
+/* Check __ppc_get_hwcap() functionality
+   Copyright (C) 2015 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/>.  */
+
+/* Tests if the hwcap and hwcap2 data can be stored in the TCB
+   via the ppc.h API.  */
+
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdint.h>
+
+#include <sys/auxv.h>
+#include <sys/platform/ppc.h>
+
+static int
+do_test (void)
+{
+  uint32_t h1, hwcap, hwcap2;
+
+  h1 = 0xDEADBEEF;
+
+  __ppc_set_hwcap(h1);
+  hwcap = __ppc_get_hwcap();
+
+  if ( h1 != hwcap )
+    {
+      printf("Fail: HWCAP is %x. Should be %x\n", h1, hwcap);
+      return 1;
+    }
+
+  __ppc_set_hwcap2(h1);
+  hwcap2 = __ppc_get_hwcap2();
+
+  if ( h1 != hwcap2 )
+    {
+      printf("Fail: HWCAP2 is %x. Should be %x\n", h1, hwcap2);
+      return 1;
+    }
+
+    printf("Pass: HWCAP and HWCAP2 are correctly set in the TCB.\n");
+
+    return 0;
+
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
+
+

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]