Help with inline functions

Go To Last Post
19 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Can I inline functions in winavr? The GCC documentation says that you can, but I'm having problems getting it to work. Are there compiler directives I need to add to my Makefile? (I'm using the default Makefile created by Mfile)

//test.h
inline void testfunc( void );
//test.c
inline void testfunc( void )
{
    int dummy = 0;
}
//main.c
#include 
#include "test.h"
int main(void)
{
    testfunc();
    testfunc();
}

Using __attribute__ ((always_inline)) doesn't seem to work either.

Last Edited: Thu. Aug 2, 2007 - 07:24 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Shouldn't the function prototype in test.h be:

inline void testfunc( void );

??

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

yes, you are correct. (edited it in the original post). But the inlining still doesn't seem to be working. =\

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Well inline is never going to work with the function to be inlined in a different C file to the one where it's being used. Remember that each compilation unit in a GCC program is compiled in complete isolation. You might have compiled test.c on 3rd May 2003 to produce a test.o and then written the main.c yesterday. When it is used all the linker can do is fix up (R)CALLs to the testfunc() when it finally links main.o and test.o together, it won't have access to the source of test.c at this time.

(admittedly it's actually usual for main.c to be compiled about 2 seconds after test.c but that's not the point!)

If, however, testfunc() had been in main.c (and also use 'static' to say that it is not going to be referenced by any other .c file outside of main.c) then the compiler would have looked at the possibility of inlining it.

However there's still no guarantee that this will hapeen because, if anything, the optimiser is too GOOD! If it can see that keeping the body of testfunc() separate at the cost of two (R)CALLs would actually generate smaller, faster code it will do that rather than inlining two adjacent copies.

Cliff

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Try "static inline"
This could work, if your function is called within the same C module.

regards

Andre

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Still, it will *only* work if the compiler can *see the entire
definition* of the function before any call to it. How else
should it know which code to inline right when it is called?

Jörg Wunsch

Please don't send me PMs, use email if you want to approach me personally.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

what the best way to include pieces of code (for example in interrupt routines) without unnecessary stack operations - through #define macros ?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

No, use the "naked" attribute but it will then become YOUR responsibility to preserve anything used in the ISR (including SREG) by adding some inline asm() to push/pop registers.

However, as the C compiler always just preserves the minimum necessary I'm not sure I see the point in trying to "out think" the compiler on this?

The one exception to that is if you make the huge mistake of actually calling a function from within an ISR (and it's not static inline in the same file and above the ISR code). In this case the compiler cannot know which registers that function may corrupt so it has no option but to preserve pretty much all the registers - which is a very costly exercise.

Bottom line: keep ISRs "lean and mean"

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

However, as the C compiler always just preserves the minimum necessary I'm not sure I see the point in trying to "out think" the compiler on this?

??? There was a puzzling save of r28/r29 in a recent thread, used to [apparently] hold a read of SPL/SPH which was never used.

https://www.avrfreaks.net/index.p...

ISR (TIMER1_OVF_vect)
{
  60:   1f 92          push   r1
  62:   0f 92          push   r0
  64:   0f b6          in   r0, 0x3f   ; 63
  66:   0f 92          push   r0
  68:   11 24          eor   r1, r1
  6a:   8f 93          push   r24
  6c:   cf 93          push   r28
  6e:   df 93          push   r29
  70:   cd b7          in   r28, 0x3d   ; 61
  72:   de b7          in   r29, 0x3e   ; 62
// Reinitialize Timer 1 value
TCNT1H=0x85;
  74:   85 e8          ldi   r24, 0x85   ; 133
  76:   80 93 4d 00    sts   0x004D, r24
TCNT1L=0xED;
  7a:   8d ee          ldi   r24, 0xED   ; 237
  7c:   80 93 4c 00    sts   0x004C, r24
// Place your code here
   sTime.ySeconds++;
  80:   80 91 60 00    lds   r24, 0x0060
  84:   8f 5f          subi   r24, 0xFF   ; 255
  86:   80 93 60 00    sts   0x0060, r24
  8a:   df 91          pop   r29
  8c:   cf 91          pop   r28
  8e:   8f 91          pop   r24
  90:   0f 90          pop   r0
  92:   0f be          out   0x3f, r0   ; 63
  94:   0f 90          pop   r0
  96:   1f 90          pop   r1
  98:   18 95          reti 

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Q: What's puzzling about this?

A: To know the reason why the author didn't enable optimizations.

Never expect anything optimal unless you told the compiler so...

Btw., static inline functions can be analyzed well about their
side-effects by the compiler, so they are also candidates for
becoming members of ISRs.

Jörg Wunsch

Please don't send me PMs, use email if you want to approach me personally.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

Q: What's puzzling about this?

A: To know the reason why the author didn't enable optimizations.

Aaah, I see. That thread never brought that up, and I didn't think of that. [Re the other thread: You'd think someone concerned with cycle counts in an ISR would be fairly proficient, and know about optimization. That's what happens when I assume.]

Just getting rid of that R28/R29 stuff brings that ISR down near 30 cycles; certainly respectable.

Lee

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Lee,

And this all comes back to the bloody AVR Studio thing. No one in their right mind (apart from an Atmel programmer having an off day when he wrote the avr-gcc plugin) would ever choose to operate the compiler in -O0 mode. It'd like be driving a 6 gear car without ever taking it out of first gear!

Cliff

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Some people prefer riding with the brakes applied, as it makes it so
easy to watch everything around.

Other people apparently prefer debugging unoptimized code, because
these damn compilers have a tendency to shake the code, and you never
really know where it actually goes along today... If we wouldn't all
have PCs with that silly CPU where the compiler never has a register
to spare which can be used for optimization, people were used to debug
optimized code from their PCs... but so, code running on a PC is
usually looking "straightforward" even with an optimizing compiler
(whereas it's then the CPU that actually performs all the low-level
optimizations, which makes them still damn fast). So now, when they
get their hands onto even only a "somewhat RISCy" CPU like the AVR,
they are simply overwhelmed with what kind of code rearrangements
modern compiler technology can actually perform... and they resort to
turn off the optimizer because it's soooo confusing to have.

I guess that's the entire story behind that stupid -O0 default.

Jörg Wunsch

Please don't send me PMs, use email if you want to approach me personally.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

> Just getting rid of that R28/R29 stuff brings that ISR down
> near 30 cycles; certainly respectable.

Btw., yes, that's basically what happens when turning on optimizations
on that code.

Jörg Wunsch

Please don't send me PMs, use email if you want to approach me personally.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

they are simply overwhelmed with what kind of code rearrangements
modern compiler technology can actually perform... and they resort to
turn off the optimizer because it's soooo confusing to have.

I guess that's the entire story behind that stupid -O0 default.


Yes, I think we have seen about the same number of threads about "disassembly/debugging jumps around/doesn't show code" as we have about -O0 gotchas.

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Yes but one just ruins your debug experience, the other ruins your application. I know which one I'd find preferable.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

> Yes but one just ruins your debug experience, ...

Even this only for a limited time. In the early 1990s, I started on
Unix (Data General Unix, DG/UX) on a true RISC machine (m88100),
and at first the jumping debugger cursor really looked confusing.
Until one realized why this must be the case, and so we simply got
used to debug optimized code.

It's probably this old experience that never made me too much
surprized about seeing similar behaviour for AVR-GCC now.

So it *is* possible to debug that code. An occasional glance at
the generated assembly is helpful in that, and has never been a
real mistake for an embedded programmer anyway. ;-)

Jörg Wunsch

Please don't send me PMs, use email if you want to approach me personally.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I think the one thing that really upsets beginners is not being able to use the watch window in Studio to watch values at the variable level (it's just a view on the SRAM locations where it has been told the values are located in the ELF file). Unfortunately the variables have actually been optimised into registers and there doesn't appear to be enough information in the ELF file for the debugger to be told "x is really in R23 and not memory location 0x3B2"

Those of us "in the know" take a squint at the assembler, find out which register the compiler has put 'x' into and then just watch the 32 registers but this seems beyond beginners. I have a sneaking feeling this was the thinking going on inside Atmel when they chose that -O0 default - so it didn't make their debugger (and specifically the watch window function) look "buggy" - it's true that there have been plenty of posts here about why the watch window is always saying things are "not in scope" when they should be.

Cliff

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I remember a statement from the GCC project about refined debugging
information, something that is IMHO work in progress right now. The
refined information is supposedly able to tell the debugger about
the beginning end ending of a particular variable's scope so the
debugger could better trace it.

Of course, even if that were ported to the AVR target, it would
probably need quite a bit of changes to AVR Studio as well...

Jörg Wunsch

Please don't send me PMs, use email if you want to approach me personally.