From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by sourceware.org (Postfix) with ESMTP id AD6763858C3B for ; Wed, 15 Sep 2021 10:25:26 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org AD6763858C3B Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 531E26D; Wed, 15 Sep 2021 03:25:26 -0700 (PDT) Received: from [10.57.22.219] (unknown [10.57.22.219]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id A66303F5A1; Wed, 15 Sep 2021 03:25:25 -0700 (PDT) Subject: Re: [PATCH RFC] c++: implement C++17 hardware interference size To: Christophe LYON , gcc-patches@gcc.gnu.org References: <36407ef6-ea30-6663-62b8-05ae37667ce9@redhat.com> <20210910131625.159525-1-jason@redhat.com> <511b262a-5187-108d-7047-16d2d87e5667@foss.st.com> From: Richard Earnshaw Message-ID: <2f1e62bc-a6ce-95ee-826b-93de6150fa92@foss.arm.com> Date: Wed, 15 Sep 2021 11:25:24 +0100 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Thunderbird/78.11.0 MIME-Version: 1.0 In-Reply-To: <511b262a-5187-108d-7047-16d2d87e5667@foss.st.com> Content-Type: text/plain; charset=utf-8; format=flowed Content-Language: en-GB Content-Transfer-Encoding: 8bit X-Spam-Status: No, score=-3497.0 required=5.0 tests=BAYES_00, BODY_8BITS, GIT_PATCH_0, KAM_DMARC_STATUS, KAM_LAZY_DOMAIN_SECURITY, NICE_REPLY_A, SPF_HELO_NONE, SPF_NONE, TXREP autolearn=ham autolearn_force=no version=3.4.4 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 15 Sep 2021 10:25:30 -0000 On 14/09/2021 08:56, Christophe LYON via Gcc-patches wrote: > > On 10/09/2021 15:16, Jason Merrill via Gcc-patches wrote: >> OK, time to finish this up.  The main change relative to the last >> patch I sent >> to the list is dropping the -finterference-tune flag and making that >> behavior >> the default.  Any more comments? >> >> ==== >> >> 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. > > While this works for an arm-linux-gnueabihf toolchain configured > --with-mode=arm, it fails --with-mode=thumb (also using > --with-cpu=cortex-a9): > > : error: '--param constructive-interference-size=64' is > greater than '--param l1-cache-line-size=32' [-Werror=interference-size] > cc1plus: all warnings being treated as errors > make[4]: *** [Makefile:678: alloc_c.lo] Error 1 > > > >> >> He proposed 64/128 for generic AArch64, but since the A64FX now has a >> 256B >> cache line, I've changed that to 64/256. > > > Similarly, for aarch64 I'm seeing: > > : error: '--param constructive-interference-size=64' is > greater than '--param l1-cache-line-size=32' [-Werror=interference-size] > cc1plus: all warnings being treated as errors > make[4]: *** [Makefile:678: alloc_c.lo] Error 1 > > > So adjustment is needed for both arm and aarch64 targets > > FWIW, I'm still in discussion with our architects about the best values to use here, but certainly this needs fixing quickly as it seems to be breaking hundreds of tests in the C++ testsuite. R. > Christophe > > >> >> 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. >> --- >>   gcc/doc/invoke.texi                           | 65 +++++++++++++++++++ >>   gcc/c-family/c.opt                            |  5 ++ >>   gcc/params.opt                                | 16 +++++ >>   gcc/c-family/c-cppbuiltin.c                   | 12 ++++ >>   gcc/config/aarch64/aarch64.c                  | 22 +++++++ >>   gcc/config/arm/arm.c                          | 22 +++++++ >>   gcc/config/i386/i386-options.c                |  6 ++ >>   gcc/cp/constexpr.c                            | 33 ++++++++++ >>   gcc/cp/decl.c                                 | 32 +++++++++ >>   gcc/testsuite/g++.dg/warn/Winterference-2.C   | 14 ++++ >>   gcc/testsuite/g++.dg/warn/Winterference.C     |  6 ++ >>   .../g++.target/aarch64/interference.C         |  9 +++ >>   gcc/testsuite/g++.target/arm/interference.C   |  9 +++ >>   gcc/testsuite/g++.target/i386/interference.C  |  8 +++ >>   gcc/testsuite/g++.dg/warn/Winterference.H     |  7 ++ >>   libstdc++-v3/include/std/version              |  3 + >>   libstdc++-v3/libsupc++/new                    | 10 ++- >>   17 files changed, 277 insertions(+), 2 deletions(-) >>   create mode 100644 gcc/testsuite/g++.dg/warn/Winterference-2.C >>   create mode 100644 gcc/testsuite/g++.dg/warn/Winterference.C >>   create mode 100644 gcc/testsuite/g++.target/aarch64/interference.C >>   create mode 100644 gcc/testsuite/g++.target/arm/interference.C >>   create mode 100644 gcc/testsuite/g++.target/i386/interference.C >>   create mode 100644 gcc/testsuite/g++.dg/warn/Winterference.H >> >> diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi >> index d4b3a66ee4f..f49d82aa508 100644 >> --- a/gcc/doc/invoke.texi >> +++ b/gcc/doc/invoke.texi >> @@ -9017,6 +9017,43 @@ that has already been done in the current >> function.  Therefore, >>   seemingly insignificant changes in the source program can cause the >>   warnings produced by @option{-Winline} to appear or disappear. >> +@item -Winterference-size >> +@opindex Winterference-size >> +Warn about use of C++17 >> @code{std::hardware_destructive_interference_size} >> +without specifying its value with @option{--param >> destructive-interference-size}. >> +Also warn about questionable values for that option. >> + >> +This variable is intended to be used for controlling class layout, to >> +avoid false sharing in concurrent code: >> + >> +@smallexample >> +struct independent_fields @{ >> +  alignas(std::hardware_destructive_interference_size) >> std::atomic one; >> +  alignas(std::hardware_destructive_interference_size) >> std::atomic two; >> +@}; >> +@end smallexample >> + >> +Here @samp{one} and @samp{two} are intended to be far enough apart >> +that stores to one won't require accesses to the other to reload the >> +cache line. >> + >> +By default, @option{--param destructive-interference-size} and >> +@option{--param constructive-interference-size} are set based on the >> +current @option{-mtune} option, typically to the L1 cache line size >> +for the particular target CPU, sometimes to a range if tuning for a >> +generic target.  So all translation units that depend on ABI >> +compatibility for the use of these variables must be compiled with >> +the same @option{-mtune} (or @option{-mcpu}). >> + >> +If ABI stability is important, such as if the use is in a header for a >> +library, you should probably not use the hardware interference size >> +variables at all.  Alternatively, you can force a particular value >> +with @option{--param}. >> + >> +If you are confident that your use of the variable does not affect ABI >> +outside a single build of your project, you can turn off the warning >> +with @option{-Wno-interference-size}. >> + >>   @item -Wint-in-bool-context >>   @opindex Wint-in-bool-context >>   @opindex Wno-int-in-bool-context >> @@ -13902,6 +13939,34 @@ prefetch hints can be issued for any constant >> stride. >>   This setting is only useful for strides that are known and constant. >> +@item destructive-interference-size >> +@item constructive-interference-size >> +The values for the C++17 variables >> +@code{std::hardware_destructive_interference_size} and >> +@code{std::hardware_constructive_interference_size}.  The destructive >> +interference size is the minimum recommended offset between two >> +independent concurrently-accessed objects; the constructive >> +interference size is the maximum recommended size of contiguous memory >> +accessed together.  Typically both will be the size of an L1 cache >> +line for the target, in bytes.  For a generic target covering a range >> of L1 >> +cache line sizes, typically the constructive interference size will be >> +the small end of the range and the destructive size will be the large >> +end. >> + >> +The destructive interference size is intended to be used for layout, >> +and thus has ABI impact.  The default value is not expected to be >> +stable, and on some targets varies with @option{-mtune}, so use of >> +this variable in a context where ABI stability is important, such as >> +the public interface of a library, is strongly discouraged; if it is >> +used in that context, users can stabilize the value using this >> +option. >> + >> +The constructive interference size is less sensitive, as it is >> +typically only used in a @samp{static_assert} to make sure that a type >> +fits within a cache line. >> + >> +See also @option{-Winterference-size}. >> + >>   @item loop-interchange-max-num-stmts >>   The maximum number of stmts in a loop to be interchanged. >> diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt >> index c5fe90003f2..9c151d19870 100644 >> --- a/gcc/c-family/c.opt >> +++ b/gcc/c-family/c.opt >> @@ -722,6 +722,11 @@ Winit-list-lifetime >>   C++ ObjC++ Var(warn_init_list) Warning Init(1) >>   Warn about uses of std::initializer_list that can result in dangling >> pointers. >> +Winterference-size >> +C++ ObjC++ Var(warn_interference_size) Warning Init(1) >> +Warn about nonsensical values of --param >> destructive-interference-size or >> +constructive-interference-size. >> + >>   Wimplicit >>   C ObjC Var(warn_implicit) Warning LangEnabledBy(C ObjC,Wall) >>   Warn about implicit declarations. >> diff --git a/gcc/params.opt b/gcc/params.opt >> index 3a701e22c46..658ca028851 100644 >> --- a/gcc/params.opt >> +++ b/gcc/params.opt >> @@ -361,6 +361,22 @@ The maximum code size growth ratio when expanding >> into a jump table (in percent) >>   Common Joined UInteger Var(param_l1_cache_line_size) Init(32) Param >> Optimization >>   The size of L1 cache line. >> +-param=destructive-interference-size= >> +Common Joined UInteger Var(param_destruct_interfere_size) Init(0) >> Param Optimization >> +The minimum recommended offset between two concurrently-accessed >> objects to >> +avoid additional performance degradation due to contention introduced >> by the >> +implementation.  Typically the L1 cache line size, but can be larger to >> +accommodate a variety of target processors with different cache line >> sizes. >> +C++17 code might use this value in structure layout, but is strongly >> +discouraged from doing so in public ABIs. >> + >> +-param=constructive-interference-size= >> +Common Joined UInteger Var(param_construct_interfere_size) Init(0) >> Param Optimization >> +The maximum recommended size of contiguous memory occupied by two >> objects >> +accessed with temporal locality by concurrent threads.  Typically the >> L1 cache >> +line size, but can be smaller to accommodate a variety of target >> processors with >> +different cache line sizes. >> + >>   -param=l1-cache-size= >>   Common Joined UInteger Var(param_l1_cache_size) Init(64) Param >> Optimization >>   The size of L1 cache. >> diff --git a/gcc/c-family/c-cppbuiltin.c b/gcc/c-family/c-cppbuiltin.c >> index 48cbefd8bf8..020e2ea4f25 100644 >> --- a/gcc/c-family/c-cppbuiltin.c >> +++ b/gcc/c-family/c-cppbuiltin.c >> @@ -741,6 +741,18 @@ cpp_atomic_builtins (cpp_reader *pfile) >>     builtin_define_with_int_value ("__GCC_ATOMIC_TEST_AND_SET_TRUEVAL", >>                    targetm.atomic_test_and_set_trueval); >> +  /* Macros for C++17 hardware interference size constants.  Either >> both or >> +     neither should be set.  */ >> +  gcc_assert (!param_destruct_interfere_size >> +          == !param_construct_interfere_size); >> +  if (param_destruct_interfere_size) >> +    { >> +      builtin_define_with_int_value ("__GCC_DESTRUCTIVE_SIZE", >> +                     param_destruct_interfere_size); >> +      builtin_define_with_int_value ("__GCC_CONSTRUCTIVE_SIZE", >> +                     param_construct_interfere_size); >> +    } >> + >>     /* ptr_type_node can't be used here since ptr_mode is only set when >>        toplev calls backend_init which is not done with -E  or pch.  */ >>     psize = POINTER_SIZE_UNITS; >> diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c >> index 1fbe9e0daa0..05d42a66c7e 100644 >> --- a/gcc/config/aarch64/aarch64.c >> +++ b/gcc/config/aarch64/aarch64.c >> @@ -16539,6 +16539,28 @@ aarch64_override_options_internal (struct >> gcc_options *opts) >>       SET_OPTION_IF_UNSET (opts, &global_options_set, >>                param_l1_cache_line_size, >>                aarch64_tune_params.prefetch->l1_cache_line_size); >> + >> +  if (aarch64_tune_params.prefetch->l1_cache_line_size >= 0) >> +    { >> +      SET_OPTION_IF_UNSET (opts, &global_options_set, >> +               param_destruct_interfere_size, >> +               aarch64_tune_params.prefetch->l1_cache_line_size); >> +      SET_OPTION_IF_UNSET (opts, &global_options_set, >> +               param_construct_interfere_size, >> +               aarch64_tune_params.prefetch->l1_cache_line_size); >> +    } >> +  else >> +    { >> +      /* For a generic AArch64 target, cover the current range of >> cache line >> +     sizes.  */ >> +      SET_OPTION_IF_UNSET (opts, &global_options_set, >> +               param_destruct_interfere_size, >> +               256); >> +      SET_OPTION_IF_UNSET (opts, &global_options_set, >> +               param_construct_interfere_size, >> +               64); >> +    } >> + >>     if (aarch64_tune_params.prefetch->l2_cache_size >= 0) >>       SET_OPTION_IF_UNSET (opts, &global_options_set, >>                param_l2_cache_size, >> diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c >> index f1e628253d0..6c6e77fab66 100644 >> --- a/gcc/config/arm/arm.c >> +++ b/gcc/config/arm/arm.c >> @@ -3669,6 +3669,28 @@ arm_option_override (void) >>       SET_OPTION_IF_UNSET (&global_options, &global_options_set, >>                param_l1_cache_line_size, >>                current_tune->prefetch.l1_cache_line_size); >> +  if (current_tune->prefetch.l1_cache_line_size >= 0) >> +    { >> +      SET_OPTION_IF_UNSET (&global_options, &global_options_set, >> +               param_destruct_interfere_size, >> +               current_tune->prefetch.l1_cache_line_size); >> +      SET_OPTION_IF_UNSET (&global_options, &global_options_set, >> +               param_construct_interfere_size, >> +               current_tune->prefetch.l1_cache_line_size); >> +    } >> +  else >> +    { >> +      /* For a generic ARM target, JF Bastien proposed using 64 for >> both.  */ >> +      /* ??? Cortex A9 has a 32-byte cache line, so why not 32 for >> +     constructive?  */ >> +      /* More recent Cortex chips have a 64-byte cache line, but are >> marked >> +     ARM_PREFETCH_NOT_BENEFICIAL, so they get these defaults.  */ >> +      SET_OPTION_IF_UNSET (&global_options, &global_options_set, >> +               param_destruct_interfere_size, 64); >> +      SET_OPTION_IF_UNSET (&global_options, &global_options_set, >> +               param_construct_interfere_size, 64); >> +    } >> + >>     if (current_tune->prefetch.l1_cache_size >= 0) >>       SET_OPTION_IF_UNSET (&global_options, &global_options_set, >>                param_l1_cache_size, >> diff --git a/gcc/config/i386/i386-options.c >> b/gcc/config/i386/i386-options.c >> index 2cb87cedec0..c0006b3674b 100644 >> --- a/gcc/config/i386/i386-options.c >> +++ b/gcc/config/i386/i386-options.c >> @@ -2579,6 +2579,12 @@ ix86_option_override_internal (bool main_args_p, >>     SET_OPTION_IF_UNSET (opts, opts_set, param_l2_cache_size, >>                  ix86_tune_cost->l2_cache_size); >> +  /* 64B is the accepted value for these for all x86.  */ >> +  SET_OPTION_IF_UNSET (&global_options, &global_options_set, >> +               param_destruct_interfere_size, 64); >> +  SET_OPTION_IF_UNSET (&global_options, &global_options_set, >> +               param_construct_interfere_size, 64); >> + >>     /* Enable sw prefetching at -O3 for CPUS that prefetching is >> helpful.  */ >>     if (opts->x_flag_prefetch_loop_arrays < 0 >>         && HAVE_prefetch >> diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c >> index 7772fe62d95..0c2498aee22 100644 >> --- a/gcc/cp/constexpr.c >> +++ b/gcc/cp/constexpr.c >> @@ -6075,6 +6075,37 @@ inline_asm_in_constexpr_error (location_t loc) >>         "% function in C++20"); >>   } >> +/* We're getting the constant value of DECL in a manifestly >> constant-evaluated >> +   context; maybe complain about that.  */ >> + >> +static void >> +maybe_warn_about_constant_value (location_t loc, tree decl) >> +{ >> +  static bool explained = false; >> +  if (cxx_dialect >= cxx17 >> +      && warn_interference_size >> +      && !global_options_set.x_param_destruct_interfere_size >> +      && DECL_CONTEXT (decl) == std_node >> +      && id_equal (DECL_NAME (decl), >> "hardware_destructive_interference_size") >> +      && (LOCATION_FILE (input_location) != main_input_filename >> +      || module_exporting_p ()) >> +      && warning_at (loc, OPT_Winterference_size, "use of %qD", decl) >> +      && !explained) >> +    { >> +      explained = true; >> +      inform (loc, "its value can vary between compiler versions or " >> +          "with different %<-mtune%> or %<-mcpu%> flags"); >> +      inform (loc, "if this use is part of a public ABI, change it to " >> +          "instead use a constant variable you define"); >> +      inform (loc, "the default value for the current CPU tuning " >> +          "is %d bytes", param_destruct_interfere_size); >> +      inform (loc, "you can stabilize this value with %<--param " >> +          "hardware_destructive_interference_size=%d%>, or disable " >> +          "this warning with %<-Wno-interference-size%>", >> +          param_destruct_interfere_size); >> +    } >> +} >> + >>   /* Attempt to reduce the expression T to a constant value. >>      On failure, issue diagnostic and return error_mark_node.  */ >>   /* FIXME unify with c_fully_fold */ >> @@ -6219,6 +6250,8 @@ cxx_eval_constant_expression (const >> constexpr_ctx *ctx, tree t, >>             r = *p; >>             break; >>           } >> +      if (ctx->manifestly_const_eval) >> +    maybe_warn_about_constant_value (loc, t); >>         if (COMPLETE_TYPE_P (TREE_TYPE (t)) >>         && is_really_empty_class (TREE_TYPE (t), /*ignore_vptr*/false)) >>       { >> diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c >> index bce62ad202a..c2065027369 100644 >> --- a/gcc/cp/decl.c >> +++ b/gcc/cp/decl.c >> @@ -4752,6 +4752,38 @@ cxx_init_decl_processing (void) >>     /* Show we use EH for cleanups.  */ >>     if (flag_exceptions) >>       using_eh_for_cleanups (); >> + >> +  /* Check that the hardware interference sizes are at least >> +     alignof(max_align_t), as required by the standard.  */ >> +  const int max_align = max_align_t_align () / BITS_PER_UNIT; >> +  if (param_destruct_interfere_size) >> +    { >> +      if (param_destruct_interfere_size < max_align) >> +    error ("%<--param destructive-interference-size=%d%> is less than " >> +           "%d", param_destruct_interfere_size, max_align); >> +      else if (param_destruct_interfere_size < param_l1_cache_line_size) >> +    warning (OPT_Winterference_size, >> +         "%<--param destructive-interference-size=%d%> " >> +         "is less than %<--param l1-cache-line-size=%d%>", >> +         param_destruct_interfere_size, param_l1_cache_line_size); >> +    } >> +  else if (param_l1_cache_line_size >= max_align) >> +    param_destruct_interfere_size = param_l1_cache_line_size; >> +  /* else leave it unset.  */ >> + >> +  if (param_construct_interfere_size) >> +    { >> +      if (param_construct_interfere_size < max_align) >> +    error ("%<--param constructive-interference-size=%d%> is less than " >> +           "%d", param_construct_interfere_size, max_align); >> +      else if (param_construct_interfere_size > >> param_l1_cache_line_size) >> +    warning (OPT_Winterference_size, >> +         "%<--param constructive-interference-size=%d%> " >> +         "is greater than %<--param l1-cache-line-size=%d%>", >> +         param_construct_interfere_size, param_l1_cache_line_size); >> +    } >> +  else if (param_l1_cache_line_size >= max_align) >> +    param_construct_interfere_size = param_l1_cache_line_size; >>   } >>   /* Enter an abi node in global-module context.  returns a cookie to >> diff --git a/gcc/testsuite/g++.dg/warn/Winterference-2.C >> b/gcc/testsuite/g++.dg/warn/Winterference-2.C >> new file mode 100644 >> index 00000000000..2af75c63f83 >> --- /dev/null >> +++ b/gcc/testsuite/g++.dg/warn/Winterference-2.C >> @@ -0,0 +1,14 @@ >> +// { dg-do compile { target c++20 } } >> +// { dg-additional-options -fmodules-ts } >> + >> +module ; >> + >> +#include >> + >> +export module foo; >> + >> +export { >> +  struct A { >> +    alignas(std::hardware_destructive_interference_size) int x; // { >> dg-warning Winterference-size } >> +  }; >> +} >> diff --git a/gcc/testsuite/g++.dg/warn/Winterference.C >> b/gcc/testsuite/g++.dg/warn/Winterference.C >> new file mode 100644 >> index 00000000000..57c001bc032 >> --- /dev/null >> +++ b/gcc/testsuite/g++.dg/warn/Winterference.C >> @@ -0,0 +1,6 @@ >> +// Test that we warn about use of >> std::hardware_destructive_interference_size >> +// in a header. >> +// { dg-do compile { target c++17 } } >> + >> +// { dg-warning Winterference-size "" { target *-*-* } 0 } >> +#include "Winterference.H" >> diff --git a/gcc/testsuite/g++.target/aarch64/interference.C >> b/gcc/testsuite/g++.target/aarch64/interference.C >> new file mode 100644 >> index 00000000000..0fc01655223 >> --- /dev/null >> +++ b/gcc/testsuite/g++.target/aarch64/interference.C >> @@ -0,0 +1,9 @@ >> +// Test C++17 hardware interference size constants >> +// { dg-do compile { target c++17 } } >> + >> +#include >> + >> +// Most AArch64 CPUs have an L1 cache line size of 64, but some >> recent ones use >> +// 128 or even 256. >> +static_assert(std::hardware_destructive_interference_size == 256); >> +static_assert(std::hardware_constructive_interference_size == 64); >> diff --git a/gcc/testsuite/g++.target/arm/interference.C >> b/gcc/testsuite/g++.target/arm/interference.C >> new file mode 100644 >> index 00000000000..34fe8a52bff >> --- /dev/null >> +++ b/gcc/testsuite/g++.target/arm/interference.C >> @@ -0,0 +1,9 @@ >> +// Test C++17 hardware interference size constants >> +// { dg-do compile { target c++17 } } >> + >> +#include >> + >> +// Recent ARM CPUs have a cache line size of 64.  Older ones have >> +// a size of 32, but I guess they're old enough that we don't care? >> +static_assert(std::hardware_destructive_interference_size == 64); >> +static_assert(std::hardware_constructive_interference_size == 64); >> diff --git a/gcc/testsuite/g++.target/i386/interference.C >> b/gcc/testsuite/g++.target/i386/interference.C >> new file mode 100644 >> index 00000000000..c7b910e3ada >> --- /dev/null >> +++ b/gcc/testsuite/g++.target/i386/interference.C >> @@ -0,0 +1,8 @@ >> +// Test C++17 hardware interference size constants >> +// { dg-do compile { target c++17 } } >> + >> +#include >> + >> +// It is generally agreed that these are the right values for all x86. >> +static_assert(std::hardware_destructive_interference_size == 64); >> +static_assert(std::hardware_constructive_interference_size == 64); >> diff --git a/gcc/testsuite/g++.dg/warn/Winterference.H >> b/gcc/testsuite/g++.dg/warn/Winterference.H >> new file mode 100644 >> index 00000000000..36f0ad5f6d1 >> --- /dev/null >> +++ b/gcc/testsuite/g++.dg/warn/Winterference.H >> @@ -0,0 +1,7 @@ >> +#include >> + >> +struct A >> +{ >> +  alignas(std::hardware_destructive_interference_size) int i; >> +  alignas(std::hardware_destructive_interference_size) int j; >> +}; >> diff --git a/libstdc++-v3/include/std/version >> b/libstdc++-v3/include/std/version >> index f950bf0f0db..f41004b5911 100644 >> --- a/libstdc++-v3/include/std/version >> +++ b/libstdc++-v3/include/std/version >> @@ -140,6 +140,9 @@ >>   #define __cpp_lib_filesystem 201703 >>   #define __cpp_lib_gcd 201606 >>   #define __cpp_lib_gcd_lcm 201606 >> +#ifdef __GCC_DESTRUCTIVE_SIZE >> +# define __cpp_lib_hardware_interference_size 201703L >> +#endif >>   #define __cpp_lib_hypot 201603 >>   #define __cpp_lib_invoke 201411L >>   #define __cpp_lib_lcm 201606 >> diff --git a/libstdc++-v3/libsupc++/new b/libstdc++-v3/libsupc++/new >> index 3349b13fd1b..7bc67a6cb02 100644 >> --- a/libstdc++-v3/libsupc++/new >> +++ b/libstdc++-v3/libsupc++/new >> @@ -183,9 +183,9 @@ inline void operator delete[](void*, void*) >> _GLIBCXX_USE_NOEXCEPT { } >>   } // extern "C++" >>   #if __cplusplus >= 201703L >> -#ifdef _GLIBCXX_HAVE_BUILTIN_LAUNDER >>   namespace std >>   { >> +#ifdef _GLIBCXX_HAVE_BUILTIN_LAUNDER >>   #define __cpp_lib_launder 201606 >>     /// Pointer optimization barrier [ptr.launder] >>     template >> @@ -205,8 +205,14 @@ namespace std >>     void launder(const void*) = delete; >>     void launder(volatile void*) = delete; >>     void launder(const volatile void*) = delete; >> -} >>   #endif // _GLIBCXX_HAVE_BUILTIN_LAUNDER >> + >> +#ifdef __GCC_DESTRUCTIVE_SIZE >> +# define __cpp_lib_hardware_interference_size 201703L >> +  inline constexpr size_t hardware_destructive_interference_size = >> __GCC_DESTRUCTIVE_SIZE; >> +  inline constexpr size_t hardware_constructive_interference_size = >> __GCC_CONSTRUCTIVE_SIZE; >> +#endif // __GCC_DESTRUCTIVE_SIZE >> +} >>   #endif // C++17 >>   #if __cplusplus > 201703L >> >> base-commit: de515ce0b209cc7e5a780d9846e5154d380a763e