5

I am using Clang as a library to generate some LLVM IR modules.

Here is the source-code of the module:

inline int getSevenInline() { return 7; } int getSeven() { return getSevenInline(); } 

I would expect the LLVM IR module to contain one function, getSeven, that returns 7.

Here is the LLVM IR that my program generates:

; ModuleID = './test.cpp' source_filename = "./test.cpp" target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-apple-macosx10.12.0" ; Function Attrs: noinline ssp uwtable define i32 @_Z8getSevenv() #0 { entry: %call = call i32 @_Z14getSevenInlinev() ret i32 %call } declare i32 @_Z14getSevenInlinev() #1 attributes #0 = { noinline ssp uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+fxsr,+mmx,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #1 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cx16,+fxsr,+mmx,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } 

When I try to execute the module, it cannot resolve the symbol for getSevenInline.

The IR seems to be wrong in two ways:

  1. The function getSevenInline should not exist because it should be inlined
  2. Despite not being inlined, getSevenInline has no implementation

What should I configure on my clang::CompilerInstance so that it correctly compiles inline functions?

I am only having problems with inline functions; Non-inline functions work correctly.


Unfortunately I have too much code to post the entire program that generates the IR, but I was hoping someone could point me towards the configuration for this in the Clang source-code.

1
  • 3
    afaik whether or not the compiler inlines a function has little to do with the presence of the keyword inline Commented Jan 27, 2017 at 15:19

2 Answers 2

2

The C++ spec gives the compiler wide latitude to decide when or when not to inline a function. Even if you explicitly declare a function as inline, it's still just a suggestion as far as the compiler is concerned, and it's free to ignore that suggestion if it decides the resulting machine code would be too bloated or inefficient. It also heavily depends on the optimization flags you pass to the compiler and many other implementation-dependent details that are entirely at the discretion of the compiler implementer.

The C++ FAQ has some more details on the topic:

There are several ways to designate that a function is inline, some of which involve the inline keyword, others do not. No matter how you designate a function as inline, it is a request that the compiler is allowed to ignore: the compiler might inline-expand some, all, or none of the places where you call a function designated as inline. (Don’t get discouraged if that seems hopelessly vague. The flexibility of the above is actually a huge advantage: it lets the compiler treat large functions differently from small ones, plus it lets the compiler generate code that is easy to debug if you select the right compiler options.)

What the inline keyword does do is guarantee that you won't get multiple definition errors for a function with the same name. For example, if you have (in myinlines.h):

inline int add(int a, int b) { return a + b; } 

and you include myinlines.h in file1.cpp and file2.cpp, you won't get linker errors when you try to link together file1.o and file2.o into a final executable, even though they both contain a definition for int add(int, int). CPPReference has some more details:

There may be more than one definition of an inline function in the program as long as each definition appears in a different translation unit and (for non-static inline functions) all definitions are identical. For example, an inline function may be defined in a header file that is #include'd in multiple source files.

Sign up to request clarification or add additional context in comments.

2 Comments

Thanks for the background, but this doesn't really answer my question. Clang should either actually inline the function or not inline it but add an implementation. In my code it is neither inlining nor generating an implementation.
@sdgfsdh, fair enough. I'm not a Clang expert so I'll defer to someone else there.
1

I managed to get this working, but I won't pretend I know exactly why it works:

for (auto declGroup : declGroups) { codeGenerator->HandleTopLevelDecl(declGroup); } // For some reason this triggers the code generation for inline functions codeGenerator->HandleTranslationUnit(compilerInstance.getASTContext()); 

I think it is about deferred decls; HandleTranslationUnit tells the CodeGenerator that it should finish compilation.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.