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)

Reply via email to