pass_2.pas 21 KB

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