pass_2.pas 21 KB

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