How to force a inline function

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

Hi there,

using WinAVR20100110, Optimization = s (size), how can I tell the compiler to always inline a function.

This doesn't work:

inline void Tasks__Exit_Critical_Section(void) __attribute__((always_inline));

Thanks

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

Joeks wrote:
Hi there,

using WinAVR20100110, Optimization = s (size), how can I tell the compiler to always inline a function.

This doesn't work:

inline void Tasks__Exit_Critical_Section(void) __attribute__((always_inline));

Thanks

How does not work? Show us an example.

JW

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

I can see in the listing file that a call is made to the function , here is a part of the listing file:

/* DE-ASSERT THE CS SIGNAL */
	SET_BIT(PORTD,IO__PD6_nMEM_CS);
    6fe4:	5e 9a       	sbi	0x0b, 6	; 11

/* EXIT CRITICAL CONDITION */
   Tasks__Exit_Critical_Section();
    6fe6:	0e 94 b5 3b 	call	0x776a	; 0x776a 
	
	return temp_Data;
}	
    6fea:	81 2f       	mov	r24, r17
    6fec:	0f 90       	pop	r0
    6fee:	0f 90       	pop	r0
    6ff0:	cf 91       	pop	r28
    6ff2:	df 91       	pop	r29
    6ff4:	1f 91       	pop	r17
    6ff6:	08 95       	ret

What to do now?

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

Crystal ball prediction #1:
If a function is defined in one compilation unit (C file) and then referenced by a different compilation unit (C file), then unless whole-program compilation is enabled, it will be impossible for GCC to inline the function.

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

Post source/command line switches a complete minimal example exhibiting the problem, so that we can reproduce them.

My crystal ball prediction is the same than lfmorrison's, though.

JW

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

Here are my compiler options taken out of the makefile:

#---------------- Compiler Options ----------------
#  -g*:          generate debugging information
#  -O*:          optimization level
#  -f...:        tuning, see GCC manual and avr-libc documentation
#  -Wall...:     warning level
#  -Wa,...:      tell GCC to pass this to the assembler.
#    -adhlns...: create assembler listing
CFLAGS = -g$(DEBUG)
CFLAGS += $(CDEFS) $(CINCS)
CFLAGS += -O$(OPT)
CFLAGS += -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums
CFLAGS += -Wall -Wstrict-prototypes -Wno-format -Wextra
CFLAGS += -Wa,-adhlns=$(<:.c=.lst)
CFLAGS += $(patsubst %,-I%,$(EXTRAINCDIRS))
CFLAGS += $(CSTANDARD)

It tried the -fwhole-program as you suggested, but now the linker gives "undefined reference to ..." errors. I declare all the functions in each one's header file and include the header files in the source files.

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

Add "static" and put it into a project-wide header.

Or make a macro out of it.

JW

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

Ok, thanks, will do the macro thing

JP

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
// always inline function x:

#define AIL(x)   static x __attribute__ ((always_inline)); static x


// never inline function x:

#define NIL(x)   x __attribute__ ((noinline)); x

Peter

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

Quote:

Ok, thanks, will do the macro thing

Eh? A static inline function in a .h is a FAR better idea. For one thing it's not polluted with '\' line terminators if it spans multiple lines and for another the input and return values are type checked by the C compiler.

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

I hear you but my macro/function is "really short", here it is:

#define Tasks__Enter_Critical_Section()	{\
	{\
	DISABLE_GLOBAL_INTERRUPTS();\
	GPIOR0++;\
	ENABLE_GLOBAL_INTERRUPTS();\
}\
}\

[code]

Just for now easier to put it in macro

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

What are you trying to achieve? If it is handling an atomicity situation, why not use the stuff already available in avrlibc?

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here

No guarantees, but if we don't report problems they won't get much of  a chance to be fixed! Details/discussions at link given just above.

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

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

Which becomes:

static inline void Tasks__Enter_Critical_Section(void)   { 
   DISABLE_GLOBAL_INTERRUPTS();
   GPIOR0++;
   ENABLE_GLOBAL_INTERRUPTS();
}

If nothing else it's not peppered with \ \ \ \

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

But this code is also called from other c-files, so can't declare is as static??

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

Quote:

But this code is also called from other c-files

You have to decide: Either the function is inlined, or it is actually called (eg from other source files). Of-course you can't have both.

One exceprion to the rule that you should not place something that actually generates code in a .h file are inlined functions. Since they will not be called in the low-level sense (no CALL instruction will be generated) but the code actually inserted at every place you have a C-level call to it this will not generate the usual problems with duplicated code generation. Indeed, the very core of inlining is that the code gets duplicated.

Understand this:

For a normal non-inlined function the compiler generates code only once. Calls from the same source file will can be resolved by the compiler. Calls from other source files has to be left to the linker to resolve.

For an inlined function the work is done entirely by the compiler, duplicating the functions code in every place you have a call to it at the C level. The linker will never know that there was a function. It has nothing to resolve, because the compiler has already done all the work.

Quote:
so can't declare is as static??

The only way you can get an inlined function to be useed in several source files is to make the implementation seen in every source file. The natural way to do this is to place the implementation in an #included file.

Next, to make sure that the compiler can at all times inline the function it has to know that there will be no ordinary calls (with a CALL instruction) from other source files (that has to be resolved by the linker). You do this by telling the compiler explicitly that the function is only visible in the currently compiled source file with the keyword static.

If such an implementation is seen in several separate compilations of separate source files, each will see "it's own copy" of the static function.

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here

No guarantees, but if we don't report problems they won't get much of  a chance to be fixed! Details/discussions at link given just above.

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

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

Along with Johan's excellent explanation, I'd like to add the following: Unless the inlined function is fairly simple, the compiler may require use of most of the registers to execute the function. In which case, the overhead generated by a call is not much more than what the compiler would need to do anyway for the inlined function.

I would look at the generated assembly for the raw function (not inlined) and see how many "call-used" registers are kept. If quite a few are saved, the function will need those registers no matter what. In that case, don't worry about inlining, since the return on investment is low.

I use inlined functions heavily, but in general I use it to break a huge function into more manageable chunks. In fact, in that case, the compiler will generally inline the code for me (if the optimization is set larger than -O1, I think, which my code always is).

Since your function is named Tasks__Exit_Critical_Section, you might be interested in how FreeRTOS does this. Inside of tasks.h is:

#define taskEXIT_CRITICAL()    portEXIT_CRITICAL()

Inside of portmacro.h is

#define portEXIT_CRITICAL()  \
    asm volatile ( "pop	 __tmp_reg__          \n\t" \
                   "out  __SREG__, __tmp_reg__" ::: "memory" )

So FreeRTOS has used the macro definition method to generate this "inlined" function.

Stu

Engineering seems to boil down to: Cheap. Fast. Good. Choose two. Sometimes choose only one.

Newbie? Be sure to read the thread Newbie? Start here!