https://gcc.gnu.org/bugzilla/show_bug.cgi?id=103090

            Bug ID: 103090
           Summary: [i386] GCC should use the SF and ZF flags in some
                    atomic_fetch_op sequences
           Product: gcc
           Version: 12.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: middle-end
          Assignee: unassigned at gcc dot gnu.org
          Reporter: thiago at kde dot org
  Target Milestone: ---

Disclaimer: I don't know this code actually exists anywhere. But I've just come
up with it.

In Bug 102566, we optimised:

bool tbit(std::atomic<int> &i)
{
    return i.fetch_or(1, std::memory_order_relaxed) & 1;
}

To emit LOCK BTS. Similarly, fetch_xor got LOCK BTC and fetch_and got LOCK BTR.
These all work because CF is set by the bit-test-and-op instructions.

It occurs to me that LOCK AND, LOCK OR and LOCK XOR reliably set the SF, ZF,
and PF flags according to the result, so they may be used too. I can't think of
any time the PF flag would be useful and obviously ZF will not be set after a
LOCK OR (unless you OR'ed zero, but why would you do that?).

So possibilities are:

static constexpr int signbit = 0x80000000;
bool tsign1(std::atomic<int> &i)
{
    int bit = 1; // any one or more bits, except for a constant sign bit
    return i.fetch_or(bit, std::memory_order_relaxed) & signbit;
}
bool tsign2(std::atomic<int> &i)
{
    int bit = 1; // any one or more bits, except for a constant sign bit
    return i.fetch_xor(bit, std::memory_order_relaxed) & signbit;
}
bool tzero1(std::atomic<int> &i)
{
    int bits = 1; // any one or more bits
    return i.fetch_and(bit, std::memory_order_relaxed) == 0;
}
bool tzero2(std::atomic<int> &i)
{
    int bits = 1; // any one or more bits
    return i.fetch_xor(bit, std::memory_order_relaxed) == 0;
}

all of the above can be negated too (op != 0 and (op & signbit) == 0).

Reply via email to