On 2/3/2026 9:04 PM, Sebastian Huber wrote:
----- Am 4. Feb 2026 um 4:38 schrieb Sebastian Huber 
[email protected]:

Hello Jeff,

----- Am 29. Dez 2025 um 20:08 schrieb Jeffrey Law [email protected]:

On 12/28/2025 7:03 PM, Sebastian Huber wrote:
I used this test case to double check that the shifting is now correct:

int a(void);
int b(void);
int c(int);
int f(int *i)
{
    if (c(i[0]) || c(i[1]) || c(i[2]) || c(i[3]) || c(i[4]) ||
        c(i[5]) || c(i[6]) || c(i[7]) || c(i[8]) || c(i[9]) ||
        c(i[10]) || c(i[11]) || c(i[12]) || c(i[13]) || c(i[14]) ||
        c(i[15]) || c(i[16]) || c(i[17]) || c(i[18]) || c(i[19]) ||
        c(i[20]) || c(i[21]) || c(i[22]) || c(i[23]) || c(i[24]) ||
        c(i[25]) || c(i[26]) || c(i[27]) || c(i[28]) || c(i[29]) ||
        c(i[30]) || c(i[31]) || c(i[32]) || c(i[33]) || c(i[34]) ||
        c(i[35]) || c(i[36]) || c(i[37]) || c(i[38]) || c(i[39])) {
      return a();
    } else {
      return b();
    }
}

Interestingly, GCC now reuses the "amoor.w zero,zero" operations (see "j .L46").
Right.  That's not a huge surprise to me.  If we look at the gimple we see:


;;   basic block 3, loop depth 0
;;    pred:       2
   __atomic_fetch_or_4 (&__gcov8.f[0], 1, 0);
   __atomic_fetch_or_4 (&MEM <long long int> [(void *)&__gcov8.f + 4B],
0, 0);
   __atomic_fetch_or_4 (&__gcov8.f[1], 0, 0);
   __atomic_fetch_or_4 (&MEM <long long int> [(void *)&__gcov8.f +
12B], 0, 0);
   _8 = a (i_3(D)); [tail call]
   goto <bb 5>; [100.00%]
;;    succ:       5

;;   basic block 4, loop depth 0
;;    pred:       2
   __atomic_fetch_or_4 (&__gcov8.f[0], 0, 0);
   __atomic_fetch_or_4 (&MEM <long long int> [(void *)&__gcov8.f + 4B],
0, 0);
   __atomic_fetch_or_4 (&__gcov8.f[1], 1, 0);
   __atomic_fetch_or_4 (&MEM <long long int> [(void *)&__gcov8.f +
12B], 0, 0);
   _6 = b (0); [tail call]
So to improve the code you need to recognize the atomic_fetch_or_4 where
the object is IOR'd with the constant 0 as a nop and remove those
statements (or not emit them to begin with).  In general our optimizers
don't do a whole lot with atomics right now.
should I try to add these optimizations for a constant 0 to the patch or can we
do this in a follow up patch?

Is there a simple check to figure out if "tree counter" is a constant 0?
What doesn't work is this:
[ ... ]
So I was reviewing a patch from another team here in Qualcomm that was meant to optimize a NOP RMW operation and concluding that in general it's never OK to elide the "W" step of an RMW atomic, even relaxed atomics.

That comes into play here.  Essentially the gimple optimizers and such have to leave those RMW operations alone, thus any optimization has to happen during generation of the profiling code.

Let's look at the code the profiler generates:

;;   basic block 7, loop depth 0, count 365072224 (estimated locally, freq 0.3400), maybe hot
;;    prev block 6, next block 8, flags: (NEW)
;;    pred:       6 [34.0% (guessed)]  count:365072224 (estimated locally, freq 0.3400) (TRUE_VALUE,EXECUTABLE)
  _130 = 0 | 1;
  _249 = ~0;
  _250 = _130 & _249;
  _251 = 0 & _249;
  __atomic_fetch_or_8 (&__gcov8.f[0], _250, 0);
  __atomic_fetch_or_8 (&__gcov8.f[1], _251, 0);
  __atomic_add_fetch_8 (&__gcov0.f[1], 1, 0);
  goto <bb 86>; [100.00%]

This explains why your hack didn't work.  Let's focus on that second atomic_fetch_or_8.    That statement references _251, not the integer constant zero.  So your integer_zerop check naturally failed.

As noted earlier, once we've got this code, we can't eliminate the fetch_or, even though it looks like a NOP.  It must be optimized before generating code.

At least some of these are coming from this code in instrument_decisions:

1168              /* _true &= ~mask, _false &= ~mask  */
1169              counters next;
1170              next[2] = emit_bitwise_op (e, prev[2], BIT_NOT_EXPR);
1171              next[0] = emit_bitwise_op (e, prev[0], BIT_AND_EXPR, next[2]); 1172              next[1] = emit_bitwise_op (e, prev[1], BIT_AND_EXPR, next[2]);

If we look at prev[1] we'd see it's:


 <integer_cst 0x7ffff70496f0 type <integer_type 0x7ffff7247738 long int> constant 0>

Which would return true for integer_zerop.  That allows you to conclude the BIT_AND produces the value zero which we then pass into the atomic IOR in the loop immediately below.   You just need to track that state and avoid generating the atomic IOR in that case.

I haven't really dove into the code, but it seems like you could probably try to fold the operation to a constant in emit_bitwise_op and return the folded constant rather than an SSA_NAME.  Then you elide the IOR when next[k] is an integer_zerop.

Does that make sense to you?

jeff







Reply via email to