From patchwork Mon Jun 8 21:03:16 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: cseo X-Patchwork-Id: 482002 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 3F49A1401F6 for ; Tue, 9 Jun 2015 07:03:36 +1000 (AEST) Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=sourceware.org header.i=@sourceware.org header.b=OCIRcQJP; dkim-atps=neutral DomainKey-Signature: a=rsa-sha1; c=nofws; d=sourceware.org; h=list-id :list-unsubscribe:list-subscribe:list-archive:list-post :list-help:sender:message-id:date:from:mime-version:to:cc :subject:content-type; q=dns; s=default; b=HshfAHarynhjcbkfwmZhc lFJUjfLaDoW3AGLcBGhkJib/5632MQa56WNaXJlW/BUOVSvW8gXCVFcqA1rr0w3t 8eX+yERTfD5WMtdOGMIyYYwgeRfC9Y/dddOPOfuWlJ3NKSWXv036utTgXczTBpMV s0QCUpqjZ3fFVYiH6wUcsk= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=sourceware.org; h=list-id :list-unsubscribe:list-subscribe:list-archive:list-post :list-help:sender:message-id:date:from:mime-version:to:cc :subject:content-type; s=default; bh=sFjKgDQzmNJokQkRKoHI9lO1oY0 =; b=OCIRcQJP4wo1D0I4/kbQGZf8zY4zt0JGyF6MLdjKKucaALadQzA+r5uVCKu GW1ygbQu9KBuHIWzhVyxYRagHFXVODUCyvMQmrqh8qOUbq7RzVahSlnJTpa6GjBF uTHDcbzsCoiycWB9QcDArY6RB5Ilcr/yHkyKidz2fKR5/hcw= Received: (qmail 94630 invoked by alias); 8 Jun 2015 21:03:29 -0000 Mailing-List: contact libc-alpha-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: libc-alpha-owner@sourceware.org Delivered-To: mailing list libc-alpha@sourceware.org Received: (qmail 94621 invoked by uid 89); 8 Jun 2015 21:03:29 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=1.3 required=5.0 tests=AWL, BAYES_50, KAM_ASCII_DIVIDERS, KAM_LAZY_DOMAIN_SECURITY, LIKELY_SPAM_BODY, T_RP_MATCHES_RCVD autolearn=no version=3.3.2 X-HELO: e24smtp04.br.ibm.com Message-ID: <55760314.6070601@linux.vnet.ibm.com> Date: Mon, 08 Jun 2015 18:03:16 -0300 From: Carlos Eduardo Seo User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:31.0) Gecko/20100101 Thunderbird/31.7.0 MIME-Version: 1.0 To: GLIBC Devel CC: Steve Munroe Subject: [PATCH] powerpc: New feature - HWCAP/HWCAP2 bits in the TCB X-TM-AS-MML: disable X-Content-Scanned: Fidelis XPS MAILER x-cbid: 15060821-0029-0000-0000-000003BD7031 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, 2015-06-08 Carlos Eduardo Seo 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 #include + +/* 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 + . */ + +/* Tests if the hwcap and hwcap2 data is stored in the TCB. */ + +#include +#include +#include + +#include +#include + +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 + . */ + +/* Tests if the hwcap and hwcap2 data can be stored in the TCB + via the ppc.h API. */ + +#include +#include +#include + +#include +#include + +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" + +