pass_2.pas 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655
  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. {$ifndef OLDASM}
  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. {$ifndef OLDASM}
  99. var
  100. hp,hp2 : pai;
  101. localfixup,parafixup,
  102. i : longint;
  103. r : preference;
  104. {$endif}
  105. begin
  106. {$ifndef OLDASM}
  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 : pnamedindexobject);
  275. var
  276. i,j,k : longint;
  277. begin
  278. if (psym(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. for i:=1 to maxvarregs do
  479. begin
  480. if assigned(regvars[i]) then
  481. begin
  482. if cs_asm_source in aktglobalswitches then
  483. procinfo.aktentrycode^.insert(new(pai_asm_comment,init(strpnew(regvars[i]^.name+
  484. ' with weight '+tostr(regvars[i]^.refs)+' assigned to register '+
  485. reg2str(regvars[i]^.reg)))));
  486. if (status.verbosity and v_debug)=v_debug then
  487. Message3(cg_d_register_weight,reg2str(regvars[i]^.reg),
  488. tostr(regvars[i]^.refs),regvars[i]^.name);
  489. end;
  490. end;
  491. if cs_asm_source in aktglobalswitches then
  492. procinfo.aktentrycode^.insert(new(pai_asm_comment,init(strpnew('Register variable assignment:'))));
  493. end;
  494. end;
  495. if assigned(aktprocsym) and
  496. ((aktprocsym^.definition^.options and poinline)<>0) then
  497. make_const_global:=true;
  498. do_secondpass(p);
  499. if assigned(procinfo.def) then
  500. procinfo.def^.fpu_used:=p^.registersfpu;
  501. { all registers can be used again }
  502. resetusableregisters;
  503. end;
  504. procinfo.aktproccode^.concatlist(exprasmlist);
  505. make_const_global:=false;
  506. end;
  507. end.
  508. {
  509. $Log$
  510. Revision 1.20 1999-05-02 21:33:54 florian
  511. * several bugs regarding -Or fixed
  512. Revision 1.19 1999/05/01 13:24:28 peter
  513. * merged nasm compiler
  514. * old asm moved to oldasm/
  515. Revision 1.18 1999/04/28 06:02:04 florian
  516. * changes of Bruessel:
  517. + message handler can now take an explicit self
  518. * typinfo fixed: sometimes the type names weren't written
  519. * the type checking for pointer comparisations and subtraction
  520. and are now more strict (was also buggy)
  521. * small bug fix to link.pas to support compiling on another
  522. drive
  523. * probable bug in popt386 fixed: call/jmp => push/jmp
  524. transformation didn't count correctly the jmp references
  525. + threadvar support
  526. * warning if ln/sqrt gets an invalid constant argument
  527. Revision 1.17 1999/03/31 13:55:11 peter
  528. * assembler inlining working for ag386bin
  529. Revision 1.16 1999/03/24 23:17:11 peter
  530. * fixed bugs 212,222,225,227,229,231,233
  531. Revision 1.15 1999/02/22 02:15:25 peter
  532. * updates for ag386bin
  533. Revision 1.14 1999/01/23 23:29:37 florian
  534. * first running version of the new code generator
  535. * when compiling exceptions under Linux fixed
  536. Revision 1.13 1998/12/30 13:41:09 peter
  537. * released valuepara
  538. Revision 1.12 1998/12/19 00:23:51 florian
  539. * ansistring memory leaks fixed
  540. Revision 1.11 1998/12/11 00:03:28 peter
  541. + globtype,tokens,version unit splitted from globals
  542. Revision 1.10 1998/11/18 15:44:14 peter
  543. * VALUEPARA for tp7 compatible value parameters
  544. Revision 1.9 1998/11/13 15:40:21 pierre
  545. + added -Se in Makefile cvstest target
  546. + lexlevel cleanup
  547. normal_function_level main_program_level and unit_init_level defined
  548. * tins_cache grown to A_EMMS (gave range check error in asm readers)
  549. (test added in code !)
  550. * -Un option was wrong
  551. * _FAIL and _SELF only keyword inside
  552. constructors and methods respectively
  553. Revision 1.8 1998/10/29 15:42:49 florian
  554. + partial disposing of temp. ansistrings
  555. Revision 1.7 1998/10/26 22:58:19 florian
  556. * new introduded problem with classes fix, the parent class wasn't set
  557. correct, if the class was defined forward before
  558. Revision 1.6 1998/09/23 09:58:52 peter
  559. * first working array of const things
  560. Revision 1.5 1998/09/21 10:01:06 peter
  561. * check if procinfo.def is assigned before storing registersfpu
  562. Revision 1.4 1998/09/21 08:45:16 pierre
  563. + added vmt_offset in tobjectdef.write for fututre use
  564. (first steps to have objects without vmt if no virtual !!)
  565. + added fpu_used field for tabstractprocdef :
  566. sets this level to 2 if the functions return with value in FPU
  567. (is then set to correct value at parsing of implementation)
  568. THIS MIGHT refuse some code with FPU expression too complex
  569. that were accepted before and even in some cases
  570. that don't overflow in fact
  571. ( like if f : float; is a forward that finally in implementation
  572. only uses one fpu register !!)
  573. Nevertheless I think that it will improve security on
  574. FPU operations !!
  575. * most other changes only for UseBrowser code
  576. (added symtable references for record and objects)
  577. local switch for refs to args and local of each function
  578. (static symtable still missing)
  579. UseBrowser still not stable and probably broken by
  580. the definition hash array !!
  581. Revision 1.3 1998/09/17 09:42:40 peter
  582. + pass_2 for cg386
  583. * Message() -> CGMessage() for pass_1/pass_2
  584. Revision 1.2 1998/09/07 18:46:07 peter
  585. * update smartlinking, uses getdatalabel
  586. * renamed ptree.value vars to value_str,value_real,value_set
  587. Revision 1.1 1998/09/01 09:07:12 peter
  588. * m68k fixes, splitted cg68k like cgi386
  589. }