Inlining basics

I’m curious, how does the inlining functions calls in LLVM work? Are you supposed to make any effort to inline code yourself or does the optimizer do all of this for you?

In particular I’m thinking of adding what compilers call “intrinsics” but I don’t see how these are different from any normal inlined function call. Maybe LLVM can’t inline all functions optimally so for intrinsics you should just inject the correct instructions and avoid the call instruction entirely?

Sorry if that’s vague but I don’t understand the basics here :slight_smile:

If you mean, do you need to do this in your frontend, no. The optimizer handles inlining.

clang/lib/Headers is full of header files that define “intrinsic” functions. I believe these are all marked inline so the optimizer will eliminate the overhead of a call instruction.

Some of these intrinsic functions have function bodies that are normal C code, but most of them call a “builtin” function. Builtin functions are predefined, i.e. recognized by Clang as special, and typically map to a specific target instruction. In that case the correct instructions are injected directly without a call instruction.

1 Like

Does LLVM try to guess which functions should be inlined or do you need to explicitly specify or disallow inlining?

I guess it makes sense to do this in some cases. For C for example there are no generics so certain functions that operate on different types would not be possible in normal C syntax.

For the modern Module Inliner inlining decisions will be driven by machine learning. It is completely automatic and transparent to users.

In C, you still haven option of the inline keyword and __attribute__((always_inline)) to define the inlining policy.

I don’t see anyway to explicitly mark a function as inline or no-inline in LLVM. Is it all automatic inlining now? I can imagine you may want to disable inlining or override the automatic inlining in case it fails.

There are LLVM IR attributes to control inlining; in textual IR they are alwaysinline, noinline, and inlinehint. If a given function doesn’t have an attribute then the inliner uses its heuristic to decide.

The inline cost model is built which determines whether it is profitable to perform inline substitution.

Inline substitution can fail and is not guaranteed. You can use attributes to force inline substitution to always or never be attempted.

Most intrinsic functions in LLVM boil away to nothing during the compilation pipeline. It’s perhaps more flexible in a compiler IR to call an intrinsic function than it is to add more and more new instructions to the IR.

The cost model uses heuristics to make such decisions. You can use function attributes (or command line optimization level flags) to change the behavior as well.

1 Like