This is the mail archive of the gcc-help@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: Are arrays guaranteed to be affected by a "memory" clobber?


On 13/06/15 21:51, Andrew Haley wrote:
On 13/06/15 18:49, Sebastian wrote:
On Fri, 12 Jun 2015 19:53:03 +0100
Andrew Haley <aph@redhat.com> wrote:

That's the whole point about the example.

No it's not.  The only thing moved across the barrier is the
division.  A memory op cannot  be moved across a memory barrier.

One memory barrier is at the cli(), as the article points out "where
the potentially slow division is moved across cli(),". The
assignment to val is moved, over that.

Ah, okay.  I wasn't even thinking of that assignment as a memory
operation: see below.

It was before cli() in the C
source and it's after cli() after optimization. As your own comment
shows.

Here's the code:

00000112 <test2>:
  112:   bc 01           movw    r22, r24
  114:   f8 94           cli
That's the cli().

  116:   8f ef           ldi     r24, 0xFF       ; 255
  118:   9f ef           ldi     r25, 0xFF       ; 255
  11a:   0e 94 96 00     call    0x12c   ; 0x12c <__udivmodhi4>
  11e:   70 93 01 02     sts     0x0201, r23
  122:   60 93 00 02     sts     0x0200, r22

The store to val is here ^

Thanks. Didn't try to find that, just figured that it would be
difficult to assign the result of the division before the division
happened.

So you just confirmed everything. This is after cli().

Actually, I think you're wrong here - this is not the store to val
(I guess you could r24 consider to be val, since that's it at the
beginning of the function), it's the store to ivar.

Sorry, yes.  I made a mistake.  I meant the store to ivar.

The store to val never happens, it is optimized away because val is
not a volatile variable, it's just a temporary one which is never
used afterwards.

Yes.  val has been eliminated by the compiler.

Which, still, is the point of the article: Because val is not
declared volatile, it is not "memory", so assignments to it (and the
division required to happen before the assignment) can be moved
across the barrier.

The question of whether a local variable is considered by GCC to be
"in memory" depends on whether it has ever had its address taken.

So, if you say

    int n;
    int *p = &n;

then n is potentially a memory operand.  (But be careful not to extend
this too far: if GCC knows that p is not used, it may be eliminated
and n is no longer potentially in memory.)  If a variable is global it
is also a memory operand.  But if a local variable never has its
address taken, no memory operation can access it (because there is no
way to know where it is.)  Therefore it is not affected by a memory
clobber.

So, again, why would it be ok to remove the volatile qualifier from
my array elements?  How else can I be sure a variable of mine is
"memory"?

The only way to be really sure is to use volatile.  But it depends
on exactly what you're trying to do: if you're more specific we can
provide better advice.

Andrew.


There is another way to force the calculation here - using a fake assembly input to force the calculation:

#define cli() __asm volatile( "cli" ::: "memory" )
#define sei() __asm volatile( "sei" ::: "memory" )
unsigned int ivar;
void test2( unsigned int val )
{
    val = 65535U / val;
    asm volatile("" :: "" (val));
    cli();
    ivar = val;
    sei();
}

The memory clobber on cli() and sei() ensures that no memory operations are moved before or after those statements. But as already noted, the memory clobber does not affect non-memory operations such as calculations or register-only manipulation.

But the extra "asm volatile" here with a fake input tells the compiler that "val" is an input to the (empty) assembly, and must therefore be calculated before the statement is executed. The empty input constraint (no "r" or "m") gives the compiler complete freedom about where it wants to put this fake input - all we are saying is that the value "val" must be calculated before executing

	asm volatile("" :: "" (val))

Generating assembly from this (using gcc-4.5.1, which is the latest avr-gcc I have installed at the moment) shows the division being done before the cli() - the code is optimal and correct, with no unnecessary memory operations (as you would need by making "val" volatile).






Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]