Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/thirdparty/basis_universal/encoder/cppspmd_flow.h
9902 views
1
// Do not include this header directly.
2
// Control flow functionality in common between all the headers.
3
//
4
// Copyright 2020-2024 Binomial LLC
5
//
6
// Licensed under the Apache License, Version 2.0 (the "License");
7
// you may not use this file except in compliance with the License.
8
// You may obtain a copy of the License at
9
//
10
// http://www.apache.org/licenses/LICENSE-2.0
11
//
12
// Unless required by applicable law or agreed to in writing, software
13
// distributed under the License is distributed on an "AS IS" BASIS,
14
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
// See the License for the specific language governing permissions and
16
// limitations under the License.
17
18
#ifdef _DEBUG
19
CPPSPMD_FORCE_INLINE void spmd_kernel::check_masks()
20
{
21
assert(!any(andnot(m_kernel_exec, m_exec)));
22
}
23
#endif
24
25
CPPSPMD_FORCE_INLINE void spmd_kernel::spmd_break()
26
{
27
#ifdef _DEBUG
28
assert(m_in_loop);
29
#endif
30
31
m_exec = exec_mask::all_off();
32
}
33
34
CPPSPMD_FORCE_INLINE void spmd_kernel::spmd_continue()
35
{
36
#ifdef _DEBUG
37
assert(m_in_loop);
38
#endif
39
40
// Kill any active lanes, and remember which lanes were active so we can re-enable them at the end of the loop body.
41
m_continue_mask = m_continue_mask | m_exec;
42
m_exec = exec_mask::all_off();
43
}
44
45
CPPSPMD_FORCE_INLINE void spmd_kernel::spmd_return()
46
{
47
// Permenantly kill all active lanes
48
m_kernel_exec = andnot(m_exec, m_kernel_exec);
49
m_exec = exec_mask::all_off();
50
}
51
52
template<typename UnmaskedBody>
53
CPPSPMD_FORCE_INLINE void spmd_kernel::spmd_unmasked(const UnmaskedBody& unmaskedBody)
54
{
55
exec_mask orig_exec = m_exec, orig_kernel_exec = m_kernel_exec;
56
57
m_kernel_exec = exec_mask::all_on();
58
m_exec = exec_mask::all_on();
59
60
unmaskedBody();
61
62
m_kernel_exec = m_kernel_exec & orig_kernel_exec;
63
m_exec = m_exec & orig_exec;
64
65
check_masks();
66
}
67
68
struct scoped_unmasked_restorer
69
{
70
spmd_kernel *m_pKernel;
71
exec_mask m_orig_exec, m_orig_kernel_exec;
72
73
CPPSPMD_FORCE_INLINE scoped_unmasked_restorer(spmd_kernel *pKernel) :
74
m_pKernel(pKernel),
75
m_orig_exec(pKernel->m_exec),
76
m_orig_kernel_exec(pKernel->m_kernel_exec)
77
{
78
pKernel->m_kernel_exec = exec_mask::all_on();
79
pKernel->m_exec = exec_mask::all_on();
80
}
81
82
CPPSPMD_FORCE_INLINE ~scoped_unmasked_restorer()
83
{
84
m_pKernel->m_kernel_exec = m_pKernel->m_kernel_exec & m_orig_kernel_exec;
85
m_pKernel->m_exec = m_pKernel->m_exec & m_orig_exec;
86
m_pKernel->check_masks();
87
}
88
};
89
90
#define SPMD_UNMASKED_BEGIN { scoped_unmasked_restorer _unmasked_restorer(this);
91
#define SPMD_UNMASKED_END }
92
93
#if 0
94
template<typename SPMDKernel, typename... Args>
95
CPPSPMD_FORCE_INLINE decltype(auto) spmd_kernel::spmd_call(Args&&... args)
96
{
97
SPMDKernel kernel;
98
kernel.init(m_exec);
99
return kernel._call(std::forward<Args>(args)...);
100
}
101
#else
102
template<typename SPMDKernel, typename... Args>
103
CPPSPMD_FORCE_INLINE void spmd_kernel::spmd_call(Args&&... args)
104
{
105
SPMDKernel kernel;
106
kernel.init(m_exec);
107
kernel._call(std::forward<Args>(args)...);
108
}
109
#endif
110
111
CPPSPMD_FORCE_INLINE void spmd_kernel::spmd_if_break(const vbool& cond)
112
{
113
#ifdef _DEBUG
114
assert(m_in_loop);
115
#endif
116
117
exec_mask cond_exec(cond);
118
119
m_exec = andnot(m_exec & cond_exec, m_exec);
120
121
check_masks();
122
}
123
124
// No SPMD breaks, continues, etc. allowed
125
template<typename IfBody>
126
CPPSPMD_FORCE_INLINE void spmd_kernel::spmd_sif(const vbool& cond, const IfBody& ifBody)
127
{
128
exec_mask im = m_exec & exec_mask(cond);
129
130
if (any(im))
131
{
132
const exec_mask orig_exec = m_exec;
133
m_exec = im;
134
ifBody();
135
m_exec = orig_exec;
136
}
137
}
138
139
// No SPMD breaks, continues, etc. allowed
140
template<typename IfBody, typename ElseBody>
141
CPPSPMD_FORCE_INLINE void spmd_kernel::spmd_sifelse(const vbool& cond, const IfBody& ifBody, const ElseBody &elseBody)
142
{
143
const exec_mask orig_exec = m_exec;
144
145
exec_mask im = m_exec & exec_mask(cond);
146
147
if (any(im))
148
{
149
m_exec = im;
150
ifBody();
151
}
152
153
exec_mask em = orig_exec & exec_mask(!cond);
154
155
if (any(em))
156
{
157
m_exec = em;
158
elseBody();
159
}
160
161
m_exec = orig_exec;
162
}
163
164
template<typename IfBody>
165
CPPSPMD_FORCE_INLINE void spmd_kernel::spmd_if(const vbool& cond, const IfBody& ifBody)
166
{
167
exec_mask cond_exec(cond);
168
169
exec_mask pre_if_exec = cond_exec & m_exec;
170
171
if (any(pre_if_exec))
172
{
173
exec_mask unexecuted_lanes = andnot(cond_exec, m_exec);
174
m_exec = pre_if_exec;
175
176
ifBody();
177
178
// Propagate any lanes that got disabled inside the if body into the exec mask outside the if body, but turn on any lanes that didn't execute inside the if body.
179
m_exec = m_exec | unexecuted_lanes;
180
181
check_masks();
182
}
183
}
184
185
template<typename IfBody, typename ElseBody>
186
CPPSPMD_FORCE_INLINE void spmd_kernel::spmd_ifelse(const vbool& cond, const IfBody& ifBody, const ElseBody& elseBody)
187
{
188
bool all_flag = false;
189
190
exec_mask cond_exec(cond);
191
192
{
193
exec_mask pre_if_exec = cond_exec & m_exec;
194
195
int mask = pre_if_exec.get_movemask();
196
if (mask != 0)
197
{
198
all_flag = ((uint32_t)mask == m_exec.get_movemask());
199
200
exec_mask unexecuted_lanes = andnot(cond_exec, m_exec);
201
m_exec = pre_if_exec;
202
203
ifBody();
204
205
// Propagate any lanes that got disabled inside the if body into the exec mask outside the if body, but turn on any lanes that didn't execute inside the if body.
206
m_exec = m_exec | unexecuted_lanes;
207
208
check_masks();
209
}
210
}
211
212
if (!all_flag)
213
{
214
exec_mask pre_if_exec = andnot(cond_exec, m_exec);
215
216
if (any(pre_if_exec))
217
{
218
exec_mask unexecuted_lanes = cond_exec & m_exec;
219
m_exec = pre_if_exec;
220
221
ifBody();
222
223
// Propagate any lanes that got disabled inside the if body into the exec mask outside the if body, but turn on any lanes that didn't execute inside the if body.
224
m_exec = m_exec | unexecuted_lanes;
225
226
check_masks();
227
}
228
}
229
}
230
231
struct scoped_exec_restorer
232
{
233
exec_mask *m_pMask;
234
exec_mask m_prev_mask;
235
CPPSPMD_FORCE_INLINE scoped_exec_restorer(exec_mask *pExec_mask) : m_pMask(pExec_mask), m_prev_mask(*pExec_mask) { }
236
CPPSPMD_FORCE_INLINE ~scoped_exec_restorer() { *m_pMask = m_prev_mask; }
237
};
238
239
// Cannot use SPMD break, continue, or return inside "simple" if/else
240
#define SPMD_SIF(cond) exec_mask CPPSPMD_GLUER2(_exec_temp, __LINE__)(m_exec & exec_mask(vbool(cond))); if (any(CPPSPMD_GLUER2(_exec_temp, __LINE__))) \
241
{ CPPSPMD::scoped_exec_restorer CPPSPMD_GLUER2(_exec_restore_, __LINE__)(&m_exec); m_exec = CPPSPMD_GLUER2(_exec_temp, __LINE__);
242
243
#define SPMD_SELSE(cond) } exec_mask CPPSPMD_GLUER2(_exec_temp, __LINE__)(m_exec & exec_mask(!vbool(cond))); if (any(CPPSPMD_GLUER2(_exec_temp, __LINE__))) \
244
{ CPPSPMD::scoped_exec_restorer CPPSPMD_GLUER2(_exec_restore_, __LINE__)(&m_exec); m_exec = CPPSPMD_GLUER2(_exec_temp, __LINE__);
245
246
#define SPMD_SENDIF }
247
248
// Same as SPMD_SIF, except doesn't use a scoped object
249
#define SPMD_SIF2(cond) exec_mask CPPSPMD_GLUER2(_exec_temp, __LINE__)(m_exec & exec_mask(vbool(cond))); if (any(CPPSPMD_GLUER2(_exec_temp, __LINE__))) \
250
{ exec_mask _orig_exec = m_exec; m_exec = CPPSPMD_GLUER2(_exec_temp, __LINE__);
251
252
#define SPMD_SELSE2(cond) m_exec = _orig_exec; } exec_mask CPPSPMD_GLUER2(_exec_temp, __LINE__)(m_exec & exec_mask(!vbool(cond))); if (any(CPPSPMD_GLUER2(_exec_temp, __LINE__))) \
253
{ exec_mask _orig_exec = m_exec; m_exec = CPPSPMD_GLUER2(_exec_temp, __LINE__);
254
255
#define SPMD_SEND_IF2 m_exec = _orig_exec; }
256
257
// Same as SPMD_SIF(), except the if/else blocks are always executed
258
#define SPMD_SAIF(cond) exec_mask CPPSPMD_GLUER2(_exec_temp, __LINE__)(m_exec & exec_mask(vbool(cond))); { CPPSPMD::scoped_exec_restorer CPPSPMD_GLUER2(_exec_restore_, __LINE__)(&m_exec); \
259
m_exec = CPPSPMD_GLUER2(_exec_temp, __LINE__);
260
261
#define SPMD_SAELSE(cond) } exec_mask CPPSPMD_GLUER2(_exec_temp, __LINE__)(m_exec & exec_mask(!vbool(cond))); { CPPSPMD::scoped_exec_restorer CPPSPMD_GLUER2(_exec_restore_, __LINE__)(&m_exec); \
262
m_exec = CPPSPMD_GLUER2(_exec_temp, __LINE__);
263
264
#define SPMD_SAENDIF }
265
266
// Cannot use SPMD break, continue, or return inside sselect
267
#define SPMD_SSELECT(var) do { vint_t _select_var = var; scoped_exec_restorer _orig_exec(&m_exec); exec_mask _select_executed(exec_mask::all_off());
268
#define SPMD_SCASE(value) exec_mask CPPSPMD_GLUER2(_exec_temp, __LINE__)(_orig_exec.m_prev_mask & exec_mask(vbool(_select_var == (value)))); if (any(CPPSPMD_GLUER2(_exec_temp, __LINE__))) \
269
{ m_exec = CPPSPMD_GLUER2(_exec_temp, __LINE__); _select_executed = _select_executed | m_exec;
270
271
//#define SPMD_SCASE_END if (_select_executed.get_movemask() == _orig_exec.m_prev_mask.get_movemask()) break; }
272
#define SPMD_SCASE_END if (!any(_select_executed ^ _orig_exec.m_prev_mask)) break; }
273
#define SPMD_SDEFAULT exec_mask _all_other_lanes(andnot(_select_executed, _orig_exec.m_prev_mask)); if (any(_all_other_lanes)) { m_exec = _all_other_lanes;
274
#define SPMD_SDEFAULT_END }
275
#define SPMD_SSELECT_END } while(0);
276
277
// Same as SPMD_SSELECT, except all cases are executed.
278
// Cannot use SPMD break, continue, or return inside sselect
279
#define SPMD_SASELECT(var) do { vint_t _select_var = var; scoped_exec_restorer _orig_exec(&m_exec); exec_mask _select_executed(exec_mask::all_off());
280
281
#define SPMD_SACASE(value) exec_mask CPPSPMD_GLUER2(_exec_temp, __LINE__)(_orig_exec.m_prev_mask & exec_mask(vbool(_select_var == (value)))); { m_exec = CPPSPMD_GLUER2(_exec_temp, __LINE__); \
282
_select_executed = _select_executed | m_exec;
283
284
#define SPMD_SACASE_END }
285
#define SPMD_SADEFAULT exec_mask _all_other_lanes(andnot(_select_executed, _orig_exec.m_prev_mask)); { m_exec = _all_other_lanes;
286
#define SPMD_SADEFAULT_END }
287
#define SPMD_SASELECT_END } while(0);
288
289
struct scoped_exec_restorer2
290
{
291
spmd_kernel *m_pKernel;
292
exec_mask m_unexecuted_lanes;
293
294
CPPSPMD_FORCE_INLINE scoped_exec_restorer2(spmd_kernel *pKernel, const vbool &cond) :
295
m_pKernel(pKernel)
296
{
297
exec_mask cond_exec(cond);
298
m_unexecuted_lanes = andnot(cond_exec, pKernel->m_exec);
299
pKernel->m_exec = cond_exec & pKernel->m_exec;
300
}
301
302
CPPSPMD_FORCE_INLINE ~scoped_exec_restorer2()
303
{
304
m_pKernel->m_exec = m_pKernel->m_exec | m_unexecuted_lanes;
305
m_pKernel->check_masks();
306
}
307
};
308
309
#define SPMD_IF(cond) { CPPSPMD::scoped_exec_restorer2 CPPSPMD_GLUER2(_exec_restore2_, __LINE__)(this, vbool(cond)); if (any(m_exec)) {
310
#define SPMD_ELSE(cond) } } { CPPSPMD::scoped_exec_restorer2 CPPSPMD_GLUER2(_exec_restore2_, __LINE__)(this, !vbool(cond)); if (any(m_exec)) {
311
#define SPMD_END_IF } }
312
313
// Same as SPMD_IF, except the conditional block is always executed.
314
#define SPMD_AIF(cond) { CPPSPMD::scoped_exec_restorer2 CPPSPMD_GLUER2(_exec_restore2_, __LINE__)(this, vbool(cond)); {
315
#define SPMD_AELSE(cond) } } { CPPSPMD::scoped_exec_restorer2 CPPSPMD_GLUER2(_exec_restore2_, __LINE__)(this, !vbool(cond)); {
316
#define SPMD_AEND_IF } }
317
318
class scoped_exec_saver
319
{
320
exec_mask m_exec, m_kernel_exec, m_continue_mask;
321
spmd_kernel *m_pKernel;
322
#ifdef _DEBUG
323
bool m_in_loop;
324
#endif
325
326
public:
327
inline scoped_exec_saver(spmd_kernel *pKernel) :
328
m_exec(pKernel->m_exec), m_kernel_exec(pKernel->m_kernel_exec), m_continue_mask(pKernel->m_continue_mask),
329
m_pKernel(pKernel)
330
{
331
#ifdef _DEBUG
332
m_in_loop = pKernel->m_in_loop;
333
#endif
334
}
335
336
inline ~scoped_exec_saver()
337
{
338
m_pKernel->m_exec = m_exec;
339
m_pKernel->m_continue_mask = m_continue_mask;
340
m_pKernel->m_kernel_exec = m_kernel_exec;
341
#ifdef _DEBUG
342
m_pKernel->m_in_loop = m_in_loop;
343
m_pKernel->check_masks();
344
#endif
345
}
346
};
347
348
#define SPMD_BEGIN_CALL scoped_exec_saver CPPSPMD_GLUER2(_begin_call_scoped_exec_saver, __LINE__)(this); m_continue_mask = exec_mask::all_off();
349
#define SPMD_BEGIN_CALL_ALL_LANES scoped_exec_saver CPPSPMD_GLUER2(_begin_call_scoped_exec_saver, __LINE__)(this); m_exec = exec_mask::all_on(); m_continue_mask = exec_mask::all_off();
350
351
template<typename ForeachBody>
352
CPPSPMD_FORCE_INLINE void spmd_kernel::spmd_foreach(int begin, int end, const ForeachBody& foreachBody)
353
{
354
if (begin == end)
355
return;
356
357
if (!any(m_exec))
358
return;
359
360
// We don't support iterating backwards.
361
if (begin > end)
362
std::swap(begin, end);
363
364
exec_mask prev_continue_mask = m_continue_mask, prev_exec = m_exec;
365
366
int total_full = (end - begin) / PROGRAM_COUNT;
367
int total_partial = (end - begin) % PROGRAM_COUNT;
368
369
lint_t loop_index = begin + program_index;
370
371
const int total_loops = total_full + (total_partial ? 1 : 0);
372
373
m_continue_mask = exec_mask::all_off();
374
375
for (int i = 0; i < total_loops; i++)
376
{
377
int n = PROGRAM_COUNT;
378
if ((i == (total_loops - 1)) && (total_partial))
379
{
380
exec_mask partial_mask = exec_mask(vint_t(total_partial) > vint_t(program_index));
381
m_exec = m_exec & partial_mask;
382
n = total_partial;
383
}
384
385
foreachBody(loop_index, n);
386
387
m_exec = m_exec | m_continue_mask;
388
if (!any(m_exec))
389
break;
390
391
m_continue_mask = exec_mask::all_off();
392
check_masks();
393
394
store_all(loop_index, loop_index + PROGRAM_COUNT);
395
}
396
397
m_exec = prev_exec & m_kernel_exec;
398
m_continue_mask = prev_continue_mask;
399
check_masks();
400
}
401
402
template<typename WhileCondBody, typename WhileBody>
403
CPPSPMD_FORCE_INLINE void spmd_kernel::spmd_while(const WhileCondBody& whileCondBody, const WhileBody& whileBody)
404
{
405
exec_mask orig_exec = m_exec;
406
407
exec_mask orig_continue_mask = m_continue_mask;
408
m_continue_mask = exec_mask::all_off();
409
410
#ifdef _DEBUG
411
const bool prev_in_loop = m_in_loop;
412
m_in_loop = true;
413
#endif
414
415
while(true)
416
{
417
exec_mask cond_exec = exec_mask(whileCondBody());
418
m_exec = m_exec & cond_exec;
419
420
if (!any(m_exec))
421
break;
422
423
whileBody();
424
425
m_exec = m_exec | m_continue_mask;
426
m_continue_mask = exec_mask::all_off();
427
check_masks();
428
}
429
430
#ifdef _DEBUG
431
m_in_loop = prev_in_loop;
432
#endif
433
434
m_exec = orig_exec & m_kernel_exec;
435
m_continue_mask = orig_continue_mask;
436
check_masks();
437
}
438
439
struct scoped_while_restorer
440
{
441
spmd_kernel *m_pKernel;
442
exec_mask m_orig_exec, m_orig_continue_mask;
443
#ifdef _DEBUG
444
bool m_prev_in_loop;
445
#endif
446
447
CPPSPMD_FORCE_INLINE scoped_while_restorer(spmd_kernel *pKernel) :
448
m_pKernel(pKernel),
449
m_orig_exec(pKernel->m_exec),
450
m_orig_continue_mask(pKernel->m_continue_mask)
451
{
452
pKernel->m_continue_mask.all_off();
453
454
#ifdef _DEBUG
455
m_prev_in_loop = pKernel->m_in_loop;
456
pKernel->m_in_loop = true;
457
#endif
458
}
459
460
CPPSPMD_FORCE_INLINE ~scoped_while_restorer()
461
{
462
m_pKernel->m_exec = m_orig_exec & m_pKernel->m_kernel_exec;
463
m_pKernel->m_continue_mask = m_orig_continue_mask;
464
#ifdef _DEBUG
465
m_pKernel->m_in_loop = m_prev_in_loop;
466
m_pKernel->check_masks();
467
#endif
468
}
469
};
470
471
#undef SPMD_WHILE
472
#undef SPMD_WEND
473
#define SPMD_WHILE(cond) { scoped_while_restorer CPPSPMD_GLUER2(_while_restore_, __LINE__)(this); while(true) { exec_mask CPPSPMD_GLUER2(cond_exec, __LINE__) = exec_mask(vbool(cond)); \
474
m_exec = m_exec & CPPSPMD_GLUER2(cond_exec, __LINE__); if (!any(m_exec)) break;
475
476
#define SPMD_WEND m_exec = m_exec | m_continue_mask; m_continue_mask = exec_mask::all_off(); check_masks(); } }
477
478
// Nesting is not supported (although it will compile, but the results won't make much sense).
479
#define SPMD_FOREACH(loop_var, bi, ei) if (((bi) != (ei)) && (any(m_exec))) { \
480
scoped_while_restorer CPPSPMD_GLUER2(_while_restore_, __LINE__)(this); \
481
uint32_t b = (uint32_t)(bi), e = (uint32_t)(ei); if ((b) > (e)) { std::swap(b, e); } const uint32_t total_full = ((e) - (b)) >> PROGRAM_COUNT_SHIFT, total_partial = ((e) - (b)) & (PROGRAM_COUNT - 1); \
482
lint_t loop_var = program_index + (int)b; const uint32_t total_loops = total_full + (total_partial ? 1U : 0U); \
483
for (uint32_t CPPSPMD_GLUER2(_foreach_counter, __LINE__) = 0; CPPSPMD_GLUER2(_foreach_counter, __LINE__) < total_loops; ++CPPSPMD_GLUER2(_foreach_counter, __LINE__)) { \
484
if ((CPPSPMD_GLUER2(_foreach_counter, __LINE__) == (total_loops - 1)) && (total_partial)) { exec_mask partial_mask = exec_mask(vint_t((int)total_partial) > vint_t(program_index)); m_exec = m_exec & partial_mask; }
485
486
#define SPMD_FOREACH_END(loop_var) m_exec = m_exec | m_continue_mask; if (!any(m_exec)) break; m_continue_mask = exec_mask::all_off(); check_masks(); store_all(loop_var, loop_var + PROGRAM_COUNT); } }
487
488
// Okay to use spmd_continue or spmd_return, but not spmd_break
489
#define SPMD_FOREACH_ACTIVE(index_var) int64_t index_var; { uint64_t _movemask = m_exec.get_movemask(); if (_movemask) { scoped_while_restorer CPPSPMD_GLUER2(_while_restore_, __LINE__)(this); \
490
for (uint32_t _i = 0; _i < PROGRAM_COUNT; ++_i) { \
491
if (_movemask & (1U << _i)) { \
492
m_exec.enable_lane(_i); m_exec = m_exec & m_kernel_exec; \
493
(index_var) = _i; \
494
495
#define SPMD_FOREACH_ACTIVE_END } } } }
496
497
// Okay to use spmd_continue, but not spmd_break/spmd_continue
498
#define SPMD_FOREACH_UNIQUE_INT(index_var, var) { scoped_while_restorer CPPSPMD_GLUER2(_while_restore_, __LINE__)(this); \
499
CPPSPMD_DECL(int_t, _vals[PROGRAM_COUNT]); store_linear_all(_vals, var); std::sort(_vals, _vals + PROGRAM_COUNT); \
500
const int _n = (int)(std::unique(_vals, _vals + PROGRAM_COUNT) - _vals); \
501
for (int _i = 0; _i < _n; ++_i) { int index_var = _vals[_i]; vbool cond = (vint_t(var) == vint_t(index_var)); m_exec = exec_mask(cond);
502
503
#define SPMD_FOREACH_UNIQUE_INT_END } }
504
505
struct scoped_simple_while_restorer
506
{
507
spmd_kernel* m_pKernel;
508
exec_mask m_orig_exec;
509
#ifdef _DEBUG
510
bool m_prev_in_loop;
511
#endif
512
513
CPPSPMD_FORCE_INLINE scoped_simple_while_restorer(spmd_kernel* pKernel) :
514
m_pKernel(pKernel),
515
m_orig_exec(pKernel->m_exec)
516
{
517
518
#ifdef _DEBUG
519
m_prev_in_loop = pKernel->m_in_loop;
520
pKernel->m_in_loop = true;
521
#endif
522
}
523
524
CPPSPMD_FORCE_INLINE ~scoped_simple_while_restorer()
525
{
526
m_pKernel->m_exec = m_orig_exec;
527
#ifdef _DEBUG
528
m_pKernel->m_in_loop = m_prev_in_loop;
529
m_pKernel->check_masks();
530
#endif
531
}
532
};
533
534
// Cannot use SPMD break, continue, or return inside simple while
535
536
#define SPMD_SWHILE(cond) { scoped_simple_while_restorer CPPSPMD_GLUER2(_while_restore_, __LINE__)(this); \
537
while(true) { \
538
exec_mask CPPSPMD_GLUER2(cond_exec, __LINE__) = exec_mask(vbool(cond)); m_exec = m_exec & CPPSPMD_GLUER2(cond_exec, __LINE__); if (!any(m_exec)) break;
539
#define SPMD_SWEND } }
540
541
// Cannot use SPMD break, continue, or return inside simple do
542
#define SPMD_SDO { scoped_simple_while_restorer CPPSPMD_GLUER2(_while_restore_, __LINE__)(this); while(true) {
543
#define SPMD_SEND_DO(cond) exec_mask CPPSPMD_GLUER2(cond_exec, __LINE__) = exec_mask(vbool(cond)); m_exec = m_exec & CPPSPMD_GLUER2(cond_exec, __LINE__); if (!any(m_exec)) break; } }
544
545
#undef SPMD_FOR
546
#undef SPMD_END_FOR
547
#define SPMD_FOR(for_init, for_cond) { for_init; scoped_while_restorer CPPSPMD_GLUER2(_while_restore_, __LINE__)(this); while(true) { exec_mask CPPSPMD_GLUER2(cond_exec, __LINE__) = exec_mask(vbool(for_cond)); \
548
m_exec = m_exec & CPPSPMD_GLUER2(cond_exec, __LINE__); if (!any(m_exec)) break;
549
#define SPMD_END_FOR(for_inc) m_exec = m_exec | m_continue_mask; m_continue_mask = exec_mask::all_off(); check_masks(); for_inc; } }
550
551
template<typename ForInitBody, typename ForCondBody, typename ForIncrBody, typename ForBody>
552
CPPSPMD_FORCE_INLINE void spmd_kernel::spmd_for(const ForInitBody& forInitBody, const ForCondBody& forCondBody, const ForIncrBody& forIncrBody, const ForBody& forBody)
553
{
554
exec_mask orig_exec = m_exec;
555
556
forInitBody();
557
558
exec_mask orig_continue_mask = m_continue_mask;
559
m_continue_mask = exec_mask::all_off();
560
561
#ifdef _DEBUG
562
const bool prev_in_loop = m_in_loop;
563
m_in_loop = true;
564
#endif
565
566
while(true)
567
{
568
exec_mask cond_exec = exec_mask(forCondBody());
569
m_exec = m_exec & cond_exec;
570
571
if (!any(m_exec))
572
break;
573
574
forBody();
575
576
m_exec = m_exec | m_continue_mask;
577
m_continue_mask = exec_mask::all_off();
578
check_masks();
579
580
forIncrBody();
581
}
582
583
m_exec = orig_exec & m_kernel_exec;
584
m_continue_mask = orig_continue_mask;
585
586
#ifdef _DEBUG
587
m_in_loop = prev_in_loop;
588
check_masks();
589
#endif
590
}
591
592