cg386flw.pas 42 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240
  1. {
  2. $Id$
  3. Copyright (c) 1998-2000 by Florian Klaempfl
  4. Generate i386 assembler for nodes that influence the flow
  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 FPC}
  19. {$goto on}
  20. {$endif FPC}
  21. unit cg386flw;
  22. interface
  23. uses
  24. tree;
  25. procedure second_while_repeatn(var p : ptree);
  26. procedure secondifn(var p : ptree);
  27. procedure secondfor(var p : ptree);
  28. procedure secondexitn(var p : ptree);
  29. procedure secondbreakn(var p : ptree);
  30. procedure secondcontinuen(var p : ptree);
  31. procedure secondgoto(var p : ptree);
  32. procedure secondlabel(var p : ptree);
  33. procedure secondraise(var p : ptree);
  34. procedure secondtryexcept(var p : ptree);
  35. procedure secondtryfinally(var p : ptree);
  36. procedure secondon(var p : ptree);
  37. procedure secondfail(var p : ptree);
  38. type
  39. tenumflowcontrol = (fc_exit,fc_break,fc_continue);
  40. tflowcontrol = set of tenumflowcontrol;
  41. var
  42. flowcontrol : tflowcontrol;
  43. implementation
  44. uses
  45. cobjects,verbose,globtype,globals,systems,
  46. symconst,symtable,aasm,types,
  47. hcodegen,temp_gen,pass_2,
  48. cpubase,cpuasm,
  49. cgai386,tgeni386,tcflw;
  50. {*****************************************************************************
  51. Second_While_RepeatN
  52. *****************************************************************************}
  53. procedure second_while_repeatn(var p : ptree);
  54. var
  55. lcont,lbreak,lloop,
  56. oldclabel,oldblabel : pasmlabel;
  57. otlabel,oflabel : pasmlabel;
  58. begin
  59. getlabel(lloop);
  60. getlabel(lcont);
  61. getlabel(lbreak);
  62. { arrange continue and breaklabels: }
  63. oldclabel:=aktcontinuelabel;
  64. oldblabel:=aktbreaklabel;
  65. { handling code at the end as it is much more efficient, and makes
  66. while equal to repeat loop, only the end true/false is swapped (PFV) }
  67. if p^.treetype=whilen then
  68. emitjmp(C_None,lcont);
  69. emitlab(lloop);
  70. aktcontinuelabel:=lcont;
  71. aktbreaklabel:=lbreak;
  72. cleartempgen;
  73. if assigned(p^.right) then
  74. secondpass(p^.right);
  75. emitlab(lcont);
  76. otlabel:=truelabel;
  77. oflabel:=falselabel;
  78. if p^.treetype=whilen then
  79. begin
  80. truelabel:=lloop;
  81. falselabel:=lbreak;
  82. end
  83. { repeatn }
  84. else
  85. begin
  86. truelabel:=lbreak;
  87. falselabel:=lloop;
  88. end;
  89. cleartempgen;
  90. secondpass(p^.left);
  91. maketojumpbool(p^.left);
  92. emitlab(lbreak);
  93. truelabel:=otlabel;
  94. falselabel:=oflabel;
  95. aktcontinuelabel:=oldclabel;
  96. aktbreaklabel:=oldblabel;
  97. { a break/continue in a while/repeat block can't be seen outside }
  98. flowcontrol:=flowcontrol-[fc_break,fc_continue];
  99. end;
  100. {*****************************************************************************
  101. SecondIfN
  102. *****************************************************************************}
  103. procedure secondifn(var p : ptree);
  104. var
  105. hl,otlabel,oflabel : pasmlabel;
  106. begin
  107. otlabel:=truelabel;
  108. oflabel:=falselabel;
  109. getlabel(truelabel);
  110. getlabel(falselabel);
  111. cleartempgen;
  112. secondpass(p^.left);
  113. maketojumpbool(p^.left);
  114. if assigned(p^.right) then
  115. begin
  116. emitlab(truelabel);
  117. cleartempgen;
  118. secondpass(p^.right);
  119. end;
  120. if assigned(p^.t1) then
  121. begin
  122. if assigned(p^.right) then
  123. begin
  124. getlabel(hl);
  125. { do go back to if line !! }
  126. aktfilepos:=exprasmlist^.getlasttaifilepos^;
  127. emitjmp(C_None,hl);
  128. end;
  129. emitlab(falselabel);
  130. cleartempgen;
  131. secondpass(p^.t1);
  132. if assigned(p^.right) then
  133. emitlab(hl);
  134. end
  135. else
  136. begin
  137. emitlab(falselabel);
  138. end;
  139. if not(assigned(p^.right)) then
  140. begin
  141. emitlab(truelabel);
  142. end;
  143. truelabel:=otlabel;
  144. falselabel:=oflabel;
  145. end;
  146. {*****************************************************************************
  147. SecondFor
  148. *****************************************************************************}
  149. procedure secondfor(var p : ptree);
  150. var
  151. l3,oldclabel,oldblabel : pasmlabel;
  152. omitfirstcomp,temptovalue : boolean;
  153. hs : byte;
  154. temp1 : treference;
  155. hop : tasmop;
  156. hcond : tasmcond;
  157. cmpreg,cmp32 : tregister;
  158. opsize : topsize;
  159. count_var_is_signed : boolean;
  160. begin
  161. oldclabel:=aktcontinuelabel;
  162. oldblabel:=aktbreaklabel;
  163. getlabel(aktcontinuelabel);
  164. getlabel(aktbreaklabel);
  165. getlabel(l3);
  166. { could we spare the first comparison ? }
  167. omitfirstcomp:=false;
  168. if p^.right^.treetype=ordconstn then
  169. if p^.left^.right^.treetype=ordconstn then
  170. omitfirstcomp:=(p^.backward and (p^.left^.right^.value>=p^.right^.value))
  171. or (not(p^.backward) and (p^.left^.right^.value<=p^.right^.value));
  172. { only calculate reference }
  173. cleartempgen;
  174. secondpass(p^.t2);
  175. hs:=p^.t2^.resulttype^.size;
  176. if p^.t2^.location.loc <> LOC_CREGISTER then
  177. cmp32:=getregister32;
  178. case hs of
  179. 1 : begin
  180. opsize:=S_B;
  181. if p^.t2^.location.loc <> LOC_CREGISTER then
  182. cmpreg:=reg32toreg8(cmp32);
  183. end;
  184. 2 : begin
  185. opsize:=S_W;
  186. if p^.t2^.location.loc <> LOC_CREGISTER then
  187. cmpreg:=reg32toreg16(cmp32);
  188. end;
  189. 4 : begin
  190. opsize:=S_L;
  191. if p^.t2^.location.loc <> LOC_CREGISTER then
  192. cmpreg:=cmp32;
  193. end;
  194. end;
  195. { first set the to value
  196. because the count var can be in the expression !! }
  197. cleartempgen;
  198. secondpass(p^.right);
  199. { calculate pointer value and check if changeable and if so }
  200. { load into temporary variable }
  201. if p^.right^.treetype<>ordconstn then
  202. begin
  203. temp1.symbol:=nil;
  204. gettempofsizereference(hs,temp1);
  205. temptovalue:=true;
  206. if (p^.right^.location.loc=LOC_REGISTER) or
  207. (p^.right^.location.loc=LOC_CREGISTER) then
  208. begin
  209. emit_reg_ref(A_MOV,opsize,p^.right^.location.register,
  210. newreference(temp1));
  211. end
  212. else
  213. concatcopy(p^.right^.location.reference,temp1,hs,false,false);
  214. end
  215. else
  216. temptovalue:=false;
  217. { produce start assignment }
  218. cleartempgen;
  219. secondpass(p^.left);
  220. count_var_is_signed:=is_signed(porddef(p^.t2^.resulttype));
  221. if temptovalue then
  222. begin
  223. if p^.t2^.location.loc=LOC_CREGISTER then
  224. begin
  225. emit_ref_reg(A_CMP,opsize,newreference(temp1),
  226. p^.t2^.location.register);
  227. end
  228. else
  229. begin
  230. emit_ref_reg(A_MOV,opsize,newreference(p^.t2^.location.reference),
  231. cmpreg);
  232. emit_ref_reg(A_CMP,opsize,newreference(temp1),
  233. cmpreg);
  234. { temp register not necessary anymore currently (JM) }
  235. ungetregister32(cmp32);
  236. end;
  237. end
  238. else
  239. begin
  240. if not(omitfirstcomp) then
  241. begin
  242. if p^.t2^.location.loc=LOC_CREGISTER then
  243. emit_const_reg(A_CMP,opsize,p^.right^.value,
  244. p^.t2^.location.register)
  245. else
  246. emit_const_ref(A_CMP,opsize,p^.right^.value,
  247. newreference(p^.t2^.location.reference));
  248. end;
  249. end;
  250. if p^.backward then
  251. if count_var_is_signed then
  252. hcond:=C_L
  253. else
  254. hcond:=C_B
  255. else
  256. if count_var_is_signed then
  257. hcond:=C_G
  258. else
  259. hcond:=C_A;
  260. if not(omitfirstcomp) or temptovalue then
  261. emitjmp(hcond,aktbreaklabel);
  262. { align loop target }
  263. if not(cs_littlesize in aktglobalswitches) then
  264. exprasmlist^.concat(new(pai_align,init_op(4,$90)));
  265. emitlab(l3);
  266. { help register must not be in instruction block }
  267. cleartempgen;
  268. if assigned(p^.t1) then
  269. secondpass(p^.t1);
  270. emitlab(aktcontinuelabel);
  271. { makes no problems there }
  272. cleartempgen;
  273. if (p^.t2^.location.loc <> LOC_CREGISTER) then
  274. begin
  275. { demand help register again }
  276. cmp32:=getregister32;
  277. case hs of
  278. 1 : cmpreg:=reg32toreg8(cmp32);
  279. 2 : cmpreg:=reg32toreg16(cmp32);
  280. 4 : cmpreg:=cmp32;
  281. end;
  282. end;
  283. { produce comparison and the corresponding }
  284. { jump }
  285. if temptovalue then
  286. begin
  287. if p^.t2^.location.loc=LOC_CREGISTER then
  288. begin
  289. emit_ref_reg(A_CMP,opsize,newreference(temp1),
  290. p^.t2^.location.register);
  291. end
  292. else
  293. begin
  294. emit_ref_reg(A_MOV,opsize,newreference(p^.t2^.location.reference),
  295. cmpreg);
  296. emit_ref_reg(A_CMP,opsize,newreference(temp1),
  297. cmpreg);
  298. end;
  299. end
  300. else
  301. begin
  302. if p^.t2^.location.loc=LOC_CREGISTER then
  303. emit_const_reg(A_CMP,opsize,p^.right^.value,
  304. p^.t2^.location.register)
  305. else
  306. emit_const_ref(A_CMP,opsize,p^.right^.value,
  307. newreference(p^.t2^.location.reference));
  308. end;
  309. if p^.backward then
  310. if count_var_is_signed then
  311. hcond:=C_LE
  312. else
  313. hcond:=C_BE
  314. else
  315. if count_var_is_signed then
  316. hcond:=C_GE
  317. else
  318. hcond:=C_AE;
  319. emitjmp(hcond,aktbreaklabel);
  320. { according to count direction DEC or INC... }
  321. { must be after the test because of 0to 255 for bytes !! }
  322. if p^.backward then
  323. hop:=A_DEC
  324. else
  325. hop:=A_INC;
  326. if p^.t2^.location.loc=LOC_CREGISTER then
  327. emit_reg(hop,opsize,p^.t2^.location.register)
  328. else
  329. emit_ref(hop,opsize,newreference(p^.t2^.location.reference));
  330. emitjmp(C_None,l3);
  331. if (p^.t2^.location.loc <> LOC_CREGISTER) then
  332. ungetregister32(cmp32);
  333. if temptovalue then
  334. ungetiftemp(temp1);
  335. { this is the break label: }
  336. emitlab(aktbreaklabel);
  337. aktcontinuelabel:=oldclabel;
  338. aktbreaklabel:=oldblabel;
  339. { a break/continue in a for block can't be seen outside }
  340. flowcontrol:=flowcontrol-[fc_break,fc_continue];
  341. end;
  342. {*****************************************************************************
  343. SecondExitN
  344. *****************************************************************************}
  345. procedure secondexitn(var p : ptree);
  346. var
  347. is_mem : boolean;
  348. {op : tasmop;
  349. s : topsize;}
  350. otlabel,oflabel : pasmlabel;
  351. r : preference;
  352. label
  353. do_jmp;
  354. begin
  355. include(flowcontrol,fc_exit);
  356. if assigned(p^.left) then
  357. if p^.left^.treetype=assignn then
  358. begin
  359. { just do a normal assignment followed by exit }
  360. secondpass(p^.left);
  361. emitjmp(C_None,aktexitlabel);
  362. end
  363. else
  364. begin
  365. otlabel:=truelabel;
  366. oflabel:=falselabel;
  367. getlabel(truelabel);
  368. getlabel(falselabel);
  369. secondpass(p^.left);
  370. case p^.left^.location.loc of
  371. LOC_FPU : goto do_jmp;
  372. LOC_MEM,
  373. LOC_REFERENCE : is_mem:=true;
  374. LOC_CREGISTER,
  375. LOC_REGISTER : is_mem:=false;
  376. LOC_FLAGS : begin
  377. emit_flag2reg(p^.left^.location.resflags,R_AL);
  378. goto do_jmp;
  379. end;
  380. LOC_JUMP : begin
  381. emitlab(truelabel);
  382. emit_const_reg(A_MOV,S_B,1,R_AL);
  383. emitjmp(C_None,aktexit2label);
  384. emitlab(falselabel);
  385. emit_reg_reg(A_XOR,S_B,R_AL,R_AL);
  386. goto do_jmp;
  387. end;
  388. else
  389. internalerror(2001);
  390. end;
  391. case procinfo^.returntype.def^.deftype of
  392. pointerdef,
  393. procvardef : begin
  394. if is_mem then
  395. emit_ref_reg(A_MOV,S_L,
  396. newreference(p^.left^.location.reference),R_EAX)
  397. else
  398. emit_reg_reg(A_MOV,S_L,
  399. p^.left^.location.register,R_EAX);
  400. end;
  401. floatdef : begin
  402. if pfloatdef(procinfo^.returntype.def)^.typ=f32bit then
  403. begin
  404. if is_mem then
  405. emit_ref_reg(A_MOV,S_L,
  406. newreference(p^.left^.location.reference),R_EAX)
  407. else
  408. emit_reg_reg(A_MOV,S_L,p^.left^.location.register,R_EAX);
  409. end
  410. else
  411. if is_mem then
  412. floatload(pfloatdef(procinfo^.returntype.def)^.typ,p^.left^.location.reference);
  413. end;
  414. { orddef,
  415. enumdef : }
  416. else
  417. { it can be anything shorter than 4 bytes PM
  418. this caused form bug 711 }
  419. begin
  420. case procinfo^.returntype.def^.size of
  421. { it can be a qword/int64 too ... }
  422. 8 : if is_mem then
  423. begin
  424. emit_ref_reg(A_MOV,S_L,
  425. newreference(p^.left^.location.reference),R_EAX);
  426. r:=newreference(p^.left^.location.reference);
  427. inc(r^.offset,4);
  428. emit_ref_reg(A_MOV,S_L,r,R_EDX);
  429. end
  430. else
  431. begin
  432. emit_reg_reg(A_MOV,S_L,p^.left^.location.registerlow,R_EAX);
  433. emit_reg_reg(A_MOV,S_L,p^.left^.location.registerhigh,R_EDX);
  434. end;
  435. { if its 3 bytes only we can still
  436. copy one of garbage ! PM }
  437. 4,3 : if is_mem then
  438. emit_ref_reg(A_MOV,S_L,
  439. newreference(p^.left^.location.reference),R_EAX)
  440. else
  441. emit_reg_reg(A_MOV,S_L,p^.left^.location.register,R_EAX);
  442. 2 : if is_mem then
  443. emit_ref_reg(A_MOV,S_W,
  444. newreference(p^.left^.location.reference),R_AX)
  445. else
  446. emit_reg_reg(A_MOV,S_W,makereg16(p^.left^.location.register),R_AX);
  447. 1 : if is_mem then
  448. emit_ref_reg(A_MOV,S_B,
  449. newreference(p^.left^.location.reference),R_AL)
  450. else
  451. emit_reg_reg(A_MOV,S_B,makereg8(p^.left^.location.register),R_AL);
  452. else internalerror(605001);
  453. end;
  454. end;
  455. end;
  456. do_jmp:
  457. truelabel:=otlabel;
  458. falselabel:=oflabel;
  459. emitjmp(C_None,aktexit2label);
  460. end
  461. else
  462. begin
  463. emitjmp(C_None,aktexitlabel);
  464. end;
  465. end;
  466. {*****************************************************************************
  467. SecondBreakN
  468. *****************************************************************************}
  469. procedure secondbreakn(var p : ptree);
  470. begin
  471. include(flowcontrol,fc_break);
  472. if aktbreaklabel<>nil then
  473. emitjmp(C_None,aktbreaklabel)
  474. else
  475. CGMessage(cg_e_break_not_allowed);
  476. end;
  477. {*****************************************************************************
  478. SecondContinueN
  479. *****************************************************************************}
  480. procedure secondcontinuen(var p : ptree);
  481. begin
  482. include(flowcontrol,fc_continue);
  483. if aktcontinuelabel<>nil then
  484. emitjmp(C_None,aktcontinuelabel)
  485. else
  486. CGMessage(cg_e_continue_not_allowed);
  487. end;
  488. {*****************************************************************************
  489. SecondGoto
  490. *****************************************************************************}
  491. procedure secondgoto(var p : ptree);
  492. begin
  493. emitjmp(C_None,p^.labelnr);
  494. { the assigned avoids only crashes if the label isn't defined }
  495. if assigned(p^.labsym) and
  496. assigned(p^.labsym^.code) and
  497. (aktexceptblock<>ptree(p^.labsym^.code)^.exceptionblock) then
  498. CGMessage(cg_e_goto_inout_of_exception_block);
  499. end;
  500. {*****************************************************************************
  501. SecondLabel
  502. *****************************************************************************}
  503. procedure secondlabel(var p : ptree);
  504. begin
  505. emitlab(p^.labelnr);
  506. cleartempgen;
  507. secondpass(p^.left);
  508. end;
  509. {*****************************************************************************
  510. SecondRaise
  511. *****************************************************************************}
  512. procedure secondraise(var p : ptree);
  513. var
  514. a : pasmlabel;
  515. begin
  516. if assigned(p^.left) then
  517. begin
  518. { multiple parameters? }
  519. if assigned(p^.right) then
  520. begin
  521. { push frame }
  522. if assigned(p^.frametree) then
  523. begin
  524. secondpass(p^.frametree);
  525. if codegenerror then
  526. exit;
  527. emit_push_loc(p^.frametree^.location);
  528. end
  529. else
  530. emit_const(A_PUSH,S_L,0);
  531. { push address }
  532. secondpass(p^.right);
  533. if codegenerror then
  534. exit;
  535. emit_push_loc(p^.right^.location);
  536. end
  537. else
  538. begin
  539. getlabel(a);
  540. emitlab(a);
  541. emit_const(A_PUSH,S_L,0);
  542. emit_sym(A_PUSH,S_L,a);
  543. end;
  544. { push object }
  545. secondpass(p^.left);
  546. if codegenerror then
  547. exit;
  548. emit_push_loc(p^.left^.location);
  549. emitcall('FPC_RAISEEXCEPTION');
  550. end
  551. else
  552. begin
  553. emitcall('FPC_POPADDRSTACK');
  554. emitcall('FPC_RERAISE');
  555. end;
  556. end;
  557. {*****************************************************************************
  558. SecondTryExcept
  559. *****************************************************************************}
  560. var
  561. endexceptlabel : pasmlabel;
  562. { does the necessary things to clean up the object stack }
  563. { in the except block }
  564. procedure cleanupobjectstack;
  565. begin
  566. emitcall('FPC_POPOBJECTSTACK');
  567. exprasmlist^.concat(new(pairegalloc,alloc(R_EAX)));
  568. emit_reg(A_PUSH,S_L,R_EAX);
  569. emitcall('FPC_DESTROYEXCEPTION');
  570. exprasmlist^.concat(new(pairegalloc,dealloc(R_EAX)));
  571. maybe_loadesi;
  572. end;
  573. { pops one element from the exception address stack }
  574. { and removes the flag }
  575. procedure cleanupaddrstack;
  576. begin
  577. emitcall('FPC_POPADDRSTACK');
  578. { allocate eax }
  579. exprasmlist^.concat(new(pairegalloc,alloc(R_EAX)));
  580. emit_reg(A_POP,S_L,R_EAX);
  581. { deallocate eax }
  582. exprasmlist^.concat(new(pairegalloc,dealloc(R_EAX)));
  583. end;
  584. procedure secondtryexcept(var p : ptree);
  585. var
  586. exceptlabel,doexceptlabel,oldendexceptlabel,
  587. lastonlabel,
  588. exitexceptlabel,
  589. continueexceptlabel,
  590. breakexceptlabel,
  591. exittrylabel,
  592. continuetrylabel,
  593. breaktrylabel,
  594. doobjectdestroy,
  595. doobjectdestroyandreraise,
  596. oldaktexitlabel,
  597. oldaktexit2label,
  598. oldaktcontinuelabel,
  599. oldaktbreaklabel : pasmlabel;
  600. oldexceptblock : ptree;
  601. oldflowcontrol,tryflowcontrol,
  602. exceptflowcontrol : tflowcontrol;
  603. begin
  604. oldflowcontrol:=flowcontrol;
  605. flowcontrol:=[];
  606. { this can be called recursivly }
  607. oldendexceptlabel:=endexceptlabel;
  608. { we modify EAX }
  609. usedinproc:=usedinproc or ($80 shr byte(R_EAX));
  610. { save the old labels for control flow statements }
  611. oldaktexitlabel:=aktexitlabel;
  612. oldaktexit2label:=aktexit2label;
  613. if assigned(aktbreaklabel) then
  614. begin
  615. oldaktcontinuelabel:=aktcontinuelabel;
  616. oldaktbreaklabel:=aktbreaklabel;
  617. end;
  618. { get new labels for the control flow statements }
  619. getlabel(exittrylabel);
  620. getlabel(exitexceptlabel);
  621. if assigned(aktbreaklabel) then
  622. begin
  623. getlabel(breaktrylabel);
  624. getlabel(continuetrylabel);
  625. getlabel(breakexceptlabel);
  626. getlabel(continueexceptlabel);
  627. end;
  628. getlabel(exceptlabel);
  629. getlabel(doexceptlabel);
  630. getlabel(endexceptlabel);
  631. getlabel(lastonlabel);
  632. push_int (1); { push type of exceptionframe }
  633. emitcall('FPC_PUSHEXCEPTADDR');
  634. { allocate eax }
  635. exprasmlist^.concat(new(pairegalloc,alloc(R_EAX)));
  636. emit_reg(A_PUSH,S_L,R_EAX);
  637. emitcall('FPC_SETJMP');
  638. emit_reg(A_PUSH,S_L,R_EAX);
  639. emit_reg_reg(A_TEST,S_L,R_EAX,R_EAX);
  640. { deallocate eax }
  641. exprasmlist^.concat(new(pairegalloc,dealloc(R_EAX)));
  642. emitjmp(C_NE,exceptlabel);
  643. { try block }
  644. { set control flow labels for the try block }
  645. aktexitlabel:=exittrylabel;
  646. aktexit2label:=exittrylabel;
  647. if assigned(oldaktbreaklabel) then
  648. begin
  649. aktcontinuelabel:=continuetrylabel;
  650. aktbreaklabel:=breaktrylabel;
  651. end;
  652. oldexceptblock:=aktexceptblock;
  653. aktexceptblock:=p^.left;
  654. flowcontrol:=[];
  655. secondpass(p^.left);
  656. tryflowcontrol:=flowcontrol;
  657. aktexceptblock:=oldexceptblock;
  658. if codegenerror then
  659. exit;
  660. emitlab(exceptlabel);
  661. emitcall('FPC_POPADDRSTACK');
  662. exprasmlist^.concat(new(pairegalloc,alloc(R_EAX)));
  663. emit_reg(A_POP,S_L,R_EAX);
  664. emit_reg_reg(A_TEST,S_L,R_EAX,R_EAX);
  665. exprasmlist^.concat(new(pairegalloc,dealloc(R_EAX)));
  666. emitjmp(C_E,endexceptlabel);
  667. emitlab(doexceptlabel);
  668. { set control flow labels for the except block }
  669. { and the on statements }
  670. aktexitlabel:=exitexceptlabel;
  671. aktexit2label:=exitexceptlabel;
  672. if assigned(oldaktbreaklabel) then
  673. begin
  674. aktcontinuelabel:=continueexceptlabel;
  675. aktbreaklabel:=breakexceptlabel;
  676. end;
  677. flowcontrol:=[];
  678. { on statements }
  679. if assigned(p^.right) then
  680. begin
  681. oldexceptblock:=aktexceptblock;
  682. aktexceptblock:=p^.right;
  683. secondpass(p^.right);
  684. aktexceptblock:=oldexceptblock;
  685. end;
  686. emitlab(lastonlabel);
  687. { default handling except handling }
  688. if assigned(p^.t1) then
  689. begin
  690. { FPC_CATCHES must be called with
  691. 'default handler' flag (=-1)
  692. }
  693. push_int (-1);
  694. emitcall('FPC_CATCHES');
  695. maybe_loadesi;
  696. { the destruction of the exception object must be also }
  697. { guarded by an exception frame }
  698. getlabel(doobjectdestroy);
  699. getlabel(doobjectdestroyandreraise);
  700. exprasmlist^.concat(new(paicpu,op_const(A_PUSH,S_L,1)));
  701. emitcall('FPC_PUSHEXCEPTADDR');
  702. exprasmlist^.concat(new(pairegalloc,alloc(R_EAX)));
  703. exprasmlist^.concat(new(paicpu,
  704. op_reg(A_PUSH,S_L,R_EAX)));
  705. exprasmlist^.concat(new(pairegalloc,dealloc(R_EAX)));
  706. emitcall('FPC_SETJMP');
  707. exprasmlist^.concat(new(pairegalloc,alloc(R_EAX)));
  708. exprasmlist^.concat(new(paicpu,
  709. op_reg(A_PUSH,S_L,R_EAX)));
  710. exprasmlist^.concat(new(paicpu,
  711. op_reg_reg(A_TEST,S_L,R_EAX,R_EAX)));
  712. exprasmlist^.concat(new(pairegalloc,dealloc(R_EAX)));
  713. emitjmp(C_NE,doobjectdestroyandreraise);
  714. oldexceptblock:=aktexceptblock;
  715. aktexceptblock:=p^.t1;
  716. { here we don't have to reset flowcontrol }
  717. { the default and on flowcontrols are handled equal }
  718. secondpass(p^.t1);
  719. exceptflowcontrol:=flowcontrol;
  720. aktexceptblock:=oldexceptblock;
  721. emitlab(doobjectdestroyandreraise);
  722. emitcall('FPC_POPADDRSTACK');
  723. exprasmlist^.concat(new(pairegalloc,alloc(R_EAX)));
  724. exprasmlist^.concat(new(paicpu,
  725. op_reg(A_POP,S_L,R_EAX)));
  726. exprasmlist^.concat(new(paicpu,
  727. op_reg_reg(A_TEST,S_L,R_EAX,R_EAX)));
  728. exprasmlist^.concat(new(pairegalloc,dealloc(R_EAX)));
  729. emitjmp(C_E,doobjectdestroy);
  730. emitcall('FPC_POPSECONDOBJECTSTACK');
  731. exprasmlist^.concat(new(pairegalloc,alloc(R_EAX)));
  732. emit_reg(A_PUSH,S_L,R_EAX);
  733. emitcall('FPC_DESTROYEXCEPTION');
  734. exprasmlist^.concat(new(pairegalloc,dealloc(R_EAX)));
  735. { we don't need to restore esi here because reraise never }
  736. { returns }
  737. emitcall('FPC_RERAISE');
  738. emitlab(doobjectdestroy);
  739. cleanupobjectstack;
  740. emitjmp(C_None,endexceptlabel);
  741. end
  742. else
  743. begin
  744. emitcall('FPC_RERAISE');
  745. exceptflowcontrol:=flowcontrol;
  746. end;
  747. if fc_exit in exceptflowcontrol then
  748. begin
  749. { do some magic for exit in the try block }
  750. emitlab(exitexceptlabel);
  751. { we must also destroy the address frame which guards }
  752. { exception object }
  753. cleanupaddrstack;
  754. cleanupobjectstack;
  755. emitjmp(C_None,oldaktexitlabel);
  756. end;
  757. if fc_break in exceptflowcontrol then
  758. begin
  759. emitlab(breakexceptlabel);
  760. { we must also destroy the address frame which guards }
  761. { exception object }
  762. cleanupaddrstack;
  763. cleanupobjectstack;
  764. emitjmp(C_None,oldaktbreaklabel);
  765. end;
  766. if fc_continue in exceptflowcontrol then
  767. begin
  768. emitlab(continueexceptlabel);
  769. { we must also destroy the address frame which guards }
  770. { exception object }
  771. cleanupaddrstack;
  772. cleanupobjectstack;
  773. emitjmp(C_None,oldaktcontinuelabel);
  774. end;
  775. if fc_exit in tryflowcontrol then
  776. begin
  777. { do some magic for exit in the try block }
  778. emitlab(exittrylabel);
  779. cleanupaddrstack;
  780. emitjmp(C_None,oldaktexitlabel);
  781. end;
  782. if fc_break in tryflowcontrol then
  783. begin
  784. emitlab(breaktrylabel);
  785. cleanupaddrstack;
  786. emitjmp(C_None,oldaktbreaklabel);
  787. end;
  788. if fc_continue in tryflowcontrol then
  789. begin
  790. emitlab(continuetrylabel);
  791. cleanupaddrstack;
  792. emitjmp(C_None,oldaktcontinuelabel);
  793. end;
  794. emitlab(endexceptlabel);
  795. endexceptlabel:=oldendexceptlabel;
  796. { restore the control flow labels }
  797. aktexitlabel:=oldaktexitlabel;
  798. aktexit2label:=oldaktexit2label;
  799. if assigned(oldaktbreaklabel) then
  800. begin
  801. aktcontinuelabel:=oldaktcontinuelabel;
  802. aktbreaklabel:=oldaktbreaklabel;
  803. end;
  804. { return all used control flow statements }
  805. flowcontrol:=oldflowcontrol+exceptflowcontrol+
  806. tryflowcontrol;
  807. end;
  808. procedure secondon(var p : ptree);
  809. var
  810. nextonlabel,
  811. exitonlabel,
  812. continueonlabel,
  813. breakonlabel,
  814. oldaktexitlabel,
  815. oldaktexit2label,
  816. oldaktcontinuelabel,
  817. doobjectdestroyandreraise,
  818. doobjectdestroy,
  819. oldaktbreaklabel : pasmlabel;
  820. ref : treference;
  821. oldexceptblock : ptree;
  822. oldflowcontrol : tflowcontrol;
  823. begin
  824. oldflowcontrol:=flowcontrol;
  825. flowcontrol:=[];
  826. getlabel(nextonlabel);
  827. { push the vmt }
  828. emit_sym(A_PUSH,S_L,
  829. newasmsymbol(p^.excepttype^.vmt_mangledname));
  830. emitcall('FPC_CATCHES');
  831. { allocate eax }
  832. exprasmlist^.concat(new(pairegalloc,alloc(R_EAX)));
  833. emit_reg_reg(A_TEST,S_L,R_EAX,R_EAX);
  834. emitjmp(C_E,nextonlabel);
  835. ref.symbol:=nil;
  836. gettempofsizereference(4,ref);
  837. { what a hack ! }
  838. if assigned(p^.exceptsymtable) then
  839. pvarsym(p^.exceptsymtable^.symindex^.first)^.address:=ref.offset;
  840. emit_reg_ref(A_MOV,S_L,
  841. R_EAX,newreference(ref));
  842. { deallocate eax }
  843. exprasmlist^.concat(new(pairegalloc,dealloc(R_EAX)));
  844. { in the case that another exception is risen }
  845. { we've to destroy the old one }
  846. getlabel(doobjectdestroyandreraise);
  847. exprasmlist^.concat(new(paicpu,op_const(A_PUSH,S_L,1)));
  848. emitcall('FPC_PUSHEXCEPTADDR');
  849. exprasmlist^.concat(new(pairegalloc,alloc(R_EAX)));
  850. exprasmlist^.concat(new(paicpu,
  851. op_reg(A_PUSH,S_L,R_EAX)));
  852. exprasmlist^.concat(new(pairegalloc,dealloc(R_EAX)));
  853. emitcall('FPC_SETJMP');
  854. exprasmlist^.concat(new(pairegalloc,alloc(R_EAX)));
  855. exprasmlist^.concat(new(paicpu,
  856. op_reg(A_PUSH,S_L,R_EAX)));
  857. exprasmlist^.concat(new(paicpu,
  858. op_reg_reg(A_TEST,S_L,R_EAX,R_EAX)));
  859. exprasmlist^.concat(new(pairegalloc,dealloc(R_EAX)));
  860. emitjmp(C_NE,doobjectdestroyandreraise);
  861. if assigned(p^.right) then
  862. begin
  863. oldaktexitlabel:=aktexitlabel;
  864. oldaktexit2label:=aktexit2label;
  865. getlabel(exitonlabel);
  866. aktexitlabel:=exitonlabel;
  867. aktexit2label:=exitonlabel;
  868. if assigned(aktbreaklabel) then
  869. begin
  870. oldaktcontinuelabel:=aktcontinuelabel;
  871. oldaktbreaklabel:=aktbreaklabel;
  872. getlabel(breakonlabel);
  873. getlabel(continueonlabel);
  874. aktcontinuelabel:=continueonlabel;
  875. aktbreaklabel:=breakonlabel;
  876. end;
  877. { esi is destroyed by FPC_CATCHES }
  878. maybe_loadesi;
  879. oldexceptblock:=aktexceptblock;
  880. aktexceptblock:=p^.right;
  881. secondpass(p^.right);
  882. aktexceptblock:=oldexceptblock;
  883. end;
  884. getlabel(doobjectdestroy);
  885. emitlab(doobjectdestroyandreraise);
  886. emitcall('FPC_POPADDRSTACK');
  887. exprasmlist^.concat(new(pairegalloc,alloc(R_EAX)));
  888. exprasmlist^.concat(new(paicpu,
  889. op_reg(A_POP,S_L,R_EAX)));
  890. exprasmlist^.concat(new(paicpu,
  891. op_reg_reg(A_TEST,S_L,R_EAX,R_EAX)));
  892. exprasmlist^.concat(new(pairegalloc,dealloc(R_EAX)));
  893. emitjmp(C_E,doobjectdestroy);
  894. emitcall('FPC_POPSECONDOBJECTSTACK');
  895. exprasmlist^.concat(new(pairegalloc,alloc(R_EAX)));
  896. emit_reg(A_PUSH,S_L,R_EAX);
  897. emitcall('FPC_DESTROYEXCEPTION');
  898. exprasmlist^.concat(new(pairegalloc,dealloc(R_EAX)));
  899. { we don't need to restore esi here because reraise never }
  900. { returns }
  901. emitcall('FPC_RERAISE');
  902. emitlab(doobjectdestroy);
  903. cleanupobjectstack;
  904. { clear some stuff }
  905. ungetiftemp(ref);
  906. emitjmp(C_None,endexceptlabel);
  907. if assigned(p^.right) then
  908. begin
  909. { special handling for control flow instructions }
  910. if fc_exit in flowcontrol then
  911. begin
  912. { the address and object pop does secondtryexcept }
  913. emitlab(exitonlabel);
  914. emitjmp(C_None,oldaktexitlabel);
  915. end;
  916. if fc_break in flowcontrol then
  917. begin
  918. { the address and object pop does secondtryexcept }
  919. emitlab(breakonlabel);
  920. emitjmp(C_None,oldaktbreaklabel);
  921. end;
  922. if fc_continue in flowcontrol then
  923. begin
  924. { the address and object pop does secondtryexcept }
  925. emitlab(continueonlabel);
  926. emitjmp(C_None,oldaktcontinuelabel);
  927. end;
  928. aktexitlabel:=oldaktexitlabel;
  929. aktexit2label:=oldaktexit2label;
  930. if assigned(oldaktbreaklabel) then
  931. begin
  932. aktcontinuelabel:=oldaktcontinuelabel;
  933. aktbreaklabel:=oldaktbreaklabel;
  934. end;
  935. end;
  936. emitlab(nextonlabel);
  937. flowcontrol:=oldflowcontrol+flowcontrol;
  938. { next on node }
  939. if assigned(p^.left) then
  940. begin
  941. cleartempgen;
  942. secondpass(p^.left);
  943. end;
  944. end;
  945. {*****************************************************************************
  946. SecondTryFinally
  947. *****************************************************************************}
  948. procedure secondtryfinally(var p : ptree);
  949. var
  950. reraiselabel,
  951. finallylabel,
  952. endfinallylabel,
  953. exitfinallylabel,
  954. continuefinallylabel,
  955. breakfinallylabel,
  956. oldaktexitlabel,
  957. oldaktexit2label,
  958. oldaktcontinuelabel,
  959. oldaktbreaklabel : pasmlabel;
  960. oldexceptblock : ptree;
  961. oldflowcontrol,tryflowcontrol : tflowcontrol;
  962. decconst : longint;
  963. begin
  964. { check if child nodes do a break/continue/exit }
  965. oldflowcontrol:=flowcontrol;
  966. flowcontrol:=[];
  967. { we modify EAX }
  968. usedinproc:=usedinproc or ($80 shr byte(R_EAX));
  969. getlabel(finallylabel);
  970. getlabel(endfinallylabel);
  971. getlabel(reraiselabel);
  972. { the finally block must catch break, continue and exit }
  973. { statements }
  974. oldaktexitlabel:=aktexitlabel;
  975. oldaktexit2label:=aktexit2label;
  976. getlabel(exitfinallylabel);
  977. aktexitlabel:=exitfinallylabel;
  978. aktexit2label:=exitfinallylabel;
  979. if assigned(aktbreaklabel) then
  980. begin
  981. oldaktcontinuelabel:=aktcontinuelabel;
  982. oldaktbreaklabel:=aktbreaklabel;
  983. getlabel(breakfinallylabel);
  984. getlabel(continuefinallylabel);
  985. aktcontinuelabel:=continuefinallylabel;
  986. aktbreaklabel:=breakfinallylabel;
  987. end;
  988. push_int(1); { Type of stack-frame must be pushed}
  989. emitcall('FPC_PUSHEXCEPTADDR');
  990. { allocate eax }
  991. exprasmlist^.concat(new(pairegalloc,alloc(R_EAX)));
  992. emit_reg(A_PUSH,S_L,R_EAX);
  993. emitcall('FPC_SETJMP');
  994. emit_reg(A_PUSH,S_L,R_EAX);
  995. emit_reg_reg(A_TEST,S_L,R_EAX,R_EAX);
  996. { deallocate eax }
  997. exprasmlist^.concat(new(pairegalloc,dealloc(R_EAX)));
  998. emitjmp(C_NE,finallylabel);
  999. { try code }
  1000. if assigned(p^.left) then
  1001. begin
  1002. oldexceptblock:=aktexceptblock;
  1003. aktexceptblock:=p^.left;
  1004. secondpass(p^.left);
  1005. tryflowcontrol:=flowcontrol;
  1006. if codegenerror then
  1007. exit;
  1008. aktexceptblock:=oldexceptblock;
  1009. end;
  1010. emitlab(finallylabel);
  1011. emitcall('FPC_POPADDRSTACK');
  1012. { finally code }
  1013. oldexceptblock:=aktexceptblock;
  1014. aktexceptblock:=p^.right;
  1015. flowcontrol:=[];
  1016. secondpass(p^.right);
  1017. if flowcontrol<>[] then
  1018. CGMessage(cg_e_control_flow_outside_finally);
  1019. aktexceptblock:=oldexceptblock;
  1020. if codegenerror then
  1021. exit;
  1022. { allocate eax }
  1023. exprasmlist^.concat(new(pairegalloc,alloc(R_EAX)));
  1024. emit_reg(A_POP,S_L,R_EAX);
  1025. emit_reg_reg(A_TEST,S_L,R_EAX,R_EAX);
  1026. emitjmp(C_E,endfinallylabel);
  1027. emit_reg(A_DEC,S_L,R_EAX);
  1028. emitjmp(C_Z,reraiselabel);
  1029. if fc_exit in tryflowcontrol then
  1030. begin
  1031. emit_reg(A_DEC,S_L,R_EAX);
  1032. emitjmp(C_Z,oldaktexitlabel);
  1033. decconst:=1;
  1034. end
  1035. else
  1036. decconst:=2;
  1037. if fc_break in tryflowcontrol then
  1038. begin
  1039. emit_const_reg(A_SUB,S_L,decconst,R_EAX);
  1040. emitjmp(C_Z,oldaktbreaklabel);
  1041. decconst:=1;
  1042. end
  1043. else
  1044. inc(decconst);
  1045. if fc_continue in tryflowcontrol then
  1046. begin
  1047. emit_const_reg(A_SUB,S_L,decconst,R_EAX);
  1048. emitjmp(C_Z,oldaktcontinuelabel);
  1049. end;
  1050. { deallocate eax }
  1051. exprasmlist^.concat(new(pairegalloc,dealloc(R_EAX)));
  1052. emitlab(reraiselabel);
  1053. emitcall('FPC_RERAISE');
  1054. { do some magic for exit,break,continue in the try block }
  1055. if fc_exit in tryflowcontrol then
  1056. begin
  1057. emitlab(exitfinallylabel);
  1058. { allocate eax }
  1059. exprasmlist^.concat(new(pairegalloc,alloc(R_EAX)));
  1060. emit_reg(A_POP,S_L,R_EAX);
  1061. exprasmlist^.concat(new(pairegalloc,alloc(R_EAX)));
  1062. emit_const(A_PUSH,S_L,2);
  1063. emitjmp(C_NONE,finallylabel);
  1064. end;
  1065. if fc_break in tryflowcontrol then
  1066. begin
  1067. emitlab(breakfinallylabel);
  1068. { allocate eax }
  1069. exprasmlist^.concat(new(pairegalloc,alloc(R_EAX)));
  1070. emit_reg(A_POP,S_L,R_EAX);
  1071. { deallocate eax }
  1072. exprasmlist^.concat(new(pairegalloc,dealloc(R_EAX)));
  1073. emit_const(A_PUSH,S_L,3);
  1074. emitjmp(C_NONE,finallylabel);
  1075. end;
  1076. if fc_continue in tryflowcontrol then
  1077. begin
  1078. emitlab(continuefinallylabel);
  1079. exprasmlist^.concat(new(pairegalloc,alloc(R_EAX)));
  1080. emit_reg(A_POP,S_L,R_EAX);
  1081. exprasmlist^.concat(new(pairegalloc,alloc(R_EAX)));
  1082. emit_const(A_PUSH,S_L,4);
  1083. emitjmp(C_NONE,finallylabel);
  1084. end;
  1085. emitlab(endfinallylabel);
  1086. aktexitlabel:=oldaktexitlabel;
  1087. aktexit2label:=oldaktexit2label;
  1088. if assigned(aktbreaklabel) then
  1089. begin
  1090. aktcontinuelabel:=oldaktcontinuelabel;
  1091. aktbreaklabel:=oldaktbreaklabel;
  1092. end;
  1093. flowcontrol:=oldflowcontrol+tryflowcontrol;
  1094. end;
  1095. {*****************************************************************************
  1096. SecondFail
  1097. *****************************************************************************}
  1098. procedure secondfail(var p : ptree);
  1099. begin
  1100. emitjmp(C_None,faillabel);
  1101. end;
  1102. end.
  1103. {
  1104. $Log$
  1105. Revision 1.2 2000-07-13 11:32:33 michael
  1106. + removed logs
  1107. }