pass_2.pas 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669
  1. {
  2. $Id$
  3. Copyright (c) 1993-98 by Florian Klaempfl
  4. This unit handles the codegeneration pass
  5. This program is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 2 of the License, or
  8. (at your option) any later version.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with this program; if not, write to the Free Software
  15. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  16. ****************************************************************************
  17. }
  18. {$ifdef TP}
  19. {$E+,F+,N+}
  20. {$endif}
  21. unit pass_2;
  22. interface
  23. uses
  24. tree;
  25. { produces assembler for the expression in variable p }
  26. { and produces an assembler node at the end }
  27. procedure generatecode(var p : ptree);
  28. { produces the actual code }
  29. function do_secondpass(var p : ptree) : boolean;
  30. procedure secondpass(var p : ptree);
  31. implementation
  32. uses
  33. globtype,systems,
  34. cobjects,comphook,verbose,globals,files,
  35. symconst,symtable,types,aasm,scanner,
  36. pass_1,hcodegen,temp_gen
  37. {$ifdef GDB}
  38. ,gdb
  39. {$endif}
  40. {$ifdef i386}
  41. ,i386base,i386asm
  42. ,tgeni386,cgai386
  43. ,cg386con,cg386mat,cg386cnv,cg386set,cg386add
  44. ,cg386mem,cg386cal,cg386ld,cg386flw,cg386inl
  45. {$endif}
  46. {$ifdef m68k}
  47. ,m68k,tgen68k,cga68k
  48. ,cg68kcon,cg68kmat,cg68kcnv,cg68kset,cg68kadd
  49. ,cg68kmem,cg68kcal,cg68kld,cg68kflw,cg68kinl
  50. {$endif}
  51. ;
  52. {*****************************************************************************
  53. SecondPass
  54. *****************************************************************************}
  55. type
  56. secondpassproc = procedure(var p : ptree);
  57. procedure secondnothing(var p : ptree);
  58. begin
  59. end;
  60. procedure seconderror(var p : ptree);
  61. begin
  62. p^.error:=true;
  63. codegenerror:=true;
  64. end;
  65. procedure secondstatement(var p : ptree);
  66. var
  67. hp : ptree;
  68. begin
  69. hp:=p;
  70. while assigned(hp) do
  71. begin
  72. if assigned(hp^.right) then
  73. begin
  74. cleartempgen;
  75. {!!!!!!
  76. oldrl:=temptoremove;
  77. temptoremove:=new(plinkedlist,init);
  78. }
  79. secondpass(hp^.right);
  80. { !!!!!!!
  81. some temporary data which can't be released elsewhere
  82. removetemps(exprasmlist,temptoremove);
  83. dispose(temptoremove,done);
  84. temptoremove:=oldrl;
  85. }
  86. end;
  87. hp:=hp^.left;
  88. end;
  89. end;
  90. procedure secondblockn(var p : ptree);
  91. begin
  92. { do second pass on left node }
  93. if assigned(p^.left) then
  94. secondpass(p^.left);
  95. end;
  96. procedure secondasm(var p : ptree);
  97. var
  98. hp,hp2 : pai;
  99. localfixup,parafixup,
  100. i : longint;
  101. r : preference;
  102. begin
  103. if (pocall_inline in aktprocsym^.definition^.proccalloptions) then
  104. begin
  105. localfixup:=aktprocsym^.definition^.localst^.address_fixup;
  106. parafixup:=aktprocsym^.definition^.parast^.address_fixup;
  107. hp:=pai(p^.p_asm^.first);
  108. while assigned(hp) do
  109. begin
  110. hp2:=pai(hp^.getcopy);
  111. case hp2^.typ of
  112. ait_instruction :
  113. begin
  114. { fixup the references }
  115. for i:=1 to pai386(hp2)^.ops do
  116. if pai386(hp2)^.oper[i-1].typ=top_ref then
  117. begin
  118. r:=pai386(hp2)^.oper[i-1].ref;
  119. case r^.options of
  120. ref_parafixup :
  121. r^.offsetfixup:=parafixup;
  122. ref_localfixup :
  123. r^.offsetfixup:=localfixup;
  124. end;
  125. end;
  126. exprasmlist^.concat(hp2);
  127. end;
  128. ait_marker :
  129. begin
  130. { it's not an assembler block anymore }
  131. if not(pai_marker(hp2)^.kind in [AsmBlockStart, AsmBlockEnd]) then
  132. exprasmlist^.concat(hp2);
  133. end;
  134. else
  135. exprasmlist^.concat(hp2);
  136. end;
  137. hp:=pai(hp^.next);
  138. end
  139. end
  140. else
  141. exprasmlist^.concatlist(p^.p_asm);
  142. if not p^.object_preserved then
  143. begin
  144. {$ifdef i386}
  145. maybe_loadesi;
  146. {$endif}
  147. {$ifdef m68k}
  148. maybe_loada5;
  149. {$endif}
  150. end;
  151. end;
  152. procedure secondpass(var p : ptree);
  153. const
  154. procedures : array[ttreetyp] of secondpassproc =
  155. (secondadd, {addn}
  156. secondadd, {muln}
  157. secondadd, {subn}
  158. secondmoddiv, {divn}
  159. secondadd, {symdifn}
  160. secondmoddiv, {modn}
  161. secondassignment, {assignn}
  162. secondload, {loadn}
  163. secondnothing, {range}
  164. secondadd, {ltn}
  165. secondadd, {lten}
  166. secondadd, {gtn}
  167. secondadd, {gten}
  168. secondadd, {equaln}
  169. secondadd, {unequaln}
  170. secondin, {inn}
  171. secondadd, {orn}
  172. secondadd, {xorn}
  173. secondshlshr, {shrn}
  174. secondshlshr, {shln}
  175. secondadd, {slashn}
  176. secondadd, {andn}
  177. secondsubscriptn, {subscriptn}
  178. secondderef, {derefn}
  179. secondaddr, {addrn}
  180. seconddoubleaddr, {doubleaddrn}
  181. secondordconst, {ordconstn}
  182. secondtypeconv, {typeconvn}
  183. secondcalln, {calln}
  184. secondnothing, {callparan}
  185. secondrealconst, {realconstn}
  186. secondfixconst, {fixconstn}
  187. secondumminus, {umminusn}
  188. secondasm, {asmn}
  189. secondvecn, {vecn}
  190. secondstringconst, {stringconstn}
  191. secondfuncret, {funcretn}
  192. secondselfn, {selfn}
  193. secondnot, {notn}
  194. secondinline, {inlinen}
  195. secondniln, {niln}
  196. seconderror, {errorn}
  197. secondnothing, {typen}
  198. secondhnewn, {hnewn}
  199. secondhdisposen, {hdisposen}
  200. secondnewn, {newn}
  201. secondsimplenewdispose, {simpledisposen}
  202. secondsetelement, {setelementn}
  203. secondsetconst, {setconstn}
  204. secondblockn, {blockn}
  205. secondstatement, {statementn}
  206. secondnothing, {loopn}
  207. secondifn, {ifn}
  208. secondbreakn, {breakn}
  209. secondcontinuen, {continuen}
  210. second_while_repeatn, {repeatn}
  211. second_while_repeatn, {whilen}
  212. secondfor, {forn}
  213. secondexitn, {exitn}
  214. secondwith, {withn}
  215. secondcase, {casen}
  216. secondlabel, {labeln}
  217. secondgoto, {goton}
  218. secondsimplenewdispose, {simplenewn}
  219. secondtryexcept, {tryexceptn}
  220. secondraise, {raisen}
  221. secondnothing, {switchesn}
  222. secondtryfinally, {tryfinallyn}
  223. secondon, {onn}
  224. secondis, {isn}
  225. secondas, {asn}
  226. seconderror, {caretn}
  227. secondfail, {failn}
  228. secondadd, {starstarn}
  229. secondprocinline, {procinlinen}
  230. secondarrayconstruct, {arrayconstructn}
  231. secondnothing, {arrayconstructrangen}
  232. secondnothing, {nothingn}
  233. secondloadvmt {loadvmtn}
  234. );
  235. var
  236. oldcodegenerror : boolean;
  237. oldlocalswitches : tlocalswitches;
  238. oldpos : tfileposinfo;
  239. begin
  240. if not(p^.error) then
  241. begin
  242. oldcodegenerror:=codegenerror;
  243. oldlocalswitches:=aktlocalswitches;
  244. oldpos:=aktfilepos;
  245. aktfilepos:=p^.fileinfo;
  246. aktlocalswitches:=p^.localswitches;
  247. codegenerror:=false;
  248. procedures[p^.treetype](p);
  249. p^.error:=codegenerror;
  250. codegenerror:=codegenerror or oldcodegenerror;
  251. aktlocalswitches:=oldlocalswitches;
  252. aktfilepos:=oldpos;
  253. end
  254. else
  255. codegenerror:=true;
  256. end;
  257. function do_secondpass(var p : ptree) : boolean;
  258. begin
  259. codegenerror:=false;
  260. if not(p^.error) then
  261. secondpass(p);
  262. do_secondpass:=codegenerror;
  263. end;
  264. var
  265. regvars : array[1..maxvarregs] of pvarsym;
  266. regvars_para : array[1..maxvarregs] of boolean;
  267. regvars_refs : array[1..maxvarregs] of longint;
  268. parasym : boolean;
  269. procedure searchregvars(p : pnamedindexobject);
  270. var
  271. i,j,k : longint;
  272. begin
  273. if (psym(p)^.typ=varsym) and (vo_regable in pvarsym(p)^.varoptions) then
  274. begin
  275. { walk through all momentary register variables }
  276. for i:=1 to maxvarregs do
  277. begin
  278. { free register ? }
  279. if regvars[i]=nil then
  280. begin
  281. regvars[i]:=pvarsym(p);
  282. regvars_para[i]:=parasym;
  283. break;
  284. end;
  285. { else throw out a variable ? }
  286. j:=pvarsym(p)^.refs;
  287. { parameter get a less value }
  288. if parasym then
  289. begin
  290. if cs_littlesize in aktglobalswitches then
  291. dec(j,1)
  292. else
  293. dec(j,100);
  294. end;
  295. if (j>regvars_refs[i]) and (j>0) then
  296. begin
  297. for k:=maxvarregs-1 downto i do
  298. begin
  299. regvars[k+1]:=regvars[k];
  300. regvars_para[k+1]:=regvars_para[k];
  301. end;
  302. { calc the new refs
  303. pvarsym(p)^.refs:=j; }
  304. regvars[i]:=pvarsym(p);
  305. regvars_para[i]:=parasym;
  306. regvars_refs[i]:=j;
  307. break;
  308. end;
  309. end;
  310. end;
  311. end;
  312. procedure generatecode(var p : ptree);
  313. var
  314. i : longint;
  315. regsize : topsize;
  316. hr : preference;
  317. label
  318. nextreg;
  319. begin
  320. {!!!!!!!! temptoremove:=nil; }
  321. cleartempgen;
  322. { when size optimization only count occurrence }
  323. if cs_littlesize in aktglobalswitches then
  324. t_times:=1
  325. else
  326. { reference for repetition is 100 }
  327. t_times:=100;
  328. { clear register count }
  329. clearregistercount;
  330. use_esp_stackframe:=false;
  331. if not(do_firstpass(p)) then
  332. begin
  333. { max. optimizations }
  334. { only if no asm is used }
  335. { and no try statement }
  336. if (cs_regalloc in aktglobalswitches) and
  337. ((procinfo.flags and (pi_uses_asm or pi_uses_exceptions))=0) then
  338. begin
  339. { can we omit the stack frame ? }
  340. { conditions:
  341. 1. procedure (not main block)
  342. 2. no constructor or destructor
  343. 3. no call to other procedures
  344. 4. no interrupt handler
  345. }
  346. if assigned(aktprocsym) then
  347. begin
  348. if not(aktprocsym^.definition^.proctypeoption in [potype_constructor,potype_destructor]) and
  349. not(po_interrupt in aktprocsym^.definition^.procoptions) and
  350. ((procinfo.flags and pi_do_call)=0) and
  351. (lexlevel>=normal_function_level) then
  352. begin
  353. { use ESP as frame pointer }
  354. procinfo.framepointer:=stack_pointer;
  355. use_esp_stackframe:=true;
  356. { calc parameter distance new }
  357. dec(procinfo.framepointer_offset,4);
  358. dec(procinfo.ESI_offset,4);
  359. { is this correct ???}
  360. { retoffset can be negativ for results in eax !! }
  361. { the value should be decreased only if positive }
  362. if procinfo.retoffset>=0 then
  363. dec(procinfo.retoffset,4);
  364. dec(procinfo.call_offset,4);
  365. aktprocsym^.definition^.parast^.address_fixup:=procinfo.call_offset;
  366. end;
  367. end;
  368. if (p^.registers32<4) then
  369. begin
  370. for i:=1 to maxvarregs do
  371. regvars[i]:=nil;
  372. parasym:=false;
  373. symtablestack^.foreach({$ifndef TP}@{$endif}searchregvars);
  374. { copy parameter into a register ? }
  375. parasym:=true;
  376. symtablestack^.next^.foreach({$ifndef TP}@{$endif}searchregvars);
  377. { hold needed registers free }
  378. for i:=maxvarregs downto maxvarregs-p^.registers32+1 do
  379. regvars[i]:=nil;
  380. { now assign register }
  381. for i:=1 to maxvarregs-p^.registers32 do
  382. begin
  383. if assigned(regvars[i]) then
  384. begin
  385. { it is nonsens, to copy the variable to }
  386. { a register because we need then much }
  387. { too pushes ? }
  388. if reg_pushes[varregs[i]]>=regvars[i]^.refs then
  389. begin
  390. regvars[i]:=nil;
  391. goto nextreg;
  392. end;
  393. { register is no longer available for }
  394. { expressions }
  395. { search the register which is the most }
  396. { unused }
  397. usableregs:=usableregs-[varregs[i]];
  398. is_reg_var[varregs[i]]:=true;
  399. dec(c_usableregs);
  400. { possibly no 32 bit register are needed }
  401. { call by reference/const ? }
  402. if (regvars[i]^.varspez=vs_var) or
  403. ((regvars[i]^.varspez=vs_const) and
  404. push_addr_param(regvars[i]^.definition)) then
  405. begin
  406. regvars[i]^.reg:=varregs[i];
  407. regsize:=S_L;
  408. end
  409. else
  410. if (regvars[i]^.definition^.deftype=orddef) and
  411. (porddef(regvars[i]^.definition)^.size=1) then
  412. begin
  413. {$ifdef i386}
  414. regvars[i]^.reg:=reg32toreg8(varregs[i]);
  415. {$endif}
  416. regsize:=S_B;
  417. end
  418. else
  419. if (regvars[i]^.definition^.deftype=orddef) and
  420. (porddef(regvars[i]^.definition)^.size=2) then
  421. begin
  422. {$ifdef i386}
  423. regvars[i]^.reg:=reg32toreg16(varregs[i]);
  424. {$endif}
  425. regsize:=S_W;
  426. end
  427. else
  428. begin
  429. regvars[i]^.reg:=varregs[i];
  430. regsize:=S_L;
  431. end;
  432. { parameter must be load }
  433. if regvars_para[i] then
  434. begin
  435. { procinfo is there actual, }
  436. { because we can't never be in a }
  437. { nested procedure }
  438. { when loading parameter to reg }
  439. new(hr);
  440. reset_reference(hr^);
  441. hr^.offset:=pvarsym(regvars[i])^.address+procinfo.call_offset;
  442. hr^.base:=procinfo.framepointer;
  443. {$ifdef i386}
  444. procinfo.aktentrycode^.concat(new(pai386,op_ref_reg(A_MOV,regsize,
  445. hr,regvars[i]^.reg)));
  446. {$endif i386}
  447. {$ifdef m68k}
  448. procinfo.aktentrycode^.concat(new(pai68k,op_ref_reg(A_MOVE,regsize,
  449. hr,regvars[i]^.reg)));
  450. {$endif m68k}
  451. unused:=unused - [regvars[i]^.reg];
  452. end;
  453. { procedure uses this register }
  454. {$ifdef i386}
  455. usedinproc:=usedinproc or ($80 shr byte(varregs[i]));
  456. {$endif i386}
  457. {$ifdef m68k}
  458. usedinproc:=usedinproc or ($800 shr word(varregs[i]));
  459. {$endif m68k}
  460. end;
  461. nextreg:
  462. { dummy }
  463. regsize:=S_W;
  464. end;
  465. for i:=1 to maxvarregs do
  466. begin
  467. if assigned(regvars[i]) then
  468. begin
  469. if cs_asm_source in aktglobalswitches then
  470. procinfo.aktentrycode^.insert(new(pai_asm_comment,init(strpnew(regvars[i]^.name+
  471. ' with weight '+tostr(regvars[i]^.refs)+' assigned to register '+
  472. reg2str(regvars[i]^.reg)))));
  473. if (status.verbosity and v_debug)=v_debug then
  474. Message3(cg_d_register_weight,reg2str(regvars[i]^.reg),
  475. tostr(regvars[i]^.refs),regvars[i]^.name);
  476. end;
  477. end;
  478. if cs_asm_source in aktglobalswitches then
  479. procinfo.aktentrycode^.insert(new(pai_asm_comment,init(strpnew('Register variable assignment:'))));
  480. end;
  481. end;
  482. if assigned(aktprocsym) and
  483. (pocall_inline in aktprocsym^.definition^.proccalloptions) then
  484. make_const_global:=true;
  485. do_secondpass(p);
  486. if assigned(procinfo.def) then
  487. procinfo.def^.fpu_used:=p^.registersfpu;
  488. { all registers can be used again }
  489. resetusableregisters;
  490. end;
  491. procinfo.aktproccode^.concatlist(exprasmlist);
  492. make_const_global:=false;
  493. end;
  494. end.
  495. {
  496. $Log$
  497. Revision 1.27 1999-08-03 22:02:55 peter
  498. * moved bitmask constants to sets
  499. * some other type/const renamings
  500. Revision 1.26 1999/06/02 22:44:08 pierre
  501. * previous wrong log corrected
  502. Revision 1.25 1999/06/02 22:25:41 pierre
  503. * changed $ifdef FPC @ into $ifndef TP
  504. Revision 1.24 1999/06/01 14:45:50 peter
  505. * @procvar is now always needed for FPC
  506. Revision 1.23 1999/05/27 19:44:43 peter
  507. * removed oldasm
  508. * plabel -> pasmlabel
  509. * -a switches to source writing automaticly
  510. * assembler readers OOPed
  511. * asmsymbol automaticly external
  512. * jumptables and other label fixes for asm readers
  513. Revision 1.22 1999/05/18 14:15:50 peter
  514. * containsself fixes
  515. * checktypes()
  516. Revision 1.21 1999/05/17 21:57:11 florian
  517. * new temporary ansistring handling
  518. Revision 1.20 1999/05/02 21:33:54 florian
  519. * several bugs regarding -Or fixed
  520. Revision 1.19 1999/05/01 13:24:28 peter
  521. * merged nasm compiler
  522. * old asm moved to oldasm/
  523. Revision 1.18 1999/04/28 06:02:04 florian
  524. * changes of Bruessel:
  525. + message handler can now take an explicit self
  526. * typinfo fixed: sometimes the type names weren't written
  527. * the type checking for pointer comparisations and subtraction
  528. and are now more strict (was also buggy)
  529. * small bug fix to link.pas to support compiling on another
  530. drive
  531. * probable bug in popt386 fixed: call/jmp => push/jmp
  532. transformation didn't count correctly the jmp references
  533. + threadvar support
  534. * warning if ln/sqrt gets an invalid constant argument
  535. Revision 1.17 1999/03/31 13:55:11 peter
  536. * assembler inlining working for ag386bin
  537. Revision 1.16 1999/03/24 23:17:11 peter
  538. * fixed bugs 212,222,225,227,229,231,233
  539. Revision 1.15 1999/02/22 02:15:25 peter
  540. * updates for ag386bin
  541. Revision 1.14 1999/01/23 23:29:37 florian
  542. * first running version of the new code generator
  543. * when compiling exceptions under Linux fixed
  544. Revision 1.13 1998/12/30 13:41:09 peter
  545. * released valuepara
  546. Revision 1.12 1998/12/19 00:23:51 florian
  547. * ansistring memory leaks fixed
  548. Revision 1.11 1998/12/11 00:03:28 peter
  549. + globtype,tokens,version unit splitted from globals
  550. Revision 1.10 1998/11/18 15:44:14 peter
  551. * VALUEPARA for tp7 compatible value parameters
  552. Revision 1.9 1998/11/13 15:40:21 pierre
  553. + added -Se in Makefile cvstest target
  554. + lexlevel cleanup
  555. normal_function_level main_program_level and unit_init_level defined
  556. * tins_cache grown to A_EMMS (gave range check error in asm readers)
  557. (test added in code !)
  558. * -Un option was wrong
  559. * _FAIL and _SELF only keyword inside
  560. constructors and methods respectively
  561. Revision 1.8 1998/10/29 15:42:49 florian
  562. + partial disposing of temp. ansistrings
  563. Revision 1.7 1998/10/26 22:58:19 florian
  564. * new introduded problem with classes fix, the parent class wasn't set
  565. correct, if the class was defined forward before
  566. Revision 1.6 1998/09/23 09:58:52 peter
  567. * first working array of const things
  568. Revision 1.5 1998/09/21 10:01:06 peter
  569. * check if procinfo.def is assigned before storing registersfpu
  570. Revision 1.4 1998/09/21 08:45:16 pierre
  571. + added vmt_offset in tobjectdef.write for fututre use
  572. (first steps to have objects without vmt if no virtual !!)
  573. + added fpu_used field for tabstractprocdef :
  574. sets this level to 2 if the functions return with value in FPU
  575. (is then set to correct value at parsing of implementation)
  576. THIS MIGHT refuse some code with FPU expression too complex
  577. that were accepted before and even in some cases
  578. that don't overflow in fact
  579. ( like if f : float; is a forward that finally in implementation
  580. only uses one fpu register !!)
  581. Nevertheless I think that it will improve security on
  582. FPU operations !!
  583. * most other changes only for UseBrowser code
  584. (added symtable references for record and objects)
  585. local switch for refs to args and local of each function
  586. (static symtable still missing)
  587. UseBrowser still not stable and probably broken by
  588. the definition hash array !!
  589. Revision 1.3 1998/09/17 09:42:40 peter
  590. + pass_2 for cg386
  591. * Message() -> CGMessage() for pass_1/pass_2
  592. Revision 1.2 1998/09/07 18:46:07 peter
  593. * update smartlinking, uses getdatalabel
  594. * renamed ptree.value vars to value_str,value_real,value_set
  595. Revision 1.1 1998/09/01 09:07:12 peter
  596. * m68k fixes, splitted cg68k like cgi386
  597. }