annotate libcilkrts/include/internal/cilk_fake.h @ 117:f81c5aa9f14f

fix
author mir3636
date Tue, 28 Nov 2017 21:17:15 +0900
parents 04ced10e8804
children
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
111
kono
parents:
diff changeset
1 /* cilk_fake.h -*-C++-*-
kono
parents:
diff changeset
2 *
kono
parents:
diff changeset
3 *************************************************************************
kono
parents:
diff changeset
4 *
kono
parents:
diff changeset
5 * Copyright (C) 2011-2016, Intel Corporation
kono
parents:
diff changeset
6 * All rights reserved.
kono
parents:
diff changeset
7 *
kono
parents:
diff changeset
8 * Redistribution and use in source and binary forms, with or without
kono
parents:
diff changeset
9 * modification, are permitted provided that the following conditions
kono
parents:
diff changeset
10 * are met:
kono
parents:
diff changeset
11 *
kono
parents:
diff changeset
12 * * Redistributions of source code must retain the above copyright
kono
parents:
diff changeset
13 * notice, this list of conditions and the following disclaimer.
kono
parents:
diff changeset
14 * * Redistributions in binary form must reproduce the above copyright
kono
parents:
diff changeset
15 * notice, this list of conditions and the following disclaimer in
kono
parents:
diff changeset
16 * the documentation and/or other materials provided with the
kono
parents:
diff changeset
17 * distribution.
kono
parents:
diff changeset
18 * * Neither the name of Intel Corporation nor the names of its
kono
parents:
diff changeset
19 * contributors may be used to endorse or promote products derived
kono
parents:
diff changeset
20 * from this software without specific prior written permission.
kono
parents:
diff changeset
21 *
kono
parents:
diff changeset
22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
kono
parents:
diff changeset
23 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
kono
parents:
diff changeset
24 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
kono
parents:
diff changeset
25 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
kono
parents:
diff changeset
26 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
kono
parents:
diff changeset
27 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
kono
parents:
diff changeset
28 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
kono
parents:
diff changeset
29 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
kono
parents:
diff changeset
30 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
kono
parents:
diff changeset
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
kono
parents:
diff changeset
32 * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
kono
parents:
diff changeset
33 * POSSIBILITY OF SUCH DAMAGE.
kono
parents:
diff changeset
34 *
kono
parents:
diff changeset
35 * *********************************************************************
kono
parents:
diff changeset
36 *
kono
parents:
diff changeset
37 * PLEASE NOTE: This file is a downstream copy of a file mainitained in
kono
parents:
diff changeset
38 * a repository at cilkplus.org. Changes made to this file that are not
kono
parents:
diff changeset
39 * submitted through the contribution process detailed at
kono
parents:
diff changeset
40 * http://www.cilkplus.org/submit-cilk-contribution will be lost the next
kono
parents:
diff changeset
41 * time that a new version is released. Changes only submitted to the
kono
parents:
diff changeset
42 * GNU compiler collection or posted to the git repository at
kono
parents:
diff changeset
43 * https://bitbucket.org/intelcilkruntime/intel-cilk-runtime.git are
kono
parents:
diff changeset
44 * not tracked.
kono
parents:
diff changeset
45 *
kono
parents:
diff changeset
46 * We welcome your contributions to this open source project. Thank you
kono
parents:
diff changeset
47 * for your assistance in helping us improve Cilk Plus.
kono
parents:
diff changeset
48 **************************************************************************/
kono
parents:
diff changeset
49
kono
parents:
diff changeset
50 /**
kono
parents:
diff changeset
51 * @file cilk_fake.h
kono
parents:
diff changeset
52 *
kono
parents:
diff changeset
53 * @brief Macros to simulate a compiled Cilk program.
kono
parents:
diff changeset
54 *
kono
parents:
diff changeset
55 * Used carefully, these macros can be used to create a Cilk program with a
kono
parents:
diff changeset
56 * non-Cilk compiler by manually inserting the code necessary for interacting
kono
parents:
diff changeset
57 * with the Cilk runtime library. They are not intended to be pretty (you
kono
parents:
diff changeset
58 * wouldn't want to write a whole program using these macros), but they are
kono
parents:
diff changeset
59 * useful for experiments. They also work well as an illustration of what the
kono
parents:
diff changeset
60 * compiler generates.
kono
parents:
diff changeset
61 *
kono
parents:
diff changeset
62 * Details of the mechanisms used in these macros are described in
kono
parents:
diff changeset
63 * design-notes/CilkPlusABI.docx
kono
parents:
diff changeset
64 *
kono
parents:
diff changeset
65 * Example 1: fib in C++
kono
parents:
diff changeset
66 * ---------------------
kono
parents:
diff changeset
67 *
kono
parents:
diff changeset
68 * #include <internal/cilk_fake.h>
kono
parents:
diff changeset
69 *
kono
parents:
diff changeset
70 * int fib(int n)
kono
parents:
diff changeset
71 * {
kono
parents:
diff changeset
72 * CILK_FAKE_PROLOG();
kono
parents:
diff changeset
73 *
kono
parents:
diff changeset
74 * if (n < 2)
kono
parents:
diff changeset
75 * return n;
kono
parents:
diff changeset
76 *
kono
parents:
diff changeset
77 * int a, b;
kono
parents:
diff changeset
78 * CILK_FAKE_SPAWN_R(a, fib(n - 1));
kono
parents:
diff changeset
79 * b = fib(n - 2);
kono
parents:
diff changeset
80 * CILK_FAKE_SYNC();
kono
parents:
diff changeset
81 *
kono
parents:
diff changeset
82 * return a + b;
kono
parents:
diff changeset
83 * }
kono
parents:
diff changeset
84 *
kono
parents:
diff changeset
85 *
kono
parents:
diff changeset
86 * Example 2: fib in C
kono
parents:
diff changeset
87 * -------------------
kono
parents:
diff changeset
88 *
kono
parents:
diff changeset
89 * #include <internal/cilk_fake.h>
kono
parents:
diff changeset
90 *
kono
parents:
diff changeset
91 * int fib(int n);
kono
parents:
diff changeset
92 *
kono
parents:
diff changeset
93 * void fib_spawn_helper(__cilkrts_stack_frame* parent_sf, int* a, int n)
kono
parents:
diff changeset
94 * {
kono
parents:
diff changeset
95 * CILK_FAKE_SPAWN_HELPER_PROLOG(*parent_sf);
kono
parents:
diff changeset
96 * *a = fib(n - 1);
kono
parents:
diff changeset
97 * CILK_FAKE_SPAWN_HELPER_EPILOG();
kono
parents:
diff changeset
98 * }
kono
parents:
diff changeset
99 *
kono
parents:
diff changeset
100 * int fib(int n)
kono
parents:
diff changeset
101 * {
kono
parents:
diff changeset
102 * CILK_FAKE_PROLOG();
kono
parents:
diff changeset
103 *
kono
parents:
diff changeset
104 * if (n < 2)
kono
parents:
diff changeset
105 * return n;
kono
parents:
diff changeset
106 *
kono
parents:
diff changeset
107 * int a, b;
kono
parents:
diff changeset
108 * CILK_FAKE_CALL_SPAWN_HELPER(fib_spawn_helper(&__cilk_sf, &a, n));
kono
parents:
diff changeset
109 * b = fib(n - 2);
kono
parents:
diff changeset
110 * CILK_FAKE_SYNC();
kono
parents:
diff changeset
111 *
kono
parents:
diff changeset
112 * CILK_FAKE_EPILOG();
kono
parents:
diff changeset
113 * return a + b;
kono
parents:
diff changeset
114 * }
kono
parents:
diff changeset
115 */
kono
parents:
diff changeset
116
kono
parents:
diff changeset
117 #ifndef INCLUDED_CILK_FAKE_DOT_H
kono
parents:
diff changeset
118 #define INCLUDED_CILK_FAKE_DOT_H
kono
parents:
diff changeset
119
kono
parents:
diff changeset
120 // This header implements ABI version 1. If __CILKRTS_ABI_VERSION is already
kono
parents:
diff changeset
121 // defined but is less than 1, then the data structures in <internal/abi.h>
kono
parents:
diff changeset
122 // will not match the expectations of facilities in this header. Therefore,
kono
parents:
diff changeset
123 // for successful compilation, __CILKRTS_ABI_VERSION must either be not
kono
parents:
diff changeset
124 // defined, or defined to be 1 or greater.
kono
parents:
diff changeset
125 #ifndef __CILKRTS_ABI_VERSION
kono
parents:
diff changeset
126 // ABI version was not specified. Set it to 1.
kono
parents:
diff changeset
127 # define __CILKRTS_ABI_VERSION 1
kono
parents:
diff changeset
128 #elif __CILKRTS_ABI_VERSION < 1
kono
parents:
diff changeset
129 // ABI version was specified but was too old. Fail compilation.
kono
parents:
diff changeset
130 # error cilk_fake.h requirs an ABI version of 1 or greater
kono
parents:
diff changeset
131 #endif
kono
parents:
diff changeset
132
kono
parents:
diff changeset
133 #include <internal/abi.h>
kono
parents:
diff changeset
134
kono
parents:
diff changeset
135 // alloca is defined in malloc.h on Windows, alloca.h on Linux
kono
parents:
diff changeset
136 #ifndef _MSC_VER
kono
parents:
diff changeset
137 #include <alloca.h>
kono
parents:
diff changeset
138 #else
kono
parents:
diff changeset
139 #include <malloc.h>
kono
parents:
diff changeset
140 // Define offsetof
kono
parents:
diff changeset
141 #include <stddef.h>
kono
parents:
diff changeset
142 #endif
kono
parents:
diff changeset
143
kono
parents:
diff changeset
144 // Allows use of a different version that the one defined in abi.h
kono
parents:
diff changeset
145 #define CILK_FAKE_VERSION_FLAG (__CILKRTS_ABI_VERSION << 24)
kono
parents:
diff changeset
146
kono
parents:
diff changeset
147 /* Initialize frame. To be called when worker is known */
kono
parents:
diff changeset
148 __CILKRTS_INLINE void __cilk_fake_enter_frame_fast(__cilkrts_stack_frame *sf,
kono
parents:
diff changeset
149 __cilkrts_worker *w)
kono
parents:
diff changeset
150 {
kono
parents:
diff changeset
151 sf->call_parent = w->current_stack_frame;
kono
parents:
diff changeset
152 sf->worker = w;
kono
parents:
diff changeset
153 sf->flags = CILK_FAKE_VERSION_FLAG;
kono
parents:
diff changeset
154 w->current_stack_frame = sf;
kono
parents:
diff changeset
155 }
kono
parents:
diff changeset
156
kono
parents:
diff changeset
157 /* Initialize frame. To be called when worker is not known */
kono
parents:
diff changeset
158 __CILKRTS_INLINE void __cilk_fake_enter_frame(__cilkrts_stack_frame *sf)
kono
parents:
diff changeset
159 {
kono
parents:
diff changeset
160 __cilkrts_worker* w = __cilkrts_get_tls_worker();
kono
parents:
diff changeset
161 uint32_t last_flag = 0;
kono
parents:
diff changeset
162 if (! w) {
kono
parents:
diff changeset
163 w = __cilkrts_bind_thread_1();
kono
parents:
diff changeset
164 last_flag = CILK_FRAME_LAST;
kono
parents:
diff changeset
165 }
kono
parents:
diff changeset
166 __cilk_fake_enter_frame_fast(sf, w);
kono
parents:
diff changeset
167 sf->flags |= last_flag;
kono
parents:
diff changeset
168 }
kono
parents:
diff changeset
169
kono
parents:
diff changeset
170 /* Initialize frame. To be called within the spawn helper */
kono
parents:
diff changeset
171 __CILKRTS_INLINE void __cilk_fake_helper_enter_frame(
kono
parents:
diff changeset
172 __cilkrts_stack_frame *sf,
kono
parents:
diff changeset
173 __cilkrts_stack_frame *parent_sf)
kono
parents:
diff changeset
174 {
kono
parents:
diff changeset
175 sf->worker = 0;
kono
parents:
diff changeset
176 sf->call_parent = parent_sf;
kono
parents:
diff changeset
177 }
kono
parents:
diff changeset
178
kono
parents:
diff changeset
179 /* Called from the spawn helper to push the parent continuation on the task
kono
parents:
diff changeset
180 * deque so that it can be stolen.
kono
parents:
diff changeset
181 */
kono
parents:
diff changeset
182 __CILKRTS_INLINE void __cilk_fake_detach(__cilkrts_stack_frame *sf)
kono
parents:
diff changeset
183 {
kono
parents:
diff changeset
184 /* Initialize spawn helper frame.
kono
parents:
diff changeset
185 * call_parent was saved in __cilk_fake_helper_enter_frame */
kono
parents:
diff changeset
186 __cilkrts_stack_frame *parent = sf->call_parent;
kono
parents:
diff changeset
187 __cilkrts_worker *w = parent->worker;
kono
parents:
diff changeset
188 __cilk_fake_enter_frame_fast(sf, w);
kono
parents:
diff changeset
189
kono
parents:
diff changeset
190 /* Append a node to the pedigree */
kono
parents:
diff changeset
191 sf->spawn_helper_pedigree = w->pedigree;
kono
parents:
diff changeset
192 parent->parent_pedigree = w->pedigree;
kono
parents:
diff changeset
193 w->pedigree.rank = 0;
kono
parents:
diff changeset
194 w->pedigree.parent = &sf->spawn_helper_pedigree;
kono
parents:
diff changeset
195
kono
parents:
diff changeset
196 /* Push parent onto the task deque */
kono
parents:
diff changeset
197 __cilkrts_stack_frame *volatile *tail = w->tail;
kono
parents:
diff changeset
198 *tail++ = sf->call_parent;
kono
parents:
diff changeset
199 /* The stores must be separated by a store fence (noop on x86)
kono
parents:
diff changeset
200 * or the second store is a release (st8.rel on Itanium) */
kono
parents:
diff changeset
201 w->tail = tail;
kono
parents:
diff changeset
202 sf->flags |= CILK_FRAME_DETACHED;
kono
parents:
diff changeset
203 }
kono
parents:
diff changeset
204
kono
parents:
diff changeset
205 /* This variable is used in CILK_FAKE_FORCE_FRAME_PTR(), below */
kono
parents:
diff changeset
206 static int __cilk_fake_dummy = 8;
kono
parents:
diff changeset
207
kono
parents:
diff changeset
208 /* The following macro is used to force the compiler into generating a frame
kono
parents:
diff changeset
209 * pointer. We never change the value of __cilk_fake_dummy, so the alloca()
kono
parents:
diff changeset
210 * is never called, but we need the 'if' statement and the __cilk_fake_dummy
kono
parents:
diff changeset
211 * variable so that the compiler does not attempt to optimize it away.
kono
parents:
diff changeset
212 */
kono
parents:
diff changeset
213 #define CILK_FAKE_FORCE_FRAME_PTR(sf) do { \
kono
parents:
diff changeset
214 if (__builtin_expect(1 & __cilk_fake_dummy, 0)) \
kono
parents:
diff changeset
215 (sf).worker = (__cilkrts_worker*) alloca(__cilk_fake_dummy); \
kono
parents:
diff changeset
216 } while (0)
kono
parents:
diff changeset
217
kono
parents:
diff changeset
218 #ifndef CILK_FAKE_NO_SHRINKWRAP
kono
parents:
diff changeset
219 /* "shrink-wrap" optimization enabled. Do not initialize frame on entry,
kono
parents:
diff changeset
220 * except to clear worker pointer. Instead, defer initialization until
kono
parents:
diff changeset
221 * the first spawn.
kono
parents:
diff changeset
222 */
kono
parents:
diff changeset
223 # define CILK_FAKE_INITIAL_ENTER_FRAME(sf) ((void) ((sf).worker = 0))
kono
parents:
diff changeset
224 # define CILK_FAKE_DEFERRED_ENTER_FRAME(sf) do { \
kono
parents:
diff changeset
225 if (! (sf).worker) __cilk_fake_enter_frame(&(sf)); \
kono
parents:
diff changeset
226 } while (0)
kono
parents:
diff changeset
227 #else
kono
parents:
diff changeset
228 /* "shrink-wrap" optimization disabled. Initialize frame immediately on
kono
parents:
diff changeset
229 * entry. Do not initialize frame on spawn.
kono
parents:
diff changeset
230 */
kono
parents:
diff changeset
231 # define CILK_FAKE_INITIAL_ENTER_FRAME(sf) \
kono
parents:
diff changeset
232 __cilk_fake_enter_frame(&(sf))
kono
parents:
diff changeset
233 # define CILK_FAKE_DEFERRED_ENTER_FRAME(sf) ((void) &(sf))
kono
parents:
diff changeset
234 #endif
kono
parents:
diff changeset
235
kono
parents:
diff changeset
236 /* Prologue of a spawning function. Declares and initializes the stack
kono
parents:
diff changeset
237 * frame.
kono
parents:
diff changeset
238 */
kono
parents:
diff changeset
239 #define CILK_FAKE_PROLOG() \
kono
parents:
diff changeset
240 __cilk_fake_stack_frame __cilk_sf; \
kono
parents:
diff changeset
241 CILK_FAKE_FORCE_FRAME_PTR(__cilk_sf); \
kono
parents:
diff changeset
242 CILK_FAKE_INITIAL_ENTER_FRAME(__cilk_sf)
kono
parents:
diff changeset
243
kono
parents:
diff changeset
244 /* Prologue of a spawning function where the current worker is already known.
kono
parents:
diff changeset
245 * Declares and initializes the stack frame without looking up the worker from
kono
parents:
diff changeset
246 * TLS.
kono
parents:
diff changeset
247 */
kono
parents:
diff changeset
248 #define CILK_FAKE_PROLOG_FAST(w) \
kono
parents:
diff changeset
249 __cilk_fake_stack_frame __cilk_sf; \
kono
parents:
diff changeset
250 CILK_FAKE_FORCE_FRAME_PTR(__cilk_sf); \
kono
parents:
diff changeset
251 __cilk_fake_enter_frame_fast(&__cilk_sf, (w))
kono
parents:
diff changeset
252
kono
parents:
diff changeset
253 /* Simulate a cilk_sync */
kono
parents:
diff changeset
254 #define CILK_FAKE_SYNC() CILK_FAKE_SYNC_IMP(__cilk_sf)
kono
parents:
diff changeset
255
kono
parents:
diff changeset
256 /* Epilog at the end of a spawning function. Does a sync and calls the
kono
parents:
diff changeset
257 * runtime for leaving the frame.
kono
parents:
diff changeset
258 */
kono
parents:
diff changeset
259 #ifdef __cplusplus
kono
parents:
diff changeset
260 // Epilogue is run automatically by __cilk_fake_stack_frame destructor.
kono
parents:
diff changeset
261 # define CILK_FAKE_EPILOG() ((void) __cilk_sf)
kono
parents:
diff changeset
262 #else
kono
parents:
diff changeset
263 # define CILK_FAKE_EPILOG() CILK_FAKE_CLEANUP_FRAME(__cilk_sf)
kono
parents:
diff changeset
264 #endif // C
kono
parents:
diff changeset
265
kono
parents:
diff changeset
266 /* Implementation of spawning function epilog. See CILK_FAKE_EPILOG macro and
kono
parents:
diff changeset
267 * __cilk_fake_stack_frame destructor body.
kono
parents:
diff changeset
268 */
kono
parents:
diff changeset
269 #define CILK_FAKE_CLEANUP_FRAME(sf) do { \
kono
parents:
diff changeset
270 if (! (sf).worker) break; \
kono
parents:
diff changeset
271 CILK_FAKE_SYNC_IMP(sf); \
kono
parents:
diff changeset
272 CILK_FAKE_POP_FRAME(sf); \
kono
parents:
diff changeset
273 if ((sf).flags != CILK_FAKE_VERSION_FLAG) \
kono
parents:
diff changeset
274 __cilkrts_leave_frame(&(sf)); \
kono
parents:
diff changeset
275 } while (0)
kono
parents:
diff changeset
276
kono
parents:
diff changeset
277 /* Implementation of CILK_FAKE_SYNC with sf argument */
kono
parents:
diff changeset
278 #define CILK_FAKE_SYNC_IMP(sf) do { \
kono
parents:
diff changeset
279 if (__builtin_expect((sf).flags & CILK_FRAME_UNSYNCHED, 0)) { \
kono
parents:
diff changeset
280 (sf).parent_pedigree = (sf).worker->pedigree; \
kono
parents:
diff changeset
281 CILK_FAKE_SAVE_FP(sf); \
kono
parents:
diff changeset
282 if (! CILK_SETJMP((sf).ctx)) \
kono
parents:
diff changeset
283 __cilkrts_sync(&(sf)); \
kono
parents:
diff changeset
284 } \
kono
parents:
diff changeset
285 ++(sf).worker->pedigree.rank; \
kono
parents:
diff changeset
286 } while (0)
kono
parents:
diff changeset
287
kono
parents:
diff changeset
288 /* Save the floating-point control registers.
kono
parents:
diff changeset
289 * The definition of CILK_FAKE_SAVE_FP is compiler specific (and
kono
parents:
diff changeset
290 * architecture specific on Windows)
kono
parents:
diff changeset
291 */
kono
parents:
diff changeset
292 #ifdef _MSC_VER
kono
parents:
diff changeset
293 # define MXCSR_OFFSET offsetof(struct __cilkrts_stack_frame, mxcsr)
kono
parents:
diff changeset
294 # define FPCSR_OFFSET offsetof(struct __cilkrts_stack_frame, fpcsr)
kono
parents:
diff changeset
295 # if defined(_M_IX86)
kono
parents:
diff changeset
296 /* Windows x86 */
kono
parents:
diff changeset
297 # define CILK_FAKE_SAVE_FP(sf) do { \
kono
parents:
diff changeset
298 __asm \
kono
parents:
diff changeset
299 { \
kono
parents:
diff changeset
300 mov eax, sf \
kono
parents:
diff changeset
301 stmxcsr [eax+MXCSR_OFFSET] \
kono
parents:
diff changeset
302 fnstcw [eax+FPCSR_OFFSET] \
kono
parents:
diff changeset
303 } \
kono
parents:
diff changeset
304 } while (0)
kono
parents:
diff changeset
305 # elif defined(_M_X64)
kono
parents:
diff changeset
306 /* Windows Intel64 - Not needed - saved by setjmp call */
kono
parents:
diff changeset
307 # define CILK_FAKE_SAVE_FP(sf) ((void) sf)
kono
parents:
diff changeset
308 # else
kono
parents:
diff changeset
309 # error "Unknown architecture"
kono
parents:
diff changeset
310 # endif /* Microsoft architecture specifics */
kono
parents:
diff changeset
311 #else
kono
parents:
diff changeset
312 /* Non-Windows */
kono
parents:
diff changeset
313 # define CILK_FAKE_SAVE_FP(sf) do { \
kono
parents:
diff changeset
314 __asm__ ( "stmxcsr %0\n\t" \
kono
parents:
diff changeset
315 "fnstcw %1" : : "m" ((sf).mxcsr), "m" ((sf).fpcsr)); \
kono
parents:
diff changeset
316 } while (0)
kono
parents:
diff changeset
317 #endif
kono
parents:
diff changeset
318
kono
parents:
diff changeset
319 /* Call the spawn helper as part of a fake spawn */
kono
parents:
diff changeset
320 #define CILK_FAKE_CALL_SPAWN_HELPER(helper) do { \
kono
parents:
diff changeset
321 CILK_FAKE_DEFERRED_ENTER_FRAME(__cilk_sf); \
kono
parents:
diff changeset
322 CILK_FAKE_SAVE_FP(__cilk_sf); \
kono
parents:
diff changeset
323 if (__builtin_expect(! CILK_SETJMP(__cilk_sf.ctx), 1)) { \
kono
parents:
diff changeset
324 helper; \
kono
parents:
diff changeset
325 } \
kono
parents:
diff changeset
326 } while (0)
kono
parents:
diff changeset
327
kono
parents:
diff changeset
328 /* Body of a spawn helper function. In addition to the worker and the
kono
parents:
diff changeset
329 * expression to spawn, pass it any number of statements to be executed before
kono
parents:
diff changeset
330 * detaching.
kono
parents:
diff changeset
331 */
kono
parents:
diff changeset
332 #define CILK_FAKE_SPAWN_HELPER_BODY(parent_sf, expr, ...) \
kono
parents:
diff changeset
333 CILK_FAKE_SPAWN_HELPER_PROLOG(parent_sf); \
kono
parents:
diff changeset
334 __VA_ARGS__; \
kono
parents:
diff changeset
335 __cilk_fake_detach(&__cilk_sf); \
kono
parents:
diff changeset
336 expr; \
kono
parents:
diff changeset
337 CILK_FAKE_SPAWN_HELPER_EPILOG()
kono
parents:
diff changeset
338
kono
parents:
diff changeset
339 /* Prolog for a spawn helper function */
kono
parents:
diff changeset
340 #define CILK_FAKE_SPAWN_HELPER_PROLOG(parent_sf) \
kono
parents:
diff changeset
341 __cilk_fake_spawn_helper_stack_frame __cilk_sf; \
kono
parents:
diff changeset
342 __cilk_fake_helper_enter_frame(&__cilk_sf, &(parent_sf))
kono
parents:
diff changeset
343
kono
parents:
diff changeset
344 /* Implementation of spawn helper epilog. See CILK_FAKE_SPAWN_HELPER_EPILOG
kono
parents:
diff changeset
345 * and the __cilk_fake_spawn_helper_frame destructor.
kono
parents:
diff changeset
346 */
kono
parents:
diff changeset
347 #define CILK_FAKE_SPAWN_HELPER_CLEANUP_FRAME(sf) do { \
kono
parents:
diff changeset
348 if (! (sf).worker) break; \
kono
parents:
diff changeset
349 CILK_FAKE_POP_FRAME(sf); \
kono
parents:
diff changeset
350 __cilkrts_leave_frame(&(sf)); \
kono
parents:
diff changeset
351 } while (0)
kono
parents:
diff changeset
352
kono
parents:
diff changeset
353 /* Epilog to execute at the end of a spawn helper */
kono
parents:
diff changeset
354 #ifdef __cplusplus
kono
parents:
diff changeset
355 // Epilog handled by __cilk_fake_spawn_helper_stack_frame destructor
kono
parents:
diff changeset
356 # define CILK_FAKE_SPAWN_HELPER_EPILOG() ((void) __cilk_sf)
kono
parents:
diff changeset
357 #else
kono
parents:
diff changeset
358 # define CILK_FAKE_SPAWN_HELPER_EPILOG() \
kono
parents:
diff changeset
359 CILK_FAKE_SPAWN_HELPER_CLEANUP_FRAME(__cilk_sf)
kono
parents:
diff changeset
360 #endif
kono
parents:
diff changeset
361
kono
parents:
diff changeset
362 /* Pop the current frame off of the call chain */
kono
parents:
diff changeset
363 #define CILK_FAKE_POP_FRAME(sf) do { \
kono
parents:
diff changeset
364 (sf).worker->current_stack_frame = (sf).call_parent; \
kono
parents:
diff changeset
365 (sf).call_parent = 0; \
kono
parents:
diff changeset
366 } while (0)
kono
parents:
diff changeset
367
kono
parents:
diff changeset
368 #ifdef _WIN32
kono
parents:
diff changeset
369 /* define macros for synching functions before allowing them to propagate. */
kono
parents:
diff changeset
370 # define CILK_FAKE_EXCEPT_BEGIN \
kono
parents:
diff changeset
371 if (0 == CILK_SETJMP(__cilk_sf.except_ctx)) {
kono
parents:
diff changeset
372
kono
parents:
diff changeset
373 # define CILK_FAKE_EXCEPT_END \
kono
parents:
diff changeset
374 } else { \
kono
parents:
diff changeset
375 assert((__cilk_sf.flags & (CILK_FRAME_UNSYNCHED|CILK_FRAME_EXCEPTING))\
kono
parents:
diff changeset
376 == CILK_FRAME_EXCEPTING); \
kono
parents:
diff changeset
377 __cilkrts_rethrow(&__cilk_sf); \
kono
parents:
diff changeset
378 exit(0); \
kono
parents:
diff changeset
379 }
kono
parents:
diff changeset
380 #else
kono
parents:
diff changeset
381 # define CILK_EXCEPT_BEGIN {
kono
parents:
diff changeset
382 # define CILK_EXCEPT_END }
kono
parents:
diff changeset
383 #endif
kono
parents:
diff changeset
384
kono
parents:
diff changeset
385 #ifdef __cplusplus
kono
parents:
diff changeset
386 // The following definitions depend on C++ features.
kono
parents:
diff changeset
387
kono
parents:
diff changeset
388 // Wrap a functor (probably a lambda), so that a call to it cannot be
kono
parents:
diff changeset
389 // inlined.
kono
parents:
diff changeset
390 template <typename F>
kono
parents:
diff changeset
391 class __cilk_fake_noinline_wrapper
kono
parents:
diff changeset
392 {
kono
parents:
diff changeset
393 F&& m_fn;
kono
parents:
diff changeset
394 public:
kono
parents:
diff changeset
395 __cilk_fake_noinline_wrapper(F&& fn) : m_fn(static_cast<F&&>(fn)) { }
kono
parents:
diff changeset
396
kono
parents:
diff changeset
397 #ifdef _WIN32
kono
parents:
diff changeset
398 __declspec(noinline) void operator()(__cilkrts_stack_frame *sf);
kono
parents:
diff changeset
399 #else
kono
parents:
diff changeset
400 void operator()(__cilkrts_stack_frame *sf) __attribute__((noinline));
kono
parents:
diff changeset
401 #endif
kono
parents:
diff changeset
402
kono
parents:
diff changeset
403 };
kono
parents:
diff changeset
404
kono
parents:
diff changeset
405 template <typename F>
kono
parents:
diff changeset
406 void __cilk_fake_noinline_wrapper<F>::operator()(__cilkrts_stack_frame *sf)
kono
parents:
diff changeset
407 {
kono
parents:
diff changeset
408 m_fn(sf);
kono
parents:
diff changeset
409 }
kono
parents:
diff changeset
410
kono
parents:
diff changeset
411 template <typename F>
kono
parents:
diff changeset
412 inline
kono
parents:
diff changeset
413 __cilk_fake_noinline_wrapper<F> __cilk_fake_make_noinline_wrapper(F&& fn)
kono
parents:
diff changeset
414 {
kono
parents:
diff changeset
415 return __cilk_fake_noinline_wrapper<F>(static_cast<F&&>(fn));
kono
parents:
diff changeset
416 }
kono
parents:
diff changeset
417
kono
parents:
diff changeset
418 // Simulate "_Cilk_spawn expr", where expr must be a function call.
kono
parents:
diff changeset
419 //
kono
parents:
diff changeset
420 // Note: this macro does not correctly construct function arguments.
kono
parents:
diff changeset
421 // According to the ABI specification, function arguments should be evaluated
kono
parents:
diff changeset
422 // before the detach and destroyed after the detach. This macro both
kono
parents:
diff changeset
423 // evaluates and destroys them after the detach. This means that if any part
kono
parents:
diff changeset
424 // of the function argument expression depends on a value that is modified in
kono
parents:
diff changeset
425 // the continuation of the spawn, race will occur between the continuation and
kono
parents:
diff changeset
426 // the argument evaluation.
kono
parents:
diff changeset
427 //
kono
parents:
diff changeset
428 // To work around this problem, this macro accepts an arbitrary list of
kono
parents:
diff changeset
429 // declarations and statements (separated by semicolons) that are evaluated
kono
parents:
diff changeset
430 // before the detach. Thus, to simulate:
kono
parents:
diff changeset
431 //
kono
parents:
diff changeset
432 // _Cilk_spawn f(expr);
kono
parents:
diff changeset
433 //
kono
parents:
diff changeset
434 // one would write:
kono
parents:
diff changeset
435 //
kono
parents:
diff changeset
436 // CILK_FAKE_SPAWN(f(arg), auto arg = expr);
kono
parents:
diff changeset
437 //
kono
parents:
diff changeset
438 // Despite appearing in the reverse order, the 'arg' variable is created and
kono
parents:
diff changeset
439 // initialized before the detach and the call to f(arg) occurs after the
kono
parents:
diff changeset
440 // detach.
kono
parents:
diff changeset
441 #define CILK_FAKE_SPAWN(expr, ...) \
kono
parents:
diff changeset
442 CILK_FAKE_CALL_SPAWN_HELPER( \
kono
parents:
diff changeset
443 CILK_FAKE_SPAWN_HELPER(expr, __VA_ARGS__)(&__cilk_sf))
kono
parents:
diff changeset
444
kono
parents:
diff changeset
445 // Simulate "ret = cilk_spawn expr". See CILK_FAKE_SPAWN for constraints.
kono
parents:
diff changeset
446 #define CILK_FAKE_SPAWN_R(ret, expr, ...) \
kono
parents:
diff changeset
447 CILK_FAKE_SPAWN(((ret) = (expr)), __VA_ARGS__)
kono
parents:
diff changeset
448
kono
parents:
diff changeset
449 // Create a spawn helper as a C++11 lambda function. In addition to the
kono
parents:
diff changeset
450 // expression to spawn, this macro takes a any number of statements to be
kono
parents:
diff changeset
451 // executed before detaching.
kono
parents:
diff changeset
452 #define CILK_FAKE_SPAWN_HELPER(expr, ...) \
kono
parents:
diff changeset
453 __cilk_fake_make_noinline_wrapper([&](__cilkrts_stack_frame *parent_sf) { \
kono
parents:
diff changeset
454 CILK_FAKE_SPAWN_HELPER_BODY(*parent_sf, expr, __VA_ARGS__); \
kono
parents:
diff changeset
455 })
kono
parents:
diff changeset
456
kono
parents:
diff changeset
457 // C++ version of a __cilkrts_stack_frame for a spawning function.
kono
parents:
diff changeset
458 // This struct is identical to __cilkrts_stack_frame except that the
kono
parents:
diff changeset
459 // destructor automatically does frame cleanup.
kono
parents:
diff changeset
460 struct __cilk_fake_stack_frame : __cilkrts_stack_frame
kono
parents:
diff changeset
461 {
kono
parents:
diff changeset
462 // Extension of __cilkrts_stack_frame with constructor and destructor
kono
parents:
diff changeset
463 __cilk_fake_stack_frame() { }
kono
parents:
diff changeset
464 __forceinline ~__cilk_fake_stack_frame() {
kono
parents:
diff changeset
465 CILK_FAKE_CLEANUP_FRAME(*this);
kono
parents:
diff changeset
466 }
kono
parents:
diff changeset
467 };
kono
parents:
diff changeset
468
kono
parents:
diff changeset
469 // C++ version of a __cilkrts_stack_frame for a spawn helper.
kono
parents:
diff changeset
470 // This struct is identical to __cilkrts_stack_frame except that the
kono
parents:
diff changeset
471 // destructor automatically does frame cleanup.
kono
parents:
diff changeset
472 struct __cilk_fake_spawn_helper_stack_frame : __cilkrts_stack_frame
kono
parents:
diff changeset
473 {
kono
parents:
diff changeset
474 // Extension of __cilkrts_stack_frame with constructor and destructor
kono
parents:
diff changeset
475 __cilk_fake_spawn_helper_stack_frame() { worker = 0; }
kono
parents:
diff changeset
476 __forceinline ~__cilk_fake_spawn_helper_stack_frame() {
kono
parents:
diff changeset
477 CILK_FAKE_SPAWN_HELPER_CLEANUP_FRAME(*this);
kono
parents:
diff changeset
478 }
kono
parents:
diff changeset
479 };
kono
parents:
diff changeset
480 #else
kono
parents:
diff changeset
481 // For C, __cilk_fake_stack_frame and __cilk_fake_spawn_helper_stack_frame are
kono
parents:
diff changeset
482 // identical to __cilkrts_stack_frame. Frame cleanup must be performed
kono
parents:
diff changeset
483 // excplicitly (in CILK_FAKE_EPILOG and CILK_FAKE_SPAWN_HELPER_EPILOG)
kono
parents:
diff changeset
484 typedef __cilkrts_stack_frame __cilk_fake_stack_frame;
kono
parents:
diff changeset
485 typedef __cilkrts_stack_frame __cilk_fake_spawn_helper_stack_frame;
kono
parents:
diff changeset
486 #endif
kono
parents:
diff changeset
487
kono
parents:
diff changeset
488 #endif // ! defined(INCLUDED_CILK_FAKE_DOT_H)