https://gcc.gnu.org/bugzilla/show_bug.cgi?id=116333
Bug ID: 116333 Summary: unused result of pure function is not optimized out Product: gcc Version: 12.2.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: lto Assignee: unassigned at gcc dot gnu.org Reporter: pali at kernel dot org Target Milestone: --- If some function is marked with __attribute__((pure)) and return value of this function call is not used at all then gcc could optimize out and completely drop calling this function. This kind of optimization does not happen for example below which uses 3 source files with LTO enabled compilation (so gcc should see inter-file calls). $ cat pure0.c extern int main(); __attribute__((used)) int WinMainCRTStartup(void) { char * argv[] = { "argv0", (char *)0 }; return main(1, argv); } __attribute__((used)) void __main(void) {} $ cat pure1.c #define STARTF_USESHOWWINDOW 0x00000001 #define SW_SHOWDEFAULT 10 typedef struct _STARTUPINFOA { unsigned int cb; char* lpReserved; char* lpDesktop; char* lpTitle; unsigned int dwX; unsigned int dwY; unsigned int dwXSize; unsigned int dwYSize; unsigned int dwXCountChars; unsigned int dwYCountChars; unsigned int dwFillAttribute; unsigned int dwFlags; unsigned short wShowWindow; unsigned short cbReserved2; unsigned char* lpReserved2; void* hStdInput; void* hStdOutput; void* hStdError; } STARTUPINFOA, *LPSTARTUPINFOA; __declspec(dllimport) extern void __stdcall GetStartupInfoA(LPSTARTUPINFOA); __attribute__((pure)) static int _winshowcmd (void) { STARTUPINFOA StartupInfo = {}; GetStartupInfoA(&StartupInfo); if (StartupInfo.dwFlags & STARTF_USESHOWWINDOW) return StartupInfo.wShowWindow; else return SW_SHOWDEFAULT; } extern int __stdcall WinMain(void *, void *, char *, int); extern unsigned char __ImageBase[]; int main() { return WinMain(&__ImageBase, (void *)0, "argv0", _winshowcmd()); } $ cat pure2.c __declspec(dllimport) extern int __stdcall MessageBoxA(void *, const char *, const char *, unsigned int); int __stdcall WinMain(void *instance __attribute__((unused)), void *prev_instance __attribute__((unused)), char *cmdln __attribute__((unused)), int showcmd __attribute__((unused))) { MessageBoxA((void *)0, "Message", "Title", 0); return 0; } Two additional helper files are needed to have example self-contained without any external dependency and also executable on windows: $ cat kernel32.def LIBRARY "kernel32.dll" EXPORTS GetStartupInfoA@4 $ cat user32.def LIBRARY "user32.dll" EXPORTS MessageBoxA@16 Compile these sources as: $ i686-w64-mingw32-dlltool -d kernel32.def -k -l libkernel32.a $ i686-w64-mingw32-dlltool -d user32.def -k -l libuser32.a $ i686-w64-mingw32-gcc pure0.c pure1.c pure2.c -o pure.exe -mwindows -nostartfiles -nostdlib libkernel32.a libuser32.a -Wl,--disable-runtime-pseudo-reloc -W -Wall -Os -flto objdump on compiled pure.exe shows: $ objdump -d pure.exe pure.exe: file format pei-i386 Disassembly of section .text: 00401000 <_WinMainCRTStartup>: 401000: 55 push %ebp 401001: 31 c0 xor %eax,%eax 401003: b9 11 00 00 00 mov $0x11,%ecx 401008: 89 e5 mov %esp,%ebp 40100a: 57 push %edi 40100b: 8d 7d b4 lea -0x4c(%ebp),%edi 40100e: 83 ec 64 sub $0x64,%esp 401011: f3 ab rep stos %eax,%es:(%edi) 401013: 8d 45 b4 lea -0x4c(%ebp),%eax 401016: 89 04 24 mov %eax,(%esp) 401019: ff 15 4c 40 40 00 call *0x40404c 40101f: 31 d2 xor %edx,%edx 401021: 31 c9 xor %ecx,%ecx 401023: 50 push %eax 401024: 89 54 24 0c mov %edx,0xc(%esp) 401028: c7 44 24 08 00 20 40 movl $0x402000,0x8(%esp) 40102f: 00 401030: c7 44 24 04 06 20 40 movl $0x402006,0x4(%esp) 401037: 00 401038: 89 0c 24 mov %ecx,(%esp) 40103b: ff 15 54 40 40 00 call *0x404054 401041: 8b 7d fc mov -0x4(%ebp),%edi 401044: 31 c0 xor %eax,%eax 401046: 83 ec 10 sub $0x10,%esp 401049: c9 leave 40104a: c3 ret 0040104b <___main>: 40104b: c3 ret 0040104c <_GetStartupInfoA@4>: 40104c: ff 25 4c 40 40 00 jmp *0x40404c 401052: 90 nop 401053: 90 nop 00401054 <_MessageBoxA@16>: 401054: ff 25 54 40 40 00 jmp *0x404054 40105a: 90 nop 40105b: 90 nop 0040105c <__CTOR_LIST__>: 40105c: ff (bad) 40105d: ff (bad) 40105e: ff (bad) 40105f: ff 00 incl (%eax) 401061: 00 00 add %al,(%eax) ... 00401064 <__DTOR_LIST__>: 401064: ff (bad) 401065: ff (bad) 401066: ff (bad) 401067: ff 00 incl (%eax) 401069: 00 00 add %al,(%eax) ... Function GetStartupInfoA() was called only in _winshowcmd() function and return value of _winshowcmd() function is unused. So _winshowcmd() function is marked as pure and its return value is unused then gcc could completely optimize out _winshowcmd() function call in LTO build. But objdump on above example shows that gcc had not dropped _winshowcmd() function and it is there. Changing __attribute__((pure)) to __attribute__((const)) for _winshowcmd() function does not help gcc to optimize out the _winshowcmd() function call.