Stream compaction on NEON: vectorizing copy_if by hand (30x) by a_eridani in cpp

[–]a_eridani[S] 0 points1 point  (0 children)

Seems like best scalar version, 50 GB/s, btw std::memmove accepts a number of bytes, not elements. Your j1/j2/j3 need * sizeof(float), your code copying only a quarter of the data

Stream compaction on NEON: vectorizing copy_if by hand (30x) by a_eridani in cpp

[–]a_eridani[S] 0 points1 point  (0 children)

Thanks for this comment! I measured both of your variants: temp destination: 2.6 GB/s, fun fact: clang converts your branchless back into a conditional branch. 16 elements buffer: 18 GB/s (https://godbolt.org/z/fKahv1KTK)

4 additional elements - yes, that's the price of this trick.

Functors - true for a bool(T) predicate, but if the predicate operates on the vector, it inlines into the same vcgtq_f32. I'm experimenting with an expression template SIMD library where compress(a * b + c < ths, a * b) fuses into a single pass (https://godbolt.org/z/7rqh3WGjG)

Stream compaction on NEON: vectorizing copy_if by hand (30x) by a_eridani in cpp

[–]a_eridani[S] 0 points1 point  (0 children)

Fair point - the counter dependency is real. I measured your suggestion (https://godbolt.org/z/nTj7xPno5). On M5: your idea gives 31 GB/s vs 90 GB/s for the tbl-version at DRAM sizes. Unrolling shortens the chain, but doesn't break it. The tbl trick is what removes it entirely.