/* Copyright (c) 2010 Jan Waclawek
   Copyright (c) 2010 Joerg Wunsch
   All rights reserved.

   Redistribution and use in source and binary forms, with or without
   modification, are permitted provided that the following conditions are met:

   * Redistributions of source code must retain the above copyright
     notice, this list of conditions and the following disclaimer.
   * Redistributions in binary form must reproduce the above copyright
     notice, this list of conditions and the following disclaimer in
     the documentation and/or other materials provided with the
     distribution.

  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  POSSIBILITY OF SUCH DAMAGE. */

/* $Id$ */

/** \page optimization Compiler optimization

\section optim_code_reorder Problems with reordering code
\author Jan Waclawek

Programs contain sequences of statements, and a naive compiler would
execute them exactly in the order as they are written. But an
optimizing compiler is free to \e reorder the statements --- or even
parts of them --- if the resulting "net effect" is the same. The
"measure" of the "net effect" is what the standard calls "side
effects", and is accomplished exclusively through accesses (reads and
writes) to variables qualified as \c volatile. So, as long as all
volatile reads and writes are to the same addresses and in the same
order (and writes write the same values), the program is correct,
regardless of other operations in it. One important point to note
here is, that time duration between consecutive volatile accesses is
not considered at all.

Unfortunately, there are also operations which are not covered by
volatile accesses. An example of this in AVR-GCC/AVR-LibC are the
\c cli() and \c sei() macros defined in <avr/interrupt.h>, which convert
directly to the respective assembler mnemonics through the \c __asm__()
statement. They constitute a variable access by means of their
memory clobber, and they are (implicitly) volatile because they don't
have an output operand.  So the compiler may not reorder these
\ref inline_asm "inline asm" statements with respect to other
memory accesses or volatile actions.
However, such asm statementy may still be reordered with
other statement that are neither volatile nor access memory.

<em>Note that even a volatile asm instruction can be moved
relative to other code, including across (expensive) arithmetic
and jump instructions [...]</em>

\sa http://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html

However, not even a volatile memory barrier like
\code
__asm __volatile__ ("" ::: "memory");
\endcode

keeps GCC from reordering non-volatile, non-memory accesses across
such barriers.
Peter Dannegger provided a nice example of this effect:

\code
#define cli() __asm volatile( "cli" ::: "memory" )
#define sei() __asm volatile( "sei" ::: "memory" )

unsigned int ivar;

void test2 (unsigned int val)
{
  val = 65535U / val;

  cli();

  ivar = val;

  sei();
}
\endcode

avr-gcc v5.4 or v14 compile with optimisations switched on (\c -Os) to

\verbatim
00000112 <test2>:
 112:	bc 01       	movw	r22, r24
 114:	f8 94       	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
 126:	78 94       	sei
 128:	08 95       	ret
\endverbatim

where the potentially slow division is moved across \c cli(),
resulting in interrupts to be disabled longer than intended. Note,
that the volatile access occurs in order with respect to \c cli() or
\c sei(); so the "net effect" required by the standard is achieved as
intended, it is "only" the timing which is off. However, for most of
embedded applications, timing is an important, sometimes critical
factor.

\sa https://www.mikrocontroller.net/topic/65923

Unfortunately, at the moment, in avr-gcc (nor in the C standard),
there is no mechanism to enforce complete match of written and
executed code ordering --- except maybe of switching the optimization
completely off (\c -O0), or writing all the critical code in assembly.

\note The artifact with the \c __udivmodhi4 function is specific to
avr-gcc and how the compiler represents the division internally.
On other target platforms that are using a library function for
division or whatever expensive operation, this eccect will not occur.
The reason is that avr-gcc does not represent the library call as a
function call but rather like an ordinary instruction. Outcome is that
the GCC middle-end concludes that the division is cheap (because the
backend has an instruction for it) but in fact it's not.

A work around for the code from above would be to enforce that the
division havvens prior to the \c cli():
\code
  val = 65535U / val;
  __asm __volatile__ ("" : "+r" (val));
  cli();
\endcode

- The \c volatile forces the asm statememt prior to the \c cli.
- The asm has \c val as input operand, hence the division must be carried
out prior to the asm because \c val is set by the division.

Notice that this work around does not work in general due to a variety of
reasons:

- The division might be located in an inlined function.
- The variable might be read-only or may not be appropriate as an asm operand.
- There may be more such instruction prior to the division, and it is not
practical to treat all of them like this.

To sum it up:

\li volatile memory barriers don't ensure statements with no volatile accesses to be reordered across the barrier

*/
