Force a function to be inline in Clang/LLVM
Asked Answered
F

5

23

Is there a way to force an inline function in Clang/LLVM?

AFAIK, the following is just a hint to the compiler but it can ignore the request.

__attribute__((always_inline))

I don’t mind that the compilation will fail if it can’t inline the function.

Forgiving answered 1/9, 2014 at 9:32 Comment(0)
F
21

There is a good solution if compiling with C99 which is Clang's default. Its simply using inline attribute.

inline void foo() {} 

It is well written in Clang's compatibility page:

By default, Clang builds C code according to the C99 standard, which provides different semantics for the inline keyword than GCC's default behavior...

In C99, inline means that a function's definition is provided only for inlining, and that there is another definition (without inline) somewhere else in the program. That means that this program is incomplete, because if add isn't inlined (for example, when compiling without optimization), then main will have an unresolved reference to that other definition. Therefore we'll get a (correct) link-time error...

GCC recognizes it as an extension and just treats it as a hint to the optimizer.

So in order to guarantee that the function is inlined:

  1. Don’t use static inline.
  2. Don’t add another implementation for the function that doesn't have inline attribute.
  3. You must use optimization. But even if there isn't optimization the compilation will fail which is good.
  4. Make sure not to compile with GNU89.
Forgiving answered 2/9, 2014 at 12:27 Comment(5)
don't use static inline? i guess in that way you'll get the link error in clang(as its default behavior is c99)Kolinsky
It may fail linking if it failed to inline (and the function wasn't declared as static). But this is the intention as I wrote in the question: "I don’t mind that the compilation will fail if it can’t inline the function".Forgiving
ok, i see your idea; you exactly answered your question. However you requirement is a bit odd:-)Kolinsky
Its not odd, I want to know for sure that it was inlined (for some security reasons). If it can't, I want to know that. AFAIK, There is no other way to do this.Forgiving
Whats the behavior for c11 and above?Rubicon
M
7

I am going to treat your question as asking for any tools within the Clang/LLVM framework. Here is my suggestion: compile your code to LLVM bitcode and then run the Always inline pass.

For example:

> clang <other CFLAGS> -emit-llvm -c -o foo.bc foo.c
> opt -always-inline foo.bc -o foo_inline.bc
> clang -c -o foo.o foo_inline.bc

I have used this sequence before and it has inlined all of my functions marked "always_inline". In my case, I was already doing other analyses and transforms on the bitcode, so I only had to add the flag to opt.

Mastoiditis answered 1/9, 2014 at 12:59 Comment(2)
How is it different from the always_inline attribute? is the inline guaranteed when using this flag with opt? or is it just a hint?Forgiving
The command to opt tells it to run the always inline transformation pass on the LLVM IR. This pass goes through the IR and finds all of the functions with the always_inline attribute and inlines them. Looking at the source code - llvm.org/docs/doxygen/html/InlineAlways_8cpp_source.html, the comments indicate that it should inline everything that is marked always_inline and is possible to do so. You could write a pass that will fail if it finds any calls to a function that is marked "always_inline".Mastoiditis
S
6

You can start with experimenting with: clang -mllvm -inline-threshold=n

The greater the parameter n, the more agressive the inlining will be. Default is 225 so set it to something bigger. Expect big code size and long compilation times with very agressive inlining. When you hit the point of diminishing returns you can try profiling the code and looking for frequently called but uninlined functions and try marking them with attribute((always_inline)) for even more inlining.

If you have functions marked "inline", you can also experiment with -inlinehint-threshold bigger than -inline-threshold and see whether this changes anything.

Also, are you compiling with link-time optimizations? Without them inlining is limited to individual compilation units.

**taken from groups.google.com forum

Sven answered 1/1, 2018 at 19:38 Comment(0)
K
3

Brute force method is just turning it into a macro.

Karena answered 16/8, 2016 at 17:25 Comment(1)
And if you really need cross-platform compatibility, it might be the only viable method.Ranna
I
2

Just a few remarks that might be useful too.

For the OP's comments:

  1. Multiple static inline definitions is a caveat because it can cause, upon changing one of them, multiple different functions that can cause lots of head-scratching, especially if inlining kicks in and the actual calls evaporate to different sequences of statements.
  2. This can have similar effects as 1.
  3. Inlining is an optimization and you can look into your compiler's manual to see when it kicks in (e.g. gcc doc page). Usually, it is in the first level. See also this answer.

A useful discussion and recommendation can be found here. The advice for C99 is summed up as follows:

  1. In a header file define the following and include it wherever it's required:

    inline void foo() { /*...*/ }

  2. In a single source file declare it using extern to generate the external symbol:

    extern inline foo();

As for the LLVM IR method proposed, it works but then you are passed the source language domain and subject to a different set of rules (highly dependent on the tool). A brief indicative discussion can be found here.

Intoxicating answered 16/4, 2017 at 21:14 Comment(1)
I'd appreciate some constructive feedback/pointers/etc when being downvoted.Intoxicating

© 2022 - 2024 — McMap. All rights reserved.