Thread (121 messages) 121 messages, 13 authors, 2021-09-24

Re: [RFC] LKMM: Add volatile_if()

From: Segher Boessenkool <hidden>
Date: 2021-06-06 13:04:22
Also in: linux-arch, lkml

On Sat, Jun 05, 2021 at 08:41:00PM -0700, Linus Torvalds wrote:
On Sat, Jun 5, 2021 at 6:29 PM Alan Stern [off-list ref] wrote:
quoted
Interesting.  And changing one of the branches from barrier() to __asm__
__volatile__("nop": : :"memory") also causes a branch to be emitted.  So
even though the compiler doesn't "look inside" assembly code, it does
compare two pieces at least textually and apparently assumes if they are
identical then they do the same thing.
That's actually a feature in some cases, ie the ability to do CSE on
asm statements (ie the "always has the same output" optimization that
the docs talk about).

So gcc has always looked at the asm string for that reason, afaik.
GCC does not pretend it can understand the asm.  But it can see when
two asm statements are identical.
I think it's something of a bug when it comes to "asm volatile", but
the documentation isn't exactly super-specific.
Why would that be?  "asm volatile" does not prevent optimisation.  It
says this code has some unspecified side effect, and that is all!  All
the usual C rules cover everything needed: the same side effects have to
be executed in the same order on the real machine as they would on the
abstract machine.
There is a statement of "Under certain circumstances, GCC may
duplicate (or remove duplicates of) your assembly code when
optimizing" and a suggestion of using "%=" to generate a unique
instance of an asm.
"%=" outputs a number unique for every output instruction (the whole asm
is one instruction; these are GCC internal instructions, not the same
thing as machine instructions).  This will not help here.  The actual
thing the manual says is
  Under certain circumstances, GCC may duplicate (or remove duplicates
  of) your assembly code when optimizing.  This can lead to unexpected
  duplicate symbol errors during compilation if your 'asm' code defines
  symbols or labels.  Using '%=' may help resolve this problem.
It helps prevent duplicated symbols and labels.  It does not do much
else.
Which might actually be a good idea for "barrier()", just in case.
However, the problem with that is that I don't think we are guaranteed
to have a universal comment character for asm statements.
That's right.  But ";#" works on most systems, you may be able to use
that?
IOW, it might be a good idea to do something like

   #define barrier() \
        __asm__ __volatile__("# barrier %=": : :"memory")

but I'm  not 100% convinced that '#' is always a comment in asm code,
so the above might not actually build everywhere.
Some assemblers use ";", some use "!", and there are more variations.

But this will not do what you want.  "%=" is output as a unique number
*after* everything GCC has done with the asm.
However, *testing* the above (in my config, where '#' does work as a
comment character) shows that gcc doesn't actually consider them to be
distinct EVEN THEN, and will still merge two barrier statements.
Yes, the insns have the same templates, will output the exact same to
the generated assembler code, so are CSEd.
So the gcc docs are actively wrong, and %= does nothing - it will
still compare as the exact same inline asm, because the string
equality testing is apparently done before any expansion.
They are not wrong.  Maybe the doc could be clearer though?  Patches
welcome.
Something like this *does* seem to work:

   #define ____barrier(id) __asm__ __volatile__("#" #id: : :"memory")
   #define __barrier(id) ____barrier(id)
   #define barrier() __barrier(__COUNTER__)

which is "interesting" or "disgusting" depending on how you happen to feel.
__COUNTER__ is a preprocessor thing, much more like what you want here:
this does its work *before* everything the compiler does, while %= does
its thing *after* :-)

(Not that I actually understand what you are trying to do with this).


Segher
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help