c++: implement C++17 hardware interference size
authorJason Merrill <jason@redhat.com>
Thu, 15 Jul 2021 19:30:17 +0000 (15:30 -0400)
committerJason Merrill <jason@redhat.com>
Mon, 13 Sep 2021 16:28:06 +0000 (12:28 -0400)
commit76b75018b3d053a890ebe155e47814de14b3c9fb
tree1e9480506219bbb1af3acdd921bf264c6c9342c5
parent8ea292591e42aa4d52b4b7a00b86335bfd2e2e85
c++: implement C++17 hardware interference size

The last missing piece of the C++17 standard library is the hardware
intereference size constants.  Much of the delay in implementing these has
been due to uncertainty about what the right values are, and even whether
there is a single constant value that is suitable; the destructive
interference size is intended to be used in structure layout, so program
ABIs will depend on it.

In principle, both of these values should be the same as the target's L1
cache line size.  When compiling for a generic target that is intended to
support a range of target CPUs with different cache line sizes, the
constructive size should probably be the minimum size, and the destructive
size the maximum, unless you are constrained by ABI compatibility with
previous code.

From discussion on gcc-patches, I've come to the conclusion that the
solution to the difficulty of choosing stable values is to give up on it,
and instead encourage only uses where ABI stability is unimportant: in
particular, uses where the ABI is shared at most between translation units
built at the same time with the same flags.

To that end, I've added a warning for any use of the constant value of
std::hardware_destructive_interference_size in a header or module export.
Appropriate uses within a project can disable the warning.

A previous iteration of this patch included an -finterference-tune flag to
make the value vary with -mtune; this iteration makes that the default
behavior, which should be appropriate for all reasonable uses of the
variable.  The previous default of "stable-ish" seems to me likely to have
been more of an attractive nuisance; since we can't promise actual
stability, we should instead make proper uses more convenient.

JF Bastien's implementation proposal is summarized at
https://github.com/itanium-cxx-abi/cxx-abi/issues/74

I implement this by adding new --params for the two sizes.  Targets can
override these values in targetm.target_option.override() to support a range
of values for the generic target; otherwise, both will default to the L1
cache line size.

64 bytes still seems correct for all x86.

I'm not sure why he proposed 64/64 for generic 32-bit ARM, since the Cortex
A9 has a 32-byte cache line, so I'd think 32/64 would make more sense.

He proposed 64/128 for generic AArch64, but since the A64FX now has a 256B
cache line, I've changed that to 64/256.

Other arch maintainers are invited to set ranges for their generic targets
if that seems better than using the default cache line size for both values.

With the above choice to reject stability as a goal, getting these values
"right" is now just a matter of what we want the default optimization to be,
and we can feel free to adjust them as CPUs with different cache lines
become more and less common.

gcc/ChangeLog:

* params.opt: Add destructive-interference-size and
constructive-interference-size.
* doc/invoke.texi: Document them.
* config/aarch64/aarch64.c (aarch64_override_options_internal):
Set them.
* config/arm/arm.c (arm_option_override): Set them.
* config/i386/i386-options.c (ix86_option_override_internal):
Set them.

gcc/c-family/ChangeLog:

* c.opt: Add -Winterference-size.
* c-cppbuiltin.c (cpp_atomic_builtins): Add __GCC_DESTRUCTIVE_SIZE
and __GCC_CONSTRUCTIVE_SIZE.

gcc/cp/ChangeLog:

* constexpr.c (maybe_warn_about_constant_value):
Complain about std::hardware_destructive_interference_size.
(cxx_eval_constant_expression): Call it.
* decl.c (cxx_init_decl_processing): Check
--param *-interference-size values.

libstdc++-v3/ChangeLog:

* include/std/version: Define __cpp_lib_hardware_interference_size.
* libsupc++/new: Define hardware interference size variables.

gcc/testsuite/ChangeLog:

* g++.dg/warn/Winterference.H: New file.
* g++.dg/warn/Winterference.C: New test.
* g++.target/aarch64/interference.C: New test.
* g++.target/arm/interference.C: New test.
* g++.target/i386/interference.C: New test.
17 files changed:
gcc/c-family/c-cppbuiltin.c
gcc/c-family/c.opt
gcc/config/aarch64/aarch64.c
gcc/config/arm/arm.c
gcc/config/i386/i386-options.c
gcc/cp/constexpr.c
gcc/cp/decl.c
gcc/doc/invoke.texi
gcc/params.opt
gcc/testsuite/g++.dg/warn/Winterference-2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/warn/Winterference.C [new file with mode: 0644]
gcc/testsuite/g++.dg/warn/Winterference.H [new file with mode: 0644]
gcc/testsuite/g++.target/aarch64/interference.C [new file with mode: 0644]
gcc/testsuite/g++.target/arm/interference.C [new file with mode: 0644]
gcc/testsuite/g++.target/i386/interference.C [new file with mode: 0644]
libstdc++-v3/include/std/version
libstdc++-v3/libsupc++/new