浏览代码

+ symbol liveness wpo information extracted from smartlinked programs
(-OW/-Owsymbolliveness)
+ use symbol liveness information to improve devirtualisation (don't
consider classes created in code that has been dead code stripped).
This requires at least two passes of using wpo (first uses dead code
info to locate classes that are constructed only in dead code,
second pass uses this info to potentially further devirtualise).
I.e.:
1) generate initial liveness and devirtualisation feedback
fpc -FWtt.wpo -OWall tt.pp -Xs- -CX -XX
2) use previously generated feedback, and regenerate new feedback
based on this (i.e., disregard classes created in dead code)
fpc -FWtt-1.wpo -OWall -Fwtt.wo -Owall tt.pp -Xs- -CX -XX
3) use the newly generated feedback (in theory, it is possible
that even more opportunities pop up afterwards; you can
continue until the program does not get smaller anymore)
fpc -Fwtt-1.wpo -Owall tt.pp -CX -XX
* changed all message() to cgmessage() calls so the set codegenerror
* changed static fsectionhandlers field to a regular field called
fwpocomponents
* changed registration of wpocomponents: no longer happens in the
initialization section of their unit, but in the InitWpo routine
(which has been moved from the woinfo to the wpo unit). This way
you can register different classes based on the target/parameters.
+ added static method to twpocomponentbase for checking whether
the command line parameters don't conflict with the requested
optimisations (e.g. generating liveness info requires that
smartlinking is turned on)
+ added static method to twpocomponentbase to request the
section name

git-svn-id: branches/wpo@11892 -

Jonas Maebe 17 年之前
父节点
当前提交
f9031b8078
共有 13 个文件被更改,包括 747 次插入202 次删除
  1. 1 0
      .gitattributes
  2. 2 3
      compiler/compiler.pas
  3. 0 1
      compiler/fpcdefs.inc
  4. 4 3
      compiler/globtype.pas
  5. 22 3
      compiler/msg/errore.msg
  6. 8 2
      compiler/msgidx.inc
  7. 118 107
      compiler/msgtxt.inc
  8. 61 33
      compiler/ncal.pas
  9. 404 0
      compiler/optdead.pas
  10. 7 2
      compiler/optvirt.pas
  11. 38 1
      compiler/wpo.pas
  12. 71 29
      compiler/wpobase.pas
  13. 11 18
      compiler/wpoinfo.pas

+ 1 - 0
.gitattributes

@@ -310,6 +310,7 @@ compiler/oglx.pas svneol=native#text/plain
 compiler/ogmap.pas svneol=native#text/plain
 compiler/ogmap.pas svneol=native#text/plain
 compiler/optbase.pas svneol=native#text/plain
 compiler/optbase.pas svneol=native#text/plain
 compiler/optcse.pas svneol=native#text/plain
 compiler/optcse.pas svneol=native#text/plain
+compiler/optdead.pas svneol=native#text/plain
 compiler/optdfa.pas svneol=native#text/plain
 compiler/optdfa.pas svneol=native#text/plain
 compiler/options.pas svneol=native#text/plain
 compiler/options.pas svneol=native#text/plain
 compiler/optloop.pas svneol=native#text/plain
 compiler/optloop.pas svneol=native#text/plain

+ 2 - 3
compiler/compiler.pas

@@ -40,7 +40,7 @@ uses
 {$ENDIF}
 {$ENDIF}
   verbose,comphook,systems,
   verbose,comphook,systems,
   cutils,cfileutl,cclasses,globals,options,fmodule,parser,symtable,
   cutils,cfileutl,cclasses,globals,options,fmodule,parser,symtable,
-  assemble,link,dbgbase,import,export,tokens,pass_1,wpobase,wpoinfo
+  assemble,link,dbgbase,import,export,tokens,pass_1,wpobase,wpo
   { cpu parameter handling }
   { cpu parameter handling }
   ,cpupara
   ,cpupara
   { procinfo stuff }
   { procinfo stuff }
@@ -117,8 +117,7 @@ function Compile(const cmd:string):longint;
 implementation
 implementation
 
 
 uses
 uses
-  aasmcpu,
-  wpo;
+  aasmcpu;
 
 
 {$if defined(EXTDEBUG) or defined(MEMDEBUG)}
 {$if defined(EXTDEBUG) or defined(MEMDEBUG)}
   {$define SHOWUSEDMEM}
   {$define SHOWUSEDMEM}

+ 0 - 1
compiler/fpcdefs.inc

@@ -4,7 +4,6 @@
 {$goto on}
 {$goto on}
 {$inline on}
 {$inline on}
 {$interfaces corba}
 {$interfaces corba}
-{$static on}
 
 
 {$ifdef win32}
 {$ifdef win32}
   { 256 MB stack }
   { 256 MB stack }

+ 4 - 3
compiler/globtype.pas

@@ -189,7 +189,8 @@ interface
 
 
        { whole program optimizer }
        { whole program optimizer }
        twpoptimizerswitch = (
        twpoptimizerswitch = (
-         cs_wpo_devirtualize_calls,cs_wpo_optimize_vmts
+         cs_wpo_devirtualize_calls,cs_wpo_optimize_vmts,
+         cs_wpo_symbol_liveness
        );
        );
        twpoptimizerswitches = set of twpoptimizerswitch;
        twpoptimizerswitches = set of twpoptimizerswitch;
 
 
@@ -200,8 +201,8 @@ interface
          'REGVAR','UNCERTAIN','SIZE','STACKFRAME',
          'REGVAR','UNCERTAIN','SIZE','STACKFRAME',
          'PEEPHOLE','ASMCSE','LOOPUNROLL','TAILREC','CSE','DFA','STRENGTH'
          'PEEPHOLE','ASMCSE','LOOPUNROLL','TAILREC','CSE','DFA','STRENGTH'
        );
        );
-       WPOptimizerSwitchStr : array [twpoptimizerswitch] of string[11] = (
-         'DEVIRTCALLS','OPTVMTS'
+       WPOptimizerSwitchStr : array [twpoptimizerswitch] of string[14] = (
+         'DEVIRTCALLS','OPTVMTS','SYMBOLLIVENESS'
        );
        );
 
 
        DebugSwitchStr : array[tdebugswitch] of string[9] = ('',
        DebugSwitchStr : array[tdebugswitch] of string[9] = ('',

+ 22 - 3
compiler/msg/errore.msg

@@ -2504,7 +2504,7 @@ option_ppc386_deprecated=11042_W_Use of ppc386.cfg is deprecated, please use fpc
 % \section{Whole program optimisation messages}
 % \section{Whole program optimisation messages}
 % This section lists errors that occur when the compiler is performing
 % This section lists errors that occur when the compiler is performing
 % whole program optimization.
 % whole program optimization.
-wpo_cant_find_file=12000_E_Cannot open whole program optimization feedback file $1
+wpo_cant_find_file=12000_F_Cannot open whole program optimization feedback file $1
 % The compiler cannot open the specified feedback file with whole program optimization information.
 % The compiler cannot open the specified feedback file with whole program optimization information.
 wpo_begin_processing=12001_D_Processing whole program optimization information in wpo feedback file $1
 wpo_begin_processing=12001_D_Processing whole program optimization information in wpo feedback file $1
 % The compiler starts processing whole program optimization information found in the named file.
 % The compiler starts processing whole program optimization information found in the named file.
@@ -2519,7 +2519,7 @@ wpo_no_section_handler=12004_W_No handler registered for whole program optimizat
 wpo_found_section=12005_D_Found whole program optimization section "$1" with information about "$2"
 wpo_found_section=12005_D_Found whole program optimization section "$1" with information about "$2"
 % The compiler encountered a section with whole program optimization information, and according
 % The compiler encountered a section with whole program optimization information, and according
 % to its handler this section contains information usable for the mentioned purpose.
 % to its handler this section contains information usable for the mentioned purpose.
-wpo_no_input_specified=12006_E_The selected whole program optimizations require a previously generated feedback file (use -Fw to specify)
+wpo_no_input_specified=12006_F_The selected whole program optimizations require a previously generated feedback file (use -Fw to specify)
 % The compiler needs information gathered during a previous compilation run to perform the selected
 % The compiler needs information gathered during a previous compilation run to perform the selected
 % whole program optimizations. You can specify the location of the feedback file containing this
 % whole program optimizations. You can specify the location of the feedback file containing this
 % information using the -Fw switch.
 % information using the -Fw switch.
@@ -2527,7 +2527,7 @@ wpo_not_enough_info=12007_E_No collected information necessary to perform "$1" w
 % While you pointed the compiler to a file containing whole program optimization feedback, it
 % While you pointed the compiler to a file containing whole program optimization feedback, it
 % did not contain the information necessary to perform the selected optimizations. You most likely
 % did not contain the information necessary to perform the selected optimizations. You most likely
 % have to recompile the program using the appropate -OWxxx switch.
 % have to recompile the program using the appropate -OWxxx switch.
-wpo_no_output_specified=12008_E_Specify a whole program optimization feedback file to store the generated info in (using -FW)
+wpo_no_output_specified=12008_F_Specify a whole program optimization feedback file to store the generated info in (using -FW)
 % You have to specify the feedback file in which the compiler has to store the whole program optimization
 % You have to specify the feedback file in which the compiler has to store the whole program optimization
 % information that is generated during the compilation run. This can be done using the -FW switch.
 % information that is generated during the compilation run. This can be done using the -FW switch.
 wpo_output_without_info_gen=12009_E_Not generating any whole program optimization information, yet a feedback file was specified (using -FW)
 wpo_output_without_info_gen=12009_E_Not generating any whole program optimization information, yet a feedback file was specified (using -FW)
@@ -2546,6 +2546,25 @@ wpo_duplicate_wpotype=12012_W_Overriding previously read information for "$1" fr
 % information about which virtual methods can be devirtualized). In this case, the information in last encountered
 % information about which virtual methods can be devirtualized). In this case, the information in last encountered
 % seciont is used. Turn on debugging output (-vd) to see for each section what class of information
 % seciont is used. Turn on debugging output (-vd) to see for each section what class of information
 % it provides.
 % it provides.
+wpo_cannot_extract_live_symbol_info_strip=12013_E_Cannot extract symbol liveness information from program when stripping symbols, use -Xs-
+% Certain symbol liveness collectors extract the symbol information from the linked program. If the symbol information
+% is stripped (option -Xs), this is not possible.
+wpo_cannot_extract_live_symbol_info_no_link=12014_E_Cannot extract symbol liveness information from program when when not linking on host
+% Certain symbol liveness collectors extract the symbol information from the linked program. If the program does not
+% get linked by the compiler, this is not possible.
+wpo_cannot_find_symbol_progs=12015_F_Cannot find "$1" or "$2" to extract symbol liveness information from linked program
+% Certain symbol liveness collectors need a helper program to extract the symbol information from the linked program.
+% This helper program is normally 'nm', which is part of the GNU binutils
+wpo_error_reading_symbol_file=12016_E_Error during reading symbol liveness information produced by "$2"
+% An error occurred during the reading of the symbol liveness file that was generated using the 'nm' or 'objdump' program. The reason
+% can be that it was shorter than expected, or that its format was not understood.
+wpo_error_executing_symbol_prog=12017_F_Error executing "$1" (exitcode: $2) to extract symbol information from linked program
+% Certain symbol liveness collectors need a helper program to extract the symbol information from the linked program.
+% The helper program produced the reported error code when it was ran on the linked program.
+wpo_symbol_live_info_needs_smart_linking=12018_E_Collection of symbol liveness information can only help when using smart linking, use -CX -XX
+% Whether or not a symbol is live is determined by looking whether it exists in the final linked program.
+% Without smart linking/dead code stripping, all symbols are always included, regardless of whether they are
+% actually used or not. So in that case all symbols will be seen as live, even if they are not.
 %\end{description}
 %\end{description}
 # EndOfTeX
 # EndOfTeX
 
 

+ 8 - 2
compiler/msgidx.inc

@@ -763,13 +763,19 @@ const
   wpo_input_without_info_use=12010;
   wpo_input_without_info_use=12010;
   wpo_skipping_unnecessary_section=12011;
   wpo_skipping_unnecessary_section=12011;
   wpo_duplicate_wpotype=12012;
   wpo_duplicate_wpotype=12012;
+  wpo_cannot_extract_live_symbol_info_strip=12013;
+  wpo_cannot_extract_live_symbol_info_no_link=12014;
+  wpo_cannot_find_symbol_progs=12015;
+  wpo_error_reading_symbol_file=12016;
+  wpo_error_executing_symbol_prog=12017;
+  wpo_symbol_live_info_needs_smart_linking=12018;
   option_logo=11023;
   option_logo=11023;
   option_info=11024;
   option_info=11024;
   option_help_pages=11025;
   option_help_pages=11025;
 
 
-  MsgTxtSize = 48555;
+  MsgTxtSize = 49108;
 
 
   MsgIdxMax : array[1..20] of longint=(
   MsgIdxMax : array[1..20] of longint=(
     24,87,248,84,65,50,108,22,201,61,
     24,87,248,84,65,50,108,22,201,61,
-    43,13,1,1,1,1,1,1,1,1
+    43,19,1,1,1,1,1,1,1,1
   );
   );

+ 118 - 107
compiler/msgtxt.inc

@@ -1,7 +1,7 @@
 {$ifdef Delphi}
 {$ifdef Delphi}
-const msgtxt : array[0..000202] of string[240]=(
+const msgtxt : array[0..000204] of string[240]=(
 {$else Delphi}
 {$else Delphi}
-const msgtxt : array[0..000202,1..240] of char=(
+const msgtxt : array[0..000204,1..240] of char=(
 {$endif Delphi}
 {$endif Delphi}
   '01000_T_Compiler: $1'#000+
   '01000_T_Compiler: $1'#000+
   '01001_D_Compiler OS: $1'#000+
   '01001_D_Compiler OS: $1'#000+
@@ -836,7 +836,7 @@ const msgtxt : array[0..000202,1..240] of char=(
   '11041_W_Ass','embler output selected "$1" cannot generate debug info, d'+
   '11041_W_Ass','embler output selected "$1" cannot generate debug info, d'+
   'ebugging disabled'#000+
   'ebugging disabled'#000+
   '11042_W_Use of ppc386.cfg is deprecated, please use fpc.cfg instead'#000+
   '11042_W_Use of ppc386.cfg is deprecated, please use fpc.cfg instead'#000+
-  '12000_E_Cannot open whole program optimization feedback file $1'#000+
+  '12000_F_Cannot open whole program optimization feedback file $1'#000+
   '12001_D_Processing whole program ','optimization information in wpo fee'+
   '12001_D_Processing whole program ','optimization information in wpo fee'+
   'dback file $1'#000+
   'dback file $1'#000+
   '12002_D_Finished processing the whole program optimization information'+
   '12002_D_Finished processing the whole program optimization information'+
@@ -847,11 +847,11 @@ const msgtxt : array[0..000202,1..240] of char=(
   ' "$2" at line $1 of wpo feedback file, ignoring'#000+
   ' "$2" at line $1 of wpo feedback file, ignoring'#000+
   '12005_D_Found whole program optimization section "$1" with information'+
   '12005_D_Found whole program optimization section "$1" with information'+
   ' about "$2"'#000+
   ' about "$2"'#000+
-  '12006_E_The selected whole program optimizations require a p','reviousl'+
+  '12006_F_The selected whole program optimizations require a p','reviousl'+
   'y generated feedback file (use -Fw to specify)'#000+
   'y generated feedback file (use -Fw to specify)'#000+
   '12007_E_No collected information necessary to perform "$1" whole progr'+
   '12007_E_No collected information necessary to perform "$1" whole progr'+
   'am optimization found'#000+
   'am optimization found'#000+
-  '12008_E_Specify a whole program optimization feedback file to store th'+
+  '12008_F_Specify a whole program optimization feedback file to store th'+
   'e generated info in (us','ing -FW)'#000+
   'e generated info in (us','ing -FW)'#000+
   '12009_E_Not generating any whole program optimization information, yet'+
   '12009_E_Not generating any whole program optimization information, yet'+
   ' a feedback file was specified (using -FW)'#000+
   ' a feedback file was specified (using -FW)'#000+
@@ -861,18 +861,30 @@ const msgtxt : array[0..000202,1..240] of char=(
   't needed by the requested optimizations'#000+
   't needed by the requested optimizations'#000+
   '12012_W_Overriding previously read information for "$1" from feedback '+
   '12012_W_Overriding previously read information for "$1" from feedback '+
   'input file using information in section "$2"'#000+
   'input file using information in section "$2"'#000+
-  '11023_Free Pascal Compiler',' version $FPCFULLVERSION [$FPCDATE] for $F'+
-  'PCCPU'#010+
+  '12013_E_Cannot extract sym','bol liveness information from program when'+
+  ' stripping symbols, use -Xs-'#000+
+  '12014_E_Cannot extract symbol liveness information from program when w'+
+  'hen not linking on host'#000+
+  '12015_F_Cannot find "$1" or "$2" to extract symbol liveness informatio'+
+  'n fro','m linked program'#000+
+  '12016_E_Error during reading symbol liveness information produced by "'+
+  '$2"'#000+
+  '12017_F_Error executing "$1" (exitcode: $2) to extract symbol informat'+
+  'ion from linked program'#000+
+  '12018_E_Collection of symbol liveness information can o','nly help when'+
+  ' using smart linking, use -CX -XX'#000+
+  '11023_Free Pascal Compiler version $FPCFULLVERSION [$FPCDATE] for $FPC'+
+  'CPU'#010+
   'Copyright (c) 1993-2008 by Florian Klaempfl'#000+
   'Copyright (c) 1993-2008 by Florian Klaempfl'#000+
   '11024_Free Pascal Compiler version $FPCVERSION'#010+
   '11024_Free Pascal Compiler version $FPCVERSION'#010+
   #010+
   #010+
-  'Compiler Date      : $FPCDATE'#010+
+  'Compiler Date      : $FPCDA','TE'#010+
   'Compiler CPU Target: $FPCCPU'#010+
   'Compiler CPU Target: $FPCCPU'#010+
   #010+
   #010+
   'Supported targets:'#010+
   'Supported targets:'#010+
   '  $OSTARGETS'#010+
   '  $OSTARGETS'#010+
   #010+
   #010+
-  'Support','ed CPU instruction sets:'#010+
+  'Supported CPU instruction sets:'#010+
   '  $INSTRUCTIONSETS'#010+
   '  $INSTRUCTIONSETS'#010+
   #010+
   #010+
   'Supported FPU instruction sets:'#010+
   'Supported FPU instruction sets:'#010+
@@ -882,277 +894,276 @@ const msgtxt : array[0..000202,1..240] of char=(
   '  $ABITARGETS'#010+
   '  $ABITARGETS'#010+
   #010+
   #010+
   'Supported Optimizations:'#010+
   'Supported Optimizations:'#010+
-  '  $OPTIMIZATIONS'#010+
+  '  $O','PTIMIZATIONS'#010+
   #010+
   #010+
   'Supported Whole Program Optimizations:'#010+
   'Supported Whole Program Optimizations:'#010+
   '  All'#010+
   '  All'#010+
-  '  $WPOPTIMIZAT','IONS'#010+
+  '  $WPOPTIMIZATIONS'#010+
   #010+
   #010+
   'This program comes under the GNU General Public Licence'#010+
   'This program comes under the GNU General Public Licence'#010+
   'For more information read COPYING.FPC'#010+
   'For more information read COPYING.FPC'#010+
   #010+
   #010+
   'Report bugs,suggestions etc to:'#010+
   'Report bugs,suggestions etc to:'#010+
-  '                 [email protected]'#000+
-  '11025_**0*_Put + after a boolean switch option to enable it, - to disa',
+  '                 [email protected]','rg'#000+
+  '11025_**0*_Put + after a boolean switch option to enable it, - to disa'+
   'ble it'#010+
   'ble it'#010+
   '**1a_The compiler doesn'#039't delete the generated assembler file'#010+
   '**1a_The compiler doesn'#039't delete the generated assembler file'#010+
   '**2al_List sourcecode lines in assembler file'#010+
   '**2al_List sourcecode lines in assembler file'#010+
   '**2an_List node info in assembler file'#010+
   '**2an_List node info in assembler file'#010+
-  '*L2ap_Use pipes instead of creating temporary assembler files'#010+
-  '**2ar_List register allo','cation/release info in assembler file'#010+
+  '*L2ap_Use pip','es instead of creating temporary assembler files'#010+
+  '**2ar_List register allocation/release info in assembler file'#010+
   '**2at_List temp allocation/release info in assembler file'#010+
   '**2at_List temp allocation/release info in assembler file'#010+
   '**1A<x>_Output format:'#010+
   '**1A<x>_Output format:'#010+
   '**2Adefault_Use default assembler'#010+
   '**2Adefault_Use default assembler'#010+
-  '3*2Aas_Assemble using GNU AS'#010+
+  '3*2Aas_Assembl','e using GNU AS'#010+
   '3*2Anasmcoff_COFF (Go32v2) file using Nasm'#010+
   '3*2Anasmcoff_COFF (Go32v2) file using Nasm'#010+
-  '3*2Anasmelf_ELF','32 (Linux) file using Nasm'#010+
+  '3*2Anasmelf_ELF32 (Linux) file using Nasm'#010+
   '3*2Anasmwin32_Win32 object file using Nasm'#010+
   '3*2Anasmwin32_Win32 object file using Nasm'#010+
   '3*2Anasmwdosx_Win32/WDOSX object file using Nasm'#010+
   '3*2Anasmwdosx_Win32/WDOSX object file using Nasm'#010+
   '3*2Awasm_Obj file using Wasm (Watcom)'#010+
   '3*2Awasm_Obj file using Wasm (Watcom)'#010+
-  '3*2Anasmobj_Obj file using Nasm'#010+
+  '3*2Anasmob','j_Obj file using Nasm'#010+
   '3*2Amasm_Obj file using Masm (Microsoft)'#010+
   '3*2Amasm_Obj file using Masm (Microsoft)'#010+
-  '3*2Atasm_O','bj file using Tasm (Borland)'#010+
+  '3*2Atasm_Obj file using Tasm (Borland)'#010+
   '3*2Aelf_ELF (Linux) using internal writer'#010+
   '3*2Aelf_ELF (Linux) using internal writer'#010+
   '3*2Acoff_COFF (Go32v2) using internal writer'#010+
   '3*2Acoff_COFF (Go32v2) using internal writer'#010+
   '3*2Apecoff_PE-COFF (Win32) using internal writer'#010+
   '3*2Apecoff_PE-COFF (Win32) using internal writer'#010+
-  '4*2Aas_Assemble using GNU AS'#010+
+  '4*','2Aas_Assemble using GNU AS'#010+
   '6*2Aas_Unix o-file using GNU AS'#010+
   '6*2Aas_Unix o-file using GNU AS'#010+
-  '6*2Agas_GNU Mo','torola assembler'#010+
+  '6*2Agas_GNU Motorola assembler'#010+
   '6*2Amit_MIT Syntax (old GAS)'#010+
   '6*2Amit_MIT Syntax (old GAS)'#010+
   '6*2Amot_Standard Motorola assembler'#010+
   '6*2Amot_Standard Motorola assembler'#010+
   'A*2Aas_Assemble using GNU AS'#010+
   'A*2Aas_Assemble using GNU AS'#010+
   'P*2Aas_Assemble using GNU AS'#010+
   'P*2Aas_Assemble using GNU AS'#010+
-  'S*2Aas_Assemble using GNU AS'#010+
+  'S*2Aas_Assemble using GNU A','S'#010+
   '**1b_Generate browser info'#010+
   '**1b_Generate browser info'#010+
   '**2bl_Generate local symbol info'#010+
   '**2bl_Generate local symbol info'#010+
-  '**1B_Build ','all modules'#010+
+  '**1B_Build all modules'#010+
   '**1C<x>_Code generation options:'#010+
   '**1C<x>_Code generation options:'#010+
   '**2Ca<x>_Select ABI, see fpc -i for possible values'#010+
   '**2Ca<x>_Select ABI, see fpc -i for possible values'#010+
   '**2Cb_Generate big-endian code'#010+
   '**2Cb_Generate big-endian code'#010+
-  '**2Cc<x>_Set default calling convention to <x>'#010+
+  '**2Cc<x>_Set default calling convention',' to <x>'#010+
   '**2CD_Create also dynamic library (not supported)'#010+
   '**2CD_Create also dynamic library (not supported)'#010+
-  '**2Ce_Compilati','on with emulated floating point opcodes'#010+
+  '**2Ce_Compilation with emulated floating point opcodes'#010+
   '**2Cf<x>_Select fpu instruction set to use, see fpc -i for possible va'+
   '**2Cf<x>_Select fpu instruction set to use, see fpc -i for possible va'+
   'lues'#010+
   'lues'#010+
-  '**2CF<x>_Minimal floating point constant precision (default, 32, 64)'#010+
+  '**2CF<x>_Minimal floating point constant precision (','default, 32, 64)'+
+  #010+
   '**2Cg_Generate PIC code'#010+
   '**2Cg_Generate PIC code'#010+
-  '**2Ch<n>_<n> bytes heap (between',' 1023 and 67107840)'#010+
+  '**2Ch<n>_<n> bytes heap (between 1023 and 67107840)'#010+
   '**2Ci_IO-checking'#010+
   '**2Ci_IO-checking'#010+
   '**2Cn_Omit linking stage'#010+
   '**2Cn_Omit linking stage'#010+
   '**2Co_Check overflow of integer operations'#010+
   '**2Co_Check overflow of integer operations'#010+
   '**2CO_Check for possible overflow of integer operations'#010+
   '**2CO_Check for possible overflow of integer operations'#010+
-  '**2Cp<x>_Select instruction set, see fpc -i for possible values'#010+
-  '**2CP<x>=<y>_ ','packing settings'#010+
+  '**2Cp','<x>_Select instruction set, see fpc -i for possible values'#010+
+  '**2CP<x>=<y>_ packing settings'#010+
   '**3CPPACKSET=<y>_ <y> set allocation: 0, 1 or DEFAULT or NORMAL, 2, 4 '+
   '**3CPPACKSET=<y>_ <y> set allocation: 0, 1 or DEFAULT or NORMAL, 2, 4 '+
   'and 8'#010+
   'and 8'#010+
   '**2Cr_Range checking'#010+
   '**2Cr_Range checking'#010+
   '**2CR_Verify object method call validity'#010+
   '**2CR_Verify object method call validity'#010+
-  '**2Cs<n>_Set stack size to <n>'#010+
+  '**2Cs<n>_Set',' stack size to <n>'#010+
   '**2Ct_Stack checking'#010+
   '**2Ct_Stack checking'#010+
-  '**2CX_Create also smartlinked lib','rary'#010+
+  '**2CX_Create also smartlinked library'#010+
   '**1d<x>_Defines the symbol <x>'#010+
   '**1d<x>_Defines the symbol <x>'#010+
   '**1D_Generate a DEF file'#010+
   '**1D_Generate a DEF file'#010+
   '**2Dd<x>_Set description to <x>'#010+
   '**2Dd<x>_Set description to <x>'#010+
   '**2Dv<x>_Set DLL version to <x>'#010+
   '**2Dv<x>_Set DLL version to <x>'#010+
   '*O2Dw_PM application'#010+
   '*O2Dw_PM application'#010+
-  '**1e<x>_Set path to executable'#010+
+  '**1e<x>_Set path to e','xecutable'#010+
   '**1E_Same as -Cn'#010+
   '**1E_Same as -Cn'#010+
   '**1fPIC_Same as -Cg'#010+
   '**1fPIC_Same as -Cg'#010+
-  '**1F<x>_Set file names and',' paths:'#010+
+  '**1F<x>_Set file names and paths:'#010+
   '**2Fa<x>[,y]_(for a program) load units <x> and [y] before uses is par'+
   '**2Fa<x>[,y]_(for a program) load units <x> and [y] before uses is par'+
   'sed'#010+
   'sed'#010+
   '**2Fc<x>_Set input codepage to <x>'#010+
   '**2Fc<x>_Set input codepage to <x>'#010+
   '**2FC<x>_Set RC compiler binary name to <x>'#010+
   '**2FC<x>_Set RC compiler binary name to <x>'#010+
-  '**2FD<x>_Set the directory where to search for compiler utilities'#010+
-  '**2Fe<x>_Redi','rect error output to <x>'#010+
+  '**2FD<','x>_Set the directory where to search for compiler utilities'#010+
+  '**2Fe<x>_Redirect error output to <x>'#010+
   '**2Ff<x>_Add <x> to framework path (Darwin only)'#010+
   '**2Ff<x>_Add <x> to framework path (Darwin only)'#010+
   '**2FE<x>_Set exe/unit output path to <x>'#010+
   '**2FE<x>_Set exe/unit output path to <x>'#010+
   '**2Fi<x>_Add <x> to include path'#010+
   '**2Fi<x>_Add <x> to include path'#010+
-  '**2Fl<x>_Add <x> to library path'#010+
+  '**2Fl<x>_Add <x> to',' library path'#010+
   '**2FL<x>_Use <x> as dynamic linker'#010+
   '**2FL<x>_Use <x> as dynamic linker'#010+
-  '**2Fm<x>_Load unicode co','nversion table from <x>.txt in the compiler '+
-  'dir'#010+
+  '**2Fm<x>_Load unicode conversion table from <x>.txt in the compiler di'+
+  'r'#010+
   '**2Fo<x>_Add <x> to object path'#010+
   '**2Fo<x>_Add <x> to object path'#010+
   '**2Fr<x>_Load error message file <x>'#010+
   '**2Fr<x>_Load error message file <x>'#010+
   '**2FR<x>_Set resource (.res) linker to <x>'#010+
   '**2FR<x>_Set resource (.res) linker to <x>'#010+
-  '**2Fu<x>_Add <x> to unit path'#010+
-  '**2FU<x>_Set unit output path to <x>, overrides -F','E'#010+
+  '**2Fu<x','>_Add <x> to unit path'#010+
+  '**2FU<x>_Set unit output path to <x>, overrides -FE'#010+
   '*g1g_Generate debug information (default format for target)'#010+
   '*g1g_Generate debug information (default format for target)'#010+
   '*g2gc_Generate checks for pointers'#010+
   '*g2gc_Generate checks for pointers'#010+
   '*g2gh_Use heaptrace unit (for memory leak/corruption debugging)'#010+
   '*g2gh_Use heaptrace unit (for memory leak/corruption debugging)'#010+
-  '*g2gl_Use line info unit (show more info with backtraces)'#010+
-  '*g2go<x>_Set debug in','formation options'#010+
+  '*g2gl_','Use line info unit (show more info with backtraces)'#010+
+  '*g2go<x>_Set debug information options'#010+
   '*g3godwarfsets_ Enable Dwarf set debug information (breaks gdb < 6.5)'#010+
   '*g3godwarfsets_ Enable Dwarf set debug information (breaks gdb < 6.5)'#010+
   '*g2gp_Preserve case in stabs symbol names'#010+
   '*g2gp_Preserve case in stabs symbol names'#010+
-  '*g2gs_Generate stabs debug information'#010+
+  '*g2gs_Generate stabs debug informatio','n'#010+
   '*g2gt_Trash local variables (to detect uninitialized uses)'#010+
   '*g2gt_Trash local variables (to detect uninitialized uses)'#010+
-  '*g2gv_Genera','tes programs traceable with valgrind'#010+
+  '*g2gv_Generates programs traceable with valgrind'#010+
   '*g2gw_Generate dwarf-2 debug information (same as -gw2)'#010+
   '*g2gw_Generate dwarf-2 debug information (same as -gw2)'#010+
   '*g2gw2_Generate dwarf-2 debug information'#010+
   '*g2gw2_Generate dwarf-2 debug information'#010+
-  '*g2gw3_Generate dwarf-3 debug information'#010+
+  '*g2gw3_Generate dwarf-3 debug in','formation'#010+
   '**1i_Information'#010+
   '**1i_Information'#010+
   '**2iD_Return compiler date'#010+
   '**2iD_Return compiler date'#010+
-  '**2iV_Return short ','compiler version'#010+
+  '**2iV_Return short compiler version'#010+
   '**2iW_Return full compiler version'#010+
   '**2iW_Return full compiler version'#010+
   '**2iSO_Return compiler OS'#010+
   '**2iSO_Return compiler OS'#010+
   '**2iSP_Return compiler host processor'#010+
   '**2iSP_Return compiler host processor'#010+
   '**2iTO_Return target OS'#010+
   '**2iTO_Return target OS'#010+
-  '**2iTP_Return target processor'#010+
+  '**2iTP_Return target proces','sor'#010+
   '**1I<x>_Add <x> to include path'#010+
   '**1I<x>_Add <x> to include path'#010+
   '**1k<x>_Pass <x> to the linker'#010+
   '**1k<x>_Pass <x> to the linker'#010+
-  '**1l_W','rite logo'#010+
+  '**1l_Write logo'#010+
   '**1M<x>_Set language mode to <x>'#010+
   '**1M<x>_Set language mode to <x>'#010+
   '**2Mfpc_Free Pascal dialect (default)'#010+
   '**2Mfpc_Free Pascal dialect (default)'#010+
   '**2Mobjfpc_FPC mode with Object Pascal support'#010+
   '**2Mobjfpc_FPC mode with Object Pascal support'#010+
-  '**2Mdelphi_Delphi 7 compatibility mode'#010+
+  '**2Mdelphi_Delphi 7 compatibility mode'#010,
   '**2Mtp_TP/BP 7.0 compatibility mode'#010+
   '**2Mtp_TP/BP 7.0 compatibility mode'#010+
-  '**2Mmacpas_Macintosh Pascal dialects ','compatibility mode'#010+
+  '**2Mmacpas_Macintosh Pascal dialects compatibility mode'#010+
   '**1n_Do not read the default config files'#010+
   '**1n_Do not read the default config files'#010+
   '**1N<x>_Node tree optimizations'#010+
   '**1N<x>_Node tree optimizations'#010+
   '**2Nu_Unroll loops'#010+
   '**2Nu_Unroll loops'#010+
-  '**1o<x>_Change the name of the executable produced to <x>'#010+
+  '**1o<x>_Change the name of the executable produced to <','x>'#010+
   '**1O<x>_Optimizations:'#010+
   '**1O<x>_Optimizations:'#010+
   '**2O-_Disable optimizations'#010+
   '**2O-_Disable optimizations'#010+
-  '**2O1_Level 1 optim','izations (quick and debugger friendly)'#010+
+  '**2O1_Level 1 optimizations (quick and debugger friendly)'#010+
   '**2O2_Level 2 optimizations (-O1 + quick optimizations)'#010+
   '**2O2_Level 2 optimizations (-O1 + quick optimizations)'#010+
   '**2O3_Level 3 optimizations (-O2 + slow optimizations)'#010+
   '**2O3_Level 3 optimizations (-O2 + slow optimizations)'#010+
-  '**2Oa<x>=<y>_Set alignment'#010+
-  '**2Oo[NO]<x>_Enable or disable optimizations, see fpc -i for po','ssibl'+
-  'e values'#010+
+  '**2Oa<x>=<y>_Set ','alignment'#010+
+  '**2Oo[NO]<x>_Enable or disable optimizations, see fpc -i for possible '+
+  'values'#010+
   '**2Op<x>_Set target cpu for optimizing, see fpc -i for possible values'+
   '**2Op<x>_Set target cpu for optimizing, see fpc -i for possible values'+
   #010+
   #010+
   '**2Os_Optimize for size rather than speed'#010+
   '**2Os_Optimize for size rather than speed'#010+
-  '**1pg_Generate profile code for gprof (defines FPC_PROFILE)'#010+
+  '**1pg_Generate profile code for gprof (d','efines FPC_PROFILE)'#010+
   '**1R<x>_Assembler reading style:'#010+
   '**1R<x>_Assembler reading style:'#010+
-  '**2Rdefault_Use defa','ult assembler for target'#010+
+  '**2Rdefault_Use default assembler for target'#010+
   '3*2Ratt_Read AT&T style assembler'#010+
   '3*2Ratt_Read AT&T style assembler'#010+
   '3*2Rintel_Read Intel style assembler'#010+
   '3*2Rintel_Read Intel style assembler'#010+
   '6*2RMOT_Read motorola style assembler'#010+
   '6*2RMOT_Read motorola style assembler'#010+
   '**1S<x>_Syntax options:'#010+
   '**1S<x>_Syntax options:'#010+
-  '**2S2_Same as -Mobjfpc'#010+
+  '**2S2_Sam','e as -Mobjfpc'#010+
   '**2Sc_Support operators like C (*=,+=,/= and -=)'#010+
   '**2Sc_Support operators like C (*=,+=,/= and -=)'#010+
-  '**2Sa_Turn',' on assertions'#010+
+  '**2Sa_Turn on assertions'#010+
   '**2Sd_Same as -Mdelphi'#010+
   '**2Sd_Same as -Mdelphi'#010+
   '**2Se<x>_Error options. <x> is a combination of the following:'#010+
   '**2Se<x>_Error options. <x> is a combination of the following:'#010+
   '**3*_<n> : Compiler halts after the <n> errors (default is 1)'#010+
   '**3*_<n> : Compiler halts after the <n> errors (default is 1)'#010+
-  '**3*_w : Compiler also halts after warnings'#010+
-  '**3*_n : Compiler also halts afte','r notes'#010+
+  '**3*','_w : Compiler also halts after warnings'#010+
+  '**3*_n : Compiler also halts after notes'#010+
   '**3*_h : Compiler also halts after hints'#010+
   '**3*_h : Compiler also halts after hints'#010+
   '**2Sg_Enable LABEL and GOTO (default in -Mtp and -Mdelphi)'#010+
   '**2Sg_Enable LABEL and GOTO (default in -Mtp and -Mdelphi)'#010+
   '**2Sh_Use ansistrings by default instead of shortstrings'#010+
   '**2Sh_Use ansistrings by default instead of shortstrings'#010+
-  '**2Si_Turn on inlining of procedures/functions declared as "inline"'#010+
-  '**2Sk_L','oad fpcylix unit'#010+
+  '**','2Si_Turn on inlining of procedures/functions declared as "inline"'#010+
+  '**2Sk_Load fpcylix unit'#010+
   '**2SI<x>_Set interface style to <x>'#010+
   '**2SI<x>_Set interface style to <x>'#010+
   '**3SIcom_COM compatible interface (default)'#010+
   '**3SIcom_COM compatible interface (default)'#010+
   '**3SIcorba_CORBA compatible interface'#010+
   '**3SIcorba_CORBA compatible interface'#010+
-  '**2Sm_Support macros like C (global)'#010+
+  '**2Sm_Support macros like C (glo','bal)'#010+
   '**2So_Same as -Mtp'#010+
   '**2So_Same as -Mtp'#010+
-  '**2Ss_Constructor name must be init (destructor m','ust be done)'#010+
+  '**2Ss_Constructor name must be init (destructor must be done)'#010+
   '**2St_Allow static keyword in objects'#010+
   '**2St_Allow static keyword in objects'#010+
   '**2Sx_Enable exception keywords (default in Delphi/ObjFPC modes)'#010+
   '**2Sx_Enable exception keywords (default in Delphi/ObjFPC modes)'#010+
   '**1s_Do not call assembler and linker'#010+
   '**1s_Do not call assembler and linker'#010+
-  '**2sh_Generate script to link on host'#010+
+  '**2sh_Generat','e script to link on host'#010+
   '**2st_Generate script to link on target'#010+
   '**2st_Generate script to link on target'#010+
-  '**2sr_Sk','ip register allocation phase (use with -alr)'#010+
+  '**2sr_Skip register allocation phase (use with -alr)'#010+
   '**1T<x>_Target operating system:'#010+
   '**1T<x>_Target operating system:'#010+
   '3*2Temx_OS/2 via EMX (including EMX/RSX extender)'#010+
   '3*2Temx_OS/2 via EMX (including EMX/RSX extender)'#010+
   '3*2Tfreebsd_FreeBSD'#010+
   '3*2Tfreebsd_FreeBSD'#010+
-  '3*2Tgo32v2_Version 2 of DJ Delorie DOS extender'#010+
+  '3*2Tgo32v2_Version ','2 of DJ Delorie DOS extender'#010+
   '3*2Tlinux_Linux'#010+
   '3*2Tlinux_Linux'#010+
   '3*2Tnetbsd_NetBSD'#010+
   '3*2Tnetbsd_NetBSD'#010+
-  '3*2Tnetwar','e_Novell Netware Module (clib)'#010+
+  '3*2Tnetware_Novell Netware Module (clib)'#010+
   '3*2Tnetwlibc_Novell Netware Module (libc)'#010+
   '3*2Tnetwlibc_Novell Netware Module (libc)'#010+
   '3*2Topenbsd_OpenBSD'#010+
   '3*2Topenbsd_OpenBSD'#010+
   '3*2Tos2_OS/2 / eComStation'#010+
   '3*2Tos2_OS/2 / eComStation'#010+
   '3*2Tsunos_SunOS/Solaris'#010+
   '3*2Tsunos_SunOS/Solaris'#010+
-  '3*2Tsymbian_Symbian OS'#010+
+  '3*2Tsymbian_Symbian OS'#010,
   '3*2Twatcom_Watcom compatible DOS extender'#010+
   '3*2Twatcom_Watcom compatible DOS extender'#010+
   '3*2Twdosx_WDOSX DOS extender'#010+
   '3*2Twdosx_WDOSX DOS extender'#010+
-  '3*','2Twin32_Windows 32 Bit'#010+
+  '3*2Twin32_Windows 32 Bit'#010+
   '3*2Twince_Windows CE'#010+
   '3*2Twince_Windows CE'#010+
   '4*2Tlinux_Linux'#010+
   '4*2Tlinux_Linux'#010+
   '6*2Tamiga_Commodore Amiga'#010+
   '6*2Tamiga_Commodore Amiga'#010+
   '6*2Tatari_Atari ST/STe/TT'#010+
   '6*2Tatari_Atari ST/STe/TT'#010+
   '6*2Tlinux_Linux/m68k'#010+
   '6*2Tlinux_Linux/m68k'#010+
-  '6*2Tmacos_Macintosh m68k (not supported)'#010+
+  '6*2Tmacos_Macintosh m68k (not supp','orted)'#010+
   '6*2Tpalmos_PalmOS'#010+
   '6*2Tpalmos_PalmOS'#010+
   'A*2Tlinux_Linux'#010+
   'A*2Tlinux_Linux'#010+
   'A*2Twince_Windows CE'#010+
   'A*2Twince_Windows CE'#010+
-  'P*2Tamiga_A','migaOS on PowerPC'#010+
+  'P*2Tamiga_AmigaOS on PowerPC'#010+
   'P*2Tdarwin_Darwin and Mac OS X on PowerPC'#010+
   'P*2Tdarwin_Darwin and Mac OS X on PowerPC'#010+
   'P*2Tlinux_Linux on PowerPC'#010+
   'P*2Tlinux_Linux on PowerPC'#010+
   'P*2Tmacos_Mac OS (classic) on PowerPC'#010+
   'P*2Tmacos_Mac OS (classic) on PowerPC'#010+
   'P*2Tmorphos_MorphOS'#010+
   'P*2Tmorphos_MorphOS'#010+
   'S*2Tlinux_Linux'#010+
   'S*2Tlinux_Linux'#010+
-  '**1u<x>_Undefines the symbol <x>'#010+
+  '**1u<x','>_Undefines the symbol <x>'#010+
   '**1U_Unit options:'#010+
   '**1U_Unit options:'#010+
-  '**2Un_Do not check where th','e unit name matches the file name'#010+
+  '**2Un_Do not check where the unit name matches the file name'#010+
   '**2Ur_Generate release unit files (never automatically recompiled)'#010+
   '**2Ur_Generate release unit files (never automatically recompiled)'#010+
   '**2Us_Compile a system unit'#010+
   '**2Us_Compile a system unit'#010+
-  '**1v<x>_Be verbose. <x> is a combination of the following letters:'#010+
-  '**2*_e : Show errors (default)       0 : Sho','w nothing (except errors'+
-  ')'#010+
+  '**1v<x>_Be verbose. <x> is a combinati','on of the following letters:'#010+
+  '**2*_e : Show errors (default)       0 : Show nothing (except errors)'#010+
   '**2*_w : Show warnings               u : Show unit info'#010+
   '**2*_w : Show warnings               u : Show unit info'#010+
   '**2*_n : Show notes                  t : Show tried/used files'#010+
   '**2*_n : Show notes                  t : Show tried/used files'#010+
-  '**2*_h : Show hints                  c : Show conditionals'#010+
-  '**2*_i : Show general info          ',' d : Show debug info'#010+
+  '**2*_h : Show hints   ','               c : Show conditionals'#010+
+  '**2*_i : Show general info           d : Show debug info'#010+
   '**2*_l : Show linenumbers            r : Rhide/GCC compatibility mode'#010+
   '**2*_l : Show linenumbers            r : Rhide/GCC compatibility mode'#010+
   '**2*_a : Show everything             x : Executable info (Win32 only)'#010+
   '**2*_a : Show everything             x : Executable info (Win32 only)'#010+
-  '**2*_b : Write file names messages with full path'#010+
-  '**2*_v : Write fpcdebug.txt w','ith     p : Write tree.log with parse t'+
-  'ree'#010+
+  '**2*_b',' : Write file names messages with full path'#010+
+  '**2*_v : Write fpcdebug.txt with     p : Write tree.log with parse tre'+
+  'e'#010+
   '**2*_    lots of debugging info'#010+
   '**2*_    lots of debugging info'#010+
   '3*1W<x>_Target-specific options (targets)'#010+
   '3*1W<x>_Target-specific options (targets)'#010+
   'A*1W<x>_Target-specific options (targets)'#010+
   'A*1W<x>_Target-specific options (targets)'#010+
-  'P*1W<x>_Target-specific options (targets)'#010+
-  '3*2Wb_Create a bundle instead of a libr','ary (Darwin)'#010+
+  'P*1W<x>_','Target-specific options (targets)'#010+
+  '3*2Wb_Create a bundle instead of a library (Darwin)'#010+
   'P*2Wb_Create a bundle instead of a library (Darwin)'#010+
   'P*2Wb_Create a bundle instead of a library (Darwin)'#010+
   'p*2Wb_Create a bundle instead of a library (Darwin)'#010+
   'p*2Wb_Create a bundle instead of a library (Darwin)'#010+
   '3*2WB_Create a relocatable image (Windows)'#010+
   '3*2WB_Create a relocatable image (Windows)'#010+
-  'A*2WB_Create a relocatable image (Windows, Symbian)'#010+
-  '3*2WC_Specify console type a','pplication (EMX, OS/2, Windows)'#010+
+  'A*2WB_C','reate a relocatable image (Windows, Symbian)'#010+
+  '3*2WC_Specify console type application (EMX, OS/2, Windows)'#010+
   'A*2WC_Specify console type application (Windows)'#010+
   'A*2WC_Specify console type application (Windows)'#010+
   'P*2WC_Specify console type application (Classic Mac OS)'#010+
   'P*2WC_Specify console type application (Classic Mac OS)'#010+
-  '3*2WD_Use DEFFILE to export functions of DLL or EXE (Windows)'#010+
-  'A*2WD_Use DEFFILE to export functions of ','DLL or EXE (Windows)'#010+
+  '3*2WD_Use DEFFILE to export fu','nctions of DLL or EXE (Windows)'#010+
+  'A*2WD_Use DEFFILE to export functions of DLL or EXE (Windows)'#010+
   '3*2We_Use external resources (Darwin)'#010+
   '3*2We_Use external resources (Darwin)'#010+
   'P*2We_Use external resources (Darwin)'#010+
   'P*2We_Use external resources (Darwin)'#010+
   'p*2We_Use external resources (Darwin)'#010+
   'p*2We_Use external resources (Darwin)'#010+
-  '3*2WF_Specify full-screen type application (EMX, OS/2)'#010+
-  '3*2WG_Specify graphic type application (EMX, OS/2,',' Windows)'#010+
+  '3*2WF_Specify full-screen type a','pplication (EMX, OS/2)'#010+
+  '3*2WG_Specify graphic type application (EMX, OS/2, Windows)'#010+
   'A*2WG_Specify graphic type application (Windows)'#010+
   'A*2WG_Specify graphic type application (Windows)'#010+
   'P*2WG_Specify graphic type application (Classic Mac OS)'#010+
   'P*2WG_Specify graphic type application (Classic Mac OS)'#010+
   '3*2Wi_Use internal resources (Darwin)'#010+
   '3*2Wi_Use internal resources (Darwin)'#010+
-  'P*2Wi_Use internal resources (Darwin)'#010+
+  'P*2Wi_Use inte','rnal resources (Darwin)'#010+
   'p*2Wi_Use internal resources (Darwin)'#010+
   'p*2Wi_Use internal resources (Darwin)'#010+
-  '3*2WN_Do no','t generate relocation code, needed for debugging (Windows'+
-  ')'#010+
+  '3*2WN_Do not generate relocation code, needed for debugging (Windows)'#010+
   'A*2WN_Do not generate relocation code, needed for debugging (Windows)'#010+
   'A*2WN_Do not generate relocation code, needed for debugging (Windows)'#010+
-  '3*2WR_Generate relocation code (Windows)'#010+
+  '3*2WR_Generate relocation code (Window','s)'#010+
   'A*2WR_Generate relocation code (Windows)'#010+
   'A*2WR_Generate relocation code (Windows)'#010+
-  'P*2WT_Specify MPW tool type a','pplication (Classic Mac OS)'#010+
+  'P*2WT_Specify MPW tool type application (Classic Mac OS)'#010+
   '**1X_Executable options:'#010+
   '**1X_Executable options:'#010+
   '**2Xc_Pass --shared/-dynamic to the linker (BeOS, Darwin, FreeBSD, Lin'+
   '**2Xc_Pass --shared/-dynamic to the linker (BeOS, Darwin, FreeBSD, Lin'+
   'ux)'#010+
   'ux)'#010+
-  '**2Xd_Do not use standard library search path (needed for cross compil'+
-  'e)'#010+
+  '**2Xd_Do not use standard library search',' path (needed for cross comp'+
+  'ile)'#010+
   '**2Xe_Use external linker'#010+
   '**2Xe_Use external linker'#010+
-  '**2Xg_Create d','ebuginfo in a separate file and add a debuglink sectio'+
-  'n to executable'#010+
+  '**2Xg_Create debuginfo in a separate file and add a debuglink section '+
+  'to executable'#010+
   '**2XD_Try to link units dynamically      (defines FPC_LINK_DYNAMIC)'#010+
   '**2XD_Try to link units dynamically      (defines FPC_LINK_DYNAMIC)'#010+
   '**2Xi_Use internal linker'#010+
   '**2Xi_Use internal linker'#010+
-  '**2Xm_Generate link map'#010+
-  '**2XM<x>_Set the name of the '#039'main'#039' program routine ','(default'+
-  ' is '#039'main'#039')'#010+
+  '**2','Xm_Generate link map'#010+
+  '**2XM<x>_Set the name of the '#039'main'#039' program routine (default i'+
+  's '#039'main'#039')'#010+
   '**2XP<x>_Prepend the binutils names with the prefix <x>'#010+
   '**2XP<x>_Prepend the binutils names with the prefix <x>'#010+
   '**2Xr<x>_Set library search path to <x> (needed for cross compile) (Be'+
   '**2Xr<x>_Set library search path to <x> (needed for cross compile) (Be'+
   'OS, Linux)'#010+
   'OS, Linux)'#010+
-  '**2XR<x>_Prepend <x> to all linker search paths (BeOS, Darwin, FreeBSD'+
-  ', Linux, Mac ','OS, Solaris)'#010+
+  '**2XR<x>_P','repend <x> to all linker search paths (BeOS, Darwin, FreeB'+
+  'SD, Linux, Mac OS, Solaris)'#010+
   '**2Xs_Strip all symbols from executable'#010+
   '**2Xs_Strip all symbols from executable'#010+
   '**2XS_Try to link units statically (default, defines FPC_LINK_STATIC)'#010+
   '**2XS_Try to link units statically (default, defines FPC_LINK_STATIC)'#010+
-  '**2Xt_Link with static libraries (-static is passed to linker)'#010+
-  '**2XX_Try to smartlink units             (defines FPC_','LINK_SMART)'#010+
+  '**2Xt_Link with static libraries (-static is',' passed to linker)'#010+
+  '**2XX_Try to smartlink units             (defines FPC_LINK_SMART)'#010+
   '**1*_'#010+
   '**1*_'#010+
   '**1?_Show this help'#010+
   '**1?_Show this help'#010+
   '**1h_Shows this help without waiting'#000
   '**1h_Shows this help without waiting'#000

+ 61 - 33
compiler/ncal.pas

@@ -208,7 +208,8 @@ implementation
       htypechk,pass_1,
       htypechk,pass_1,
       ncnv,nld,ninl,nadd,ncon,nmem,nset,
       ncnv,nld,ninl,nadd,ncon,nmem,nset,
       procinfo,cpuinfo,
       procinfo,cpuinfo,
-      cgbase
+      cgbase,
+      wpobase
       ;
       ;
 
 
     type
     type
@@ -1517,6 +1518,22 @@ implementation
 
 
 
 
     procedure tcallnode.register_created_object_types;
     procedure tcallnode.register_created_object_types;
+
+      function checklive(def: tdef): boolean;
+        begin
+          if assigned(current_procinfo) and
+             not(po_inline in current_procinfo.procdef.procoptions) and
+             not wpoinfomanager.symbol_live(current_procinfo.procdef.mangledname) then
+            begin
+{$ifdef debug_deadcode}
+              writeln(' NOT adding creadion of ',def.typename,' because performed in dead stripped proc: ',current_procinfo.procdef.typename);
+{$endif debug_deadcode}
+              result:=false;
+            end
+          else
+            result:=true;
+        end;
+
       var
       var
         crefdef,
         crefdef,
         systobjectdef : tdef;
         systobjectdef : tdef;
@@ -1530,45 +1547,54 @@ implementation
             if (procdefinition.proctypeoption=potype_constructor) then
             if (procdefinition.proctypeoption=potype_constructor) then
               begin
               begin
                 { Only a typenode can be passed when it is called with <class of xx>.create }
                 { Only a typenode can be passed when it is called with <class of xx>.create }
-                if methodpointer.nodetype=typen then
-                  { we know the exact class type being created }
-                  tclassrefdef(methodpointer.resultdef).pointeddef.register_created_object_type
+                if (methodpointer.nodetype=typen) then
+                  begin
+                    if checklive(methodpointer.resultdef) then
+                      { we know the exact class type being created }
+                      tclassrefdef(methodpointer.resultdef).pointeddef.register_created_object_type
+                  end
                 else
                 else
                   begin
                   begin
                     { the loadvmtaddrnode is already created in case of classtype.create }
                     { the loadvmtaddrnode is already created in case of classtype.create }
                     if (methodpointer.nodetype=loadvmtaddrn) and
                     if (methodpointer.nodetype=loadvmtaddrn) and
                        (tloadvmtaddrnode(methodpointer).left.nodetype=typen) then
                        (tloadvmtaddrnode(methodpointer).left.nodetype=typen) then
-                      tclassrefdef(methodpointer.resultdef).pointeddef.register_created_object_type
+                      begin
+                        if checklive(methodpointer.resultdef) then
+                          tclassrefdef(methodpointer.resultdef).pointeddef.register_created_object_type
+                      end
                     else
                     else
                       begin
                       begin
-                        { special case: if the classref comes from x.classtype (with classtype,
-                          being tobject.classtype) then the created instance is x or a descendant
-                          of x (rather than tobject or a descendant of tobject)
-                        }
-                        systobjectdef:=search_system_type('TOBJECT').typedef;
-                        if (methodpointer.nodetype=calln) and
-                           { not a procvar call }
-                           not assigned(right) and
-                           { procdef is owned by system.tobject }
-                           (tprocdef(tcallnode(methodpointer).procdefinition).owner.defowner=systobjectdef) and
-                           { we're calling system.tobject.classtype }
-                           (tcallnode(methodpointer).symtableprocentry.name='CLASSTYPE') and
-                           { could again be a classrefdef, but unlikely }
-                           (tcallnode(methodpointer).methodpointer.resultdef.typ=objectdef) and
-                           { don't go through this trouble if it was already a tobject }
-                           (tcallnode(methodpointer).methodpointer.resultdef<>systobjectdef) then
+                        if checklive(methodpointer.resultdef) then
                           begin
                           begin
-                            { register this object type as classref, so all descendents will also
-                              be marked as instantiatable (only the pointeddef will actually be
-                              recorded, so it's no problem that the clasrefdef is only temporary)
+                            { special case: if the classref comes from x.classtype (with classtype,
+                              being tobject.classtype) then the created instance is x or a descendant
+                              of x (rather than tobject or a descendant of tobject)
                             }
                             }
-                            crefdef:=tclassrefdef.create(tcallnode(methodpointer).methodpointer.resultdef);
-                            { and register it }
-                            crefdef.register_created_object_type;
-                          end
-                         else
-                          { the created class can be any child class as well -> register classrefdef }
-                          methodpointer.resultdef.register_created_object_type;
+                            systobjectdef:=search_system_type('TOBJECT').typedef;
+                            if (methodpointer.nodetype=calln) and
+                               { not a procvar call }
+                               not assigned(right) and
+                               { procdef is owned by system.tobject }
+                               (tprocdef(tcallnode(methodpointer).procdefinition).owner.defowner=systobjectdef) and
+                               { we're calling system.tobject.classtype }
+                               (tcallnode(methodpointer).symtableprocentry.name='CLASSTYPE') and
+                               { could again be a classrefdef, but unlikely }
+                               (tcallnode(methodpointer).methodpointer.resultdef.typ=objectdef) and
+                               { don't go through this trouble if it was already a tobject }
+                               (tcallnode(methodpointer).methodpointer.resultdef<>systobjectdef) then
+                              begin
+                                { register this object type as classref, so all descendents will also
+                                  be marked as instantiatable (only the pointeddef will actually be
+                                  recorded, so it's no problem that the clasrefdef is only temporary)
+                                }
+                                crefdef:=tclassrefdef.create(tcallnode(methodpointer).methodpointer.resultdef);
+                                { and register it }
+                                crefdef.register_created_object_type;
+                              end
+                             else
+                              { the created class can be any child class as well -> register classrefdef }
+                              methodpointer.resultdef.register_created_object_type;
+                          end;
                       end;
                       end;
                   end;
                   end;
               end
               end
@@ -1580,7 +1606,8 @@ implementation
             { constructor with extended syntax called from new }
             { constructor with extended syntax called from new }
             if (cnf_new_call in callnodeflags) then
             if (cnf_new_call in callnodeflags) then
               begin
               begin
-                methodpointer.resultdef.register_created_object_type;
+                if checklive(methodpointer.resultdef) then
+                  methodpointer.resultdef.register_created_object_type;
               end
               end
             else
             else
             { normal object call like obj.proc }
             { normal object call like obj.proc }
@@ -1590,7 +1617,8 @@ implementation
              begin
              begin
                if (procdefinition.proctypeoption=potype_constructor) then
                if (procdefinition.proctypeoption=potype_constructor) then
                  begin
                  begin
-                   if (methodpointer.nodetype<>typen) then
+                   if (methodpointer.nodetype<>typen) and
+                      checklive(methodpointer.resultdef) then
                      methodpointer.resultdef.register_created_object_type;
                      methodpointer.resultdef.register_created_object_type;
                  end
                  end
              end;
              end;

+ 404 - 0
compiler/optdead.pas

@@ -0,0 +1,404 @@
+{
+    Copyright (c) 2008 by Jonas Maebe
+
+    Optimization information related to dead code removal
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ ****************************************************************************
+}
+
+unit optdead;
+
+{$i fpcdefs.inc}
+
+  interface
+
+    uses
+      globtype,
+      cclasses,
+      symtype,
+      wpobase;
+
+    type
+
+      { twpodeadcodeinfo }
+
+      twpodeadcodeinfo = class(twpodeadcodehandler)
+       private
+        { hashtable of symbols which are dead for some reason }
+        fsymbols     : tfphashlist;
+
+       public
+        constructor create; override;
+        destructor destroy; override;
+
+        class function  getwpotype: twpotype; override;
+        class function  generatesinfoforwposwitches: twpoptimizerswitches; override;
+        class function  performswpoforswitches: twpoptimizerswitches; override;
+        class function  sectionname: shortstring; override;
+
+        class procedure checkoptions; override;
+
+        { information collection }
+        procedure storewpofilesection(writer: twposectionwriterintf); override;
+
+        { information providing }
+        procedure loadfromwpofilesection(reader: twposectionreaderintf); override;
+        function  symbolinfinalbinary(const s: shortstring): boolean;override;
+
+      end;
+
+      { tdeadcodeinfofromexternallinker }
+
+      twpodeadcodeinfofromexternallinker = class(twpodeadcodeinfo)
+       private
+
+        fsymtypepos,
+        fsymnamepos  : longint;
+        fsymfile     : text;
+        fsymfilename : tcmdstr;
+        function parselinenm(const line: ansistring): boolean;
+        function parselineobjdump(const line: ansistring): boolean;
+       public
+        class procedure checkoptions; override;
+
+        { information collection }
+        procedure constructfromcompilerstate; override;
+      end;
+
+
+  implementation
+
+  uses
+    cutils,cfileutl,
+    sysutils,
+    globals,systems,fmodule,
+    verbose;
+
+
+  const
+    SYMBOL_SECTION_NAME = 'live_symbols';
+
+  { twpodeadcodeinfo }
+
+  constructor twpodeadcodeinfo.create;
+    begin
+      inherited create;
+      fsymbols:=tfphashlist.create;
+    end;
+
+
+  destructor twpodeadcodeinfo.destroy;
+    begin
+      fsymbols.free;
+      fsymbols:=nil;
+      inherited destroy;
+    end;
+
+
+  class function twpodeadcodeinfo.getwpotype: twpotype;
+    begin
+      result:=wpo_live_symbol_information;
+    end;
+
+
+  class function twpodeadcodeinfo.generatesinfoforwposwitches: twpoptimizerswitches;
+    begin
+      result:=[cs_wpo_symbol_liveness];
+    end;
+
+
+  class function twpodeadcodeinfo.performswpoforswitches: twpoptimizerswitches;
+    begin
+      result:=[cs_wpo_symbol_liveness];
+    end;
+
+
+  class function twpodeadcodeinfo.sectionname: shortstring;
+    begin
+      result:=SYMBOL_SECTION_NAME;
+    end;
+
+
+  class procedure twpodeadcodeinfo.checkoptions;
+    begin
+      { we don't have access to the symbol info if the linking
+        hasn't happend
+      }
+      if (([cs_link_on_target,cs_link_nolink] * init_settings.globalswitches) <> []) then
+        begin
+          cgmessage(wpo_cannot_extract_live_symbol_info_no_link);
+          exit;
+        end;
+
+      { without dead code stripping/smart linking, this doesn't make sense }
+      if not(cs_link_smart in init_settings.globalswitches) then
+        begin
+          cgmessage(wpo_symbol_live_info_needs_smart_linking);
+          exit;
+        end;
+    end;
+
+
+  procedure twpodeadcodeinfo.storewpofilesection(writer: twposectionwriterintf);
+    var
+      i: longint;
+    begin
+      writer.startsection(SYMBOL_SECTION_NAME);
+      for i:=0 to fsymbols.count-1 do
+        writer.sectionputline(fsymbols.nameofindex(i));
+    end;
+
+
+  procedure twpodeadcodeinfo.loadfromwpofilesection(reader: twposectionreaderintf);
+    var
+      symname: shortstring;
+    begin
+      while reader.sectiongetnextline(symname) do
+        fsymbols.add(symname,pointer(1));
+    end;
+
+
+  function twpodeadcodeinfo.symbolinfinalbinary(const s: shortstring): boolean;
+    begin
+      result:=fsymbols.find(s)<>nil;
+    end;
+
+
+  { twpodeadcodeinfofromexternallinker }
+
+{$ifdef relaxed_objdump_parsing}
+const
+  objdumpcheckstr='.text';
+{$else}
+const
+  objdumpcheckstr='F .text';
+{$endif}
+  objdumpsearchstr=' '+objdumpcheckstr;
+
+  class procedure twpodeadcodeinfofromexternallinker.checkoptions;
+    begin
+      inherited checkoptions;
+
+      { we need symbol information }
+      if (cs_link_strip in init_settings.globalswitches) then
+        begin
+          cgmessage(wpo_cannot_extract_live_symbol_info_strip);
+          exit;
+        end;
+    end;
+
+
+  function twpodeadcodeinfofromexternallinker.parselinenm(const line: ansistring): boolean;
+    begin
+      if (length(line) < fsymnamepos) then
+        begin
+          cgmessage1(wpo_error_reading_symbol_file,'nm');
+          close(fsymfile);
+          deletefile(fsymfilename);
+          result:=false;
+          exit;
+        end;
+      if (line[fsymtypepos] in ['T','t']) then
+        fsymbols.add(copy(line,fsymnamepos,length(line)),pointer(1));
+      result:=true;
+    end;
+
+
+  function twpodeadcodeinfofromexternallinker.parselineobjdump(const line: ansistring): boolean;
+    begin
+      { there are a couple of empty lines at the end }
+      if (line='') then
+        begin
+          result:=true;
+          exit;
+        end;
+      if (length(line) < fsymtypepos) then
+        begin
+          cgmessage1(wpo_error_reading_symbol_file,'objdump');
+          close(fsymfile);
+          deletefile(fsymfilename);
+          result:=false;
+          exit;
+        end;
+      if (copy(line,fsymtypepos,length(objdumpcheckstr))=objdumpcheckstr) then
+        fsymbols.add(copy(line,fsymnamepos,length(line)),pointer(1));
+      result:=true;
+    end;
+
+
+  procedure twpodeadcodeinfofromexternallinker.constructfromcompilerstate;
+
+    type
+      tparselineproc = function(const line: ansistring): boolean of object;
+
+    var
+      nmfullname,
+      objdumpfullname,
+      symbolprogfullpath  : tcmdstr;
+      line                : ansistring;
+      parseline           : tparselineproc;
+      exitcode            : longint;
+      symbolprogfound     : boolean;
+      symbolprogisnm      : boolean;
+
+
+    function findutil(const utilname: string; out fullutilname, fullutilpath: tcmdstr): boolean;
+      begin
+        result:=false;
+        fullutilname:=utilsprefix+changefileext(utilname,source_info.exeext);
+        if utilsdirectory<>'' then
+          result:=findfile(fullutilname,utilsdirectory,false,fullutilpath);
+        if not result then
+          result:=findexe(fullutilname,false,fullutilpath);
+      end;
+
+
+    function failiferror(error: boolean): boolean;
+      begin
+        result:=error;
+        if not result then
+          exit;
+        cgmessage1(wpo_error_reading_symbol_file,'fullutilname');
+{$i-}
+        close(fsymfile);
+{$i+}
+        if fileexists(fsymfilename) then
+          deletefile(fsymfilename);
+      end;
+
+
+    function setnminfo: boolean;
+      begin
+        { expected format:
+            0000bce0 T FPC_ABSTRACTERROR
+            ...
+        }
+        result:=false;
+        fsymtypepos:=pos(' ',line)+1;
+        fsymnamepos:=fsymtypepos+2;
+        if failiferror(fsymtypepos<=0) then
+          exit;
+        { make sure there's room for the name }
+        if failiferror(fsymnamepos>length(line)) then
+          exit;
+        { and that we're not in the middle of some other column }
+        if failiferror(pos(' ',copy(line,fsymnamepos,length(line)))>0) then
+          exit;
+        result:=true;
+      end;
+
+
+    function setobjdumpinfo: boolean;
+      begin
+        { expected format:
+            prog:     file format elf32-i386
+
+            SYMBOL TABLE:
+            08048080 l    d  .text  00000000 .text
+            00000000 l    d  .stabstr       00000000 .stabstr
+            00000000 l    df *ABS*  00000000 nest.pp
+            08048160 l     F .text  00000068 SYSTEM_INITSYSCALLINTF
+            ...
+        }
+        result:=false;
+        while (pos(' F .text',line)<=0) do
+          begin
+            if failiferror(eof(fsymfile)) then
+              exit;
+            readln(fsymfile,line)
+          end;
+        fsymtypepos:=pos(objdumpsearchstr,line)+1;
+        { find begin of symbol name }
+        fsymnamepos:=(pointer(strrscan(pchar(line),' '))-pointer(@line[1]))+2;
+        { sanity check }
+        if (fsymnamepos <= fsymtypepos+length(objdumpcheckstr)) then
+          exit;
+        result:=true;
+      end;
+
+
+    begin { twpodeadcodeinfofromexternallinker }
+      { try nm }
+      symbolprogfound:=findutil('nm',nmfullname,symbolprogfullpath);
+      if not symbolprogfound then
+        begin
+          { try objdump }
+          symbolprogfound:=findutil('objdump',objdumpfullname,symbolprogfullpath);
+          symbolprogfullpath:=symbolprogfullpath+' -t ';
+          symbolprogisnm:=false;
+        end
+      else
+        begin
+          symbolprogfullpath:=symbolprogfullpath+' -p ';
+          symbolprogisnm:=true;
+        end;
+      if not symbolprogfound then
+        begin
+          cgmessage2(wpo_cannot_find_symbol_progs,nmfullname,objdumpfullname);
+          exit;
+        end;
+
+      { upper case to have the least chance of tripping some long file name
+        conversion stuff
+      }
+      fsymfilename:=outputexedir+'FPCWPO.SYM';
+      { -p gives the same kind of output with Solaris nm as
+        with GNU nm, and for GNU nm it simply means "unsorted"
+      }
+      exitcode:=shell(symbolprogfullpath+maybequoted(current_module.exefilename^)+' > '+fsymfilename);
+      if (exitcode<>0) then
+        begin
+          cgmessage2(wpo_error_executing_symbol_prog,symbolprogfullpath,tostr(exitcode));
+          if fileexists(fsymfilename) then
+            deletefile(fsymfilename);
+          exit;
+        end;
+
+      assign(fsymfile,fsymfilename);
+{$i-}
+      reset(fsymfile);
+{$i+}
+      if failiferror((ioresult<>0) or eof(fsymfile)) then
+        exit;
+      readln(fsymfile, line);
+      if (symbolprogisnm) then
+        begin
+          if not setnminfo then
+            exit;
+          parseline:=@parselinenm
+        end
+      else
+        begin
+          if not setobjdumpinfo then
+            exit;
+          parseline:=@parselineobjdump;
+        end;
+      if not parseline(line) then
+        exit;
+      while not eof(fsymfile) do
+        begin
+          readln(fsymfile,line);
+          if not parseline(line) then
+            exit;
+        end;
+      close(fsymfile);
+      deletefile(fsymfilename);
+    end;
+
+
+end.
+

+ 7 - 2
compiler/optvirt.pas

@@ -137,6 +137,7 @@ unit optvirt;
         class function getwpotype: twpotype; override;
         class function getwpotype: twpotype; override;
         class function generatesinfoforwposwitches: twpoptimizerswitches; override;
         class function generatesinfoforwposwitches: twpoptimizerswitches; override;
         class function performswpoforswitches: twpoptimizerswitches; override;
         class function performswpoforswitches: twpoptimizerswitches; override;
+        class function sectionname: shortstring; override;
 
 
         { information collection }
         { information collection }
         procedure constructfromcompilerstate; override;
         procedure constructfromcompilerstate; override;
@@ -662,6 +663,12 @@ unit optvirt;
       end;
       end;
 
 
 
 
+    class function tprogdevirtinfo.sectionname: shortstring;
+      begin
+        result:=DEVIRT_SECTION_NAME;
+      end;
+
+
     procedure reset_all_impl_defs;
     procedure reset_all_impl_defs;
 
 
       procedure reset_used_unit_impl_defs(hp:tmodule);
       procedure reset_used_unit_impl_defs(hp:tmodule);
@@ -981,6 +988,4 @@ unit optvirt;
            staticname:=newname^;
            staticname:=newname^;
       end;
       end;
 
 
-initialization
-  twpoinfomanagerbase.registersectionreader(DEVIRT_SECTION_NAME,tprogdevirtinfo);
 end.
 end.

+ 38 - 1
compiler/wpo.pas

@@ -27,9 +27,46 @@ unit wpo;
 interface
 interface
 
 
 uses
 uses
-  optvirt;
+  { all units with whole program optimisation components }
+  optvirt,optdead;
+
+
+  procedure InitWpo;
+  procedure DoneWpo;
 
 
 implementation
 implementation
 
 
+  uses
+    globals,
+    wpobase, wpoinfo;
+
+  { called after command line parameters have been parsed }
+  procedure InitWpo;
+    begin
+      { always create so we don't have to litter the source with if-tests }
+      wpoinfomanager:=twpoinfomanager.create;
+
+      { register the classes we can/should potentially use }
+      wpoinfomanager.registerwpocomponentclass(tprogdevirtinfo);
+      wpoinfomanager.registerwpocomponentclass(twpodeadcodeinfofromexternallinker);
+
+      { assign input/output feedback files }
+      if (wpofeedbackinput<>'') then
+        wpoinfomanager.setwpoinputfile(wpofeedbackinput);
+      if (wpofeedbackoutput<>'') then
+        wpoinfomanager.setwpooutputfile(wpofeedbackoutput);
+
+      { parse input }
+      wpoinfomanager.parseandcheckwpoinfo;
+    end;
+
+
+  procedure DoneWpo;
+    begin
+      wpoinfomanager.free;
+      wpoinfomanager:=nil;
+    end;
+
+
 end.
 end.
 
 

+ 71 - 29
compiler/wpobase.pas

@@ -32,9 +32,9 @@ uses
 
 
 type
 type
   { the types of available whole program optimization }
   { the types of available whole program optimization }
-  twpotype = (wpo_devirtualization_context_insensitive);
+  twpotype = (wpo_devirtualization_context_insensitive,wpo_live_symbol_information);
 const
 const
-  wpo2str: array[twpotype] of string[16] = ('devirtualization');
+  wpo2str: array[twpotype] of string[16] = ('devirtualization','symbol liveness');
 
 
 type
 type
   { ************************************************************************* }
   { ************************************************************************* }
@@ -57,6 +57,9 @@ type
 
 
 
 
   { base class for wpo information stores }
   { base class for wpo information stores }
+
+  { twpocomponentbase }
+
   twpocomponentbase = class
   twpocomponentbase = class
    public
    public
     constructor create; reintroduce; virtual;
     constructor create; reintroduce; virtual;
@@ -72,6 +75,14 @@ type
     { whole program optimizations performed by this class }
     { whole program optimizations performed by this class }
     class function performswpoforswitches: twpoptimizerswitches; virtual; abstract;
     class function performswpoforswitches: twpoptimizerswitches; virtual; abstract;
 
 
+    { returns the name of the section parsed by this class }
+    class function sectionname: shortstring; virtual; abstract;
+
+    { checks whether the compiler options are compatible with this
+      optimization (default: don't check anything)
+    }
+    class procedure checkoptions; virtual;
+
     { loads the information pertinent to this whole program optimization from
     { loads the information pertinent to this whole program optimization from
       the current section being processed by reader
       the current section being processed by reader
     }
     }
@@ -197,6 +208,15 @@ type
     function staticnameforvirtualmethod(objdef, procdef: tdef; out staticname: string): boolean; virtual; abstract;
     function staticnameforvirtualmethod(objdef, procdef: tdef; out staticname: string): boolean; virtual; abstract;
   end;
   end;
 
 
+  twpodeadcodehandler = class(twpocomponentbase)
+    { checks whether a mangledname was removed as dead code from the final
+      binary (WARNING: must *not* be called for functions marked as inline,
+      since if all call sites are inlined, it won't appear in the final
+      binary but nevertheless is still necessary!)
+    }
+    function symbolinfinalbinary(const s: shortstring): boolean; virtual; abstract;
+  end;
+
 
 
   { ************************************************************************* }
   { ************************************************************************* }
   { ************ Collection of all instances of wpo components ************** }
   { ************ Collection of all instances of wpo components ************** }
@@ -209,12 +229,12 @@ type
     { array of classrefs of handler classes for the various kinds of whole
     { array of classrefs of handler classes for the various kinds of whole
       program optimization that we support
       program optimization that we support
     }
     }
-    fsectionhandlers: tfphashlist; static;
+    fwpocomponents: tfphashlist;
 
 
     freader: twpofilereader;
     freader: twpofilereader;
     fwriter: twpofilewriter;
     fwriter: twpofilewriter;
    public
    public
-    class procedure registersectionreader(const sectionname: string; sectionhandler: twpocomponentbaseclass);
+    procedure registerwpocomponentclass(wpocomponent: twpocomponentbaseclass);
     function gethandlerforsection(const secname: string): twpocomponentbaseclass;
     function gethandlerforsection(const secname: string): twpocomponentbaseclass;
 
 
     { instances of the various optimizers/information collectors (for
     { instances of the various optimizers/information collectors (for
@@ -233,6 +253,10 @@ type
     function can_be_devirtualized(objdef, procdef: tdef; out name: shortstring): boolean; virtual; abstract;
     function can_be_devirtualized(objdef, procdef: tdef; out name: shortstring): boolean; virtual; abstract;
     { 2) optimal replacement method name in vmt }
     { 2) optimal replacement method name in vmt }
     function optimized_name_for_vmt(objdef, procdef: tdef; out name: shortstring): boolean; virtual; abstract;
     function optimized_name_for_vmt(objdef, procdef: tdef; out name: shortstring): boolean; virtual; abstract;
+    { 3) is a symbol in the final binary (i.e., not removed by dead code stripping/smart linking).
+        WARNING: do *not* call for inline functions/procedures/methods/...
+    }
+    function symbol_live(const name: shortstring): boolean; virtual; abstract;
 
 
     constructor create; reintroduce;
     constructor create; reintroduce;
     destructor destroy; override;
     destructor destroy; override;
@@ -312,7 +336,7 @@ implementation
     begin
     begin
       if not FileExists(fn) then
       if not FileExists(fn) then
         begin
         begin
-          message1(wpo_cant_find_file,fn);
+          cgmessage1(wpo_cant_find_file,fn);
           exit;
           exit;
         end;
         end;
       assign(finputfile,fn);
       assign(finputfile,fn);
@@ -334,7 +358,7 @@ implementation
       s,
       s,
       sectionname: string;
       sectionname: string;
     begin
     begin
-      message1(wpo_begin_processing,ffilename);
+      cgmessage1(wpo_begin_processing,ffilename);
       reset(finputfile);
       reset(finputfile);
       flinenr:=0;
       flinenr:=0;
       while getnextnoncommentline(s) do
       while getnextnoncommentline(s) do
@@ -344,7 +368,7 @@ implementation
           { format: "% sectionname" }
           { format: "% sectionname" }
           if (s[1]<>'%') then
           if (s[1]<>'%') then
             begin
             begin
-              message2(wpo_expected_section,tostr(flinenr),s);
+              cgmessage2(wpo_expected_section,tostr(flinenr),s);
               break;
               break;
             end;
             end;
           for i:=2 to length(s) do
           for i:=2 to length(s) do
@@ -357,14 +381,14 @@ implementation
           if assigned(sectionhandler) then
           if assigned(sectionhandler) then
             begin
             begin
               wpotype:=sectionhandler.getwpotype;
               wpotype:=sectionhandler.getwpotype;
-              message2(wpo_found_section,sectionname,wpo2str[wpotype]);
+              cgmessage2(wpo_found_section,sectionname,wpo2str[wpotype]);
               { do we need this information? }
               { do we need this information? }
               if ((sectionhandler.performswpoforswitches * init_settings.dowpoptimizerswitches) <> []) then
               if ((sectionhandler.performswpoforswitches * init_settings.dowpoptimizerswitches) <> []) then
                 begin
                 begin
                   { did some other section already generate this type of information? }
                   { did some other section already generate this type of information? }
                   if assigned(fdest.wpoinfouse[wpotype]) then
                   if assigned(fdest.wpoinfouse[wpotype]) then
                     begin
                     begin
-                      message2(wpo_duplicate_wpotype,wpo2str[wpotype],sectionname);
+                      cgmessage2(wpo_duplicate_wpotype,wpo2str[wpotype],sectionname);
                       fdest.wpoinfouse[wpotype].free;
                       fdest.wpoinfouse[wpotype].free;
                     end;
                     end;
                   { process the section }
                   { process the section }
@@ -373,7 +397,7 @@ implementation
                 end
                 end
               else
               else
                 begin
                 begin
-                  message1(wpo_skipping_unnecessary_section,sectionname);
+                  cgmessage1(wpo_skipping_unnecessary_section,sectionname);
                   { skip the current section }
                   { skip the current section }
                   while sectiongetnextline(s) do
                   while sectiongetnextline(s) do
                     ;
                     ;
@@ -381,14 +405,14 @@ implementation
             end
             end
           else
           else
             begin
             begin
-              message1(wpo_no_section_handler,sectionname);
+              cgmessage1(wpo_no_section_handler,sectionname);
               { skip the current section }
               { skip the current section }
               while sectiongetnextline(s) do
               while sectiongetnextline(s) do
                 ;
                 ;
             end;
             end;
         end;
         end;
       close(finputfile);
       close(finputfile);
-      message1(wpo_end_processing,ffilename);
+      cgmessage1(wpo_end_processing,ffilename);
     end;
     end;
 
 
   function twpofilereader.sectiongetnextline(out s: string): boolean;
   function twpofilereader.sectiongetnextline(out s: string): boolean;
@@ -415,6 +439,12 @@ implementation
       { do nothing }
       { do nothing }
     end;
     end;
 
 
+
+  class procedure twpocomponentbase.checkoptions;
+    begin
+      { do nothing }
+    end;
+
   { twpofilewriter }
   { twpofilewriter }
 
 
   constructor twpofilewriter.create(const fn: tcmdstr);
   constructor twpofilewriter.create(const fn: tcmdstr);
@@ -458,19 +488,16 @@ implementation
 
 
 { twpoinfomanagerbase }
 { twpoinfomanagerbase }
 
 
-  class procedure twpoinfomanagerbase.registersectionreader(const sectionname: string; sectionhandler: twpocomponentbaseclass);
+  procedure twpoinfomanagerbase.registerwpocomponentclass(wpocomponent: twpocomponentbaseclass);
     begin
     begin
-      { avoid having to check all the time whether it's assigned or not }
-      if not assigned(fsectionhandlers) then
-        fsectionhandlers:=tfphashlist.create;
-      fsectionhandlers.add(sectionname,sectionhandler);
+      fwpocomponents.add(wpocomponent.sectionname,wpocomponent);
     end;
     end;
 
 
 
 
   function twpoinfomanagerbase.gethandlerforsection(const secname: string
   function twpoinfomanagerbase.gethandlerforsection(const secname: string
       ): twpocomponentbaseclass;
       ): twpocomponentbaseclass;
     begin
     begin
-      result:=twpocomponentbaseclass(fsectionhandlers.find(secname));
+      result:=twpocomponentbaseclass(fwpocomponents.find(secname));
     end;
     end;
 
 
   procedure twpoinfomanagerbase.setwpoinputfile(const fn: tcmdstr);
   procedure twpoinfomanagerbase.setwpoinputfile(const fn: tcmdstr);
@@ -484,12 +511,14 @@ implementation
     end;
     end;
 
 
   procedure twpoinfomanagerbase.parseandcheckwpoinfo;
   procedure twpoinfomanagerbase.parseandcheckwpoinfo;
+    var
+      i: longint;
     begin
     begin
       { error if we don't have to optimize yet have an input feedback file }
       { error if we don't have to optimize yet have an input feedback file }
       if (init_settings.dowpoptimizerswitches=[]) and
       if (init_settings.dowpoptimizerswitches=[]) and
          assigned(freader) then
          assigned(freader) then
         begin
         begin
-          message(wpo_input_without_info_use);
+          cgmessage(wpo_input_without_info_use);
           exit;
           exit;
         end;
         end;
 
 
@@ -497,7 +526,7 @@ implementation
       if (init_settings.dowpoptimizerswitches<>[]) and
       if (init_settings.dowpoptimizerswitches<>[]) and
          not assigned(freader) then
          not assigned(freader) then
         begin
         begin
-          message(wpo_no_input_specified);
+          cgmessage(wpo_no_input_specified);
           exit;
           exit;
         end;
         end;
 
 
@@ -507,14 +536,14 @@ implementation
       if (init_settings.genwpoptimizerswitches<>[]) and
       if (init_settings.genwpoptimizerswitches<>[]) and
          not assigned(fwriter) then
          not assigned(fwriter) then
         begin
         begin
-          message(wpo_no_output_specified);
+          cgmessage(wpo_no_output_specified);
           exit;
           exit;
         end;
         end;
 
 
       if (init_settings.genwpoptimizerswitches=[]) and
       if (init_settings.genwpoptimizerswitches=[]) and
          assigned(fwriter) then
          assigned(fwriter) then
         begin
         begin
-          message(wpo_output_without_info_gen);
+          cgmessage(wpo_output_without_info_gen);
           exit;
           exit;
         end;
         end;
 
 
@@ -532,10 +561,23 @@ implementation
       if (([cs_wpo_devirtualize_calls,cs_wpo_optimize_vmts] * init_settings.dowpoptimizerswitches) <> []) and
       if (([cs_wpo_devirtualize_calls,cs_wpo_optimize_vmts] * init_settings.dowpoptimizerswitches) <> []) and
          not assigned(wpoinfouse[wpo_devirtualization_context_insensitive]) then
          not assigned(wpoinfouse[wpo_devirtualization_context_insensitive]) then
         begin
         begin
-          message1(wpo_not_enough_info,wpo2str[wpo_devirtualization_context_insensitive]);
+          cgmessage1(wpo_not_enough_info,wpo2str[wpo_devirtualization_context_insensitive]);
           exit;
           exit;
         end;
         end;
 
 
+      if (cs_wpo_symbol_liveness in init_settings.dowpoptimizerswitches) and
+         not assigned(wpoinfouse[wpo_live_symbol_information]) then
+        begin
+          cgmessage1(wpo_not_enough_info,wpo2str[wpo_live_symbol_information]);
+          exit;
+        end;
+
+      { perform pre-checking to ensure there are no known incompatibilities between
+        the selected optimizations and other switches
+      }
+      for i:=0 to fwpocomponents.count-1 do
+        if (twpocomponentbaseclass(fwpocomponents[i]).generatesinfoforwposwitches*init_settings.genwpoptimizerswitches)<>[] then
+          twpocomponentbaseclass(fwpocomponents[i]).checkoptions
     end;
     end;
 
 
   procedure twpoinfomanagerbase.extractwpoinfofromprogram;
   procedure twpoinfomanagerbase.extractwpoinfofromprogram;
@@ -548,10 +590,10 @@ implementation
         exit;
         exit;
 
 
       { let all wpo components gather the necessary info from the compiler state }
       { let all wpo components gather the necessary info from the compiler state }
-      for i:=0 to fsectionhandlers.count-1 do
-        if (twpocomponentbaseclass(fsectionhandlers[i]).generatesinfoforwposwitches*current_settings.genwpoptimizerswitches)<>[] then
+      for i:=0 to fwpocomponents.count-1 do
+        if (twpocomponentbaseclass(fwpocomponents[i]).generatesinfoforwposwitches*current_settings.genwpoptimizerswitches)<>[] then
           begin
           begin
-            info:=twpocomponentbaseclass(fsectionhandlers[i]).create;
+            info:=twpocomponentbaseclass(fwpocomponents[i]).create;
             info.constructfromcompilerstate;
             info.constructfromcompilerstate;
             fwriter.registerwpocomponent(info);
             fwriter.registerwpocomponent(info);
           end;
           end;
@@ -564,6 +606,7 @@ implementation
   constructor twpoinfomanagerbase.create;
   constructor twpoinfomanagerbase.create;
     begin
     begin
       inherited create;
       inherited create;
+      fwpocomponents:=tfphashlist.create;
     end;
     end;
 
 
   destructor twpoinfomanagerbase.destroy;
   destructor twpoinfomanagerbase.destroy;
@@ -574,13 +617,12 @@ implementation
       freader:=nil;
       freader:=nil;
       fwriter.free;
       fwriter.free;
       fwriter:=nil;
       fwriter:=nil;
+      fwpocomponents.free;
+      fwpocomponents:=nil;
       for i:=low(wpoinfouse) to high(wpoinfouse) do
       for i:=low(wpoinfouse) to high(wpoinfouse) do
         if assigned(wpoinfouse[i]) then
         if assigned(wpoinfouse[i]) then
           wpoinfouse[i].free;
           wpoinfouse[i].free;
       inherited destroy;
       inherited destroy;
     end;
     end;
 
 
-finalization
-  twpoinfomanagerbase.fsectionhandlers.free;
-  twpoinfomanagerbase.fsectionhandlers:=nil;
 end.
 end.

+ 11 - 18
compiler/wpoinfo.pas

@@ -61,12 +61,10 @@ type
   twpoinfomanager = class(twpoinfomanagerbase)
   twpoinfomanager = class(twpoinfomanagerbase)
     function can_be_devirtualized(objdef, procdef: tdef; out name: shortstring): boolean; override;
     function can_be_devirtualized(objdef, procdef: tdef; out name: shortstring): boolean; override;
     function optimized_name_for_vmt(objdef, procdef: tdef; out name: shortstring): boolean; override;
     function optimized_name_for_vmt(objdef, procdef: tdef; out name: shortstring): boolean; override;
+    function symbol_live(const name: shortstring): boolean; override;
   end;
   end;
 
 
 
 
-  procedure InitWpo;
-  procedure DoneWpo;
-
 implementation
 implementation
 
 
   uses
   uses
@@ -120,7 +118,7 @@ implementation
     begin
     begin
       { load start of definition section, which holds the amount of defs }
       { load start of definition section, which holds the amount of defs }
       if ppufile.readentry<>ibcreatedobjtypes then
       if ppufile.readentry<>ibcreatedobjtypes then
-        Message(unit_f_ppu_read_error);
+        cgmessage(unit_f_ppu_read_error);
       len:=ppufile.getlongint;
       len:=ppufile.getlongint;
       fcreatedobjtypes:=tfpobjectlist.create(false);
       fcreatedobjtypes:=tfpobjectlist.create(false);
       fcreatedobjtypes.count:=len;
       fcreatedobjtypes.count:=len;
@@ -203,22 +201,17 @@ implementation
     end;
     end;
 
 
 
 
-  procedure InitWpo;
+  function twpoinfomanager.symbol_live(const name: shortstring): boolean;
     begin
     begin
-      { always create so we don't have to litter the source with if-tests }
-      wpoinfomanager:=twpoinfomanager.create;
-      if (wpofeedbackinput<>'') then
-        wpoinfomanager.setwpoinputfile(wpofeedbackinput);
-      if (wpofeedbackoutput<>'') then
-        wpoinfomanager.setwpooutputfile(wpofeedbackoutput);
-      wpoinfomanager.parseandcheckwpoinfo;
+      if not assigned(wpoinfouse[wpo_live_symbol_information]) or
+         not(cs_wpo_symbol_liveness in current_settings.dowpoptimizerswitches) then
+        begin
+          { if we don't know, say that the symbol is live }
+          result:=true;
+          exit;
+        end;
+      result:=twpodeadcodehandler(wpoinfouse[wpo_live_symbol_information]).symbolinfinalbinary(name);
     end;
     end;
 
 
 
 
-  procedure DoneWpo;
-    begin
-      wpoinfomanager.free;
-      wpoinfomanager:=nil;
-    end;
-
 end.
 end.