Skip to content

Commit 4565d48

Browse files
sifakisclaude
andcommitted
nanovdb/util/Simd.h: remove unused gather and popcount
The hybrid StencilAccessor/BatchAccessor stack was the only consumer of util::gather, util::gather_if, util::popcount, and util::popcount64; all four became dead code when that stack was removed (commit 79004aa). Verified no live caller in the tree (the disabled examples didn't use them either) and that ex_weno_nanovdb_cpu's WenoStencil<16> path is syntax-clean against the trimmed header. - Drop the three gather overloads (unmasked / masked / merge-masked) from both backends and the scalar fallback path. - Drop popcount64 plus the lane-wise popcount<W> and scalar popcount. - Update the simd_cast doc comment to drop the "when building gather indices" justification (widening between integer types remains). Net: -104 lines (562 -> 458). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> Signed-off-by: Efty Sifakis <esifakis@nvidia.com>
1 parent 412cd4b commit 4565d48

1 file changed

Lines changed: 5 additions & 109 deletions

File tree

nanovdb/nanovdb/util/Simd.h

Lines changed: 5 additions & 109 deletions
Original file line numberDiff line numberDiff line change
@@ -134,39 +134,6 @@ inline void store(Simd<T,W> v, T* p, element_aligned_tag = {}) {
134134
v.copy_to(p, element_aligned);
135135
}
136136

137-
// Unmasked gather: result[i] = ptr[idx[i]] for all lanes.
138-
// IdxT may be int32_t or int64_t; the compiler selects the matching hardware
139-
// instruction (vpgatherdps/vpgatherdq for 32-bit idx, vpgatherqq for 64-bit idx).
140-
template<typename T, typename IdxT, int W>
141-
inline Simd<T,W> gather(const T* __restrict__ ptr, Simd<IdxT,W> idx) {
142-
return Simd<T,W>([&](int i) { return ptr[idx[i]]; });
143-
}
144-
145-
// Masked gather: result[i] = mask[i] ? ptr[idx[i]] : fallback.
146-
// Implemented as a full gather + where-blend; ptr is accessed for ALL lanes,
147-
// so every idx[i] must be a valid offset regardless of mask[i].
148-
template<typename T, typename IdxT, int W>
149-
inline Simd<T,W> gather(SimdMask<T,W> mask, const T* __restrict__ ptr,
150-
Simd<IdxT,W> idx, T fallback = T(0)) {
151-
auto result = Simd<T,W>(fallback);
152-
stdx::where(mask, result) = Simd<T,W>([&](int i) { return ptr[idx[i]]; });
153-
return result;
154-
}
155-
156-
// Merge-masked gather: dst[i] = mask[i] ? ptr[idx[i]] : dst[i] (unchanged).
157-
// MaskElemT may differ from T (heterogeneous mask, e.g. SimdMask<uint32_t,W>
158-
// applied to Simd<uint64_t,W> data). When T==MaskElemT, delegates directly
159-
// to stdx::where; otherwise uses the WhereExpression boolean round-trip.
160-
template<typename T, typename IdxT, typename MaskElemT, int W>
161-
inline void gather_if(Simd<T,W>& dst, SimdMask<MaskElemT,W> mask,
162-
const T* __restrict__ ptr, Simd<IdxT,W> idx) {
163-
if constexpr (std::is_same_v<T, MaskElemT>) {
164-
stdx::where(mask, dst) = Simd<T,W>([&](int i) { return ptr[idx[i]]; });
165-
} else {
166-
where(mask, dst) = Simd<T,W>([&](int i) { return ptr[idx[i]]; });
167-
}
168-
}
169-
170137
// ===========================================================================
171138
// Implementation B: std::array backend (default)
172139
// ===========================================================================
@@ -346,44 +313,16 @@ __hostdev__ void store(Simd<T,W> v, T* p, element_aligned_tag = {}) {
346313
v.store(p);
347314
}
348315

349-
// Unmasked gather: result[i] = ptr[idx[i]] for all lanes.
350-
template<typename T, typename IdxT, int W>
351-
__hostdev__ Simd<T,W> gather(const T* __restrict__ ptr, Simd<IdxT,W> idx) {
352-
Simd<T,W> r;
353-
for (int i = 0; i < W; i++) r[i] = ptr[idx[i]];
354-
return r;
355-
}
356-
357-
// Masked gather: result[i] = mask[i] ? ptr[idx[i]] : fallback.
358-
// Scalar path: accesses ptr only for true lanes (ternary short-circuits).
359-
template<typename T, typename IdxT, int W>
360-
__hostdev__ Simd<T,W> gather(SimdMask<T,W> mask, const T* __restrict__ ptr,
361-
Simd<IdxT,W> idx, T fallback = T(0)) {
362-
Simd<T,W> r;
363-
for (int i = 0; i < W; i++) r[i] = mask[i] ? ptr[idx[i]] : fallback;
364-
return r;
365-
}
366-
367-
// Merge-masked gather: dst[i] = mask[i] ? ptr[idx[i]] : dst[i] (unchanged).
368-
// MaskElemT may differ from T (heterogeneous mask).
369-
// Scalar path: only accesses ptr for true lanes.
370-
template<typename T, typename IdxT, typename MaskElemT, int W>
371-
__hostdev__ void gather_if(Simd<T,W>& dst, SimdMask<MaskElemT,W> mask,
372-
const T* __restrict__ ptr, Simd<IdxT,W> idx) {
373-
for (int i = 0; i < W; i++)
374-
if (mask[i]) dst[i] = ptr[idx[i]];
375-
}
376-
377316
#endif // NANOVDB_USE_STD_SIMD
378317

379318
// ---------------------------------------------------------------------------
380319
// simd_cast<DstT> — element-wise static_cast between Simd types of the same W.
381320
//
382-
// Used for widening (uint16_t → uint32_t, uint32_t → uint64_t) and for
383-
// reinterpreting signedness (uint32_t → int32_t) when building gather indices.
384-
// Both backends: the array backend uses a lane loop; the stdx backend uses the
385-
// generator constructor, which the compiler lowers to a vpmovsxbw / vpmovzxwd
386-
// sequence or similar sign/zero-extend instruction depending on the types.
321+
// Used for widening between integer element types (uint16_t → uint32_t,
322+
// uint32_t → uint64_t). Both backends: the array backend uses a lane loop;
323+
// the stdx backend uses the generator constructor, which the compiler lowers
324+
// to a vpmovsxbw / vpmovzxwd sequence or similar sign/zero-extend instruction
325+
// depending on the types.
387326
// Scalar overload: degrades to static_cast for plain scalar types.
388327
// ---------------------------------------------------------------------------
389328
template<typename DstT, typename SrcT, int W>
@@ -420,39 +359,6 @@ __hostdev__ void simd_cast_if(DstT& dst, bool mask, SrcT src) {
420359
if (mask) dst = static_cast<DstT>(src);
421360
}
422361

423-
// ---------------------------------------------------------------------------
424-
// popcount64 — scalar SWAR popcount, always uses arithmetic (no __builtin_popcountll).
425-
//
426-
// Safe to call per-lane inside a vectorizable loop: every operation (>>, &, +, -)
427-
// maps to an AVX2 instruction for 64-bit elements (vpsrlq, vpand, vpaddq, vpsubq).
428-
// The final byte-sum uses a shift-and-add tree instead of the multiply trick
429-
// (v * 0x0101...) since 64x64->64 multiply has no AVX2 equivalent (vpmullq is AVX-512).
430-
// ---------------------------------------------------------------------------
431-
__hostdev__ inline uint64_t popcount64(uint64_t v)
432-
{
433-
v -= (v >> 1) & uint64_t(0x5555555555555555);
434-
v = (v & uint64_t(0x3333333333333333)) + ((v >> 2) & uint64_t(0x3333333333333333));
435-
v = (v + (v >> 4)) & uint64_t(0x0F0F0F0F0F0F0F0F); // per-byte counts
436-
v += v >> 8; v &= uint64_t(0x00FF00FF00FF00FF);
437-
v += v >> 16; v &= uint64_t(0x0000FFFF0000FFFF);
438-
v += v >> 32;
439-
return v & uint64_t(63);
440-
}
441-
442-
// Lane-wise SIMD popcount: applies popcount64 to every lane.
443-
// Backend A: generator constructor; Backend B: element loop (auto-vectorized by GCC/Clang).
444-
template<int W>
445-
__hostdev__ Simd<uint64_t,W> popcount(Simd<uint64_t,W> v) {
446-
#ifdef NANOVDB_USE_STD_SIMD
447-
return Simd<uint64_t,W>([&](int i) { return popcount64(v[i]); });
448-
#else
449-
Simd<uint64_t,W> r;
450-
for (int i = 0; i < W; ++i) r[i] = popcount64(v[i]);
451-
return r;
452-
#endif
453-
}
454-
__hostdev__ inline uint64_t popcount(uint64_t v) { return popcount64(v); }
455-
456362
// ---------------------------------------------------------------------------
457363
// simd_traits — generic per-lane access for scalar and Simd<T,W> types.
458364
//
@@ -548,15 +454,5 @@ __hostdev__ ScalarWhereProxy<T> where(bool mask, T& target) {
548454
return {mask, target};
549455
}
550456

551-
// Unmasked scalar gather: result = ptr[idx].
552-
template<typename T, typename IdxT>
553-
__hostdev__ T gather(const T* __restrict__ ptr, IdxT idx) { return ptr[idx]; }
554-
555-
// Merge-masked scalar gather: dst = ptr[idx] only if mask, else dst unchanged.
556-
template<typename T, typename IdxT>
557-
__hostdev__ void gather_if(T& dst, bool mask, const T* __restrict__ ptr, IdxT idx) {
558-
if (mask) dst = ptr[idx];
559-
}
560-
561457
} // namespace util
562458
} // namespace nanovdb

0 commit comments

Comments
 (0)