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: New test.
* gcc.misc-tests/gcov-36.c: New test.
Signed-off-by: Sebastian Huber <[email protected]>
---
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(-)
create mode 100644 gcc/testsuite/gcc.dg/gcov-atomic-or-zero.c
create mode 100644 gcc/testsuite/gcc.misc-tests/gcov-35.c
create mode 100644 gcc/testsuite/gcc.misc-tests/gcov-36.c
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 00000000000..76c645822be
--- /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 00000000000..677119d3adc
--- /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 00000000000..66458859730
--- /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 a03f1f3704f..cf81608df0c 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)
--
2.51.0