[gcc r17-2464] gcov: Optimize condition coverage code generation

Sebastian Huber via Gcc-cvs <[email protected]>
Newsgroups gmane.comp.gcc.cvs
Message-ID <[email protected]>
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)
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.