Functions not working after optimization in IAR
Started by ●February 8, 2012
I have thus far been using only "Low" optimization level in IAR (which
basically means no optimization). Since I am hitting the code size limit, I
tried using the Medium setting. On doing so, it is observed that a particular
feature does not work. How should I approach finding out why that particular
function has (apparently) been optimized out?
Reply by ●February 8, 20122012-02-08
First place I would look will be listing and map files.
Most likely is that the functions are still there, but something like a
latent volatile or timing bug has now surfaced.
Also check the compilers output for warnings, they will sometimes point you
in the right direction.
--
Andy
Most likely is that the functions are still there, but something like a
latent volatile or timing bug has now surfaced.
Also check the compilers output for warnings, they will sometimes point you
in the right direction.
--
Andy
Reply by ●February 8, 20122012-02-08
Indeed, when I put a logic analyzer on the UART I see that it is not functioning
correctly. Not all what is supposed to be sent is sent and nothing is received.
Some I/O lines that toggle in a certain way (as set by the logic) are also not
functioning correctly. Why would any "optimization" mess with any of
these pieces of code?
Reply by ●February 8, 20122012-02-08
Below is some code I use to set three port pins (P4.4 P4.5 and P4.6).
Could this have been removed and if so why?
#define SWITCH_CH1() do { P4OUT &= ~(BIT4+BIT5+BIT6); } while ( 0 )
#define SWITCH_CH2() do { P4OUT &= ~(BIT6+BIT5); P4OUT |= (BIT4); } while ( 0 )
#define SWITCH_CH3() do { P4OUT &= ~(BIT4+BIT6); P4OUT |= (BIT5); } while ( 0 )
#define SWITCH_CH4() do { P4OUT &= ~(BIT6); P4OUT |= (BIT4+BIT5); } while ( 0 )
#define SWITCH_CH5() do { P4OUT &= ~(BIT4+BIT5); P4OUT |= (BIT6); } while ( 0 )
#define SWITCH_CH6() do { P4OUT &= ~(BIT5); P4OUT |= (BIT4+BIT6); } while ( 0 )
#define SWITCH_CH7() do { P4OUT &= ~(BIT4); P4OUT |= (BIT5+BIT6); } while ( 0 )
#define SWITCH_CH8() do { P4OUT |= (BIT4+BIT5+BIT6); } while ( 0 )
Could this have been removed and if so why?
#define SWITCH_CH1() do { P4OUT &= ~(BIT4+BIT5+BIT6); } while ( 0 )
#define SWITCH_CH2() do { P4OUT &= ~(BIT6+BIT5); P4OUT |= (BIT4); } while ( 0 )
#define SWITCH_CH3() do { P4OUT &= ~(BIT4+BIT6); P4OUT |= (BIT5); } while ( 0 )
#define SWITCH_CH4() do { P4OUT &= ~(BIT6); P4OUT |= (BIT4+BIT5); } while ( 0 )
#define SWITCH_CH5() do { P4OUT &= ~(BIT4+BIT5); P4OUT |= (BIT6); } while ( 0 )
#define SWITCH_CH6() do { P4OUT &= ~(BIT5); P4OUT |= (BIT4+BIT6); } while ( 0 )
#define SWITCH_CH7() do { P4OUT &= ~(BIT4); P4OUT |= (BIT5+BIT6); } while ( 0 )
#define SWITCH_CH8() do { P4OUT |= (BIT4+BIT5+BIT6); } while ( 0 )
Reply by ●February 8, 20122012-02-08
It is possible that the do {} while (0) is removed because the while(0) is
never true. Just take out the do and while(0) leaving the braces and what is
in the braces...
#define SWITCH_CH1() { P4OUT &= ~(BIT4+BIT5+BIT6); }
#define SWITCH_CH2() { P4OUT &= ~(BIT6+BIT5); P4OUT |= (BIT4); }
#define SWITCH_CH3() { P4OUT &= ~(BIT4+BIT6); P4OUT |= (BIT5); }
#define SWITCH_CH4() { P4OUT &= ~(BIT6); P4OUT |= (BIT4+BIT5); }
#define SWITCH_CH5() { P4OUT &= ~(BIT4+BIT5); P4OUT |= (BIT6); }
#define SWITCH_CH6() { P4OUT &= ~(BIT5); P4OUT |= (BIT4+BIT6); }
#define SWITCH_CH7() { P4OUT &= ~(BIT4); P4OUT |= (BIT5+BIT6); }
#define SWITCH_CH8() { P4OUT |= (BIT4+BIT5+BIT6); }
never true. Just take out the do and while(0) leaving the braces and what is
in the braces...
#define SWITCH_CH1() { P4OUT &= ~(BIT4+BIT5+BIT6); }
#define SWITCH_CH2() { P4OUT &= ~(BIT6+BIT5); P4OUT |= (BIT4); }
#define SWITCH_CH3() { P4OUT &= ~(BIT4+BIT6); P4OUT |= (BIT5); }
#define SWITCH_CH4() { P4OUT &= ~(BIT6); P4OUT |= (BIT4+BIT5); }
#define SWITCH_CH5() { P4OUT &= ~(BIT4+BIT5); P4OUT |= (BIT6); }
#define SWITCH_CH6() { P4OUT &= ~(BIT5); P4OUT |= (BIT4+BIT6); }
#define SWITCH_CH7() { P4OUT &= ~(BIT4); P4OUT |= (BIT5+BIT6); }
#define SWITCH_CH8() { P4OUT |= (BIT4+BIT5+BIT6); }
Reply by ●February 8, 20122012-02-08
Reply by ●February 8, 20122012-02-08
OK. So. Problem seems to be solved, but I don't understand why. What solved
it was using functions instead of #define. Functionally they are the same, so
why should they be treated differently? Examples below:
This did not work (when optimized):
#define SWITCH_CH1() { P4OUT &= ~(BIT4+BIT5+BIT6); }
This does work:
void SWITCH_CH1 (void)
{
P4OUT &= ~(BIT4+BIT5+BIT6);
}
This did not work (when optimized):
#define SWITCH_CH1() { P4OUT &= ~(BIT4+BIT5+BIT6); }
This does work:
void SWITCH_CH1 (void)
{
P4OUT &= ~(BIT4+BIT5+BIT6);
}
Reply by ●February 8, 20122012-02-08
Mea culpa mea culpa mea culpa..... OK so I am a dork and feel free to laugh out
loud. Problem not solved after all... With all the switching between Low/Medium
optimization to try and work it out, I forgot to switch to Madium after making
functions out of the #defines so obviously it "worked" in Low
optimization.... So, problem remains....
Damn
Need a new approach, any suggestions?
Damn
Need a new approach, any suggestions?
Reply by ●February 8, 20122012-02-08
On 08/02/2012 09:03, merapcb wrote:
>
> Mea culpa mea culpa mea culpa..... OK so I am a dork and feel free to
> laugh out loud. Problem not solved after all... With all the
> switching between Low/Medium optimization to try and work it out, I
> forgot to switch to Madium after making functions out of the #defines
> so obviously it "worked" in Low optimization.... So, problem
> remains....
>
> Damn
>
> Need a new approach, any suggestions?
I'd second Andy's suggestion - look at the listing and map files.
The key thing to remember in C is your volatiles (that includes access
to hardware ports and registers, as they are defined as volatile). In
the great majority of cases where something works without optimisation,
but fails when optimisations are enabled, the cause is missing
"volatile". The compiler will not simply remove code that accesses a
port like this - but it /will/ remove it if it can see from other code
that this section is never run.
So look at the code that calls these macros or functions, and see what
is going wrong there. If it looks okay, go back to the code that calls
that, and so on.
mvh.,
David
>
> Mea culpa mea culpa mea culpa..... OK so I am a dork and feel free to
> laugh out loud. Problem not solved after all... With all the
> switching between Low/Medium optimization to try and work it out, I
> forgot to switch to Madium after making functions out of the #defines
> so obviously it "worked" in Low optimization.... So, problem
> remains....
>
> Damn
>
> Need a new approach, any suggestions?
I'd second Andy's suggestion - look at the listing and map files.
The key thing to remember in C is your volatiles (that includes access
to hardware ports and registers, as they are defined as volatile). In
the great majority of cases where something works without optimisation,
but fails when optimisations are enabled, the cause is missing
"volatile". The compiler will not simply remove code that accesses a
port like this - but it /will/ remove it if it can see from other code
that this section is never run.
So look at the code that calls these macros or functions, and see what
is going wrong there. If it looks okay, go back to the code that calls
that, and so on.
mvh.,
David
Reply by ●February 8, 20122012-02-08
--- In m..., "Steve Mayfield" wrote:
>
> It is possible that the do {} while (0) is removed because the while(0) is
> never true.
That would be a major bug in the optimizer / compiler ! The "do" part in such construct is always executed at least once, since the test is not performed until after the first iteration.
> Just take out the do and while(0) leaving the braces and what is
> in the braces...
Not a good idea. Code such as :
if ( test )
SWITCH_CH1();
else
..
will generate
if ( test )
{ };
else
..
which is incorrect (two statements, { } and ; before "else"). You would need to write
if ( test )
SWITCH_CH1() // no ;
else
..
for it to compile, which is not intuitive.
The do / while( 0 ) construct is needed to make multi-statement macro behave like real function calls.
>
> It is possible that the do {} while (0) is removed because the while(0) is
> never true.
That would be a major bug in the optimizer / compiler ! The "do" part in such construct is always executed at least once, since the test is not performed until after the first iteration.
> Just take out the do and while(0) leaving the braces and what is
> in the braces...
Not a good idea. Code such as :
if ( test )
SWITCH_CH1();
else
..
will generate
if ( test )
{ };
else
..
which is incorrect (two statements, { } and ; before "else"). You would need to write
if ( test )
SWITCH_CH1() // no ;
else
..
for it to compile, which is not intuitive.
The do / while( 0 ) construct is needed to make multi-statement macro behave like real function calls.