2
0

wpobase.pas 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865
  1. {
  2. Copyright (c) 2008 by Jonas Maebe
  3. Whole program optimisation information collection base class
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program; if not, write to the Free Software
  14. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  15. ****************************************************************************
  16. }
  17. unit wpobase;
  18. {$i fpcdefs.inc}
  19. interface
  20. uses
  21. globtype,
  22. cclasses,
  23. symtype;
  24. type
  25. { the types of available whole program optimization }
  26. twpotype = (wpo_devirtualization_context_insensitive,wpo_live_symbol_information);
  27. const
  28. wpo2str: array[twpotype] of string[16] = ('devirtualization','symbol liveness');
  29. type
  30. { ************************************************************************* }
  31. { ******************** General base classes/interfaces ******************** }
  32. { ************************************************************************* }
  33. { interface to reading a section from a file with wpo info }
  34. twposectionreaderintf = interface
  35. ['{51BE3F89-C9C5-4965-9C83-AE7490C92E3E}']
  36. function sectiongetnextline(out s: string): boolean;
  37. end;
  38. { interface to writing sections to a file with wpoinfo }
  39. twposectionwriterintf = interface
  40. ['{C056F0DD-62B1-4612-86C7-2D39944C4437}']
  41. procedure startsection(const name: string);
  42. procedure sectionputline(const s: string);
  43. end;
  44. { base class for wpo information stores }
  45. { twpocomponentbase }
  46. twpocomponentbase = class
  47. public
  48. constructor create; reintroduce; virtual;
  49. { type of whole program optimization information collected/provided by
  50. this class
  51. }
  52. class function getwpotype: twpotype; virtual; abstract;
  53. { whole program optimizations for which this class generates information }
  54. class function generatesinfoforwposwitches: twpoptimizerswitches; virtual; abstract;
  55. { whole program optimizations performed by this class }
  56. class function performswpoforswitches: twpoptimizerswitches; virtual; abstract;
  57. { returns the name of the section parsed by this class }
  58. class function sectionname: shortstring; virtual; abstract;
  59. { checks whether the compiler options are compatible with this
  60. optimization (default: don't check anything)
  61. }
  62. class procedure checkoptions; virtual;
  63. { loads the information pertinent to this whole program optimization from
  64. the current section being processed by reader
  65. }
  66. procedure loadfromwpofilesection(reader: twposectionreaderintf); virtual; abstract;
  67. { stores the information of this component to a file in a format that can
  68. be loaded again using loadfromwpofilesection()
  69. }
  70. procedure storewpofilesection(writer: twposectionwriterintf); virtual; abstract;
  71. { extracts the information pertinent to this whole program optimization
  72. from the current compiler state (loaded units, ...)
  73. }
  74. procedure constructfromcompilerstate; virtual; abstract;
  75. end;
  76. twpocomponentbaseclass = class of twpocomponentbase;
  77. { forward declaration of overall wpo info manager class }
  78. twpoinfomanagerbase = class;
  79. { ************************************************************************* }
  80. { ** Information created per unit for use during subsequent compilation *** }
  81. { ************************************************************************* }
  82. { information about called vmt entries for a class }
  83. tcalledvmtentries = class
  84. protected
  85. { the class }
  86. fobjdef: tdef;
  87. fobjdefderef: tderef;
  88. { the vmt entries }
  89. fcalledentries: tbitset;
  90. public
  91. constructor create(_objdef: tdef; nentries: longint);
  92. constructor ppuload(ppufile: tcompilerppufile);
  93. destructor destroy; override;
  94. procedure ppuwrite(ppufile: tcompilerppufile);
  95. procedure buildderef;
  96. procedure buildderefimpl;
  97. procedure deref;
  98. procedure derefimpl;
  99. property objdef: tdef read fobjdef write fobjdef;
  100. property objdefderef: tderef read fobjdefderef write fobjdefderef;
  101. property calledentries: tbitset read fcalledentries write fcalledentries;
  102. end;
  103. { base class of information collected per unit. Still needs to be
  104. generalised for different kinds of wpo information, currently specific
  105. to devirtualization.
  106. }
  107. tunitwpoinfobase = class
  108. protected
  109. { created object types }
  110. fcreatedobjtypes: tfpobjectlist;
  111. { objectdefs pointed to by created classrefdefs }
  112. fcreatedclassrefobjtypes: tfpobjectlist;
  113. { objtypes potentially instantiated by fcreatedclassrefobjtypes
  114. (objdectdefs pointed to by classrefdefs that are
  115. passed as a regular parameter, loaded in a variable, ...
  116. so they can end up in a classrefdef var and be instantiated)
  117. }
  118. fmaybecreatedbyclassrefdeftypes: tfpobjectlist;
  119. { called virtual methods for all classes (hashed by mangled classname,
  120. entries bitmaps indicating which vmt entries per class are called --
  121. tcalledvmtentries)
  122. }
  123. fcalledvmtentries: tfphashlist;
  124. public
  125. constructor create; reintroduce; virtual;
  126. destructor destroy; override;
  127. property createdobjtypes: tfpobjectlist read fcreatedobjtypes;
  128. property createdclassrefobjtypes: tfpobjectlist read fcreatedclassrefobjtypes;
  129. property maybecreatedbyclassrefdeftypes: tfpobjectlist read fmaybecreatedbyclassrefdeftypes;
  130. property calledvmtentries: tfphashlist read fcalledvmtentries;
  131. procedure addcreatedobjtype(def: tdef);
  132. procedure addcreatedobjtypeforclassref(def: tdef);
  133. procedure addmaybecreatedbyclassref(def: tdef);
  134. procedure addcalledvmtentry(def: tdef; index: longint);
  135. { resets the "I've been registered with wpo" flags for all defs in the
  136. above lists }
  137. procedure resetdefs;
  138. end;
  139. { ************************************************************************* }
  140. { **** Total information created for use during subsequent compilation **** }
  141. { ************************************************************************* }
  142. { class to create a file with wpo information }
  143. { tavailablewpofilewriter }
  144. twpofilewriter = class(tobject,twposectionwriterintf)
  145. private
  146. { array of class *instances* that wish to be written out to the
  147. whole program optimization feedback file
  148. }
  149. fsectioncontents: tfpobjectlist;
  150. ffilename: tcmdstr;
  151. foutputfile: text;
  152. public
  153. constructor create(const fn: tcmdstr);
  154. destructor destroy; override;
  155. procedure writefile;
  156. { starts a new section with name "name" }
  157. procedure startsection(const name: string);
  158. { writes s to the wpo file }
  159. procedure sectionputline(const s: string);
  160. { register a component instance that needs to be written
  161. to the wpo feedback file
  162. }
  163. procedure registerwpocomponent(component: twpocomponentbase);
  164. end;
  165. { ************************************************************************* }
  166. { ************ Information for use during current compilation ************* }
  167. { ************************************************************************* }
  168. { class to read a file with wpo information }
  169. twpofilereader = class(tobject,twposectionreaderintf)
  170. private
  171. ffilename: tcmdstr;
  172. flinenr: longint;
  173. finputfile: text;
  174. fcurline: string;
  175. fusecurline: boolean;
  176. { destination for the read information }
  177. fdest: twpoinfomanagerbase;
  178. function getnextnoncommentline(out s: string): boolean;
  179. public
  180. constructor create(const fn: tcmdstr; dest: twpoinfomanagerbase);
  181. destructor destroy; override;
  182. { processes the wpo info in the file }
  183. procedure processfile;
  184. { returns next line of the current section in s, and false if no more
  185. lines in the current section
  186. }
  187. function sectiongetnextline(out s: string): boolean;
  188. end;
  189. { ************************************************************************* }
  190. { ******* Specific kinds of whole program optimization components ********* }
  191. { ************************************************************************* }
  192. { method devirtualisation }
  193. twpodevirtualisationhandler = class(twpocomponentbase)
  194. { checks whether procdef (a procdef for a virtual method) can be replaced with
  195. a static call when it's called as objdef.procdef, and if so returns the
  196. mangled name in staticname.
  197. }
  198. function staticnameforcallingvirtualmethod(objdef, procdef: tdef; out staticname: TSymStr): boolean; virtual; abstract;
  199. { checks whether procdef (a procdef for a virtual method) can be replaced with
  200. a different procname in the vmt of objdef, and if so returns the new
  201. mangledname in staticname
  202. }
  203. function staticnameforvmtentry(objdef, procdef: tdef; out staticname: TSymStr): boolean; virtual; abstract;
  204. end;
  205. twpodeadcodehandler = class(twpocomponentbase)
  206. { checks whether a mangledname was removed as dead code from the final
  207. binary (WARNING: must *not* be called for functions marked as inline,
  208. since if all call sites are inlined, it won't appear in the final
  209. binary but nevertheless is still necessary!)
  210. }
  211. function symbolinfinalbinary(const s: shortstring): boolean; virtual; abstract;
  212. end;
  213. { ************************************************************************* }
  214. { ************ Collection of all instances of wpo components ************** }
  215. { ************************************************************************* }
  216. { class doing all the bookkeeping for everything }
  217. twpoinfomanagerbase = class
  218. private
  219. { array of classrefs of handler classes for the various kinds of whole
  220. program optimizations that we support
  221. }
  222. fwpocomponents: tfphashlist;
  223. freader: twpofilereader;
  224. fwriter: twpofilewriter;
  225. public
  226. { instances of the various optimizers/information collectors (for
  227. information used during this compilation)
  228. }
  229. wpoinfouse: array[twpotype] of twpocomponentbase;
  230. { register a whole program optimization class type }
  231. procedure registerwpocomponentclass(wpocomponent: twpocomponentbaseclass);
  232. { get the program optimization class type that can parse the contents
  233. of the section with name "secname" in the wpo feedback file
  234. }
  235. function gethandlerforsection(const secname: string): twpocomponentbaseclass;
  236. { tell all instantiated wpo component classes to collect the information
  237. from the global compiler state that they need (done at the very end of
  238. the compilation process)
  239. }
  240. procedure extractwpoinfofromprogram;
  241. { set the name of the feedback file from which all whole-program information
  242. to be used during the current compilation will be read
  243. }
  244. procedure setwpoinputfile(const fn: tcmdstr);
  245. { set the name of the feedback file to which all whole-program information
  246. collected during the current compilation will be written
  247. }
  248. procedure setwpooutputfile(const fn: tcmdstr);
  249. { check whether the specified wpo options (-FW/-Fw/-OW/-Ow) are complete
  250. and sensical, and parse the wpo feedback file specified with
  251. setwpoinputfile
  252. }
  253. procedure parseandcheckwpoinfo;
  254. { routines accessing the optimizer information }
  255. { 1) devirtualization at the symbol name level }
  256. function can_be_devirtualized(objdef, procdef: tdef; out name: TSymStr): boolean; virtual; abstract;
  257. { 2) optimal replacement method name in vmt }
  258. function optimized_name_for_vmt(objdef, procdef: tdef; out name: TSymStr): boolean; virtual; abstract;
  259. { 3) does a symbol appear in the final binary (i.e., not removed by dead code stripping/smart linking).
  260. WARNING: do *not* call for inline functions/procedures/methods/...
  261. }
  262. function symbol_live(const name: shortstring): boolean; virtual; abstract;
  263. function symbol_live_in_currentproc(fordef: tdef): boolean;
  264. constructor create; reintroduce;
  265. destructor destroy; override;
  266. end;
  267. var
  268. wpoinfomanager: twpoinfomanagerbase;
  269. implementation
  270. uses
  271. globals,
  272. cutils,
  273. sysutils,
  274. symconst,symdef,
  275. procinfo,
  276. verbose;
  277. { tcreatedwpoinfobase }
  278. constructor tunitwpoinfobase.create;
  279. begin
  280. fcreatedobjtypes:=tfpobjectlist.create(false);
  281. fcreatedclassrefobjtypes:=tfpobjectlist.create(false);
  282. fmaybecreatedbyclassrefdeftypes:=tfpobjectlist.create(false);
  283. fcalledvmtentries:=tfphashlist.create;
  284. end;
  285. destructor tunitwpoinfobase.destroy;
  286. var
  287. i: longint;
  288. begin
  289. { don't call resetdefs here, because the defs may have been freed
  290. already }
  291. fcreatedobjtypes.free;
  292. fcreatedobjtypes:=nil;
  293. fcreatedclassrefobjtypes.free;
  294. fcreatedclassrefobjtypes:=nil;
  295. fmaybecreatedbyclassrefdeftypes.free;
  296. fmaybecreatedbyclassrefdeftypes:=nil;
  297. { may not be assigned in case the info was loaded from a ppu and we
  298. are not generating a wpo feedback file (see tunitwpoinfo.ppuload)
  299. }
  300. if assigned(fcalledvmtentries) then
  301. begin
  302. for i:=0 to fcalledvmtentries.count-1 do
  303. tcalledvmtentries(fcalledvmtentries[i]).free;
  304. fcalledvmtentries.free;
  305. fcalledvmtentries:=nil;
  306. end;
  307. inherited destroy;
  308. end;
  309. procedure tunitwpoinfobase.resetdefs;
  310. var
  311. i: ptrint;
  312. begin
  313. if assigned(fcreatedobjtypes) then
  314. for i:=0 to fcreatedobjtypes.count-1 do
  315. tobjectdef(fcreatedobjtypes[i]).created_in_current_module:=false;
  316. if assigned(fcreatedclassrefobjtypes) then
  317. for i:=0 to fcreatedclassrefobjtypes.count-1 do
  318. tobjectdef(fcreatedclassrefobjtypes[i]).classref_created_in_current_module:=false;
  319. if assigned(fmaybecreatedbyclassrefdeftypes) then
  320. for i:=0 to fmaybecreatedbyclassrefdeftypes.count-1 do
  321. tobjectdef(fmaybecreatedbyclassrefdeftypes[i]).maybe_created_in_current_module:=false;
  322. end;
  323. procedure tunitwpoinfobase.addcreatedobjtype(def: tdef);
  324. begin
  325. fcreatedobjtypes.add(def);
  326. end;
  327. procedure tunitwpoinfobase.addcreatedobjtypeforclassref(def: tdef);
  328. begin
  329. fcreatedclassrefobjtypes.add(def);
  330. end;
  331. procedure tunitwpoinfobase.addmaybecreatedbyclassref(def: tdef);
  332. begin
  333. fmaybecreatedbyclassrefdeftypes.add(def);
  334. end;
  335. procedure tunitwpoinfobase.addcalledvmtentry(def: tdef; index: longint);
  336. var
  337. entries: tcalledvmtentries;
  338. key: shortstring;
  339. begin
  340. key:=tobjectdef(def).vmt_mangledname;
  341. entries:=tcalledvmtentries(fcalledvmtentries.find(key));
  342. if not assigned(entries) then
  343. begin
  344. entries:=tcalledvmtentries.create(def,tobjectdef(def).vmtentries.count);
  345. fcalledvmtentries.add(key,entries);
  346. end;
  347. entries.calledentries.include(index);
  348. end;
  349. { twpofilereader }
  350. function twpofilereader.getnextnoncommentline(out s: string):
  351. boolean;
  352. begin
  353. if (fusecurline) then
  354. begin
  355. s:=fcurline;
  356. fusecurline:=false;
  357. result:=true;
  358. exit;
  359. end;
  360. repeat
  361. readln(finputfile,s);
  362. if (s='') and
  363. eof(finputfile) then
  364. begin
  365. result:=false;
  366. exit;
  367. end;
  368. inc(flinenr);
  369. until (s='') or
  370. (s[1]<>'#');
  371. result:=true;
  372. end;
  373. constructor twpofilereader.create(const fn: tcmdstr; dest: twpoinfomanagerbase);
  374. begin
  375. if not FileExists(fn) or
  376. { FileExists also returns true for directories }
  377. DirectoryExists(fn) then
  378. begin
  379. cgmessage1(wpo_cant_find_file,fn);
  380. exit;
  381. end;
  382. assign(finputfile,fn);
  383. ffilename:=fn;
  384. fdest:=dest;
  385. end;
  386. destructor twpofilereader.destroy;
  387. begin
  388. inherited destroy;
  389. end;
  390. procedure twpofilereader.processfile;
  391. var
  392. sectionhandler: twpocomponentbaseclass;
  393. i: longint;
  394. wpotype: twpotype;
  395. s,
  396. sectionname: string;
  397. begin
  398. cgmessage1(wpo_begin_processing,ffilename);
  399. reset(finputfile);
  400. flinenr:=0;
  401. while getnextnoncommentline(s) do
  402. begin
  403. if (s='') then
  404. continue;
  405. { format: "% sectionname" }
  406. if (s[1]<>'%') then
  407. begin
  408. cgmessage2(wpo_expected_section,tostr(flinenr),s);
  409. break;
  410. end;
  411. i:=2;
  412. for i:=2 to length(s) do
  413. if (s[i]<>' ') then
  414. break;
  415. sectionname:=copy(s,i,255);
  416. { find handler for section and process }
  417. sectionhandler:=fdest.gethandlerforsection(sectionname);
  418. if assigned(sectionhandler) then
  419. begin
  420. wpotype:=sectionhandler.getwpotype;
  421. cgmessage2(wpo_found_section,sectionname,wpo2str[wpotype]);
  422. { do we need this information? }
  423. if ((sectionhandler.performswpoforswitches * init_settings.dowpoptimizerswitches) <> []) then
  424. begin
  425. { did some other section already generate this type of information? }
  426. if assigned(fdest.wpoinfouse[wpotype]) then
  427. begin
  428. cgmessage2(wpo_duplicate_wpotype,wpo2str[wpotype],sectionname);
  429. fdest.wpoinfouse[wpotype].free;
  430. end;
  431. { process the section }
  432. fdest.wpoinfouse[wpotype]:=sectionhandler.create;
  433. twpocomponentbase(fdest.wpoinfouse[wpotype]).loadfromwpofilesection(self);
  434. end
  435. else
  436. begin
  437. cgmessage1(wpo_skipping_unnecessary_section,sectionname);
  438. { skip the current section }
  439. while sectiongetnextline(s) do
  440. ;
  441. end;
  442. end
  443. else
  444. begin
  445. cgmessage1(wpo_no_section_handler,sectionname);
  446. { skip the current section }
  447. while sectiongetnextline(s) do
  448. ;
  449. end;
  450. end;
  451. close(finputfile);
  452. cgmessage1(wpo_end_processing,ffilename);
  453. end;
  454. function twpofilereader.sectiongetnextline(out s: string): boolean;
  455. begin
  456. result:=getnextnoncommentline(s);
  457. if not result then
  458. exit;
  459. { start of new section? }
  460. if (s<>'') and
  461. (s[1]='%') then
  462. begin
  463. { keep read line for next call to getnextnoncommentline() }
  464. fcurline:=s;
  465. fusecurline:=true;
  466. result:=false;
  467. end;
  468. end;
  469. { twpocomponentbase }
  470. constructor twpocomponentbase.create;
  471. begin
  472. { do nothing }
  473. end;
  474. class procedure twpocomponentbase.checkoptions;
  475. begin
  476. { do nothing }
  477. end;
  478. { twpofilewriter }
  479. constructor twpofilewriter.create(const fn: tcmdstr);
  480. begin
  481. assign(foutputfile,fn);
  482. ffilename:=fn;
  483. fsectioncontents:=tfpobjectlist.create(true);
  484. end;
  485. destructor twpofilewriter.destroy;
  486. begin
  487. fsectioncontents.free;
  488. inherited destroy;
  489. end;
  490. procedure twpofilewriter.writefile;
  491. var
  492. i: longint;
  493. begin
  494. {$push}{$i-}
  495. rewrite(foutputfile);
  496. {$pop}
  497. if (ioresult <> 0) then
  498. begin
  499. cgmessage1(wpo_cant_create_feedback_file,ffilename);
  500. exit;
  501. end;
  502. for i:=0 to fsectioncontents.count-1 do
  503. twpocomponentbase(fsectioncontents[i]).storewpofilesection(self);
  504. close(foutputfile);
  505. end;
  506. procedure twpofilewriter.startsection(const name: string);
  507. begin
  508. writeln(foutputfile,'% ',name);
  509. end;
  510. procedure twpofilewriter.sectionputline(const s: string);
  511. begin
  512. writeln(foutputfile,s);
  513. end;
  514. procedure twpofilewriter.registerwpocomponent(
  515. component: twpocomponentbase);
  516. begin
  517. fsectioncontents.add(component);
  518. end;
  519. { twpoinfomanagerbase }
  520. procedure twpoinfomanagerbase.registerwpocomponentclass(wpocomponent: twpocomponentbaseclass);
  521. begin
  522. fwpocomponents.add(wpocomponent.sectionname,wpocomponent);
  523. end;
  524. function twpoinfomanagerbase.gethandlerforsection(const secname: string
  525. ): twpocomponentbaseclass;
  526. begin
  527. result:=twpocomponentbaseclass(fwpocomponents.find(secname));
  528. end;
  529. procedure twpoinfomanagerbase.setwpoinputfile(const fn: tcmdstr);
  530. begin
  531. freader:=twpofilereader.create(fn,self);
  532. end;
  533. procedure twpoinfomanagerbase.setwpooutputfile(const fn: tcmdstr);
  534. begin
  535. fwriter:=twpofilewriter.create(fn);
  536. end;
  537. procedure twpoinfomanagerbase.parseandcheckwpoinfo;
  538. var
  539. i: longint;
  540. begin
  541. { error if we don't have to optimize yet have an input feedback file }
  542. if (init_settings.dowpoptimizerswitches=[]) and
  543. assigned(freader) then
  544. begin
  545. cgmessage(wpo_input_without_info_use);
  546. exit;
  547. end;
  548. { error if we have to optimize yet don't have an input feedback file }
  549. if (init_settings.dowpoptimizerswitches<>[]) and
  550. not assigned(freader) then
  551. begin
  552. cgmessage(wpo_no_input_specified);
  553. exit;
  554. end;
  555. { if we have to generate wpo information, check that a file has been
  556. specified and that we have something to write to it
  557. }
  558. if (init_settings.genwpoptimizerswitches<>[]) and
  559. not assigned(fwriter) then
  560. begin
  561. cgmessage(wpo_no_output_specified);
  562. exit;
  563. end;
  564. if (init_settings.genwpoptimizerswitches=[]) and
  565. assigned(fwriter) then
  566. begin
  567. cgmessage(wpo_output_without_info_gen);
  568. exit;
  569. end;
  570. { now read the input feedback file }
  571. if assigned(freader) then
  572. begin
  573. freader.processfile;
  574. freader.free;
  575. freader:=nil;
  576. end;
  577. { and for each specified optimization check whether the input feedback
  578. file contained the necessary information
  579. }
  580. if (([cs_wpo_devirtualize_calls,cs_wpo_optimize_vmts] * init_settings.dowpoptimizerswitches) <> []) and
  581. not assigned(wpoinfouse[wpo_devirtualization_context_insensitive]) then
  582. begin
  583. cgmessage1(wpo_not_enough_info,wpo2str[wpo_devirtualization_context_insensitive]);
  584. exit;
  585. end;
  586. if (cs_wpo_symbol_liveness in init_settings.dowpoptimizerswitches) and
  587. not assigned(wpoinfouse[wpo_live_symbol_information]) then
  588. begin
  589. cgmessage1(wpo_not_enough_info,wpo2str[wpo_live_symbol_information]);
  590. exit;
  591. end;
  592. { perform pre-checking to ensure there are no known incompatibilities between
  593. the selected optimizations and other switches
  594. }
  595. for i:=0 to fwpocomponents.count-1 do
  596. if (twpocomponentbaseclass(fwpocomponents[i]).generatesinfoforwposwitches*init_settings.genwpoptimizerswitches)<>[] then
  597. twpocomponentbaseclass(fwpocomponents[i]).checkoptions
  598. end;
  599. function twpoinfomanagerbase.symbol_live_in_currentproc(fordef: tdef): boolean;
  600. function alias_symbol_live: boolean;
  601. var
  602. item: TCmdStrListItem;
  603. begin
  604. result:=true;
  605. item:=TCmdStrListItem(current_procinfo.procdef.aliasnames.first);
  606. while assigned(item) do
  607. begin
  608. if symbol_live(item.Str) then
  609. exit;
  610. item:=TCmdStrListItem(item.Next);
  611. end;
  612. result:=false;
  613. end;
  614. begin
  615. if assigned(current_procinfo) and
  616. not(po_inline in current_procinfo.procdef.procoptions) and
  617. not symbol_live(current_procinfo.procdef.mangledname) and
  618. not alias_symbol_live then
  619. begin
  620. {$ifdef debug_deadcode}
  621. writeln(' NOT adding creation of ',fordef.typename,' because performed in dead stripped proc: ',current_procinfo.procdef.typename);
  622. {$endif debug_deadcode}
  623. result:=false;
  624. end
  625. else
  626. result:=true;
  627. end;
  628. procedure twpoinfomanagerbase.extractwpoinfofromprogram;
  629. var
  630. i: longint;
  631. info: twpocomponentbase;
  632. begin
  633. { if don't have to write anything, fwriter has not been created }
  634. if not assigned(fwriter) then
  635. exit;
  636. { let all wpo components gather the necessary info from the compiler state }
  637. for i:=0 to fwpocomponents.count-1 do
  638. if (twpocomponentbaseclass(fwpocomponents[i]).generatesinfoforwposwitches*current_settings.genwpoptimizerswitches)<>[] then
  639. begin
  640. info:=twpocomponentbaseclass(fwpocomponents[i]).create;
  641. info.constructfromcompilerstate;
  642. fwriter.registerwpocomponent(info);
  643. end;
  644. { and write their info to disk }
  645. fwriter.writefile;
  646. fwriter.free;
  647. fwriter:=nil;
  648. end;
  649. constructor twpoinfomanagerbase.create;
  650. begin
  651. inherited create;
  652. fwpocomponents:=tfphashlist.create;
  653. end;
  654. destructor twpoinfomanagerbase.destroy;
  655. var
  656. i: twpotype;
  657. begin
  658. freader.free;
  659. freader:=nil;
  660. fwriter.free;
  661. fwriter:=nil;
  662. fwpocomponents.free;
  663. fwpocomponents:=nil;
  664. for i:=low(wpoinfouse) to high(wpoinfouse) do
  665. if assigned(wpoinfouse[i]) then
  666. wpoinfouse[i].free;
  667. inherited destroy;
  668. end;
  669. { tcalledvmtentries }
  670. constructor tcalledvmtentries.create(_objdef: tdef; nentries: longint);
  671. begin
  672. objdef:=_objdef;
  673. calledentries:=tbitset.create(nentries);
  674. end;
  675. constructor tcalledvmtentries.ppuload(ppufile: tcompilerppufile);
  676. var
  677. len: longint;
  678. begin
  679. ppufile.getderef(fobjdefderef);
  680. len:=ppufile.getlongint;
  681. calledentries:=tbitset.create_bytesize(len);
  682. if (len <> calledentries.datasize) then
  683. internalerror(2009060301);
  684. ppufile.readdata(calledentries.data^,len);
  685. end;
  686. destructor tcalledvmtentries.destroy;
  687. begin
  688. fcalledentries.free;
  689. inherited destroy;
  690. end;
  691. procedure tcalledvmtentries.ppuwrite(ppufile: tcompilerppufile);
  692. begin
  693. ppufile.putderef(objdefderef);
  694. ppufile.putlongint(calledentries.datasize);
  695. ppufile.putdata(calledentries.data^,calledentries.datasize);
  696. end;
  697. procedure tcalledvmtentries.buildderef;
  698. begin
  699. objdefderef.build(objdef);
  700. end;
  701. procedure tcalledvmtentries.buildderefimpl;
  702. begin
  703. end;
  704. procedure tcalledvmtentries.deref;
  705. begin
  706. objdef:=tdef(objdefderef.resolve);
  707. end;
  708. procedure tcalledvmtentries.derefimpl;
  709. begin
  710. end;
  711. end.