Blame sysdeps/unix/sysv/linux/s390/htm.h

Packit 6c4009
/* Shared HTM header.  Work around false transactional execution facility
Packit 6c4009
   intrinsics.
Packit 6c4009
Packit 6c4009
   Copyright (C) 2016-2018 Free Software Foundation, Inc.
Packit 6c4009
   This file is part of the GNU C Library.
Packit 6c4009
Packit 6c4009
   The GNU C Library is free software; you can redistribute it and/or
Packit 6c4009
   modify it under the terms of the GNU Lesser General Public
Packit 6c4009
   License as published by the Free Software Foundation; either
Packit 6c4009
   version 2.1 of the License, or (at your option) any later version.
Packit 6c4009
Packit 6c4009
   The GNU C Library is distributed in the hope that it will be useful,
Packit 6c4009
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 6c4009
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 6c4009
   Lesser General Public License for more details.
Packit 6c4009
Packit 6c4009
   You should have received a copy of the GNU Lesser General Public
Packit 6c4009
   License along with the GNU C Library; if not, see
Packit 6c4009
   <http://www.gnu.org/licenses/>.  */
Packit 6c4009
Packit 6c4009
#ifndef _HTM_H
Packit 6c4009
#define _HTM_H 1
Packit 6c4009
Packit 6c4009
#include <htmintrin.h>
Packit 6c4009
Packit 6c4009
#ifdef __s390x__
Packit 6c4009
# define TX_FPRS_BYTES 64
Packit 6c4009
# define TX_SAVE_FPRS						\
Packit 6c4009
  "   std %%f8, 0(%[R_FPRS])\n\t"				\
Packit 6c4009
  "   std %%f9, 8(%[R_FPRS])\n\t"				\
Packit 6c4009
  "   std %%f10, 16(%[R_FPRS])\n\t"				\
Packit 6c4009
  "   std %%f11, 24(%[R_FPRS])\n\t"				\
Packit 6c4009
  "   std %%f12, 32(%[R_FPRS])\n\t"				\
Packit 6c4009
  "   std %%f13, 40(%[R_FPRS])\n\t"				\
Packit 6c4009
  "   std %%f14, 48(%[R_FPRS])\n\t"				\
Packit 6c4009
  "   std %%f15, 56(%[R_FPRS])\n\t"
Packit 6c4009
Packit 6c4009
# define TX_RESTORE_FPRS					\
Packit 6c4009
  "   ld %%f8, 0(%[R_FPRS])\n\t"				\
Packit 6c4009
  "   ld %%f9, 8(%[R_FPRS])\n\t"				\
Packit 6c4009
  "   ld %%f10, 16(%[R_FPRS])\n\t"				\
Packit 6c4009
  "   ld %%f11, 24(%[R_FPRS])\n\t"				\
Packit 6c4009
  "   ld %%f12, 32(%[R_FPRS])\n\t"				\
Packit 6c4009
  "   ld %%f13, 40(%[R_FPRS])\n\t"				\
Packit 6c4009
  "   ld %%f14, 48(%[R_FPRS])\n\t"				\
Packit 6c4009
  "   ld %%f15, 56(%[R_FPRS])\n\t"
Packit 6c4009
Packit 6c4009
#else
Packit 6c4009
Packit 6c4009
# define TX_FPRS_BYTES 16
Packit 6c4009
# define TX_SAVE_FPRS						\
Packit 6c4009
  "   std %%f4, 0(%[R_FPRS])\n\t"				\
Packit 6c4009
  "   std %%f6, 8(%[R_FPRS])\n\t"
Packit 6c4009
Packit 6c4009
# define TX_RESTORE_FPRS					\
Packit 6c4009
  "   ld %%f4, 0(%[R_FPRS])\n\t"				\
Packit 6c4009
  "   ld %%f6, 8(%[R_FPRS])\n\t"
Packit 6c4009
Packit 6c4009
#endif /* ! __s390x__  */
Packit 6c4009
Packit 6c4009
/* Use own inline assembly instead of __builtin_tbegin, as tbegin
Packit 6c4009
   has to filter program interruptions which can't be done with the builtin.
Packit 6c4009
   Now the fprs have to be saved / restored here, too.
Packit 6c4009
   The fpc is also not saved / restored with the builtin.
Packit 6c4009
   The used inline assembly does not clobber the volatile fprs / vrs!
Packit 6c4009
   Clobbering the latter ones would force the compiler to save / restore
Packit 6c4009
   the call saved fprs as those overlap with the vrs, but they only need to be
Packit 6c4009
   restored if the transaction fails but not if the transaction is successfully
Packit 6c4009
   started.  Thus the user of the tbegin macros in this header file has to
Packit 6c4009
   compile the file / function with -msoft-float.  It prevents gcc from using
Packit 6c4009
   fprs / vrs.  */
Packit 6c4009
#define __libc_tbegin(tdb) __libc_tbegin_base(tdb,,,)
Packit 6c4009
Packit 6c4009
#define __libc_tbegin_retry_output_regs , [R_TX_CNT] "+&d" (__tx_cnt)
Packit 6c4009
#define __libc_tbegin_retry_input_regs(retry_cnt) , [R_RETRY] "d" (retry_cnt)
Packit 6c4009
#define __libc_tbegin_retry_abort_path_insn				\
Packit 6c4009
  /* If tbegin returned _HTM_TBEGIN_TRANSIENT, retry immediately so	\
Packit 6c4009
     that max tbegin_cnt transactions are tried.  Otherwise return and	\
Packit 6c4009
     let the caller of this macro do the fallback path.  */		\
Packit 6c4009
  "   jnh 1f\n\t" /* cc 1/3: jump to fallback path.  */			\
Packit 6c4009
  /* tbegin returned _HTM_TBEGIN_TRANSIENT: retry with transaction.  */ \
Packit 6c4009
  "   crje %[R_TX_CNT], %[R_RETRY], 1f\n\t" /* Reached max retries?  */	\
Packit 6c4009
  "   ahi %[R_TX_CNT], 1\n\t"						\
Packit 6c4009
  "   ppa %[R_TX_CNT], 0, 1\n\t" /* Transaction-Abort Assist.  */	\
Packit 6c4009
  "   j 2b\n\t" /* Loop to tbegin.  */
Packit 6c4009
Packit 6c4009
/* Same as __libc_tbegin except if tbegin aborts with _HTM_TBEGIN_TRANSIENT.
Packit 6c4009
   Then this macros restores the fpc, fprs and automatically retries up to
Packit 6c4009
   retry_cnt tbegins.  Further saving of the state is omitted as it is already
Packit 6c4009
   saved.  This macro calls tbegin at most as retry_cnt + 1 times.  */
Packit 6c4009
#define __libc_tbegin_retry(tdb, retry_cnt)				\
Packit 6c4009
  ({ int __ret;								\
Packit 6c4009
    int __tx_cnt = 0;							\
Packit 6c4009
    __ret = __libc_tbegin_base(tdb,					\
Packit 6c4009
			       __libc_tbegin_retry_abort_path_insn,	\
Packit 6c4009
			       __libc_tbegin_retry_output_regs,		\
Packit 6c4009
			       __libc_tbegin_retry_input_regs(retry_cnt)); \
Packit 6c4009
    __ret;								\
Packit 6c4009
  })
Packit 6c4009
Packit 6c4009
#define __libc_tbegin_base(tdb, abort_path_insn, output_regs, input_regs) \
Packit 6c4009
  ({ int __ret;								\
Packit 6c4009
     int __fpc;								\
Packit 6c4009
     char __fprs[TX_FPRS_BYTES];					\
Packit 6c4009
     __asm__ __volatile__ (".machine push\n\t"				\
Packit 6c4009
			   ".machinemode \"zarch_nohighgprs\"\n\t"	\
Packit 6c4009
			   ".machine \"all\"\n\t"			\
Packit 6c4009
			   /* Save state at the outermost transaction.	\
Packit 6c4009
			      As extracting nesting depth is expensive	\
Packit 6c4009
			      on at least zEC12, save fprs at inner	\
Packit 6c4009
			      transactions, too.			\
Packit 6c4009
			      The fpc and fprs are saved here as they	\
Packit 6c4009
			      are not saved by tbegin.  There exist no	\
Packit 6c4009
			      call-saved vrs, thus they are not saved	\
Packit 6c4009
			      here.  */					\
Packit 6c4009
			   "   efpc %[R_FPC]\n\t"			\
Packit 6c4009
			   TX_SAVE_FPRS					\
Packit 6c4009
			   /* Begin transaction: save all gprs, allow	\
Packit 6c4009
			      ar modification and fp operations.  Some	\
Packit 6c4009
			      program-interruptions (e.g. a null	\
Packit 6c4009
			      pointer access) are filtered and the	\
Packit 6c4009
			      transaction will abort.  In this case	\
Packit 6c4009
			      the normal lock path will execute it	\
Packit 6c4009
			      again and result in a core dump wich does	\
Packit 6c4009
			      now show at tbegin but the real executed	\
Packit 6c4009
			      instruction.				\
Packit 6c4009
			      However it is not guaranteed that this	\
Packit 6c4009
			      retry operate on the same data and thus	\
Packit 6c4009
			      may not end in an program-interruption.	\
Packit 6c4009
			      Note: This could also be used to probe	\
Packit 6c4009
			      memory for being accessible!  */		\
Packit 6c4009
			   "2: tbegin 0, 0xFF0E\n\t"			\
Packit 6c4009
			   /* Branch away in abort case (this is the	\
Packit 6c4009
			      prefered sequence.  See PoP in chapter 5	\
Packit 6c4009
			      Transactional-Execution Facility		\
Packit 6c4009
			      Operation).  */				\
Packit 6c4009
			   "   jnz 0f\n\t"				\
Packit 6c4009
			   /* Transaction has successfully started.  */	\
Packit 6c4009
			   "   lhi %[R_RET], 0\n\t"			\
Packit 6c4009
			   "   j 1f\n\t"				\
Packit 6c4009
			   /* Transaction has aborted.  Now we are at	\
Packit 6c4009
			      the outermost transaction.  Restore fprs	\
Packit 6c4009
			      and fpc. */				\
Packit 6c4009
			   "0: ipm %[R_RET]\n\t"			\
Packit 6c4009
			   "   srl %[R_RET], 28\n\t"			\
Packit 6c4009
			   "   sfpc %[R_FPC]\n\t"			\
Packit 6c4009
			   TX_RESTORE_FPRS				\
Packit 6c4009
			   abort_path_insn				\
Packit 6c4009
			   "1:\n\t"					\
Packit 6c4009
			   ".machine pop\n"				\
Packit 6c4009
			   : [R_RET] "=&d" (__ret),			\
Packit 6c4009
			     [R_FPC] "=&d" (__fpc)			\
Packit 6c4009
			     output_regs				\
Packit 6c4009
			   : [R_FPRS] "a" (__fprs)			\
Packit 6c4009
			     input_regs					\
Packit 6c4009
			   : "cc", "memory");				\
Packit 6c4009
     __ret;								\
Packit 6c4009
     })
Packit 6c4009
Packit 6c4009
/* These builtins are usable in context of glibc lock elision code without any
Packit 6c4009
   changes.  Use them.  */
Packit 6c4009
#define __libc_tend()							\
Packit 6c4009
  ({ __asm__ __volatile__ (".machine push\n\t"				\
Packit 6c4009
			   ".machinemode \"zarch_nohighgprs\"\n\t"	\
Packit 6c4009
			   ".machine \"all\"\n\t");			\
Packit 6c4009
    int __ret = __builtin_tend ();					\
Packit 6c4009
    __asm__ __volatile__ (".machine pop");				\
Packit 6c4009
    __ret;								\
Packit 6c4009
  })
Packit 6c4009
Packit 6c4009
#define __libc_tabort(abortcode)					\
Packit 6c4009
  __asm__ __volatile__ (".machine push\n\t"				\
Packit 6c4009
			".machinemode \"zarch_nohighgprs\"\n\t"		\
Packit 6c4009
			".machine \"all\"\n\t");			\
Packit 6c4009
  __builtin_tabort (abortcode);						\
Packit 6c4009
  __asm__ __volatile__ (".machine pop")
Packit 6c4009
Packit 6c4009
#define __libc_tx_nesting_depth() \
Packit 6c4009
  ({ __asm__ __volatile__ (".machine push\n\t"				\
Packit 6c4009
			   ".machinemode \"zarch_nohighgprs\"\n\t"	\
Packit 6c4009
			   ".machine \"all\"\n\t");			\
Packit 6c4009
    int __ret = __builtin_tx_nesting_depth ();				\
Packit 6c4009
    __asm__ __volatile__ (".machine pop");				\
Packit 6c4009
    __ret;								\
Packit 6c4009
  })
Packit 6c4009
Packit 6c4009
#endif