@@ -31,12 +31,9 @@ function DataLayouts.reduce_points(::ThisHost, op::O, arg; kwargs...) where {O}
3131 end
3232 T = return_type (op, NTuple{2 , eltype (arg)})
3333 empty_results = DataLayouts. scoped_array (ThisHost (), T, 0 )
34- # Launch at most one thread per point, so that every thread has at least
35- # one value to reduce (indices are divided among threads through strided
36- # ranges, which are only guaranteed to be nonempty when the total thread
37- # count does not exceed the number of points). Threads without values would
38- # need placeholders for the warp shuffles, but reduction operations without
39- # neutral elements (like the min in minimum) cannot generate placeholders.
34+ # Launch at most one thread per point, so that every thread's strided range of
35+ # indices is nonempty. Threads without values would need warp-shuffle placeholders,
36+ # which reductions without neutral elements (like min) cannot generate.
4037 max_threads = threads_via_occupancy (kernel, (empty_results, arg))
4138 threads = min (length (arg), max_threads)
4239 blocks = max (fld (length (arg), threads), 1 )
@@ -50,10 +47,8 @@ function DataLayouts.reduce_points(::ThisHost, op::O, arg; kwargs...) where {O}
5047 return CUDA. @allowscalar @inbounds results[1 ]
5148end
5249
53- # If given a warp or a partition of a warp, reduce each threads's values, then
54- # reduce the results using warp shuffles. Otherwise, reduce each warp's values,
55- # then reduce the results in the first warp. Limit warp shuffles to the active
56- # threads in each warp, since the results from inactive threads are undefined.
50+ # Reduce a warp or sub-warp with warp shuffles, limited to active threads (inactive
51+ # results are undefined); otherwise reduce each warp, then combine in the first warp.
5752DataLayouts. reduce_points (scope:: ThisCooperativeGroup , op:: O , arg; kwargs... ) where {O} =
5853 if scope != ThisBlock () && DataLayouts. num_threads (scope) <= THREADS_PER_WARP
5954 thread_result =
@@ -87,10 +82,8 @@ DataLayouts.reduce_points(scope::ThisCooperativeGroup, op::O, arg; kwargs...) wh
8782@generated num_reductions (:: ThisSubBlock{N} ) where {N} =
8883 8 * sizeof (N) - leading_zeros (N) - 1
8984
90- # Use warp shuffles to perform binary tree reductions over the first num_values
91- # threads in a warp or sub-warp. All active threads in the warp must execute the
92- # shuffles, but values from threads with ranks above num_values are ignored. The
93- # mask identifies active lanes of the warp, which correspond to its lowest bits.
85+ # Binary-tree warp-shuffle reduction over the first num_values threads: every active
86+ # lane (the mask's lowest bits) must shuffle, but ranks above num_values are ignored.
9487function shuffle_reduce (scope, op:: O , value, num_values) where {O}
9588 num_offsets = num_reductions (scope)
9689 num_inactive = THREADS_PER_WARP - num_active_threads (ThisWarp ())
@@ -104,10 +97,8 @@ function shuffle_reduce(scope, op::O, value, num_values) where {O}
10497 return value
10598end
10699
107- # CUDA's warp shuffle intrinsics only support scalar values, so register how they
108- # should shuffle the AutoBroadcaster-wrapped values produced by multi-component
109- # reductions: shuffle each of the underlying values, recursing through any nested
110- # AutoBroadcasters. shfl_recurse is CUDA's documented extension point for value
111- # types that the shuffle intrinsics do not natively support.
100+ # CUDA's warp shuffle intrinsics only support scalar values; shfl_recurse is their
101+ # documented extension point, used here to recursively shuffle each value wrapped in
102+ # the AutoBroadcasters produced by multi-component reductions.
112103CUDA. shfl_recurse (op:: O , x:: Utilities.AutoBroadcaster ) where {O} =
113104 Utilities. AutoBroadcaster (UnrolledUtilities. unrolled_map (op, Utilities. unwrap (x)))
0 commit comments