I am trying to compile the following two pieces of code with ARM Compiler 5 for a Cortex A microprocessor:
Part 1:
static
Are the error caused by the compiler version (ARM compiler 5), which does not support Extended Asm?
That's GNU C inline Extend Asm syntax, so yes obviously a compiler that doesn't support it will error.
A GCC change in 2016 (PR24414) gave non-empty Basic Asm statements an implicit "memory"
clobber, as well as making them implicitly clobber "cc"
on targets like x86 where Extended asm does that. So if your GCC version is new enough, you I guess could be able to safely use Basic Asm here, assuming that undocumented GCC behaviour continues to be present in future GCC versions to help badly written or old code work the way it was probably intended. (Assuming that's actually also safe in Keil, with an implicit memory barrier there, too). I don't know what GCC versions this made it into
(A litmus test for storing and reloading a global across an asm statement will tell you how this behaves on any given GCC version. If you see the register value being reused for asm("" ::: );
(Extended with explicitly no memory clobber) but not for asm("# comment");
(non-empty Basic), that implies non-empty Basic asm statements have an implicit memory clobber. Otherwise you'd expect the same optimization as with Extended. This Godbolt compiler explorer link shows GCC 6.4 does not have an implicit mem clobber for Basic asm, but GCC7.1 does.
Or better, you could use CPP macros to #if
detect the bad compiler and omit the ::: "memory"
part that it chokes on, on the assumption that it treats the asm statement as having a memory clobber. Or detect __GNUC__
and __GNUC_MINOR__
version, etc. and use that to detect any compiler that claims compatibility with a version of the GNU dialect of C that supports Extended asm.
Basic Asm should never be used inside functions in GNU C, even for instructions like dsb
that don't read or write registers, because there's no documented guarantee of ordering wrt. compiler-generated memory accesses. https://gcc.gnu.org/wiki/ConvertBasicAsmToExtended. Normally you should only ever use it for the body of a __attribute__((naked))
function, or at global scope.
There's no upside to Basic asm; inline asm is something you should never ever use casually, and there's nothing you can do with Basic you can't do explicitly with Extended inside a non-naked function. (And almost nothing you actually can do safely with Basic at all: you can't safely touch registers or even global vars in memory (see this, and it's not guaranteed to be ordered wrt. anything.)
So it sucks a lot to depend on undocumented Basic Asm behaviour of having an implicit "memory"
clobber. There was no good reason for that implicit mem clobber GCC change (except for maybe making old and/or bad code more likely to happen to work right); Extended asm to make that explicit is always better in GNU C.
Does Keil support stdatomic.h
for atomic_thread_fence(memory_order_seq_cst)
to emit a "dmb" that can't be reordered with surrounding code? (Doesn't help for dsb and isb, though).