1 /* Copyright (C) 2012-2018 Free Software Foundation, Inc.
2    Contributed by Richard Henderson <rth@redhat.com>.
3 
4    This file is part of the GNU Transactional Memory Library (libitm).
5 
6    Libitm is free software; you can redistribute it and/or modify it
7    under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 3 of the License, or
9    (at your option) any later version.
10 
11    Libitm is distributed in the hope that it will be useful, but WITHOUT ANY
12    WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13    FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
14    more details.
15 
16    Under Section 7 of GPL version 3, you are granted additional
17    permissions described in the GCC Runtime Library Exception, version
18    3.1, as published by the Free Software Foundation.
19 
20    You should have received a copy of the GNU General Public License and
21    a copy of the GCC Runtime Library Exception along with this program;
22    see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
23    <http://www.gnu.org/licenses/>.  */
24 
25 #ifdef HAVE_SYS_AUXV_H
26 #include <sys/auxv.h>
27 #endif
28 
29 namespace GTM HIDDEN {
30 
31 typedef int v128 __attribute__((vector_size(16), may_alias, aligned(16)));
32 typedef struct gtm_jmpbuf
33 {
34 #if defined(__ALTIVEC__) || defined(__VSX__)
35   v128 vr[12];			/* vr20-vr31 */
36   unsigned long long vscr;	/* long long for padding only */
37 #endif
38 #ifndef _SOFT_FLOAT
39   double fr[18];		/* f14-f31 */
40   double fpscr;
41 #endif
42   unsigned long gr[18];		/* r14-r31 */
43   void *cfa;
44   unsigned long pc;
45   unsigned long toc;		/* r2 on aix, r13 on darwin */
46   unsigned long cr;
47 } gtm_jmpbuf;
48 
49 /* The size of one line in hardware caches (in bytes). */
50 #if defined (__powerpc64__) || defined (__ppc64__)
51 # define HW_CACHELINE_SIZE 128
52 #else
53 # define HW_CACHELINE_SIZE 32
54 #endif
55 
56 static inline void
cpu_relax(void)57 cpu_relax (void)
58 {
59   __asm volatile ("" : : : "memory");
60 }
61 
62 // Use HTM if it is supported by the system.
63 // See gtm_thread::begin_transaction for how these functions are used.
64 #if defined (__linux__) \
65     && defined (HAVE_AS_HTM) \
66     && defined (HAVE_GETAUXVAL) \
67     && defined (AT_HWCAP2) \
68     && defined (PPC_FEATURE2_HAS_HTM)
69 
70 #include <htmintrin.h>
71 
72 #define USE_HTM_FASTPATH
73 
74 #define _TBEGIN_STARTED       0
75 #define _TBEGIN_INDETERMINATE 1
76 #define _TBEGIN_PERSISTENT    2
77 
78 /* Number of retries for transient failures.  */
79 #define _HTM_RETRIES 10
80 
81 static inline bool
htm_available(void)82 htm_available (void)
83 {
84 #ifdef __BUILTIN_CPU_SUPPORTS__
85   if (__builtin_cpu_supports ("htm-no-suspend")
86       || __builtin_cpu_supports ("htm"))
87     return true;
88 #else
89   unsigned long htm_flags = PPC_FEATURE2_HAS_HTM
90 #ifdef PPC_FEATURE2_HTM_NO_SUSPEND
91 			    | PPC_FEATURE2_HTM_NO_SUSPEND
92 #endif
93 			    | 0;
94   if (getauxval (AT_HWCAP2) & htm_flags)
95     return true;
96 #endif
97   return false;
98 }
99 
100 static inline uint32_t
htm_init(void)101 htm_init (void)
102 {
103   // Maximum number of times we try to execute a transaction
104   // as a HW transaction.
105   return htm_available () ? _HTM_RETRIES : 0;
106 }
107 
108 static inline uint32_t
htm_begin(void)109 htm_begin (void)
110 {
111   if (__builtin_expect (__builtin_tbegin (0), 1))
112     return _TBEGIN_STARTED;
113 
114   if (_TEXASRU_FAILURE_PERSISTENT (__builtin_get_texasru ()))
115     return _TBEGIN_PERSISTENT;
116 
117   return _TBEGIN_INDETERMINATE;
118 }
119 
120 static inline bool
htm_begin_success(uint32_t begin_ret)121 htm_begin_success (uint32_t begin_ret)
122 {
123   return begin_ret == _TBEGIN_STARTED;
124 }
125 
126 static inline void
htm_commit(void)127 htm_commit (void)
128 {
129   __builtin_tend (0);
130 }
131 
132 static inline void
htm_abort(void)133 htm_abort (void)
134 {
135   __builtin_tabort (0);
136 }
137 
138 static inline bool
htm_abort_should_retry(uint32_t begin_ret)139 htm_abort_should_retry (uint32_t begin_ret)
140 {
141   return begin_ret != _TBEGIN_PERSISTENT;
142 }
143 
144 /* Returns true iff a hardware transaction is currently being executed.  */
145 static inline bool
htm_transaction_active(void)146 htm_transaction_active (void)
147 {
148   return (_HTM_STATE (__builtin_ttest ()) == _HTM_TRANSACTIONAL);
149 }
150 
151 #endif
152 
153 } // namespace GTM
154