https://gcc.gnu.org/bugzilla/show_bug.cgi?id=106725
Bug ID: 106725 Summary: LTO semantics for __attribute__((leaf)) Product: gcc Version: 12.1.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: c Assignee: unassigned at gcc dot gnu.org Reporter: dthorn at google dot com Target Milestone: --- After implementing GCC's `__attribute__((leaf))` in Clang/LLVM, discussion arose (https://reviews.llvm.org/D131628#3740602) about the semantics of LTO. It seems like merging together object files in LTO might or might notproduce erroneous results, depending on how the term "compilation unit" in the docs are interpreted. A minimal example consists of three source files: main.c: __attribute__((leaf)) void foo(void); int main(void) { foo(); return 0; } foo.c: void bar(void); void foo(void) { bar(); } bar.c: void bar(void) {} If "compilation unit" in the `__attribute__((leaf))` manual means "translation unit", `__attribute__((leaf))` should be valid in main.c, since foo() only calls bar(), which is not in the main.c translation unit. Compile main.c and bar.c to LTO GIMPLE, but compile foo.c without LTO: $ gcc -flto -c main.c bar.c $ gcc -c foo.c The resulting GIMPLE and object files can then be linked together and the LTO trees dumped (Here I'm using -nostdlib just because I built gcc in isolation). I installed a simple printf hack to gimple-pretty-print to print "leaf" if ECF_LEAF is set on a printed call. This gives the following results: $ gcc -fdump-tree-all main.o bar.o foo.o $ cat a.ltrans0.ltrans.252t.optimized <...> int main () { <...> foo (); check 1 1024 leaf <...> } ;; Function bar (bar, funcdef_no=1, decl_uid=4720, cgraph_uid=1, symbol_order=2) <...> >From the above, it appears that the main and bar translation units are merged together by LTO to form a new module without altering the `__attribute__((leaf))` semantics given on the call to foo() in main(). If "compilation unit" is interpreted as "translation unit", this may be incorrect behavior, since any post-LTO passes that are expecting that foo() cannot call bar() (since it's in the same TU) would have their expectations violated. If instead "compilation unit" is interpreted as "LTO unit", `then the above program has undefined behavior, since `__attribute__((leaf)) should never have been used on foo(), since it calls something (bar()) in the same LTO unit as main.c. Accordingly, if "compilation unit" means "translation unit" and this case is incorrect behavior, this bug is to report this. If "compilation unit" instead means "LTO unit", this bug is to request clarification in the GCC manual about the precise behavior in case of LTO. Finally, if "compilation unit" means "translation unit", but GCC has some other internal mechanisms for dealing with this, feel free to close this. Please do report back with those mechanisms though, as we'll have to do something similar in LLVM in that case. It still may be worth altering the docs, given the ambiguity in the term "compilation unit" in the presence of LTO. System: Debian rodete GCC build commands used: ../configure --disable-bootstrap --enable-languages=c,c++,lto \ --prefix=$(realpath ..)/gcc-install make -j96 -l96 all-gcc make install-gcc