varasm: Add params for constant merging

Message ID PAWPR08MB8982D855775971AB4D918D068387A@PAWPR08MB8982.eurprd08.prod.outlook.com
State New
Headers
Series varasm: Add params for constant merging |

Commit Message

Wilco Dijkstra Jan. 6, 2026, 7:20 p.m. UTC
  The -fmerge-constants option controls whether constants are emitted into
mergeable sections - however this applies to all constants, including
strings.  On targets that support anchors it may be better to use anchors
for FP constants (eg. PR121240).  Add new params string-merging-threshold
and constant-merging-threshold to allow finer grained control.  The default
is zero and generated code is unchanged.

OK for commit?

gcc:
	* params.opt (constant-merging-threshold): Add new param.
	(string-merging-threshold): Add new param.
	* varasm.cc (mergeable_string_section): Compare string size with
	param_string_merging_threshold before merging.
	(mergeable_constant_section): Compare constant size with
	param_constant_merging_threshold before merging.
	* doc/invoke.texi (string-merging-threshold): Document new param.
	(constant-merging-threshold): Likewise.

---
  

Comments

Andrew Pinski Jan. 7, 2026, 12:51 a.m. UTC | #1
On Tue, Jan 6, 2026 at 11:22 AM Wilco Dijkstra <Wilco.Dijkstra@arm.com> wrote:
>
>
> The -fmerge-constants option controls whether constants are emitted into
> mergeable sections - however this applies to all constants, including
> strings.  On targets that support anchors it may be better to use anchors
> for FP constants (eg. PR121240).  Add new params string-merging-threshold
> and constant-merging-threshold to allow finer grained control.  The default
> is zero and generated code is unchanged.
>
> OK for commit?
>
> gcc:
>         * params.opt (constant-merging-threshold): Add new param.
>         (string-merging-threshold): Add new param.
>         * varasm.cc (mergeable_string_section): Compare string size with
>         param_string_merging_threshold before merging.
>         (mergeable_constant_section): Compare constant size with
>         param_constant_merging_threshold before merging.
>         * doc/invoke.texi (string-merging-threshold): Document new param.
>         (constant-merging-threshold): Likewise.

Does it make sense rather to do the non-merge based on the mode in the
case of floating point with maybe a target hook that
mergeable_constant_section calls?
I don't think a param is a good approach here rather than something
finer control.
For an example an constant array of 4 char would still be size of 4
but do you still want to merge those constants or use anchors in that
case? Or is it just floating point values where it might improve
things?
Note I am trying to convince myself which way is better because right
now it is not obvious from this patch if something finer tuned is
needed or doing it by size is always a good idea.
Maybe there are not many non-floating point constants that go into the
mergeable section so the size check won't make a huge difference in
the end; I know that the constant switch load table is now a mergeable
decl. But maybe that does not show up enough to make a difference
here. Likewise of the backing constant of a std::initializer_list.
I would rather be forward looking on this and add the hook now rather
than later on when there are much more mergeable constants which we
want to still merge.

Thanks,
Andrew

>
> ---
>
> diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
> index bae66ba6c45f9f23f3c97cc55eb292474db502db..8a6c8473d90f2a4798c71c8aeba77a166ccebdae 100644
> --- a/gcc/doc/invoke.texi
> +++ b/gcc/doc/invoke.texi
> @@ -18066,6 +18066,14 @@ bubbles.  This is the current default.  Zero means the scheduling description
>  might not be available/accurate or perhaps not applicable at all, such as for
>  modern out-of-order processors.
>
> +@item string-merging-threshold
> +Specifies the minimum size in bytes before string constants are considered for
> +merging across compilation units.
> +
> +@item constant-merging-threshold
> +Specifies the minimum size in bytes before integer/floating-point constants
> +are considered for merging across compilation units.
> +
>  @end table
>
>  The following choices of @var{name} are available on AArch64 targets:
> diff --git a/gcc/params.opt b/gcc/params.opt
> index e2b3930d5a768cb4bcd8815e2d0887190f89596e..947497fa3ac0057c9a3eed86e9db260a1b8894e1 100644
> --- a/gcc/params.opt
> +++ b/gcc/params.opt
> @@ -130,6 +130,10 @@ The smallest number of different values for which it is best to use a jump-table
>  Common Joined UInteger Var(param_comdat_sharing_probability) Init(20) Param Optimization
>  Probability that COMDAT function will be shared with different compilation unit.
>
> +-param=constant-merging-threshold=
> +Common Joined UInteger Var(param_constant_merging_threshold) Init(0) Param Optimization
> +Minimum constant size before it is considered for merging across compilation units.
> +
>  -param=cxx-max-namespaces-for-diagnostic-help=
>  Common Joined UInteger Var(param_cxx_max_namespaces_for_diagnostic_help) Init(1000) Param
>  Maximum number of namespaces to search for alternatives when name lookup fails.
> @@ -1107,6 +1111,10 @@ Maximum size of a single store merging region in bytes.
>  Common Joined UInteger Var(param_store_forwarding_max_distance) Init(10) IntegerRange(0, 1000) Param Optimization
>  Maximum number of instruction distance that a small store forwarded to a larger load may stall. Value '0' disables the cost checks for the avoid-store-forwarding pass.
>
> +-param=string-merging-threshold=
> +Common Joined UInteger Var(param_string_merging_threshold) Init(0) Param Optimization
> +Minimum string size before it is considered for merging across compilation units.
> +
>  -param=switch-conversion-max-branch-ratio=
>  Common Joined UInteger Var(param_switch_conversion_branch_ratio) Init(8) IntegerRange(1, 65536) Param Optimization
>  The maximum ratio between array size and switch branches for a switch conversion to take place.
> diff --git a/gcc/varasm.cc b/gcc/varasm.cc
> index fec792ec2326f3fb631e5d8b3538f52a57347d66..2c4669f629fcf24848d8dc6e7a5fe681a0a5b66c 100644
> --- a/gcc/varasm.cc
> +++ b/gcc/varasm.cc
> @@ -873,6 +873,7 @@ mergeable_string_section (tree decl ATTRIBUTE_UNUSED,
>        && TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE
>        && align <= MAX_MERGEABLE_BITSIZE
>        && (len = int_size_in_bytes (TREE_TYPE (decl))) > 0
> +      && len >= param_string_merging_threshold
>        && TREE_STRING_LENGTH (decl) == len)
>      {
>        scalar_int_mode mode;
> @@ -927,6 +928,7 @@ mergeable_constant_section (unsigned HOST_WIDE_INT size_bits,
>    newsize = HOST_WIDE_INT_1U << ceil_log2 (size_bits);
>    if (HAVE_GAS_SHF_MERGE && flag_merge_constants
>        && newsize <= MAX_MERGEABLE_BITSIZE
> +      && (newsize / BITS_PER_UNIT) >= param_constant_merging_threshold
>        && align >= 8
>        && align <= newsize
>        && (align & (align - 1)) == 0)
>
  
Wilco Dijkstra Jan. 13, 2026, 3:11 p.m. UTC | #2
Hi Andrew,

> Does it make sense rather to do the non-merge based on the mode in the
> case of floating point with maybe a target hook that
> mergeable_constant_section calls?
> I don't think a param is a good approach here rather than something
> finer control.

That's a good point - I was using these params for experimentation,
and while they are quite useful for that, there are existing hooks that
allow selection based on the mode.

> For an example an constant array of 4 char would still be size of 4
> but do you still want to merge those constants or use anchors in that
> case? Or is it just floating point values where it might improve
> things?

If it's an array then it cannot be merged. Switch statements using offset
tables may be mergeable, but it's not clear how useful this is since it
would be pure chance that they match and can be merged.

> Note I am trying to convince myself which way is better because right
> now it is not obvious from this patch if something finer tuned is
> needed or doing it by size is always a good idea.
> Maybe there are not many non-floating point constants that go into the
> mergeable section so the size check won't make a huge difference in
> the end; I know that the constant switch load table is now a mergeable
> decl. But maybe that does not show up enough to make a difference
> here. Likewise of the backing constant of a std::initializer_list.
> I would rather be forward looking on this and add the hook now rather
> than later on when there are much more mergeable constants which we
> want to still merge.

I think I will use the existing hooks for this - once we've got the optimal
setting, there is less need to change the value from the command-line.
So consider this patch withdrawn.

Cheers,
Wilco
  

Patch

diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index bae66ba6c45f9f23f3c97cc55eb292474db502db..8a6c8473d90f2a4798c71c8aeba77a166ccebdae 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -18066,6 +18066,14 @@  bubbles.  This is the current default.  Zero means the scheduling description
 might not be available/accurate or perhaps not applicable at all, such as for
 modern out-of-order processors.
 
+@item string-merging-threshold
+Specifies the minimum size in bytes before string constants are considered for
+merging across compilation units.
+
+@item constant-merging-threshold
+Specifies the minimum size in bytes before integer/floating-point constants
+are considered for merging across compilation units.
+
 @end table
 
 The following choices of @var{name} are available on AArch64 targets:
diff --git a/gcc/params.opt b/gcc/params.opt
index e2b3930d5a768cb4bcd8815e2d0887190f89596e..947497fa3ac0057c9a3eed86e9db260a1b8894e1 100644
--- a/gcc/params.opt
+++ b/gcc/params.opt
@@ -130,6 +130,10 @@  The smallest number of different values for which it is best to use a jump-table
 Common Joined UInteger Var(param_comdat_sharing_probability) Init(20) Param Optimization
 Probability that COMDAT function will be shared with different compilation unit.
 
+-param=constant-merging-threshold=
+Common Joined UInteger Var(param_constant_merging_threshold) Init(0) Param Optimization
+Minimum constant size before it is considered for merging across compilation units.
+
 -param=cxx-max-namespaces-for-diagnostic-help=
 Common Joined UInteger Var(param_cxx_max_namespaces_for_diagnostic_help) Init(1000) Param
 Maximum number of namespaces to search for alternatives when name lookup fails.
@@ -1107,6 +1111,10 @@  Maximum size of a single store merging region in bytes.
 Common Joined UInteger Var(param_store_forwarding_max_distance) Init(10) IntegerRange(0, 1000) Param Optimization
 Maximum number of instruction distance that a small store forwarded to a larger load may stall. Value '0' disables the cost checks for the avoid-store-forwarding pass.
 
+-param=string-merging-threshold=
+Common Joined UInteger Var(param_string_merging_threshold) Init(0) Param Optimization
+Minimum string size before it is considered for merging across compilation units.
+
 -param=switch-conversion-max-branch-ratio=
 Common Joined UInteger Var(param_switch_conversion_branch_ratio) Init(8) IntegerRange(1, 65536) Param Optimization
 The maximum ratio between array size and switch branches for a switch conversion to take place.
diff --git a/gcc/varasm.cc b/gcc/varasm.cc
index fec792ec2326f3fb631e5d8b3538f52a57347d66..2c4669f629fcf24848d8dc6e7a5fe681a0a5b66c 100644
--- a/gcc/varasm.cc
+++ b/gcc/varasm.cc
@@ -873,6 +873,7 @@  mergeable_string_section (tree decl ATTRIBUTE_UNUSED,
       && TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE
       && align <= MAX_MERGEABLE_BITSIZE
       && (len = int_size_in_bytes (TREE_TYPE (decl))) > 0
+      && len >= param_string_merging_threshold
       && TREE_STRING_LENGTH (decl) == len)
     {
       scalar_int_mode mode;
@@ -927,6 +928,7 @@  mergeable_constant_section (unsigned HOST_WIDE_INT size_bits,
   newsize = HOST_WIDE_INT_1U << ceil_log2 (size_bits);
   if (HAVE_GAS_SHF_MERGE && flag_merge_constants
       && newsize <= MAX_MERGEABLE_BITSIZE
+      && (newsize / BITS_PER_UNIT) >= param_constant_merging_threshold
       && align >= 8
       && align <= newsize
       && (align & (align - 1)) == 0)