pass_2.pas 23 KB

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