https://gcc.gnu.org/g:6566ad965dbab710ad7418021c360208f7ca3158
commit r17-2464-g6566ad965dbab710ad7418021c360208f7ca3158 Author: Sebastian Huber <[email protected]> Date: Thu Jul 16 11:53:41 2026 +0800 gcov: Optimize condition coverage code generation Change the code to avoid emitting bitwise-or operations with a zero constant operand since they are effectively no-operations. The omitted bitwise-or operations are potentially relaxed atomic operations which cannot be optimized away once emitted, so the omission has to happen while generating the profiling code in instrument_decisions(), not as a later gimple optimization. For example, consider this test case: int a(int); int b(int); int g(int i) { if (i) { return a(i); } else { return b(i); } } On 64-bit RISC-V this change results in the following code changes for options -fprofile-update=atomic -fcondition-coverage -O2: --- test.s.old 2026-06-19 06:53:06.806622709 +0200 +++ test.s.new 2026-06-19 06:53:29.187922134 +0200 @@ -9,15 +9,13 @@ .type g, @function g: lui a5,%hi(.LANCHOR0) - addi a5,a5,%lo(.LANCHOR0) beq a0,zero,.L2 li a4,1 + addi a5,a5,%lo(.LANCHOR0) amoor.d zero,a4,0(a5) - addi a5,a5,8 - amoor.d zero,zero,0(a5) tail a .L2: - amoor.d zero,zero,0(a5) + addi a5,a5,%lo(.LANCHOR0) li a4,1 addi a5,a5,8 amoor.d zero,a4,0(a5) @@ -35,7 +33,7 @@ .word 1110847786 .zero 4 .dword 0 - .word -566726224 + .word -566618674 .word 903831156 .dword .LC0 .dword 0 Tested on x86_64-pc-linux-gnu (gcov.exp, gcc.dg gcov*.c, tree-prof.exp) with no regressions, and manually cross-checked on 64-bit RISC-V for the asm diff shown above. gcc/ChangeLog: * tree-profile.cc (emit_bitwise_op): Build/fold the operation with gimple_build() instead of gimple_build_assign(), and return the folded result as-is instead of always materializing a new SSA name. (instrument_decisions): Do not emit bitwise-or operations with a zero constant operand. gcc/testsuite/ChangeLog: * gcc.dg/gcov-atomic-or-zero.c: New test. * gcc.misc-tests/gcov-35.c: Likewise. * gcc.misc-tests/gcov-36.c: Likewise. Signed-off-by: Sebastian Huber <[email protected]> Diff: --- gcc/testsuite/gcc.dg/gcov-atomic-or-zero.c | 27 +++++++++++++++++++++++++++ gcc/testsuite/gcc.misc-tests/gcov-35.c | 24 ++++++++++++++++++++++++ gcc/testsuite/gcc.misc-tests/gcov-36.c | 23 +++++++++++++++++++++++ gcc/tree-profile.cc | 21 +++++++++++++++------ 4 files changed, 89 insertions(+), 6 deletions(-) diff --git a/gcc/testsuite/gcc.dg/gcov-atomic-or-zero.c b/gcc/testsuite/gcc.dg/gcov-atomic-or-zero.c new file mode 100644 index 000000000000..76c645822beb --- /dev/null +++ b/gcc/testsuite/gcc.dg/gcov-atomic-or-zero.c @@ -0,0 +1,27 @@ +/* Test case to check that no atomic bitwise-or operations with a zero operand + are emitted by instrument_decisions(). */ +/* { dg-do compile } */ +/* { dg-options "-O2 -fprofile-update=atomic -fcondition-coverage -fdump-tree-optimized" } */ +/* { dg-require-effective-target profile_update_atomic } */ + +int a (void); +int b (void); +int c (int); + +int +f (int *p) +{ + /* Force a condition chain so tree-profile's decision instrumentation kicks in. */ + if (c (p[0]) || c (p[1]) || c (p[2]) || c (p[3])) + return a (); + else + return b (); +} + +/* We expect __atomic_fetch_or_() calls for condition counters. */ +/* { dg-final { scan-tree-dump "__atomic_fetch_or_" "optimized" } } */ + +/* After the optimization, no atomic bitwise-or operations with a zero + operand should be present. Match ", 0, 0)" in the __atomic_fetch_or_() call + argument list. */ +/* { dg-final { scan-tree-dump-not "__atomic_fetch_or_. \\(\[^\n\r]*, 0, 0\\)" "optimized" } } */ diff --git a/gcc/testsuite/gcc.misc-tests/gcov-35.c b/gcc/testsuite/gcc.misc-tests/gcov-35.c new file mode 100644 index 000000000000..677119d3adc7 --- /dev/null +++ b/gcc/testsuite/gcc.misc-tests/gcov-35.c @@ -0,0 +1,24 @@ +/* { dg-options "-fcondition-coverage -ftest-coverage -fprofile-update=atomic" } */ +/* { dg-do run } */ +/* { dg-require-effective-target profile_update_atomic } */ + +/* Some side effect to stop branches from being pruned. */ +int x = 0; + +void +zero_elision_atomic (int a, int b, int c, int d) +{ + if (a || b || c || d) /* conditions(5/8) true(1 2 3) */ + /* conditions(end) */ + x = 1; + else + x = 2; +} + +int main () +{ + zero_elision_atomic (1, 0, 0, 0); + zero_elision_atomic (0, 0, 0, 0); +} + +/* { dg-final { run-gcov conditions { --conditions gcov-35.c } } } */ diff --git a/gcc/testsuite/gcc.misc-tests/gcov-36.c b/gcc/testsuite/gcc.misc-tests/gcov-36.c new file mode 100644 index 000000000000..664588597303 --- /dev/null +++ b/gcc/testsuite/gcc.misc-tests/gcov-36.c @@ -0,0 +1,23 @@ +/* { dg-options "-fcondition-coverage -ftest-coverage" } */ +/* { dg-do run } */ + +/* Some side effect to stop branches from being pruned. */ +int x = 0; + +void +zero_elision_single (int a, int b, int c, int d) +{ + if (a || b || c || d) /* conditions(5/8) true(1 2 3) */ + /* conditions(end) */ + x = 1; + else + x = 2; +} + +int main () +{ + zero_elision_single (1, 0, 0, 0); + zero_elision_single (0, 0, 0, 0); +} + +/* { dg-final { run-gcov conditions { --conditions gcov-36.c } } } */ diff --git a/gcc/tree-profile.cc b/gcc/tree-profile.cc index a03f1f3704fa..cf81608df0c4 100644 --- a/gcc/tree-profile.cc +++ b/gcc/tree-profile.cc @@ -43,6 +43,7 @@ along with GCC; see the file COPYING3. If not see #include "tree-nested.h" #include "gimplify.h" #include "gimple-iterator.h" +#include "gimple-fold.h" #include "gimplify-me.h" #include "tree-cfg.h" #include "tree-into-ssa.h" @@ -629,14 +630,20 @@ emit_assign (edge e, tree rhs) return emit_assign (e, make_ssa_name (gcov_type_node), rhs); } -/* Emit LHS = OP1 <OP> OP2 on edges. */ -tree +/* Emit/fold OP1 <OP> [OP2] on edge E. + Return folded constant or SSA name. */ +static tree emit_bitwise_op (edge e, tree op1, tree_code op, tree op2 = NULL_TREE) { - tree lhs = make_ssa_name (gcov_type_node); - gassign *w = gimple_build_assign (lhs, op, op1, op2); - gsi_insert_on_edge (e, w); - return lhs; + gimple_seq seq = NULL; + tree rhs = op2 == NULL_TREE + ? gimple_build (&seq, op, gcov_type_node, op1) + : gimple_build (&seq, op, gcov_type_node, op1, op2); + + if (seq) + gsi_insert_seq_on_edge (e, seq); + + return rhs; } /* Visitor for make_top_index. */ @@ -1174,6 +1181,8 @@ instrument_decisions (array_slice<basic_block> expr, size_t condno, /* _global_true |= _true, _global_false |= _false */ for (size_t k = 0; k != 2; ++k) { + if (integer_zerop (next[k])) + continue; tree ref = tree_coverage_counter_ref (GCOV_COUNTER_CONDS, 2 * condno + k); if (atomic)
