 
            relevant bug reports: - https://bugs.winehq.org/show_bug.cgi?id=41712 - https://bugs.winehq.org/show_bug.cgi?id=51051
-- v15: tools: add LTO quirks makedep: support skipping/disabling LTO configure: enable building Wine with LTO makedep: support LTO builds winegcc: support LTO builds winebuild: support LTO builds tools: helper functions for LTO builds ntdll: add attribute "used" to a few symbols that shouldn't be discarded loader: add attribute "used" to a few symbols that shouldn't be discarded
 
            From: Konstantin Demin rockdrilla@gmail.com
these changes improve building Wine with LTO.
Signed-off-by: Konstantin Demin rockdrilla@gmail.com --- loader/preloader.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-)
diff --git a/loader/preloader.c b/loader/preloader.c index ce82a9f296f..12d76546c79 100644 --- a/loader/preloader.c +++ b/loader/preloader.c @@ -181,6 +181,7 @@ void __bb_init_func(void) { return; }
static int thread_data[256];
+__attribute__((used)) struct { /* this is the kernel modify_ldt struct */ @@ -335,7 +336,7 @@ static inline int wld_prctl( int code, long arg )
#elif defined(__x86_64__)
-void *thread_data[256]; +void __attribute__((used)) *thread_data[256];
/* * The _start function is the entry and exit point of this program @@ -424,7 +425,7 @@ SYSCALL_NOERR( wld_getegid, 108 /* SYS_getegid */ );
#elif defined(__aarch64__)
-void *thread_data[256]; +void __attribute__((used)) *thread_data[256];
/* * The _start function is the entry and exit point of this program @@ -531,7 +532,7 @@ SYSCALL_NOERR( wld_getegid, 177 /* SYS_getegid */ );
#elif defined(__arm__)
-void *thread_data[256]; +void __attribute__((used)) *thread_data[256];
/* * The _start function is the entry and exit point of this program @@ -630,7 +631,7 @@ SYSCALL_NOERR( wld_geteuid, 49 /* SYS_geteuid */ ); gid_t wld_getegid(void); SYSCALL_NOERR( wld_getegid, 50 /* SYS_getegid */ );
-unsigned long long __aeabi_uidivmod(unsigned int num, unsigned int den) +unsigned long long __attribute__((used)) __aeabi_uidivmod(unsigned int num, unsigned int den) { unsigned int bit = 1; unsigned int quota = 0; @@ -1397,7 +1398,7 @@ static void set_process_name( int argc, char *argv[] ) * Load the binary and then its ELF interpreter. * Note, we assume that the binary is a dynamically linked ELF shared object. */ -void* wld_start( void **stack ) +void* __attribute__((used)) wld_start( void **stack ) { long i, *pargc; char **argv, **p;
 
            From: Konstantin Demin rockdrilla@gmail.com
these changes improve building Wine with LTO.
Signed-off-by: Konstantin Demin rockdrilla@gmail.com --- dlls/ntdll/unix/loader.c | 8 ++++---- dlls/ntdll/unix/signal_arm.c | 2 +- dlls/ntdll/unix/signal_arm64.c | 4 ++-- dlls/ntdll/unix/signal_i386.c | 2 +- dlls/ntdll/unix/signal_x86_64.c | 2 +- dlls/ntdll/unix/unix_private.h | 2 +- 6 files changed, 10 insertions(+), 10 deletions(-)
diff --git a/dlls/ntdll/unix/loader.c b/dlls/ntdll/unix/loader.c index 3208499a59b..bb022a6eb14 100644 --- a/dlls/ntdll/unix/loader.c +++ b/dlls/ntdll/unix/loader.c @@ -629,7 +629,7 @@ BOOLEAN KeAddSystemServiceTable( ULONG_PTR *funcs, ULONG_PTR *counters, ULONG li return TRUE; }
-void trace_syscall( UINT id, ULONG_PTR *args, ULONG len ) +void __attribute__((used)) trace_syscall( UINT id, ULONG_PTR *args, ULONG len ) { UINT idx = (id >> 12) & 3, num = id & 0xfff; const char **names = syscall_names[idx]; @@ -648,7 +648,7 @@ void trace_syscall( UINT id, ULONG_PTR *args, ULONG len ) TRACE_(syscall)( ")\n" ); }
-void trace_sysret( UINT id, ULONG_PTR retval ) +void __attribute__((used)) trace_sysret( UINT id, ULONG_PTR retval ) { UINT idx = (id >> 12) & 3, num = id & 0xfff; const char **names = syscall_names[idx]; @@ -659,7 +659,7 @@ void trace_sysret( UINT id, ULONG_PTR retval ) TRACE_(syscall)( "\1SysRet %04x() retval=%08lx\n", id, retval ); }
-void trace_usercall( UINT id, ULONG_PTR *args, ULONG len ) +void __attribute__((used)) trace_usercall( UINT id, ULONG_PTR *args, ULONG len ) { if (usercall_names) TRACE_(syscall)("\1UserCall %s(%p,%u)\n", usercall_names[id], args, len ); @@ -667,7 +667,7 @@ void trace_usercall( UINT id, ULONG_PTR *args, ULONG len ) TRACE_(syscall)("\1UserCall %04x(%p,%u)\n", id, args, len ); }
-void trace_userret( void *ret_ptr, ULONG len, NTSTATUS status, UINT id ) +void __attribute__((used)) trace_userret( void *ret_ptr, ULONG len, NTSTATUS status, UINT id ) { if (usercall_names) TRACE_(syscall)("\1UserRet %s(%p,%u) retval=%08x\n", usercall_names[id], ret_ptr, len, status ); diff --git a/dlls/ntdll/unix/signal_arm.c b/dlls/ntdll/unix/signal_arm.c index 4af215e7fc1..532b0e9cb49 100644 --- a/dlls/ntdll/unix/signal_arm.c +++ b/dlls/ntdll/unix/signal_arm.c @@ -1112,7 +1112,7 @@ void signal_init_process(void) /*********************************************************************** * init_syscall_frame */ -void init_syscall_frame( LPTHREAD_START_ROUTINE entry, void *arg, BOOL suspend, TEB *teb ) +void __attribute__((used)) init_syscall_frame( LPTHREAD_START_ROUTINE entry, void *arg, BOOL suspend, TEB *teb ) { struct syscall_frame *frame = ((struct ntdll_thread_data *)&teb->GdiTebBatch)->syscall_frame; CONTEXT *ctx, context = { CONTEXT_ALL }; diff --git a/dlls/ntdll/unix/signal_arm64.c b/dlls/ntdll/unix/signal_arm64.c index 2e7cce6e2e1..2a4c5d5a4e1 100644 --- a/dlls/ntdll/unix/signal_arm64.c +++ b/dlls/ntdll/unix/signal_arm64.c @@ -1430,7 +1430,7 @@ void signal_init_process(void) /*********************************************************************** * syscall_dispatcher_return_slowpath */ -void syscall_dispatcher_return_slowpath(void) +void __attribute__((used)) syscall_dispatcher_return_slowpath(void) { raise( SIGUSR2 ); } @@ -1438,7 +1438,7 @@ void syscall_dispatcher_return_slowpath(void) /*********************************************************************** * init_syscall_frame */ -void init_syscall_frame( LPTHREAD_START_ROUTINE entry, void *arg, BOOL suspend, TEB *teb ) +void __attribute__((used)) init_syscall_frame( LPTHREAD_START_ROUTINE entry, void *arg, BOOL suspend, TEB *teb ) { struct syscall_frame *frame = ((struct ntdll_thread_data *)&teb->GdiTebBatch)->syscall_frame; CONTEXT *ctx, context = { CONTEXT_ALL }; diff --git a/dlls/ntdll/unix/signal_i386.c b/dlls/ntdll/unix/signal_i386.c index d4fac225430..3a9cf6e9df2 100644 --- a/dlls/ntdll/unix/signal_i386.c +++ b/dlls/ntdll/unix/signal_i386.c @@ -2434,7 +2434,7 @@ void signal_init_process(void) /*********************************************************************** * init_syscall_frame */ -void init_syscall_frame( LPTHREAD_START_ROUTINE entry, void *arg, BOOL suspend, TEB *teb ) +void __attribute__((used)) init_syscall_frame( LPTHREAD_START_ROUTINE entry, void *arg, BOOL suspend, TEB *teb ) { struct x86_thread_data *thread_data = (struct x86_thread_data *)&teb->GdiTebBatch; struct syscall_frame *frame = ((struct ntdll_thread_data *)&teb->GdiTebBatch)->syscall_frame; diff --git a/dlls/ntdll/unix/signal_x86_64.c b/dlls/ntdll/unix/signal_x86_64.c index df231c3f995..4e38307c4b6 100644 --- a/dlls/ntdll/unix/signal_x86_64.c +++ b/dlls/ntdll/unix/signal_x86_64.c @@ -2746,7 +2746,7 @@ void signal_init_process(void) /*********************************************************************** * init_syscall_frame */ -void init_syscall_frame( LPTHREAD_START_ROUTINE entry, void *arg, BOOL suspend, TEB *teb ) +void __attribute__((used)) init_syscall_frame( LPTHREAD_START_ROUTINE entry, void *arg, BOOL suspend, TEB *teb ) { struct amd64_thread_data *thread_data = (struct amd64_thread_data *)&teb->GdiTebBatch; struct syscall_frame *frame = ((struct ntdll_thread_data *)&teb->GdiTebBatch)->syscall_frame; diff --git a/dlls/ntdll/unix/unix_private.h b/dlls/ntdll/unix/unix_private.h index 501eddb1fa3..02b946e612c 100644 --- a/dlls/ntdll/unix/unix_private.h +++ b/dlls/ntdll/unix/unix_private.h @@ -263,7 +263,7 @@ extern void set_process_instrumentation_callback( void *callback ); extern void *get_cpu_area( USHORT machine ); extern void set_thread_id( TEB *teb, DWORD pid, DWORD tid ); extern NTSTATUS init_thread_stack( TEB *teb, ULONG_PTR limit, SIZE_T reserve_size, SIZE_T commit_size ); -extern void DECLSPEC_NORETURN abort_thread( int status ); +extern void DECLSPEC_NORETURN __attribute__((used)) abort_thread( int status ); extern void DECLSPEC_NORETURN abort_process( int status ); extern void DECLSPEC_NORETURN exit_process( int status ); extern void wait_suspend( CONTEXT *context );
 
            From: Konstantin Demin rockdrilla@gmail.com
Signed-off-by: Konstantin Demin rockdrilla@gmail.com --- tools/tools.h | 103 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 103 insertions(+)
diff --git a/tools/tools.h b/tools/tools.h index 0f48ad0826c..363ffd77086 100644 --- a/tools/tools.h +++ b/tools/tools.h @@ -955,4 +955,107 @@ static inline struct strarray parse_options( int argc, char **argv, const char * #undef OPT_ERR }
+static inline void append_lto_flags( struct strarray *args, int with_lto, int prefer_env ) +{ + if (with_lto < 0) return; + + if (prefer_env > 0) + { + const char *flags = NULL; + + if (with_lto > 0) + { + static int _init_lto = 0; + static const char* _env_lto = NULL; + + if (!_init_lto) + { + _env_lto = getenv( "WINE_LTO_FLAGS" ); + if (_env_lto) + _env_lto = (_env_lto[0]) ? xstrdup( _env_lto ) : NULL; + _init_lto = 1; + } + flags = _env_lto; + } + else + { + static int _init_lto_skip = 0; + static const char* _env_lto_skip = NULL; + + if (!_init_lto_skip) + { + _env_lto_skip = getenv( "WINE_LTO_SKIP_FLAGS" ); + if (_env_lto_skip) + _env_lto_skip = (_env_lto_skip[0]) ? xstrdup( _env_lto_skip ) : NULL; + _init_lto_skip = 1; + } + flags = _env_lto_skip; + } + + if (flags) { + strarray_addall( args, strarray_fromstring( flags, " " ) ); + return; + } + } + + strarray_add( args, (with_lto > 0) ? "-flto" : "-fno-lto" ); +} + +static inline int var_to_bool( const char *var ) +{ + if (!var) return 0; + if (!( var[0] )) return 0; + + switch (var[0]) + { + /* "1" */ + case '1': + if (!var[1]) return 1; + break; + + /* "[Tt]", "[Tt][Rr][Uu][Ee]" */ + case 'T': /* -fallthrough */ + case 't': + if (!var[1]) return 1; + + if (strlen( var ) != 4) break; + if ((var[1] != 'R') && (var[1] != 'r')) break; + if ((var[2] != 'U') && (var[2] != 'u')) break; + if ((var[3] != 'E') && (var[3] != 'e')) break; + return 1; + + break; + + /* "[Yy]", "[Yy][Ee][Ss]" */ + case 'Y': /* -fallthrough */ + case 'y': + if (!var[1]) return 1; + + if (strlen( var ) != 3) break; + if ((var[1] != 'E') && (var[1] != 'e')) break; + if ((var[2] != 'S') && (var[2] != 's')) break; + return 1; + + break; + } + + return 0; +} + +static inline int adjust_verbose_lto( int with_lto, int verbose ) +{ + const char* lto_debug = NULL; + + if (with_lto < 1) return verbose; + if (verbose > 0) return verbose; + + /* no need to cache/preserve environment variable + because method is to be called once. */ + + lto_debug = getenv( "WINE_LTO_DEBUG" ); + if (!lto_debug) return verbose; + + return var_to_bool( lto_debug ); +} + #endif /* __WINE_TOOLS_H */
 
            From: Konstantin Demin rockdrilla@gmail.com
Signed-off-by: Konstantin Demin rockdrilla@gmail.com --- tools/winebuild/build.h | 1 + tools/winebuild/import.c | 47 +++++++++++++++++++++++++++++++++++++--- tools/winebuild/main.c | 6 ++++- tools/winebuild/utils.c | 33 ++++++++++++++++++++++++++-- 4 files changed, 81 insertions(+), 6 deletions(-)
diff --git a/tools/winebuild/build.h b/tools/winebuild/build.h index e35bcc6ddb0..a059691e1bb 100644 --- a/tools/winebuild/build.h +++ b/tools/winebuild/build.h @@ -362,6 +362,7 @@ extern void put_pword( unsigned int val );
extern int current_line; extern int UsePIC; +extern int UseLTO; extern int nb_errors; extern int display_warnings; extern int kill_at; diff --git a/tools/winebuild/import.c b/tools/winebuild/import.c index d4389a89cab..c5a9f4b3e63 100644 --- a/tools/winebuild/import.c +++ b/tools/winebuild/import.c @@ -1237,11 +1237,31 @@ static const char *get_target_machine(void) /* build a library from the current asm files and any additional object files in argv */ void output_static_lib( const char *output_name, struct strarray files, int create ) { - struct strarray args; + struct strarray args = empty_strarray;
if (!create || target.platform != PLATFORM_WINDOWS) { - args = find_tool( "ar", NULL ); + static int _init_ar = 0; + static const char * _env_ar = NULL; + + if (!_init_ar) + { + if ((_env_ar = getenv( "WINE_AR" ))) + { + /* duplicate string if non-empty; otherwise set to NULL */ + _env_ar = (_env_ar[0]) ? xstrdup( _env_ar ) : NULL; + } + _init_ar = 1; + } + if (_env_ar) + { + const char * _cmd[2] = { _env_ar, NULL }; + args = find_tool( "ar", _cmd ); + } + if (!args.count) + { + args = find_tool( "ar", NULL ); + } strarray_add( &args, create ? "rc" : "r" ); strarray_add( &args, output_name ); } @@ -1259,7 +1279,28 @@ void output_static_lib( const char *output_name, struct strarray files, int crea
if (target.platform != PLATFORM_WINDOWS) { - struct strarray ranlib = find_tool( "ranlib", NULL ); + static int _init_ranlib = 0; + static const char * _env_ranlib = NULL; + struct strarray ranlib = empty_strarray; + + if (!_init_ranlib) + { + if ((_env_ranlib = getenv( "WINE_RANLIB" ))) + { + /* duplicate string if non-empty; otherwise set to NULL */ + _env_ranlib = (_env_ranlib[0]) ? xstrdup( _env_ranlib ) : NULL; + } + _init_ranlib = 1; + } + if (_env_ranlib) + { + const char * _cmd[2] = { _env_ranlib, NULL }; + ranlib = find_tool( "ranlib", _cmd ); + } + if (!ranlib.count) + { + ranlib = find_tool( "ranlib", NULL ); + } strarray_add( &ranlib, output_name ); spawn( ranlib ); } diff --git a/tools/winebuild/main.c b/tools/winebuild/main.c index 33d871383ae..94dd10dea3a 100644 --- a/tools/winebuild/main.c +++ b/tools/winebuild/main.c @@ -34,6 +34,7 @@ #include "build.h"
int UsePIC = 0; +int UseLTO = -1; int nb_errors = 0; int display_warnings = 0; int native_arch = -1; @@ -187,7 +188,7 @@ static const char usage_str[] = " -e, --entry=FUNC Set the DLL entry point function (default: DllMain)\n" " -E, --export=FILE Export the symbols defined in the .spec or .def file\n" " --external-symbols Allow linking to external symbols\n" -" -f FLAGS Compiler flags (-fPIC and -fasynchronous-unwind-tables are supported)\n" +" -f FLAGS Compiler flags (-fPIC, -fasynchronous-unwind-tables and -flto are supported)\n" " -F, --filename=DLLFILE Set the DLL filename (default: from input file name)\n" " --fake-module Create a fake binary module\n" " -h, --help Display this help message\n" @@ -412,6 +413,8 @@ static void option_callback( int optc, char *optarg ) if (!strcmp( optarg, "PIC") || !strcmp( optarg, "pic")) UsePIC = 1; else if (!strcmp( optarg, "asynchronous-unwind-tables")) unwind_tables = 1; else if (!strcmp( optarg, "no-asynchronous-unwind-tables")) unwind_tables = 0; + else if (!strcmp( optarg, "lto" )) UseLTO = 1; + else if (!strcmp( optarg, "no-lto" )) UseLTO = 0; /* ignore all other flags */ break; case 'h': @@ -583,6 +586,7 @@ int main(int argc, char **argv) if (is_pe()) unwind_tables = 1;
files = parse_options( argc, argv, short_options, long_options, 0, option_callback ); + verbose = adjust_verbose_lto( UseLTO, verbose );
atexit( cleanup ); /* make sure we remove the output file on exit */
diff --git a/tools/winebuild/utils.c b/tools/winebuild/utils.c index 5dde2825fd5..5d91f3a9a51 100644 --- a/tools/winebuild/utils.c +++ b/tools/winebuild/utils.c @@ -120,6 +120,12 @@ int output( const char *format, ... ) return ret; }
+/* un-inline append_lto_flags() */ +static void append_lto_flags_winebuild( struct strarray *args, int with_lto, int prefer_env ) +{ + return append_lto_flags( args, with_lto, prefer_env); +} + static struct strarray get_tools_path(void) { static int done; @@ -302,6 +308,8 @@ struct strarray get_as_command(void)
if (using_cc) { + /* disable LTO for assembly */ + append_lto_flags_winebuild( &args, (UseLTO >= 0) ? 0 : -1, 1 /* prefer flags from env */ ); strarray_add( &args, "-xassembler" ); strarray_add( &args, "-c" ); if (force_pointer_size) @@ -343,6 +351,7 @@ struct strarray get_ld_command(void) }
strarray_addall( &args, ld_command ); + append_lto_flags_winebuild( &args, UseLTO, 1 /* prefer flags from env */ );
if (force_pointer_size) { @@ -374,8 +383,28 @@ const char *get_nm_command(void) { if (!nm_command.count) { - static const char * const commands[] = { "nm", "gnm", NULL }; - nm_command = find_tool( "nm", commands ); + static int _init_nm = 0; + static const char * _env_nm = NULL; + + if (!_init_nm) + { + if ((_env_nm = getenv( "WINE_NM" ))) + { + /* duplicate string if non-empty; otherwise set to NULL */ + _env_nm = (_env_nm[0]) ? xstrdup( _env_nm ) : NULL; + } + _init_nm = 1; + } + if (_env_nm) + { + const char * _cmd[2] = { _env_nm, NULL }; + nm_command = find_tool( "nm", _cmd ); + } + if (!nm_command.count) + { + static const char * const commands[] = { "nm", "gnm", NULL }; + nm_command = find_tool( "nm", commands ); + } } if (nm_command.count > 1) fatal_error( "multiple arguments in nm command not supported yet\n" );
 
            From: Konstantin Demin rockdrilla@gmail.com
Signed-off-by: Konstantin Demin rockdrilla@gmail.com --- tools/winegcc/winegcc.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+)
diff --git a/tools/winegcc/winegcc.c b/tools/winegcc/winegcc.c index 7322feaaf80..8d851a9973c 100644 --- a/tools/winegcc/winegcc.c +++ b/tools/winegcc/winegcc.c @@ -176,6 +176,7 @@ static bool is_win16_app; static bool is_arm64x; static bool use_msvcrt; static bool use_pic = true; +static int use_lto = -1; /* tristate */ static bool use_build_id; static bool nostdinc; static bool nostdlib; @@ -349,6 +350,12 @@ static enum file_type get_lib_type(struct strarray path, const char *library, ch return file_na; }
+/* un-inline append_lto_flags() */ +static void append_lto_flags_winegcc( struct strarray *args, int with_lto, int prefer_env ) +{ + return append_lto_flags( args, with_lto, prefer_env); +} + static const char *find_binary( const char *name ) { char *file_name, *args; @@ -498,6 +505,7 @@ static struct strarray get_link_args( const char *output_name ) struct strarray flags = empty_strarray;
strarray_addall( &link_args, linker_args ); + append_lto_flags_winegcc( &link_args, use_lto, 1 /* prefer flags from env */ );
if (verbose > 1) strarray_add( &flags, "-v" );
@@ -891,6 +899,11 @@ static void compile( struct strarray files, const char *output_name, int compile
if (!is_pe) strarray_addall( &comp_args, get_compat_defines( gcc_defs ));
+ if ((processor == proc_cc) || (processor == proc_cxx)) + { + append_lto_flags_winegcc( &comp_args, use_lto, 1 /* prefer flags from env */ ); + } + strarray_add(&comp_args, "-D__WINE__");
/* options we handle explicitly */ @@ -975,6 +988,7 @@ static struct strarray get_winebuild_args( const char *target ) strarray_add( &spec_args, binary ); if (verbose) strarray_add( &spec_args, "-v" ); if (keep_generated) strarray_add( &spec_args, "--save-temps" ); + append_lto_flags_winegcc( &spec_args, use_lto, 0 /* generic LTO flags */ ); if (target) { strarray_add( &spec_args, "--target" ); @@ -1748,6 +1762,10 @@ int main(int argc, char **argv) use_pic = true; else if (!strcmp("-fno-PIC", args.str[i]) || !strcmp("-fno-pic", args.str[i])) use_pic = false; + else if (!strcmp( "-flto", args.str[i] )) + use_lto = 1; + else if (!strcmp( "-fno-lto", args.str[i] )) + use_lto = 0; break; case 'i': if (!strcmp( "-isysroot", args.str[i] )) isysroot = args.str[i + 1]; @@ -2033,6 +2051,7 @@ int main(int argc, char **argv) strarray_add( &file_args, args.str[i] ); } } + verbose = adjust_verbose_lto( use_lto, verbose );
if (target_alias && !parse_target( target_alias, &target )) error( "Invalid target specification '%s'\n", target_alias );
 
            From: Konstantin Demin rockdrilla@gmail.com
Signed-off-by: Konstantin Demin rockdrilla@gmail.com --- tools/makedep.c | 55 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+)
diff --git a/tools/makedep.c b/tools/makedep.c index 6e39ee37b4f..d7b2cfe53fe 100644 --- a/tools/makedep.c +++ b/tools/makedep.c @@ -258,6 +258,7 @@ static const char *temp_file_name; static char cwd[PATH_MAX]; static int compile_commands_mode; static int silent_rules; +static int with_lto = 0; static int input_line; static int output_column; static FILE *output_file; @@ -286,6 +287,10 @@ static void fatal_perror( const char *msg, ... ) __attribute__ ((__format__ (__p static void output( const char *format, ... ) __attribute__ ((__format__ (__printf__, 1, 2))); static char *strmake( const char* fmt, ... ) __attribute__ ((__format__ (__printf__, 1, 2)));
+static void output_lto_flags_source( struct makefile *make, struct incl_file *source, unsigned int arch, + int prefer_env ); +static void output_lto_flags_target( struct makefile *make, unsigned int arch, int prefer_env ); + /******************************************************************* * fatal_error */ @@ -2561,6 +2566,7 @@ static void output_winegcc_command( struct makefile *make, unsigned int arch ) output_filename( "--winebuild" ); output_filename( winebuild ); } + output_lto_flags_target( make, arch, 0 /* generic LTO flags */ ); output_filenames( target_flags[arch] ); if (native_archs[arch] && !make->disabled[native_archs[arch]]) output_filenames( hybrid_target_flags[arch] ); @@ -3383,6 +3389,7 @@ static void output_source_one_arch( struct makefile *make, struct incl_file *sou output_filenames( defines ); output_filenames( cflags ); output_filename( var_cflags ); + output_lto_flags_source( make, source, arch, 1 /* prefer flags from env */ ); output( "\n" );
if (make->testdll && strendswith( source->name, ".c" ) && @@ -3653,6 +3660,7 @@ static void output_import_lib( struct makefile *make, unsigned int arch ) output( "\n" ); output( "\t%s%s -w --implib -o $@", cmd_prefix( "BUILD" ), winebuild ); if (!delay_load_flags[arch]) output_filename( "--without-dlltool" ); + output_lto_flags_target( make, arch, 0 /* generic LTO flags */ ); output_filenames( target_flags[hybrid_arch ? hybrid_arch : arch] ); if (make->is_win16) output_filename( "-m16" ); if (hybrid_arch) output_filenames( hybrid_target_flags[hybrid_arch] ); @@ -3686,6 +3694,7 @@ static void output_unix_lib( struct makefile *make ) output( "\n" ); output( "\t%s$(CC) -o $@", cmd_prefix( "CCLD" )); output_filenames( get_expanded_make_var_array( make, "UNIXLDFLAGS" )); + output_lto_flags_target( make, arch, 1 /* prefer flags from env */ ); output_filenames_obj_dir( make, make->unixobj_files ); output_filenames( unix_libs ); output_filename( "$(LDFLAGS)" ); @@ -3713,6 +3722,7 @@ static void output_static_lib( struct makefile *make, unsigned int arch ) output( "\n" ); output( "\t%s%s -w --staticlib -o $@", cmd_prefix( "BUILD" ), winebuild ); output_filenames( target_flags[hybrid_arch ? hybrid_arch : arch] ); + output_lto_flags_target( make, arch, 0 /* generic LTO flags */ ); output_filenames_obj_dir( make, make->object_files[arch] ); if (hybrid_arch) output_filenames_obj_dir( make, make->object_files[hybrid_arch] ); if (!arch) output_filenames_obj_dir( make, make->unixobj_files ); @@ -3833,6 +3843,7 @@ static void output_programs( struct makefile *make ) output_filenames( deps ); output( "\n" ); output( "\t%s$(CC) -o $@", cmd_prefix( "CCLD" )); + output_lto_flags_target( make, arch, 1 /* prefer flags from env */ ); output_filenames_obj_dir( make, objs ); output_filenames( all_libs ); output_filename( "$(LDFLAGS)" ); @@ -4667,6 +4678,9 @@ static int parse_option( const char *opt ) case 'S': silent_rules = 1; break; + case 'L': + with_lto = 1; + break; default: fprintf( stderr, "Unknown option '%s'\n%s", opt, Usage ); exit(1); @@ -4686,6 +4700,47 @@ static unsigned int find_pe_arch( const char *arch ) }
+/******************************************************************* + * output_lto_flags + */ +static void output_lto_flags( int use_lto, int prefer_env ) +{ + struct strarray lto_flags = empty_strarray; + append_lto_flags( <o_flags, use_lto, prefer_env ); + output_filenames( lto_flags ); +} + + +/******************************************************************* + * output_lto_flags_source + */ +static void output_lto_flags_source( struct makefile *make, struct incl_file *source, unsigned int arch, + int prefer_env ) +{ + (void) arch; /* mark as used */ + + if (!with_lto) return; + if (!make) return; + if (!source) return; + + output_lto_flags( with_lto, prefer_env ); +} + + +/******************************************************************* + * output_lto_flags_target + */ +static void output_lto_flags_target( struct makefile *make, unsigned int arch, int prefer_env ) +{ + (void) arch; /* mark as used */ + + if (!with_lto) return; + if (!make) return; + + output_lto_flags( with_lto, prefer_env ); +} + + /******************************************************************* * main */
 
            From: Konstantin Demin rockdrilla@gmail.com
Signed-off-by: Konstantin Demin rockdrilla@gmail.com --- configure | 19 +++++++++++++++++++ configure.ac | 12 ++++++++++++ 2 files changed, 31 insertions(+)
diff --git a/configure b/configure index 44e5aa5f907..aabaf8341b1 100755 --- a/configure +++ b/configure @@ -922,6 +922,7 @@ enable_maintainer_mode enable_sast enable_silent_rules enable_werror +enable_lto with_alsa with_capi with_coreaudio @@ -2534,6 +2535,7 @@ Optional Features: Clang --enable-silent-rules use silent build rules (override: "make V=1") --enable-werror treat compilation warnings as errors + --enable-lto build with LTO (EXPERIMENTAL) --disable-largefile omit support for large files --disable-year2038 don't support timestamps after 2038
@@ -4353,6 +4355,12 @@ then : enableval=$enable_werror; fi
+# Check whether --enable-lto was given. +if test ${enable_lto+y} +then : + enableval=$enable_lto; +fi +
# Check whether --with-alsa was given. @@ -7421,6 +7429,11 @@ do esac done
+if test "x$enable_lto" = xyes +then + as_fn_append EXTRACFLAGS " -D__WINE_LTO_BUILD" +fi + for wine_arch in $cross_archs $extra_arch do case $wine_arch in @@ -7719,6 +7732,11 @@ fi eval LDFLAGS=$${wine_arch}_LDFLAGS eval "${wine_arch}_EXTRACFLAGS="-D__WINE_PE_BUILD -Wall""
+ if test "x$enable_lto" = xyes + then + as_fn_append ${wine_arch}_EXTRACFLAGS " -D__WINE_LTO_BUILD" + fi + target="" set x $CC shift @@ -22154,6 +22172,7 @@ printf %s "creating Makefile rules..." >&6
makedep_flags=" -C" test "x$enable_silent_rules" = xyes && makedep_flags="$makedep_flags -S" +test "x$enable_lto" = xyes && makedep_flags="$makedep_flags -L"
wine_srcdir= test "$srcdir" = . || wine_srcdir="$srcdir/" diff --git a/configure.ac b/configure.ac index 51572bdae66..dcf4e777bf2 100644 --- a/configure.ac +++ b/configure.ac @@ -24,6 +24,7 @@ AC_ARG_ENABLE(maintainer-mode, AS_HELP_STRING([--enable-maintainer-mode],[enable AC_ARG_ENABLE(sast, AS_HELP_STRING([--enable-sast],[enable static application security testing using Clang])) AC_ARG_ENABLE(silent-rules, AS_HELP_STRING([--enable-silent-rules],[use silent build rules (override: "make V=1")])) AC_ARG_ENABLE(werror, AS_HELP_STRING([--enable-werror],[treat compilation warnings as errors])) +AC_ARG_ENABLE(lto, AS_HELP_STRING([--enable-lto],[build with LTO (EXPERIMENTAL)]))
AC_ARG_WITH(alsa, AS_HELP_STRING([--without-alsa],[do not use the Alsa sound support])) AC_ARG_WITH(capi, AS_HELP_STRING([--without-capi],[do not use CAPI (ISDN support)])) @@ -398,6 +399,11 @@ do esac done
+if test "x$enable_lto" = xyes +then + AS_VAR_APPEND([EXTRACFLAGS],[" -D__WINE_LTO_BUILD"]) +fi + for wine_arch in $cross_archs $extra_arch do case $wine_arch in @@ -440,6 +446,11 @@ do AS_VAR_COPY([LDFLAGS],[${wine_arch}_LDFLAGS]) AS_VAR_SET([${wine_arch}_EXTRACFLAGS],["-D__WINE_PE_BUILD -Wall"])
+ if test "x$enable_lto" = xyes + then + AS_VAR_APPEND([${wine_arch}_EXTRACFLAGS],[" -D__WINE_LTO_BUILD"]) + fi + target="" set x $CC shift @@ -2429,6 +2440,7 @@ AS_ECHO_N("creating Makefile rules...") >&AS_MESSAGE_FD
makedep_flags=" -C" test "x$enable_silent_rules" = xyes && makedep_flags="$makedep_flags -S" +test "x$enable_lto" = xyes && makedep_flags="$makedep_flags -L"
wine_srcdir= test "$srcdir" = . || wine_srcdir="$srcdir/"
 
            From: Konstantin Demin rockdrilla@gmail.com
Signed-off-by: Konstantin Demin rockdrilla@gmail.com --- tools/makedep.c | 132 ++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 128 insertions(+), 4 deletions(-)
diff --git a/tools/makedep.c b/tools/makedep.c index d7b2cfe53fe..c63e902fdfe 100644 --- a/tools/makedep.c +++ b/tools/makedep.c @@ -189,6 +189,7 @@ static struct strarray disabled_dirs[MAX_ARCHS]; static unsigned int native_archs[MAX_ARCHS]; static unsigned int hybrid_archs[MAX_ARCHS]; static struct strarray hybrid_target_flags[MAX_ARCHS]; +static struct strarray global_lto_skip[MAX_ARCHS];
struct makefile { @@ -221,6 +222,8 @@ struct makefile int is_win16; int is_exe; int disabled[MAX_ARCHS]; + int lto_skip[MAX_ARCHS]; + struct strarray lto_skip_src[MAX_ARCHS];
/* values generated at output time */ struct strarray in_files; @@ -4628,6 +4631,32 @@ static void load_sources( struct makefile *make )
STRARRAY_FOR_EACH( imp, &make->delayimports ) strarray_add_uniq( &delay_import_libs, get_base_name( imp )); + + if (with_lto) + { + for (arch = 0; arch < archs.count; arch++) + { + (void) memset( &make->lto_skip_src[arch], 0, sizeof(struct strarray) ); + + make->lto_skip[arch] = var_to_bool(get_expanded_arch_var( make, "LTO_SKIP", arch )); + if (make->lto_skip[arch]) + { + /* target is marked as non-LTO for all arches: + break early */ + if (!arch) break; + + /* target is marked as non-LTO for specific arch: + no need to parse source skiplist */ + continue; + } + + value = get_expanded_arch_var_array( make, "LTO_SKIP_SRC", arch ); + STRARRAY_FOR_EACH( src, &value ) + { + strarray_add( &make->lto_skip_src[arch], xstrdup( src )); + } + } + } }
@@ -4711,19 +4740,112 @@ static void output_lto_flags( int use_lto, int prefer_env ) }
+/******************************************************************* + * parse_global_lto_skip_lists + */ +static void parse_global_lto_skip_lists(void) +{ + char *buf = NULL; + FILE *file = NULL; + + for (unsigned int arch = 0; arch < archs.count; arch++) + { + (void) memset( &global_lto_skip[arch], 0, sizeof(struct strarray) ); + + if (arch) + input_file_name = root_src_dir_path(strmake( "tools/lto-skip.%s.list", archs.str[arch] )); + else + input_file_name = root_src_dir_path( "tools/lto-skip.list" ); + + /* skip nonexistent files */ + if (!(file = fopen( input_file_name, "r" ))) + { + input_file_name = NULL; + continue; + } + input_line = 0; + + while ((buf = get_line( file ))) + { + buf = skip_spaces( buf ); + if (!(buf[0])) continue; /* empty line */ + if (buf[0] == '#') continue; /* comment */ + strarray_add( &global_lto_skip[arch], xstrdup( buf )); + } + + (void) fclose( file ); file = NULL; + input_file_name = NULL; + input_line = 0; + } +} + + +/******************************************************************* + * is_lto_enabled_source + */ +static int is_lto_enabled_source( struct makefile *make, struct incl_file *source, unsigned int arch ) +{ + if (!with_lto) return 0; + if (!make) return 0; + if (!source) return 0; + + /* target config: any arch */ + if (strarray_exists( make->lto_skip_src[0], source->name )) + return 0; + + if (arch) + { + /* target config: specific arch */ + if (strarray_exists( make->lto_skip_src[arch], source->name )) + return 0; + + /* global config: specific arch */ + if (strarray_exists( global_lto_skip[arch], source->filename )) + return 0; + } + + /* global config: any arch */ + if (strarray_exists( global_lto_skip[0], source->filename )) + return 0; + + return 1; +} + + +/******************************************************************* + * is_lto_enabled_target + */ +static int is_lto_enabled_target( struct makefile *make, unsigned int arch ) +{ + if (!with_lto) return 0; + if (!make) return 0; + + /* any arch */ + if (make->lto_skip[0]) + return 0; + + /* specific arch */ + if (arch && make->lto_skip[arch]) + return 0; + + return 1; +} + + /******************************************************************* * output_lto_flags_source */ static void output_lto_flags_source( struct makefile *make, struct incl_file *source, unsigned int arch, int prefer_env ) { - (void) arch; /* mark as used */ + int use_lto = 0;
if (!with_lto) return; if (!make) return; if (!source) return;
- output_lto_flags( with_lto, prefer_env ); + use_lto = is_lto_enabled_target( make, arch ) && is_lto_enabled_source( make, source, arch ); + output_lto_flags( use_lto, prefer_env ); }
@@ -4732,12 +4854,13 @@ static void output_lto_flags_source( struct makefile *make, struct incl_file *so */ static void output_lto_flags_target( struct makefile *make, unsigned int arch, int prefer_env ) { - (void) arch; /* mark as used */ + int use_lto = 0;
if (!with_lto) return; if (!make) return;
- output_lto_flags( with_lto, prefer_env ); + use_lto = is_lto_enabled_target( make, arch ); + output_lto_flags( use_lto, prefer_env ); }
@@ -4879,6 +5002,7 @@ int main( int argc, char *argv[] )
for (i = 0; i < subdirs.count; i++) submakes[i] = parse_makefile( subdirs.str[i] );
+ if (with_lto) parse_global_lto_skip_lists(); load_sources( top_makefile ); load_sources( include_makefile ); for (i = 0; i < subdirs.count; i++)
 
            From: Konstantin Demin rockdrilla@gmail.com
these files are hard to fix at this moment.
Signed-off-by: Konstantin Demin rockdrilla@gmail.com --- tools/lto-skip.arm.list | 3 +++ tools/lto-skip.i386.list | 21 +++++++++++++++++++++ tools/lto-skip.list | 2 ++ tools/lto-skip.x86_64.list | 6 ++++++ 4 files changed, 32 insertions(+) create mode 100644 tools/lto-skip.arm.list create mode 100644 tools/lto-skip.i386.list create mode 100644 tools/lto-skip.list create mode 100644 tools/lto-skip.x86_64.list
diff --git a/tools/lto-skip.arm.list b/tools/lto-skip.arm.list new file mode 100644 index 00000000000..8ba52bcae81 --- /dev/null +++ b/tools/lto-skip.arm.list @@ -0,0 +1,3 @@ +# __wine_setjmpex +# __wine_longjmp +dlls/winecrt0/setjmp.c diff --git a/tools/lto-skip.i386.list b/tools/lto-skip.i386.list new file mode 100644 index 00000000000..74c66af6ec4 --- /dev/null +++ b/tools/lto-skip.i386.list @@ -0,0 +1,21 @@ +# __wine_setjmpex +# __wine_longjmp +dlls/winecrt0/setjmp.c + +# RtlUshortByteSwap@4 +# RtlUlongByteSwap@4 +# RtlUlonglongByteSwap@8 +dlls/ntdll/rtl.c + +# InterlockedCompareExchange@12 +# InterlockedExchange@8 +# InterlockedExchangeAdd@8 +# InterlockedIncrement@4 +# InterlockedDecrement@4 +dlls/kernel32/sync.c + +# ExitProcess@4 +dlls/kernel32/process.c + +# _ftol +dlls/msvcrt/math.c diff --git a/tools/lto-skip.list b/tools/lto-skip.list new file mode 100644 index 00000000000..907c7e40788 --- /dev/null +++ b/tools/lto-skip.list @@ -0,0 +1,2 @@ +# _chkstk (i386) / __chkstk (others) +dlls/ntoskrnl.exe/ntoskrnl.c diff --git a/tools/lto-skip.x86_64.list b/tools/lto-skip.x86_64.list new file mode 100644 index 00000000000..1afb09c2b89 --- /dev/null +++ b/tools/lto-skip.x86_64.list @@ -0,0 +1,6 @@ +# __wine_setjmpex +# __wine_longjmp +dlls/winecrt0/setjmp.c + +# GetProcAddress +dlls/kernel32/module.c

