Your colleague is mistaken regarding re-ordering of access to
volatile-qualified objects.  David's description is correct and nicely
detailed.  In the example a will always be written before b unless the
compiler is broken.

(I should point out that mspgcc in the 3.2.3 era in fact probably *was*
broken with respect to correct ordering of some volatile operations,
because of a hack intended to improve peripheral register access
performance. There were errors in volatile behavior when I started
maintenance that didn't get cleaned up until sometime around August 2011.
There's probably traffic in the list archive around that time that explains
the problem.)

MSP430 writes of 16-bit values in any version of mspgcc I released would be
atomic except if they occurred to an object declared with the "packed"
attribute, in which case the byte values would be written separately to
prevent alignment problems.  (There were bugs in this usage too.)

I also use ARM Cortex devices these days, and am very pleased to see that
TI is moving the MSP432 to using CMSIS-Core--compatible peripheral
structure definitions as of March 2016 (
http://processors.wiki.ti.com/index.php/MSP432_CMSIS_Update?DCMP=epd-mcu-msp-gen&HQS=MSP432CMSIS).
If the Tiva and CC3K folks were that adaptable I might still use TI chips.

Peter

On Fri, Nov 27, 2015 at 9:04 PM, Wayne Uroda <w.ur...@gmail.com> wrote:

> Thanks very much David.
>
> I already disable interrupts when I need an atomic operation, such as a
> write to 32 bit variable or a read-modify-write on a 16bit variable.
>
> Am I right to assume that simple writes to 16 bit variables are always
> atomic on MSP430? Eg done = 0xabcd, the CPU doesn't do two byte writes or
> anything dumb like that, the memory will be X (don't care) before the write
> and will be 0xabcd after, or should I disable interrupts for all writes to
> shared memory (shared with an ISR)?
>
>
> My colleague asserts that the compiler is even free to reorder volatile
> accesses, like
>
> volatile int a;
> volatile int b;
> int c;
>
> int main()
> {
>     a = 5;
>     b = 0;
>     c = 1;
>     return 0;
> }
>
> You are saying that the compiler will always write a before b, even
> without a memory barrier. Is that right?
>
> But in the above, the write to c can happen anywhere, as far as I
> understand.
>
> Lastly, this compiler (3.2.3) is only used on our legacy projects. More
> recently we are using the last LTS of mspgcc before Ti/RH started their
> port.
> I've not seriously tried to use the new RH compiler, and my company is
> largely moving away from MSP430 towards ARM Cortex now.
>
> Thanks
> - Wayne
>
>
>
> > On 27 Nov 2015, at 23:19, David Brown <da...@westcontrol.com> wrote:
> >
> >> On 27/11/15 12:32, Wayne Uroda wrote:
> >> Hello,
> >>
> >> I have a question about instruction reordering in the compiler.
> >>
> >> In this blog
> >> http://preshing.com/20120625/memory-ordering-at-compile-time/ It says
> >> that a compiler barrier should be used where writes to memory must
> >> not be reordered.
> >
> > Looks like good information.
> >
> >>
> >> My MSP430 code is all bare metal, foreground-background code and I am
> >> not using any type of RTOS, so it could be considered lock-free.
> >>
> >> Anyway, a new employee at my work pointed out that the compiler is
> >> free to reorder my memory writes, even those marked volatile. I said
> >> that I had never actually seen mspgcc do this, but now I am curious:
> >> will mspgcc reorder memory writes, eg to global variables? Is this
> >> dependent on the msp430 side of gcc (the backend), or more on the
> >> AST/RTL side?
> >
> > The compiler can re-order any reads or writes it likes, except volatile
> > accesses.  The order of volatile accesses will always match the source
> > code.  But the compiler can move non-volatile reads and writes back and
> > forth between volatile accesses.
> >
> > So if you have non-volatile variables a, b, c, and volatile variables u,
> > v, and source code like this:
> >
> > a = 1;
> > u = 100;
> > b = 2;
> > v = 200;
> > c = 3;
> >
> > Then the compiler can generate code like this:
> >
> > a = 1;
> > c = 3;
> > u = 100;
> > v = 200;
> > b = 2;
> >
> > But it may not generate code like this:
> >
> > a = 1;
> > v = 200;
> > b = 2;
> > u = 100;
> > c = 3;
> >
> > (The same applies to reads.)
> >
> > The volatile accesses must be exact, in the same number and the same
> > order with respect to other volatile accesses.  But the non-volatile
> > accesses can be moved around as much as the compiler wants.
> >
> > Note that variable accesses can also be moved around with respect to
> > function calls, /if/ the compiler knows the function does not make
> > volatile accesses.
> >
> > The compiler can also eliminate "dead" stores, or unused reads.  Given:
> >
> > a = 1;
> > u = 100;
> > a = 2;
> > v = 200;
> > a = 3;
> >
> > The compiler can generate:
> >
> > u = 100;
> > v = 200;
> > a = 3;
> >
> > or
> >
> > a = 3;
> > u = 100;
> > v = 100;
> >
> >
> >>
> >> Or to put it another way, should I be reviewing my shared (between
> >> background and ISR) variables and placing compiler barriers where
> >> variables must be stored in an exact order?
> >
> > Yes, these must be handled carefully.  In particular, volatile accesses
> > give no indication about how non-volatile accesses are handled.
> > Sometimes people write code like this:
> >
> > int data[4];
> > volatile bool newData;
> >
> > void update(int x) {
> >    data[0] = data[1];
> >    data[1] = data[2];
> >    data[2] = data[3];
> >    data[3] = x;
> >    newData = true;
> > }
> >
> > And they think that making the newData flag a volatile is sufficient.
> > It is /not/ sufficient - the compiler can set newData before doing
> > anything with the data[] array.  And then your interrupt code will work
> > fine in all your testing, and hit a race condition when the customer is
> > watching.
> >
> > You have to make each access to "data" here volatile, or you need a
> > memory barrier between "data[3] = x;" and "newData = true;".  A memory
> > barrier tells the compiler that all memory writes before the barrier
> > need to be completed, no writes after the barrier may be started, and
> > any data read before the barrier is now invalid.
> >
> > And note that even then, nothing in memory barriers or volatile access
> > will ensure that the reads or writes are atomic.
> >
> > Some useful macros/functions:
> >
> > #define volatileAccess(v) *((volatile typeof((v)) *) &(v))
> >
> > static inline void compilerBarrier(void) {
> >    asm volatile("" ::: "memory");
> > }
> >
> >
> >>
> >> I am using a very old version of mspgcc, 3.2.3, I think it was the
> >> last stable Windows binary release before the CPUX instructions
> >> started making their way in, sorry I don't know the version, from
> >> 2008/2009 maybe?
> >
> > That was probably the final release before the mspgcc 4 project was
> > started.  And now there is a new port msp430-elf from Red Hat and TI,
> > which is where you should go for moving on for the future.
> >
> > gcc 3.2.3 did not optimise as aggressively as newer gcc, so it will do a
> > lot less re-arrangement of code.  In general, the compiler will
> > re-arrange the order of writes if it has good reason to do so - if the
> > result is smaller and/or faster.  If it makes no difference, then it
> > will not re-order the writes.
> >
> >
> >
> >
> >
> >
> ------------------------------------------------------------------------------
> > _______________________________________________
> > Mspgcc-users mailing list
> > Mspgcc-users@lists.sourceforge.net
> > https://lists.sourceforge.net/lists/listinfo/mspgcc-users
>
>
> ------------------------------------------------------------------------------
> _______________________________________________
> Mspgcc-users mailing list
> Mspgcc-users@lists.sourceforge.net
> https://lists.sourceforge.net/lists/listinfo/mspgcc-users
>
------------------------------------------------------------------------------
_______________________________________________
Mspgcc-users mailing list
Mspgcc-users@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/mspgcc-users

Reply via email to