https://gcc.gnu.org/bugzilla/show_bug.cgi?id=127177
--- Comment #9 from Matthias Kretz (Vir) <mkretz at gcc dot gnu.org> ---
I did some benchmarking.
TL;DR: If fpclass* is available, it doesn't hurt to use it, and it can be
better. For vectorization, the integer compare seems to be the general
preference. For scalar, the current solution seems best. But it won't hurt to
use integer compare for scalar isinf and always be correct with
-fsignaling-nans.
The benchmark is basically this loop:
for (int i = 0; i < 1'000'000; ++i)
{
float y = 1;
if (isinf(x)) x = 0;
x += y;
}
This puts isinf into the critical path and its latency directly influences the
measurement.
With -march=x86-64-v4 I get the following asm:
BENCHMARK(scalar_latency<scalar_abs_gt_max>);
40cab0: vandps xmm0,xmm1,xmm3
40cab4: vucomiss xmm0,DWORD PTR [rip+0x46558] # 453014
<_IO_stdin_used+0x14>
40cabc: vmovaps xmm0,xmm2
40cac0: jbe 40cac6 <void
scalar_latency<&(scalar_abs_gt_max(float))>(benchmark::State&)+0x96>
40cac2: vxorps xmm0,xmm0,xmm0
40cac6: vaddss xmm1,xmm1,xmm0
40caca: sub eax,0x1
40cacd: jne 40cab0 <void
scalar_latency<&(scalar_abs_gt_max(float))>(benchmark::State&)+0x80>
BENCHMARK(scalar_latency<scalar_abs_eq_inf>);
40c9f0: vandps xmm0,xmm1,xmm3
40c9f4: vucomiss xmm0,DWORD PTR [rip+0x46614] # 453010
<_IO_stdin_used+0x10>
40c9fc: vmovaps xmm0,xmm2
40ca00: jp 40ca08 <void
scalar_latency<&(scalar_abs_eq_inf(float))>(benchmark::State&)+0x98>
40ca02: jne 40ca08 <void
scalar_latency<&(scalar_abs_eq_inf(float))>(benchmark::State&)+0x98>
40ca04: vxorps xmm0,xmm0,xmm0
40ca08: vaddss xmm1,xmm1,xmm0
40ca0c: sub eax,0x1
40ca0f: jne 40c9f0 <void
scalar_latency<&(scalar_abs_eq_inf(float))>(benchmark::State&)+0x80>
BENCHMARK(scalar_latency<scalar_eq_ninf_fpcmp>);
40c930: vorps xmm0,xmm1,xmm2
40c934: vucomiss xmm0,DWORD PTR [rip+0x466d0] # 45300c
<_IO_stdin_used+0xc>
40c93c: vmovaps xmm0,xmm3
40c940: jp 40c948 <void
scalar_latency<&(scalar_eq_ninf_fpcmp(float))>(benchmark::State&)+0x98>
40c942: jne 40c948 <void
scalar_latency<&(scalar_eq_ninf_fpcmp(float))>(benchmark::State&)+0x98>
40c944: vxorps xmm0,xmm0,xmm0
40c948: vaddss xmm1,xmm1,xmm0
40c94c: sub eax,0x1
40c94f: jne 40c930 <void
scalar_latency<&(scalar_eq_ninf_fpcmp(float))>(benchmark::State&)+0x80>
BENCHMARK(scalar_latency<scalar_eq_ninf_intcmp>);
40c870: vmovd edx,xmm1
40c874: vmovaps xmm0,xmm2
40c878: or edx,0x80000000
40c87e: cmp edx,0xff800000
40c884: jne 40c88a <void
scalar_latency<&(scalar_eq_ninf_intcmp(float))>(benchmark::State&)+0x9a>
40c886: vxorps xmm0,xmm0,xmm0
40c88a: vaddss xmm1,xmm1,xmm0
40c88e: sub eax,0x1
40c891: jne 40c870 <void
scalar_latency<&(scalar_eq_ninf_intcmp(float))>(benchmark::State&)+0x80>
BENCHMARK(scalar_latency<scalar_fpclass>);
40c710: vfpclassss k0,xmm1,0x18
40c717: vmovaps xmm0,xmm2
40c71b: kortestd k0,k0
40c720: je 40c726 <void
scalar_latency<&(scalar_fpclass(float))>(benchmark::State&)+0x86>
40c722: vxorps xmm0,xmm0,xmm0
40c726: vaddss xmm1,xmm1,xmm0
40c72a: sub eax,0x1
40c72d: jne 40c710 <void
scalar_latency<&(scalar_fpclass(float))>(benchmark::State&)+0x70>
BENCHMARK(vector_latency<vec_abs_gt_max>);
40c660: vandps zmm1,zmm0,zmm3
40c666: vcmpltps k1,zmm4,zmm1
40c66d: vmovaps zmm1{k1}{z},zmm2
40c673: vaddps zmm0,zmm0,zmm1
40c679: sub eax,0x1
40c67c: jne 40c660 <void
vector_latency<&(vec_abs_gt_max(std::simd::basic_vec<float, std::simd::_Abi<16,
1, 1ull> >))>(benchmark::State&)+0xc0>
BENCHMARK(vector_latency<vec_abs_eq_inf>);
40c560: vandps zmm1,zmm0,zmm4
40c566: vcmpeqps k1,zmm1,zmm3
40c56d: vmovaps zmm1{k1}{z},zmm2
40c573: vaddps zmm0,zmm0,zmm1
40c579: sub eax,0x1
40c57c: jne 40c560 <void
vector_latency<&(vec_abs_eq_inf(std::simd::basic_vec<float, std::simd::_Abi<16,
1, 1ull> >))>(benchmark::State&)+0xc0>
BENCHMARK(vector_latency<vec_eq_ninf_fpcmp>);
40c460: vorps zmm1,zmm0,zmm4
40c466: vcmpeqps k1,zmm1,zmm3
40c46d: vmovaps zmm1{k1}{z},zmm2
40c473: vaddps zmm0,zmm0,zmm1
40c479: sub eax,0x1
40c47c: jne 40c460 <void
vector_latency<&(vec_eq_ninf_fpcmp(std::simd::basic_vec<float,
std::simd::_Abi<16, 1, 1ull> >))>(benchmark::State&)+0xc0>
BENCHMARK(vector_latency<vec_eq_ninf_intcmp>);
40c360: vorps zmm1,zmm0,zmm4
40c366: vpcmpeqd k1,zmm1,zmm2
40c36c: vmovaps zmm1{k1}{z},zmm3
40c372: vaddps zmm0,zmm0,zmm1
40c378: sub eax,0x1
40c37b: jne 40c360 <void
vector_latency<&(vec_eq_ninf_intcmp(std::simd::basic_vec<float,
std::simd::_Abi<16, 1, 1ull> >))>(benchmark::State&)+0xc0>
BENCHMARK(vector_latency<vec_fpclass_mask>);
40c1a0: vfpclassps k1,zmm0,0x18
40c1a7: vmovaps zmm1{k1}{z},zmm2
40c1ad: vaddps zmm0,zmm0,zmm1
40c1b3: sub eax,0x1
40c1b6: jne 40c1a0 <void
vector_latency<&(vec_fpclass_mask(std::simd::basic_vec<float,
std::simd::_Abi<16, 1, 1ull> >))>(benchmark::State&)+0x80>
With -march=x86-64-v3 I get:
BENCHMARK(scalar_latency<scalar_abs_gt_max>);
40c9b0: vandps xmm0,xmm1,xmm3
40c9b4: vucomiss xmm0,DWORD PTR [rip+0x46654] # 453010
<_IO_stdin_used+0x10>
40c9bc: vmovaps xmm0,xmm2
40c9c0: jbe 40c9c6 <void
scalar_latency<&(scalar_abs_gt_max(float))>(benchmark::State&)+0x96>
40c9c2: vxorps xmm0,xmm0,xmm0
40c9c6: sub eax,0x1
40c9c9: vaddss xmm1,xmm1,xmm0
40c9cd: jne 40c9b0 <void
scalar_latency<&(scalar_abs_gt_max(float))>(benchmark::State&)+0x80>
BENCHMARK(scalar_latency<scalar_abs_eq_inf>);
40c8f0: vandps xmm0,xmm1,xmm3
40c8f4: vucomiss xmm0,DWORD PTR [rip+0x46710] # 45300c
<_IO_stdin_used+0xc>
40c8fc: vmovaps xmm0,xmm2
40c900: jp 40c908 <void
scalar_latency<&(scalar_abs_eq_inf(float))>(benchmark::State&)+0x98>
40c902: jne 40c908 <void
scalar_latency<&(scalar_abs_eq_inf(float))>(benchmark::State&)+0x98>
40c904: vxorps xmm0,xmm0,xmm0
40c908: sub eax,0x1
40c90b: vaddss xmm1,xmm1,xmm0
40c90f: jne 40c8f0 <void
scalar_latency<&(scalar_abs_eq_inf(float))>(benchmark::State&)+0x80>
BENCHMARK(scalar_latency<scalar_eq_ninf_fpcmp>);
40c830: vorps xmm0,xmm1,xmm2
40c834: vucomiss xmm0,DWORD PTR [rip+0x467cc] # 453008
<_IO_stdin_used+0x8>
40c83c: vmovaps xmm0,xmm3
40c840: jp 40c848 <void
scalar_latency<&(scalar_eq_ninf_fpcmp(float))>(benchmark::State&)+0x98>
40c842: jne 40c848 <void
scalar_latency<&(scalar_eq_ninf_fpcmp(float))>(benchmark::State&)+0x98>
40c844: vxorps xmm0,xmm0,xmm0
40c848: sub eax,0x1
40c84b: vaddss xmm1,xmm1,xmm0
40c84f: jne 40c830 <void
scalar_latency<&(scalar_eq_ninf_fpcmp(float))>(benchmark::State&)+0x80>
BENCHMARK(scalar_latency<scalar_eq_ninf_intcmp>);
40c778: vmovd edx,xmm1
40c77c: vmovaps xmm0,xmm2
40c780: or edx,0x80000000
40c786: cmp edx,0xff800000
40c78c: jne 40c792 <void
scalar_latency<&(scalar_eq_ninf_intcmp(float))>(benchmark::State&)+0x92>
40c78e: vxorps xmm0,xmm0,xmm0
40c792: sub eax,0x1
40c795: vaddss xmm1,xmm1,xmm0
40c799: jne 40c778 <void
scalar_latency<&(scalar_eq_ninf_intcmp(float))>(benchmark::State&)+0x78>
BENCHMARK(vector_latency<vec_abs_gt_max>);
40c580: vandps ymm0,ymm1,ymm4
40c584: sub eax,0x1
40c587: vcmpltps ymm0,ymm3,ymm0
40c58c: vpand ymm0,ymm2,ymm0
40c590: vaddps ymm1,ymm1,ymm0
40c594: jne 40c580 <void
vector_latency<&(vec_abs_gt_max(std::simd::basic_vec<float, std::simd::_Abi<8,
1, 0ull> >))>(benchmark::State&)+0xa0>
BENCHMARK(vector_latency<vec_abs_eq_inf>);
40c4a0: vandps ymm0,ymm1,ymm4
40c4a4: sub eax,0x1
40c4a7: vcmpeqps ymm0,ymm0,ymm3
40c4ac: vpand ymm0,ymm2,ymm0
40c4b0: vaddps ymm1,ymm1,ymm0
40c4b4: jne 40c4a0 <void
vector_latency<&(vec_abs_eq_inf(std::simd::basic_vec<float, std::simd::_Abi<8,
1, 0ull> >))>(benchmark::State&)+0xa0>
BENCHMARK(vector_latency<vec_eq_ninf_fpcmp>);
40c3c0: vorps ymm0,ymm1,ymm4
40c3c4: sub eax,0x1
40c3c7: vcmpeqps ymm0,ymm0,ymm3
40c3cc: vpand ymm0,ymm2,ymm0
40c3d0: vaddps ymm1,ymm1,ymm0
40c3d4: jne 40c3c0 <void
vector_latency<&(vec_eq_ninf_fpcmp(std::simd::basic_vec<float,
std::simd::_Abi<8, 1, 0ull> >))>(benchmark::State&)+0xa0>
BENCHMARK(vector_latency<vec_eq_ninf_intcmp>);
40c2e0: vorps ymm0,ymm1,ymm4
40c2e4: sub eax,0x1
40c2e7: vpcmpeqd ymm0,ymm0,ymm3
40c2eb: vpand ymm0,ymm0,ymm2
40c2ef: vaddps ymm1,ymm1,ymm0
40c2f3: jne 40c2e0 <void
vector_latency<&(vec_eq_ninf_intcmp(std::simd::basic_vec<float,
std::simd::_Abi<8, 1, 0ull> >))>(benchmark::State&)+0xa0>
On an Intel(R) Xeon(R) W-2145 CPU @ 3.70GHz system
-march=x86-64-v3:
-------------------------------------------------------------------------------------------------------------------
Benchmark Time CPU
Iterations CYCLES INSTRUCTIONS IPC
-------------------------------------------------------------------------------------------------------------------
scalar_latency<scalar_abs_gt_max> 901170 ns 901140 ns
742 4.00241M 7.00001M 1.74895
scalar_latency<scalar_abs_eq_inf> 1082323 ns 1082119 ns
700 4.81333M 8.00001M 1.66205
scalar_latency<scalar_eq_ninf_fpcmp> 1014561 ns 1014085 ns
714 4.44968M 8.00001M 1.79788
scalar_latency<scalar_eq_ninf_intcmp> 970507 ns 970330 ns
724 4.24098M 8.00001M 1.88636
vector_latency<vec_abs_gt_max> 2711088 ns 2710493 ns
259 11.8666M 6.00001M 0.505624
vector_latency<vec_abs_eq_inf> 2714891 ns 2713491 ns
259 11.8659M 6.00001M 0.505651
vector_latency<vec_eq_ninf_fpcmp> 2697500 ns 2697030 ns
259 11.8666M 6.00001M 0.505624
vector_latency<vec_eq_ninf_intcmp> 1832236 ns 1831533 ns
383 8.12751M 6.00001M 0.738234
-march=x86-64-v4:
-------------------------------------------------------------------------------------------------------------------
Benchmark Time CPU
Iterations CYCLES INSTRUCTIONS IPC
-------------------------------------------------------------------------------------------------------------------
scalar_latency<scalar_abs_gt_max> 901364 ns 901227 ns
751 4.00131M 7.00001M 1.74943
scalar_latency<scalar_abs_eq_inf> 936893 ns 936732 ns
764 4.16215M 8.00001M 1.92208
scalar_latency<scalar_eq_ninf_fpcmp> 1038307 ns 1038038 ns
665 4.60913M 8.00001M 1.73569
scalar_latency<scalar_eq_ninf_intcmp> 903080 ns 902915 ns
779 4.00141M 8.00001M 1.9993
scalar_latency<scalar_fpclass> 913609 ns 913298 ns
744 4.0032M 7.00001M 1.74861
vector_latency<vec_abs_gt_max> 2766369 ns 2765630 ns
254 10.9426M 6.00001M 0.548316
vector_latency<vec_abs_eq_inf> 2795032 ns 2794206 ns
251 10.9459M 6.00001M 0.54815
vector_latency<vec_eq_ninf_fpcmp> 2769082 ns 2768627 ns
254 10.943M 6.00001M 0.548298
vector_latency<vec_eq_ninf_intcmp> 2793158 ns 2792376 ns
251 10.9455M 6.00001M 0.548173
vector_latency<vec_fpclass_mask> 2299563 ns 2299045 ns
303 9.02547M 5.00001M 0.553989
On an Intel(R) Core(TM) Ultra 7 165U laptop:
-march=x86-64-v3:
-------------------------------------------------------------------------------------------------------------------
Benchmark Time CPU
Iterations CYCLES INSTRUCTIONS IPC
-------------------------------------------------------------------------------------------------------------------
scalar_latency<scalar_abs_gt_max> 565470 ns 565475 ns
1265 2.07347M 7.00001M 3.37599
scalar_latency<scalar_abs_eq_inf> 515747 ns 515645 ns
1257 2.05566M 8.00001M 3.8917
scalar_latency<scalar_eq_ninf_fpcmp> 564059 ns 564065 ns
1427 2.12581M 8.00001M 3.76328
scalar_latency<scalar_eq_ninf_intcmp> 570534 ns 570358 ns
1058 2.16697M 8.00001M 3.69179
vector_latency<vec_abs_gt_max> 2428999 ns 2428794 ns
281 10.4335M 6.00001M 0.575072
vector_latency<vec_abs_eq_inf> 2477083 ns 2476535 ns
252 10.4275M 6.00001M 0.5754
vector_latency<vec_eq_ninf_fpcmp> 2352268 ns 2352001 ns
290 10.4265M 6.00001M 0.575456
vector_latency<vec_eq_ninf_intcmp> 1553970 ns 1553645 ns
482 6.15973M 6.00001M 0.974069
AMD EPYC 9654 96-Core Processor:
-march=x86-64-v3:
-------------------------------------------------------------------------------------------------------------------
Benchmark Time CPU
Iterations CYCLES INSTRUCTIONS IPC
-------------------------------------------------------------------------------------------------------------------
scalar_latency<scalar_abs_gt_max> 1334837 ns 1329645 ns
529 3.18514M 7.00001M 2.19771
scalar_latency<scalar_abs_eq_inf> 1257570 ns 1252693 ns
559 3.00086M 8.00001M 2.6659
scalar_latency<scalar_eq_ninf_fpcmp> 1257765 ns 1252755 ns
559 3.00077M 8.00001M 2.66598
scalar_latency<scalar_eq_ninf_intcmp> 1257623 ns 1252687 ns
559 3.00073M 8.00001M 2.66602
vector_latency<vec_abs_gt_max> 2933985 ns 2922812 ns
239 7.0015M 6.00001M 0.856961
vector_latency<vec_abs_eq_inf> 2934460 ns 2922794 ns
239 7.00149M 6.00001M 0.856962
vector_latency<vec_eq_ninf_fpcmp> 2935047 ns 2922894 ns
239 7.00153M 6.00001M 0.856957
vector_latency<vec_eq_ninf_intcmp> 2515700 ns 2505271 ns
279 6.00129M 6.00001M 0.999786
-march=x86-64-v4:
-------------------------------------------------------------------------------------------------------------------
Benchmark Time CPU
Iterations CYCLES INSTRUCTIONS IPC
-------------------------------------------------------------------------------------------------------------------
scalar_latency<scalar_abs_gt_max> 1258043 ns 1252814 ns
559 3.00096M 7.00001M 2.33259
scalar_latency<scalar_abs_eq_inf> 1258571 ns 1253424 ns
559 3.00236M 8.00001M 2.66457
scalar_latency<scalar_eq_ninf_fpcmp> 1258308 ns 1253125 ns
559 3.00144M 8.00001M 2.66539
scalar_latency<scalar_eq_ninf_intcmp> 1257910 ns 1252718 ns
559 3.00075M 8.00001M 2.66601
scalar_latency<scalar_fpclass> 1258088 ns 1252849 ns
559 3.00098M 7.00001M 2.33257
vector_latency<vec_abs_gt_max> 4193035 ns 4176038 ns
168 10.003M 6.00001M 0.599822
vector_latency<vec_abs_eq_inf> 4192833 ns 4175791 ns
168 10.0025M 6.00001M 0.599851
vector_latency<vec_eq_ninf_fpcmp> 4192588 ns 4175999 ns
168 10.0028M 6.00001M 0.599831
vector_latency<vec_eq_ninf_intcmp> 4192538 ns 4175702 ns
168 10.0027M 6.00001M 0.599841
vector_latency<vec_fpclass_mask> 3773481 ns 3758034 ns
186 9.00195M 5.00001M 0.555436