TDLS 0.4.0
Tiny Device-callable Linear Solvers
Loading...
Searching...
No Matches
group.hpp
Go to the documentation of this file.
1#ifndef TDLS_CORE_GROUP_HPP
2#define TDLS_CORE_GROUP_HPP
3
4
5
119
120
121
122#include <atomic>
123#include <chrono>
124#include <cstdio>
125#include <cstdlib>
126#include <thread>
127#include <type_traits>
128#include <utility>
129
130#include <tdls/core/macros.hpp>
131#include <tdls/core/target.hpp>
132
133#if defined(TDLS_DETAIL_COMPILER_NVCXX)
134#include <nv/target>
135#endif
136
137// The device printf of HIP comes with its runtime header, which a HIP
138// translation unit may include after this one.
139#if defined(TDLS_DETAIL_COMPILER_HIP_CLANG)
140#include <hip/hip_runtime.h>
141#endif
142
143
144
145/* =========================================================================
146 Side of the compilation pass (TDLS_DETAIL_PASS_*, core/target.hpp): the
147 instructions it offers to run the deduced barrier and to stop a kernel
148 or the program. The NVIDIA builtins serve the device passes outside the
149 CUDA language only, and the AMD ones the device passes of HIP and of
150 the other models. A pass without a side has no deduced barrier, and
151 TDLS_DETAIL_GROUP_NONE gives the reason.
152 ========================================================================= */
153
154#if defined(TDLS_DETAIL_PASS_NVCXX_STDPAR_OPENACC)
156#define TDLS_DETAIL_GROUP_NONE "The OpenACC backend of nvc++ for the parallel algorithms has none."
157#elif defined(TDLS_DETAIL_PASS_NVCXX_CUDA)
159#define TDLS_DETAIL_GROUP_NVCXX
160#elif defined(TDLS_DETAIL_PASS_NVCXX_OFFLOAD)
162#define TDLS_DETAIL_GROUP_NONE "nvc++ offers it to OpenMP and OpenACC offloading with -cuda."
163#elif defined(TDLS_DETAIL_PASS_AMDGCN)
165#define TDLS_DETAIL_GROUP_AMDGCN
166#elif defined(TDLS_DETAIL_PASS_CUDA)
168#define TDLS_DETAIL_GROUP_CUDA
169#elif defined(TDLS_DETAIL_PASS_NVPTX)
171#define TDLS_DETAIL_GROUP_NVPTX
172#elif defined(TDLS_DETAIL_PASS_GCC_OFFLOAD)
174#define TDLS_DETAIL_GROUP_NONE "GCC offloading has none."
175#elif defined(TDLS_DETAIL_PASS_SPIRV)
177#define TDLS_DETAIL_GROUP_NONE \
178 "On SPIR-V devices, SYCL and OpenMP offloading cannot stop a kernel whose group is " \
179 "incomplete; pass a sub-group, work-group or team barrier."
180#elif defined(TDLS_DETAIL_PASS_ACPP_GENERIC)
182#define TDLS_DETAIL_GROUP_NONE \
183 "The generic mode of AdaptiveCpp has none; its cuda and hip modes do."
184#else
186#define TDLS_DETAIL_GROUP_HOST
187#endif
188
189// Two sides lack the deduced barrier, yet still stop a kernel or the
190// program: NVIDIA before Volta has no match instruction, and a standard
191// library without std::atomic_ref no CPU barrier on the workspace.
192#if (defined(TDLS_DETAIL_GROUP_CUDA) || defined(TDLS_DETAIL_GROUP_NVPTX)) && \
193 ((defined(__CUDA_ARCH__) && __CUDA_ARCH__ < 700) || \
194 (defined(__SYCL_CUDA_ARCH__) && __SYCL_CUDA_ARCH__ < 700))
196#define TDLS_DETAIL_GROUP_NONE "NVIDIA GPUs before Volta (sm_70) have none."
197#elif defined(TDLS_DETAIL_GROUP_HOST) && !defined(__cpp_lib_atomic_ref)
199#define TDLS_DETAIL_GROUP_NONE \
200 "On CPU, it needs std::atomic_ref, missing from this standard library (libc++ before 19)."
201#endif
202
203#if !defined(TDLS_DETAIL_GROUP_NONE)
205#define TDLS_DETAIL_GROUP_BARRIER
206#endif
207
209#define TDLS_DETAIL_GROUP_EXPAND(...) __VA_ARGS__
210
211// The arguments of the selection macros are parenthesized statement
212// lists, as for NV_IF_TARGET. TDLS_DETAIL_GROUP_LANES qualifies the lane
213// functions: device functions of the CUDA and HIP languages, host-device
214// functions of nvc++, which select their body with NV_IF_TARGET, and
215// plain functions of the device passes of the other models.
216#if defined(TDLS_DETAIL_GROUP_NVCXX)
218#define TDLS_DETAIL_GROUP_ON_DEVICE(code) NV_IF_TARGET(NV_IS_DEVICE, code)
220#define TDLS_DETAIL_GROUP_SIDE(device, host) NV_IF_TARGET(NV_IS_DEVICE, device, host)
222#define TDLS_DETAIL_GROUP_LANES TDLS_HOST_DEVICE TDLS_FORCE_INLINE_GPU
223#elif defined(TDLS_DETAIL_GROUP_CUDA)
225#define TDLS_DETAIL_GROUP_ON_DEVICE(code) TDLS_DETAIL_GROUP_EXPAND code
227#define TDLS_DETAIL_GROUP_SIDE(device, host) TDLS_DETAIL_GROUP_EXPAND device
229#define TDLS_DETAIL_GROUP_LANES __device__ TDLS_FORCE_INLINE_GPU
230#elif defined(TDLS_DETAIL_GROUP_AMDGCN) && defined(TDLS_DETAIL_COMPILER_HIP_CLANG)
232#define TDLS_DETAIL_GROUP_SIDE(device, host) TDLS_DETAIL_GROUP_EXPAND device
234#define TDLS_DETAIL_GROUP_LANES __device__ TDLS_FORCE_INLINE_GPU
235#elif defined(TDLS_DETAIL_GROUP_NVPTX) || defined(TDLS_DETAIL_GROUP_AMDGCN)
237#define TDLS_DETAIL_GROUP_SIDE(device, host) TDLS_DETAIL_GROUP_EXPAND device
239#define TDLS_DETAIL_GROUP_LANES inline
240#elif defined(TDLS_DETAIL_GROUP_HOST)
242#define TDLS_DETAIL_GROUP_SIDE(device, host) TDLS_DETAIL_GROUP_EXPAND host
243#else
245#define TDLS_DETAIL_GROUP_SIDE(device, host)
246#endif
247
248#if defined(TDLS_DETAIL_GROUP_BARRIER)
250#define TDLS_DETAIL_GROUP_DISPATCH(device, host) TDLS_DETAIL_GROUP_SIDE(device, host)
251#else
253#define TDLS_DETAIL_GROUP_DISPATCH(device, host)
254#endif
255
256
257
258namespace tdls {
259
260
261
268struct AutoSync {};
269
275struct NoSync {
277 TDLS_HOST_DEVICE TDLS_FORCE_INLINE_GPU constexpr void operator()() const noexcept {
278 }
279};
280
281namespace detail {
282
285template<typename Sync>
286inline constexpr bool is_auto_sync = std::is_same_v<std::remove_cvref_t<Sync>, AutoSync>;
287
290template<typename Sync>
291inline constexpr bool is_no_sync = std::is_same_v<std::remove_cvref_t<Sync>, NoSync>;
292
300template<typename Sync, bool = is_auto_sync<Sync>>
301inline constexpr bool nothrow_sync = noexcept(std::declval<Sync&>()());
302
305template<typename Sync>
306inline constexpr bool nothrow_sync<Sync, true> = true;
307
316#if defined(TDLS_DETAIL_GROUP_BARRIER)
317template<typename T>
318inline constexpr bool group_barrier_available = true;
320#define TDLS_DETAIL_GROUP_NONE ""
321#else
322template<typename T>
323inline constexpr bool group_barrier_available = false;
324#endif
325
330inline constexpr int barrier_elements = 2;
331
335#if defined(TDLS_DETAIL_GROUP_BARRIER) && \
336 (defined(TDLS_DETAIL_GROUP_CUDA) || defined(TDLS_DETAIL_GROUP_NVPTX) || \
337 defined(TDLS_DETAIL_GROUP_NVCXX))
338inline constexpr int group_lanes = 32;
339#elif defined(TDLS_DETAIL_GROUP_BARRIER) && defined(TDLS_DETAIL_GROUP_AMDGCN)
340inline constexpr int group_lanes = 64;
341#else
342inline constexpr int group_lanes = 0;
343#endif
344
346enum class LanesFailure {
347 incomplete,
348 no_sync
349};
350
351// The messages, printed by the first lane of the group. They take no
352// argument: a formatted print would reserve a stack frame in local
353// memory for every kernel, even when it never runs. A workspace in the
354// private memory of each thread fails as an incomplete group: its address
355// is the same in every lane, so the lanes would match without sharing
356// anything.
358#define TDLS_DETAIL_GROUP_INCOMPLETE \
359 "TDLS: a group of threads is incomplete in its warp, or its workspace is private to each " \
360 "thread. The threads of a group must call the solver together, as lanes of one warp or " \
361 "wavefront, with a workspace in shared or global memory.\n"
363#define TDLS_DETAIL_GROUP_NO_SYNC \
364 "TDLS: the runtime solver runs with tdls::NoSync, valid for one thread per system, on a " \
365 "dimension above rows_per_thread. Pass a barrier, or a rows_per_thread reaching the " \
366 "dimension.\n"
367
368/* =========================================================================
369 NVIDIA, CUDA API: nvcc, clang CUDA, nvc++ on the device side.
370 ========================================================================= */
371
372#if defined(TDLS_DETAIL_GROUP_CUDA) || defined(TDLS_DETAIL_GROUP_NVCXX)
373
378TDLS_DETAIL_GROUP_LANES void lanes_fail([[maybe_unused]] const unsigned long long mask,
379 [[maybe_unused]] const LanesFailure failure) noexcept {
380 // clang-format off: a statement list as the argument of a macro
381 TDLS_DETAIL_GROUP_ON_DEVICE((
382 unsigned lane;
383 asm volatile("mov.u32 %0, %%laneid;" : "=r"(lane));
384 if (lane == static_cast<unsigned>(__ffsll(static_cast<long long>(mask)) - 1)) {
385 if (failure == LanesFailure::incomplete)
387 else
389 }
390 __trap();))
391 // clang-format on
392}
393
396TDLS_DETAIL_GROUP_LANES unsigned long long lanes_active() noexcept {
397 unsigned long long lanes = 0;
398 TDLS_DETAIL_GROUP_ON_DEVICE((lanes = __activemask();))
399 return lanes;
400}
401
402#if defined(TDLS_DETAIL_GROUP_BARRIER)
403
410TDLS_DETAIL_GROUP_LANES unsigned long long lanes_join(const void* key, const int threads) noexcept {
411 unsigned long long lanes = 0;
412 // clang-format off: a statement list as the argument of a macro
413 TDLS_DETAIL_GROUP_ON_DEVICE((
414 const unsigned mask =
415 __match_any_sync(__activemask(), reinterpret_cast<unsigned long long>(key));
416 if (__popc(mask) != threads || __isLocal(key))
417 lanes_fail(mask, LanesFailure::incomplete);
418 lanes = mask;))
419 // clang-format on
420 return lanes;
421}
422
425TDLS_DETAIL_GROUP_LANES void lanes_sync(const unsigned long long lanes) noexcept {
426 TDLS_DETAIL_GROUP_ON_DEVICE((__syncwarp(static_cast<unsigned>(lanes));))
427}
428
429#endif
430
431/* =========================================================================
432 NVIDIA, clang builtins: OpenMP offloading and SYCL device passes. The
433 active mask is read with the PTX instruction itself, as clang's CUDA
434 headers do before __nvvm_activemask (LLVM 19).
435 ========================================================================= */
436
437#elif defined(TDLS_DETAIL_GROUP_NVPTX)
438
443TDLS_DETAIL_GROUP_LANES void lanes_fail([[maybe_unused]] const unsigned long long mask,
444 [[maybe_unused]] const LanesFailure failure) noexcept {
445#if !defined(TDLS_DETAIL_LANG_SYCL_DEVICE)
446 if (__nvvm_read_ptx_sreg_laneid() == __builtin_ctzll(mask)) {
447 if (failure == LanesFailure::incomplete)
449 else
451 }
452#endif
453 __builtin_trap();
454}
455
458TDLS_DETAIL_GROUP_LANES unsigned long long lanes_active() noexcept {
459 unsigned active;
460 asm volatile("activemask.b32 %0;" : "=r"(active));
461 return active;
462}
463
464#if defined(TDLS_DETAIL_GROUP_BARRIER)
465
472TDLS_DETAIL_GROUP_LANES unsigned long long lanes_join(const void* key, const int threads) noexcept {
473 const unsigned mask = __nvvm_match_any_sync_i64(
474 static_cast<unsigned>(lanes_active()),
475 static_cast<long long>(reinterpret_cast<unsigned long long>(key)));
476 if (__builtin_popcount(mask) != threads || __nvvm_isspacep_local(key))
477 lanes_fail(mask, LanesFailure::incomplete);
478 return mask;
479}
480
483TDLS_DETAIL_GROUP_LANES void lanes_sync(const unsigned long long lanes) noexcept {
484 __nvvm_bar_warp_sync(static_cast<unsigned>(lanes));
485}
486
487#endif
488
489/* =========================================================================
490 AMD, clang builtins: HIP, OpenMP offloading and SYCL device passes.
491 The match is the loop of the __match_any of HIP: the first lane still
492 searching broadcasts its key, and the lanes holding it leave with
493 their mask. The lanes of a wavefront run in lockstep: the barrier only
494 orders the memory operations, as the __syncwarp of HIP. These are the
495 builtins HIP itself uses, available from ROCm 5.3 on, so that the
496 barrier does not depend on the HIP release. The ballot is the builtin
497 of recent clang, or the one HIP used before it.
498 ========================================================================= */
499
500#elif defined(TDLS_DETAIL_GROUP_AMDGCN)
501
503#if __clang_major__ >= 19
504#define TDLS_DETAIL_GROUP_BALLOT(predicate) __builtin_amdgcn_ballot_w64(predicate)
505#else
506#define TDLS_DETAIL_GROUP_BALLOT(predicate) \
507 __builtin_amdgcn_uicmp(static_cast<unsigned>(predicate), 0u, 33 /* ICMP_NE */)
508#endif
509
514TDLS_DETAIL_GROUP_LANES void lanes_fail([[maybe_unused]] const unsigned long long mask,
515 [[maybe_unused]] const LanesFailure failure) noexcept {
516#if !defined(TDLS_DETAIL_LANG_SYCL_DEVICE)
517 const unsigned lane = __builtin_amdgcn_mbcnt_hi(~0u, __builtin_amdgcn_mbcnt_lo(~0u, 0u));
518 if (lane == static_cast<unsigned>(__builtin_ctzll(mask))) {
519 if (failure == LanesFailure::incomplete)
521 else
523 }
524#endif
525 __builtin_trap();
526}
527
530TDLS_DETAIL_GROUP_LANES unsigned long long lanes_active() noexcept {
531 return __builtin_amdgcn_read_exec();
532}
533
540TDLS_DETAIL_GROUP_LANES unsigned long long lanes_join(const void* key, const int threads) noexcept {
541 const unsigned long long own = reinterpret_cast<unsigned long long>(key);
542 unsigned long long mask = 0;
543 bool done = false;
544 while (TDLS_DETAIL_GROUP_BALLOT(!done) != 0) {
545 if (!done) {
546 const unsigned low = __builtin_amdgcn_readfirstlane(static_cast<unsigned>(own));
547 const unsigned high = __builtin_amdgcn_readfirstlane(static_cast<unsigned>(own >> 32));
548 if (((static_cast<unsigned long long>(high) << 32) | low) == own) {
549 mask = TDLS_DETAIL_GROUP_BALLOT(true);
550 done = true;
551 }
552 }
553 }
554 // The builtin takes a generic pointer, which OpenMP offloading does not
555 // make the default. Only a C cast changes the address space, as in the
556 // OpenMP device runtime.
557 const bool isprivate =
558 __builtin_amdgcn_is_private((const __attribute__((address_space(0))) void*)key);
559 if (__builtin_popcountll(mask) != threads || isprivate)
560 lanes_fail(mask, LanesFailure::incomplete);
561 return mask;
562}
563
566TDLS_DETAIL_GROUP_LANES void lanes_sync(unsigned long long) noexcept {
567 __builtin_amdgcn_fence(__ATOMIC_RELEASE, "wavefront");
568 __builtin_amdgcn_wave_barrier();
569 __builtin_amdgcn_fence(__ATOMIC_ACQUIRE, "wavefront");
570}
571
572#endif
573
574/* =========================================================================
575 Host: a counter and a flag in the first two elements of the workspace.
576 The flag alternates between 0 and 1. A thread reads it before
577 arriving, so it cannot miss the flip of its own barrier; the last
578 thread to arrive resets the counter, then flips the flag.
579 ========================================================================= */
580
581#if defined(TDLS_DETAIL_GROUP_HOST) || defined(TDLS_DETAIL_GROUP_NVCXX)
582
585inline void host_refuse_no_sync() noexcept {
586 std::fputs(TDLS_DETAIL_GROUP_NO_SYNC, stderr);
587 std::abort();
588}
589
590#if defined(TDLS_DETAIL_GROUP_BARRIER)
591
598template<typename T>
599void host_join(T* slots, const int threads) noexcept {
600 static_assert(std::atomic_ref<T>::is_always_lock_free,
601 "TDLS: the deduced CPU barrier needs lock-free atomics on the scalar type; "
602 "pass a barrier (sync argument)");
603 const T count = std::atomic_ref<T>(slots[0]).load(std::memory_order_relaxed);
604 const T flag = std::atomic_ref<T>(slots[1]).load(std::memory_order_relaxed);
605 if (!(count >= T(0) && count < T(threads) && count == T(static_cast<int>(count)) &&
606 (flag == T(0) || flag == T(1)))) {
607 std::fprintf(stderr,
608 "TDLS: the workspace of a group of %d CPU threads was not zero before "
609 "its first use.\n",
610 threads);
611 std::abort();
612 }
613}
614
619template<typename T>
620void host_sync(T* slots, const int threads) noexcept {
621 std::atomic_ref<T> count(slots[0]);
622 std::atomic_ref<T> flag(slots[1]);
623 const T seen = flag.load(std::memory_order_acquire);
624 if (count.fetch_add(T(1), std::memory_order_acq_rel) == T(threads - 1)) {
625 count.store(T(0), std::memory_order_relaxed);
626 flag.store(seen == T(0) ? T(1) : T(0), std::memory_order_release);
627 return;
628 }
629 // Spin first, then yield. The clock is read only after the spins, once
630 // every 1024 iterations: the barriers of a running group never reach it.
631 static std::atomic<bool> warned{false};
632 std::chrono::steady_clock::time_point start{};
633 for (unsigned spins = 0; flag.load(std::memory_order_acquire) == seen; ++spins) {
634 if (spins < 1024) continue;
635 std::this_thread::yield();
636 if (spins % 1024 != 0) continue;
637 const auto now = std::chrono::steady_clock::now();
638 if (spins == 1024)
639 start = now;
640 else if (now - start > std::chrono::seconds(1) && !warned.exchange(true))
641 std::fprintf(stderr,
642 "TDLS: a group of %d CPU threads has waited for 1 s at a barrier. "
643 "The threads of a group must share its workspace and run "
644 "concurrently: not in a worksharing loop, nor in parallel STL or a "
645 "SYCL kernel on the CPU.\n",
646 threads);
647 }
648}
649
650#endif
651
652#endif
653
654#undef TDLS_DETAIL_GROUP_INCOMPLETE
655#undef TDLS_DETAIL_GROUP_NO_SYNC
656#undef TDLS_DETAIL_GROUP_BALLOT
657
662 TDLS_DETAIL_GROUP_SIDE((lanes_fail(lanes_active(), LanesFailure::no_sync);),
664}
665
670template<typename T>
672 public:
680 TDLS_FORCE_INLINE_GPU constexpr DeducedSync(T* slots, const int threads) noexcept
681 : slots(slots), threads(threads) {
682 if (threads > 1) {
683 TDLS_DETAIL_GROUP_DISPATCH((lanes = lanes_join(slots, threads);),
684 (host_join(slots, threads);))
685 }
686 }
687
690 TDLS_HOST_DEVICE TDLS_FORCE_INLINE_GPU constexpr void operator()() const noexcept {
691 if (threads > 1) {
692 TDLS_DETAIL_GROUP_DISPATCH((lanes_sync(lanes);), (host_sync(slots, threads);))
693 }
694 }
695
696 private:
697 T* slots;
698 int threads;
699 unsigned long long lanes = 0;
700};
701
719template<int static_threads, typename Sync, typename T>
720TDLS_HOST_DEVICE TDLS_FORCE_INLINE_GPU constexpr decltype(auto)
721resolve_sync(Sync& sync, [[maybe_unused]] T* slots, [[maybe_unused]] const int threads) noexcept {
722 if constexpr (is_no_sync<Sync>) {
723 static_assert(static_threads <= 1, "TDLS: a group of several threads cannot run with "
724 "tdls::NoSync (sync argument)");
725 if constexpr (static_threads == 0) {
726 if (threads > 1) refuse_no_sync();
727 }
728 return (sync);
729 } else if constexpr (!is_auto_sync<Sync>) {
730 return (sync);
731 } else if constexpr (static_threads == 1) {
732 return NoSync{};
733 } else {
734 static_assert(group_barrier_available<T>,
735 "TDLS: this compilation target offers no deduced barrier for a group of "
736 "several threads; pass a barrier (sync argument), or tdls::NoSync with one "
737 "thread per system. " TDLS_DETAIL_GROUP_NONE);
738 static_assert(group_lanes == 0 || static_threads <= group_lanes,
739 "TDLS: a group larger than a warp needs a barrier (sync argument)");
740 return DeducedSync<T>(slots, threads);
741 }
742}
743
744} // namespace detail
745
746
747
748} // namespace tdls
749
750
751
752#undef TDLS_DETAIL_GROUP_DISPATCH
753#undef TDLS_DETAIL_GROUP_SIDE
754#undef TDLS_DETAIL_GROUP_LANES
755#undef TDLS_DETAIL_GROUP_ON_DEVICE
756#undef TDLS_DETAIL_GROUP_EXPAND
757#undef TDLS_DETAIL_GROUP_BARRIER
758#undef TDLS_DETAIL_GROUP_CUDA
759#undef TDLS_DETAIL_GROUP_NVPTX
760#undef TDLS_DETAIL_GROUP_AMDGCN
761#undef TDLS_DETAIL_GROUP_NVCXX
762#undef TDLS_DETAIL_GROUP_HOST
763#undef TDLS_DETAIL_GROUP_NONE
764
765
766
767#endif // TDLS_CORE_GROUP_HPP
The barrier deduced from the compilation target, for a group of several threads. A group of one threa...
Definition group.hpp:671
TDLS_EXEC_CHECK_DISABLE TDLS_HOST_DEVICE TDLS_FORCE_INLINE_GPU constexpr DeducedSync(T *slots, const int threads) noexcept
Joins the group: the GPU check of its lanes, or the CPU check of its workspace.
Definition group.hpp:680
TDLS_EXEC_CHECK_DISABLE TDLS_HOST_DEVICE TDLS_FORCE_INLINE_GPU constexpr void operator()() const noexcept
Barrier of the group.
Definition group.hpp:690
#define TDLS_DETAIL_GROUP_NO_SYNC
Message of tdls::NoSync with a group of several threads.
Definition group.hpp:363
constexpr bool group_barrier_available
Whether the compilation pass offers the deduced barrier to a group of several threads....
Definition group.hpp:323
#define TDLS_DETAIL_GROUP_DISPATCH(device, host)
No deduced barrier: the resolution of the barrier refuses the pass.
Definition group.hpp:253
LanesFailure
Failures that stop a kernel, each with its message.
Definition group.hpp:346
@ no_sync
tdls::NoSync with a group of several threads
@ incomplete
a group incomplete in its warp, or a private workspace
TDLS_HOST_DEVICE TDLS_FORCE_INLINE_GPU constexpr decltype(auto) resolve_sync(Sync &sync, T *slots, const int threads) noexcept
Resolves the barrier argument of an entry point: the caller's barrier as is, or the deduced barrier.
Definition group.hpp:721
void host_refuse_no_sync() noexcept
Stops the program: the runtime solver runs a group of several threads with tdls::NoSync.
Definition group.hpp:585
constexpr int barrier_elements
Elements at the start of the workspace that hold the deduced CPU barrier: a counter and a flag....
Definition group.hpp:330
#define TDLS_DETAIL_GROUP_NONE
No deduced barrier in this pass; the reason, appended to the diagnostic.
Definition group.hpp:199
constexpr int group_lanes
Largest group the warp of the pass can hold, checked at compile time when the size of the group is (0...
Definition group.hpp:342
#define TDLS_DETAIL_GROUP_INCOMPLETE
Message of an incomplete group.
Definition group.hpp:358
constexpr bool is_no_sync
Whether the barrier argument is the absence of barrier.
Definition group.hpp:291
TDLS_HOST_DEVICE TDLS_FORCE_INLINE_GPU void refuse_no_sync() noexcept
Stops the program: the runtime solver runs a group of several threads with tdls::NoSync....
Definition group.hpp:661
constexpr bool is_auto_sync
Whether the barrier argument asks for the deduced barrier.
Definition group.hpp:286
constexpr bool nothrow_sync
Whether a call of the barrier is noexcept, the condition of the noexcept specification of every entry...
Definition group.hpp:301
#define TDLS_DETAIL_GROUP_SIDE(device, host)
Picks the statement list of the side of the pass.
Definition group.hpp:242
Toolchain detection and portability macros.
#define TDLS_FORCE_INLINE_GPU
Inlining forced on GPU only: __forceinline__ under CUDA, the equivalent attribute under HIP (see TDLS...
Definition macros.hpp:77
#define TDLS_EXEC_CHECK_DISABLE
Lifts the execution-space check of nvcc on the next function template; empty elsewhere.
Definition macros.hpp:274
#define TDLS_HOST_DEVICE
__host__ __device__ under CUDA, the equivalent attributes under HIP, empty elsewhere.
Definition macros.hpp:50
Barrier argument of the cooperative solvers that asks them to deduce the barrier from the compilation...
Definition group.hpp:268
Barrier that does nothing, valid only when one thread solves a system. The compile-time solver refuse...
Definition group.hpp:275
TDLS_HOST_DEVICE TDLS_FORCE_INLINE_GPU constexpr void operator()() const noexcept
Does nothing.
Definition group.hpp:277
Detection of the compiler, of the language and of the side of the compilation pass: the one place whe...