]>
Commit | Line | Data |
---|---|---|
1 | .. | |
2 | Copyright 1988-2022 Free Software Foundation, Inc. | |
3 | This is part of the GCC manual. | |
4 | For copying conditions, see the copyright.rst file. | |
5 | ||
6 | .. _powerpc-hardware-transactional-memory-built-in-functions: | |
7 | ||
8 | PowerPC Hardware Transactional Memory Built-in Functions | |
9 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | |
10 | ||
11 | GCC provides two interfaces for accessing the Hardware Transactional | |
12 | Memory (HTM) instructions available on some of the PowerPC family | |
13 | of processors (eg, POWER8). The two interfaces come in a low level | |
14 | interface, consisting of built-in functions specific to PowerPC and a | |
15 | higher level interface consisting of inline functions that are common | |
16 | between PowerPC and S/390. | |
17 | ||
18 | PowerPC HTM Low Level Built-in Functions | |
19 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | |
20 | ||
21 | The following low level built-in functions are available with | |
22 | :option:`-mhtm` or :option:`-mcpu=CPU` where CPU is 'power8' or later. | |
23 | They all generate the machine instruction that is part of the name. | |
24 | ||
25 | The HTM builtins (with the exception of ``__builtin_tbegin``) return | |
26 | the full 4-bit condition register value set by their associated hardware | |
27 | instruction. The header file ``htmintrin.h`` defines some macros that can | |
28 | be used to decipher the return value. The ``__builtin_tbegin`` builtin | |
29 | returns a simple ``true`` or ``false`` value depending on whether a transaction was | |
30 | successfully started or not. The arguments of the builtins match exactly the | |
31 | type and order of the associated hardware instruction's operands, except for | |
32 | the ``__builtin_tcheck`` builtin, which does not take any input arguments. | |
33 | Refer to the ISA manual for a description of each instruction's operands. | |
34 | ||
35 | .. code-block:: c++ | |
36 | ||
37 | unsigned int __builtin_tbegin (unsigned int); | |
38 | unsigned int __builtin_tend (unsigned int); | |
39 | ||
40 | unsigned int __builtin_tabort (unsigned int); | |
41 | unsigned int __builtin_tabortdc (unsigned int, unsigned int, unsigned int); | |
42 | unsigned int __builtin_tabortdci (unsigned int, unsigned int, int); | |
43 | unsigned int __builtin_tabortwc (unsigned int, unsigned int, unsigned int); | |
44 | unsigned int __builtin_tabortwci (unsigned int, unsigned int, int); | |
45 | ||
46 | unsigned int __builtin_tcheck (void); | |
47 | unsigned int __builtin_treclaim (unsigned int); | |
48 | unsigned int __builtin_trechkpt (void); | |
49 | unsigned int __builtin_tsr (unsigned int); | |
50 | ||
51 | In addition to the above HTM built-ins, we have added built-ins for | |
52 | some common extended mnemonics of the HTM instructions: | |
53 | ||
54 | .. code-block:: c++ | |
55 | ||
56 | unsigned int __builtin_tendall (void); | |
57 | unsigned int __builtin_tresume (void); | |
58 | unsigned int __builtin_tsuspend (void); | |
59 | ||
60 | Note that the semantics of the above HTM builtins are required to mimic | |
61 | the locking semantics used for critical sections. Builtins that are used | |
62 | to create a new transaction or restart a suspended transaction must have | |
63 | lock acquisition like semantics while those builtins that end or suspend a | |
64 | transaction must have lock release like semantics. Specifically, this must | |
65 | mimic lock semantics as specified by C++11, for example: Lock acquisition is | |
66 | as-if an execution of __atomic_exchange_n(&globallock,1,__ATOMIC_ACQUIRE) | |
67 | that returns 0, and lock release is as-if an execution of | |
68 | __atomic_store(&globallock,0,__ATOMIC_RELEASE), with globallock being an | |
69 | implicit implementation-defined lock used for all transactions. The HTM | |
70 | instructions associated with with the builtins inherently provide the | |
71 | correct acquisition and release hardware barriers required. However, | |
72 | the compiler must also be prohibited from moving loads and stores across | |
73 | the builtins in a way that would violate their semantics. This has been | |
74 | accomplished by adding memory barriers to the associated HTM instructions | |
75 | (which is a conservative approach to provide acquire and release semantics). | |
76 | Earlier versions of the compiler did not treat the HTM instructions as | |
77 | memory barriers. A ``__TM_FENCE__`` macro has been added, which can | |
78 | be used to determine whether the current compiler treats HTM instructions | |
79 | as memory barriers or not. This allows the user to explicitly add memory | |
80 | barriers to their code when using an older version of the compiler. | |
81 | ||
82 | The following set of built-in functions are available to gain access | |
83 | to the HTM specific special purpose registers. | |
84 | ||
85 | .. code-block:: c++ | |
86 | ||
87 | unsigned long __builtin_get_texasr (void); | |
88 | unsigned long __builtin_get_texasru (void); | |
89 | unsigned long __builtin_get_tfhar (void); | |
90 | unsigned long __builtin_get_tfiar (void); | |
91 | ||
92 | void __builtin_set_texasr (unsigned long); | |
93 | void __builtin_set_texasru (unsigned long); | |
94 | void __builtin_set_tfhar (unsigned long); | |
95 | void __builtin_set_tfiar (unsigned long); | |
96 | ||
97 | Example usage of these low level built-in functions may look like: | |
98 | ||
99 | .. code-block:: c++ | |
100 | ||
101 | #include <htmintrin.h> | |
102 | ||
103 | int num_retries = 10; | |
104 | ||
105 | while (1) | |
106 | { | |
107 | if (__builtin_tbegin (0)) | |
108 | { | |
109 | /* Transaction State Initiated. */ | |
110 | if (is_locked (lock)) | |
111 | __builtin_tabort (0); | |
112 | ... transaction code... | |
113 | __builtin_tend (0); | |
114 | break; | |
115 | } | |
116 | else | |
117 | { | |
118 | /* Transaction State Failed. Use locks if the transaction | |
119 | failure is "persistent" or we've tried too many times. */ | |
120 | if (num_retries-- <= 0 | |
121 | || _TEXASRU_FAILURE_PERSISTENT (__builtin_get_texasru ())) | |
122 | { | |
123 | acquire_lock (lock); | |
124 | ... non transactional fallback path... | |
125 | release_lock (lock); | |
126 | break; | |
127 | } | |
128 | } | |
129 | } | |
130 | ||
131 | One final built-in function has been added that returns the value of | |
132 | the 2-bit Transaction State field of the Machine Status Register (MSR) | |
133 | as stored in ``CR0``. | |
134 | ||
135 | .. code-block:: c++ | |
136 | ||
137 | unsigned long __builtin_ttest (void) | |
138 | ||
139 | This built-in can be used to determine the current transaction state | |
140 | using the following code example: | |
141 | ||
142 | .. code-block:: c++ | |
143 | ||
144 | #include <htmintrin.h> | |
145 | ||
146 | unsigned char tx_state = _HTM_STATE (__builtin_ttest ()); | |
147 | ||
148 | if (tx_state == _HTM_TRANSACTIONAL) | |
149 | { | |
150 | /* Code to use in transactional state. */ | |
151 | } | |
152 | else if (tx_state == _HTM_NONTRANSACTIONAL) | |
153 | { | |
154 | /* Code to use in non-transactional state. */ | |
155 | } | |
156 | else if (tx_state == _HTM_SUSPENDED) | |
157 | { | |
158 | /* Code to use in transaction suspended state. */ | |
159 | } | |
160 | ||
161 | PowerPC HTM High Level Inline Functions | |
162 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | |
163 | ||
164 | The following high level HTM interface is made available by including | |
165 | ``<htmxlintrin.h>`` and using :option:`-mhtm` or :option:`-mcpu=CPU` | |
166 | where CPU is 'power8' or later. This interface is common between PowerPC | |
167 | and S/390, allowing users to write one HTM source implementation that | |
168 | can be compiled and executed on either system. | |
169 | ||
170 | .. code-block:: c++ | |
171 | ||
172 | long __TM_simple_begin (void); | |
173 | long __TM_begin (void* const TM_buff); | |
174 | long __TM_end (void); | |
175 | void __TM_abort (void); | |
176 | void __TM_named_abort (unsigned char const code); | |
177 | void __TM_resume (void); | |
178 | void __TM_suspend (void); | |
179 | ||
180 | long __TM_is_user_abort (void* const TM_buff); | |
181 | long __TM_is_named_user_abort (void* const TM_buff, unsigned char *code); | |
182 | long __TM_is_illegal (void* const TM_buff); | |
183 | long __TM_is_footprint_exceeded (void* const TM_buff); | |
184 | long __TM_nesting_depth (void* const TM_buff); | |
185 | long __TM_is_nested_too_deep(void* const TM_buff); | |
186 | long __TM_is_conflict(void* const TM_buff); | |
187 | long __TM_is_failure_persistent(void* const TM_buff); | |
188 | long __TM_failure_address(void* const TM_buff); | |
189 | long long __TM_failure_code(void* const TM_buff); | |
190 | ||
191 | Using these common set of HTM inline functions, we can create | |
192 | a more portable version of the HTM example in the previous | |
193 | section that will work on either PowerPC or S/390: | |
194 | ||
195 | .. code-block:: c++ | |
196 | ||
197 | #include <htmxlintrin.h> | |
198 | ||
199 | int num_retries = 10; | |
200 | TM_buff_type TM_buff; | |
201 | ||
202 | while (1) | |
203 | { | |
204 | if (__TM_begin (TM_buff) == _HTM_TBEGIN_STARTED) | |
205 | { | |
206 | /* Transaction State Initiated. */ | |
207 | if (is_locked (lock)) | |
208 | __TM_abort (); | |
209 | ... transaction code... | |
210 | __TM_end (); | |
211 | break; | |
212 | } | |
213 | else | |
214 | { | |
215 | /* Transaction State Failed. Use locks if the transaction | |
216 | failure is "persistent" or we've tried too many times. */ | |
217 | if (num_retries-- <= 0 | |
218 | || __TM_is_failure_persistent (TM_buff)) | |
219 | { | |
220 | acquire_lock (lock); | |
221 | ... non transactional fallback path... | |
222 | release_lock (lock); | |
223 | break; | |
224 | } | |
225 | } | |
226 | } |