cg386flw.pas 45 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338
  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. secondpass(p^.left);
  941. end;
  942. {*****************************************************************************
  943. SecondTryFinally
  944. *****************************************************************************}
  945. procedure secondtryfinally(var p : ptree);
  946. var
  947. reraiselabel,
  948. finallylabel,
  949. endfinallylabel,
  950. exitfinallylabel,
  951. continuefinallylabel,
  952. breakfinallylabel,
  953. oldaktexitlabel,
  954. oldaktexit2label,
  955. oldaktcontinuelabel,
  956. oldaktbreaklabel : pasmlabel;
  957. oldexceptblock : ptree;
  958. oldflowcontrol,tryflowcontrol : tflowcontrol;
  959. decconst : longint;
  960. begin
  961. { check if child nodes do a break/continue/exit }
  962. oldflowcontrol:=flowcontrol;
  963. flowcontrol:=[];
  964. { we modify EAX }
  965. usedinproc:=usedinproc or ($80 shr byte(R_EAX));
  966. getlabel(finallylabel);
  967. getlabel(endfinallylabel);
  968. getlabel(reraiselabel);
  969. { the finally block must catch break, continue and exit }
  970. { statements }
  971. oldaktexitlabel:=aktexitlabel;
  972. oldaktexit2label:=aktexit2label;
  973. getlabel(exitfinallylabel);
  974. aktexitlabel:=exitfinallylabel;
  975. aktexit2label:=exitfinallylabel;
  976. if assigned(aktbreaklabel) then
  977. begin
  978. oldaktcontinuelabel:=aktcontinuelabel;
  979. oldaktbreaklabel:=aktbreaklabel;
  980. getlabel(breakfinallylabel);
  981. getlabel(continuefinallylabel);
  982. aktcontinuelabel:=continuefinallylabel;
  983. aktbreaklabel:=breakfinallylabel;
  984. end;
  985. push_int(1); { Type of stack-frame must be pushed}
  986. emitcall('FPC_PUSHEXCEPTADDR');
  987. { allocate eax }
  988. exprasmlist^.concat(new(pairegalloc,alloc(R_EAX)));
  989. emit_reg(A_PUSH,S_L,R_EAX);
  990. emitcall('FPC_SETJMP');
  991. emit_reg(A_PUSH,S_L,R_EAX);
  992. emit_reg_reg(A_TEST,S_L,R_EAX,R_EAX);
  993. { deallocate eax }
  994. exprasmlist^.concat(new(pairegalloc,dealloc(R_EAX)));
  995. emitjmp(C_NE,finallylabel);
  996. { try code }
  997. if assigned(p^.left) then
  998. begin
  999. oldexceptblock:=aktexceptblock;
  1000. aktexceptblock:=p^.left;
  1001. secondpass(p^.left);
  1002. tryflowcontrol:=flowcontrol;
  1003. if codegenerror then
  1004. exit;
  1005. aktexceptblock:=oldexceptblock;
  1006. end;
  1007. emitlab(finallylabel);
  1008. emitcall('FPC_POPADDRSTACK');
  1009. { finally code }
  1010. oldexceptblock:=aktexceptblock;
  1011. aktexceptblock:=p^.right;
  1012. flowcontrol:=[];
  1013. secondpass(p^.right);
  1014. if flowcontrol<>[] then
  1015. CGMessage(cg_e_control_flow_outside_finally);
  1016. aktexceptblock:=oldexceptblock;
  1017. if codegenerror then
  1018. exit;
  1019. { allocate eax }
  1020. exprasmlist^.concat(new(pairegalloc,alloc(R_EAX)));
  1021. emit_reg(A_POP,S_L,R_EAX);
  1022. emit_reg_reg(A_TEST,S_L,R_EAX,R_EAX);
  1023. emitjmp(C_E,endfinallylabel);
  1024. emit_reg(A_DEC,S_L,R_EAX);
  1025. emitjmp(C_Z,reraiselabel);
  1026. if fc_exit in tryflowcontrol then
  1027. begin
  1028. emit_reg(A_DEC,S_L,R_EAX);
  1029. emitjmp(C_Z,oldaktexitlabel);
  1030. decconst:=1;
  1031. end
  1032. else
  1033. decconst:=2;
  1034. if fc_break in tryflowcontrol then
  1035. begin
  1036. emit_const_reg(A_SUB,S_L,decconst,R_EAX);
  1037. emitjmp(C_Z,oldaktbreaklabel);
  1038. decconst:=1;
  1039. end
  1040. else
  1041. inc(decconst);
  1042. if fc_continue in tryflowcontrol then
  1043. begin
  1044. emit_const_reg(A_SUB,S_L,decconst,R_EAX);
  1045. emitjmp(C_Z,oldaktcontinuelabel);
  1046. end;
  1047. { deallocate eax }
  1048. exprasmlist^.concat(new(pairegalloc,dealloc(R_EAX)));
  1049. emitlab(reraiselabel);
  1050. emitcall('FPC_RERAISE');
  1051. { do some magic for exit,break,continue in the try block }
  1052. if fc_exit in tryflowcontrol then
  1053. begin
  1054. emitlab(exitfinallylabel);
  1055. { allocate eax }
  1056. exprasmlist^.concat(new(pairegalloc,alloc(R_EAX)));
  1057. emit_reg(A_POP,S_L,R_EAX);
  1058. exprasmlist^.concat(new(pairegalloc,alloc(R_EAX)));
  1059. emit_const(A_PUSH,S_L,2);
  1060. emitjmp(C_NONE,finallylabel);
  1061. end;
  1062. if fc_break in tryflowcontrol then
  1063. begin
  1064. emitlab(breakfinallylabel);
  1065. { allocate eax }
  1066. exprasmlist^.concat(new(pairegalloc,alloc(R_EAX)));
  1067. emit_reg(A_POP,S_L,R_EAX);
  1068. { deallocate eax }
  1069. exprasmlist^.concat(new(pairegalloc,dealloc(R_EAX)));
  1070. emit_const(A_PUSH,S_L,3);
  1071. emitjmp(C_NONE,finallylabel);
  1072. end;
  1073. if fc_continue in tryflowcontrol then
  1074. begin
  1075. emitlab(continuefinallylabel);
  1076. exprasmlist^.concat(new(pairegalloc,alloc(R_EAX)));
  1077. emit_reg(A_POP,S_L,R_EAX);
  1078. exprasmlist^.concat(new(pairegalloc,alloc(R_EAX)));
  1079. emit_const(A_PUSH,S_L,4);
  1080. emitjmp(C_NONE,finallylabel);
  1081. end;
  1082. emitlab(endfinallylabel);
  1083. aktexitlabel:=oldaktexitlabel;
  1084. aktexit2label:=oldaktexit2label;
  1085. if assigned(aktbreaklabel) then
  1086. begin
  1087. aktcontinuelabel:=oldaktcontinuelabel;
  1088. aktbreaklabel:=oldaktbreaklabel;
  1089. end;
  1090. flowcontrol:=oldflowcontrol+tryflowcontrol;
  1091. end;
  1092. {*****************************************************************************
  1093. SecondFail
  1094. *****************************************************************************}
  1095. procedure secondfail(var p : ptree);
  1096. begin
  1097. emitjmp(C_None,faillabel);
  1098. end;
  1099. end.
  1100. {
  1101. $Log$
  1102. Revision 1.74 2000-05-09 19:05:56 florian
  1103. * fixed a problem when returning int64/qword from a function in -Or: in some
  1104. cases a wrong result was returned
  1105. Revision 1.73 2000/04/24 11:11:50 peter
  1106. * backtraces for exceptions are now only generated from the place of the
  1107. exception
  1108. * frame is also pushed for exceptions
  1109. * raise statement enhanced with [,<frame>]
  1110. Revision 1.72 2000/04/22 15:29:26 jonas
  1111. * cleaner register (de)allocation in secondfor (for optimizer)
  1112. Revision 1.71 2000/04/16 08:08:44 jonas
  1113. * release register used in for-loop before end label (for better
  1114. optimizations)
  1115. Revision 1.70 2000/02/29 23:58:19 pierre
  1116. Use $GOTO ON
  1117. Revision 1.69 2000/02/10 23:44:42 florian
  1118. * big update for exception handling code generation: possible mem holes
  1119. fixed, break/continue/exit should work always now as expected
  1120. Revision 1.68 2000/02/09 13:22:47 peter
  1121. * log truncated
  1122. Revision 1.67 2000/01/21 12:17:42 jonas
  1123. * regallocation fixes
  1124. Revision 1.66 2000/01/07 01:14:20 peter
  1125. * updated copyright to 2000
  1126. Revision 1.65 1999/12/22 23:30:06 peter
  1127. * nested try blocks work again
  1128. Revision 1.64 1999/12/22 01:01:46 peter
  1129. - removed freelabel()
  1130. * added undefined label detection in internal assembler, this prevents
  1131. a lot of ld crashes and wrong .o files
  1132. * .o files aren't written anymore if errors have occured
  1133. * inlining of assembler labels is now correct
  1134. Revision 1.63 1999/12/19 17:02:45 peter
  1135. * support exit,break,continue in try...except
  1136. * support break,continue in try...finally
  1137. Revision 1.62 1999/12/17 11:20:06 florian
  1138. * made the goto checking for excpetions more fool proof against errors
  1139. Revision 1.61 1999/12/14 09:58:41 florian
  1140. + compiler checks now if a goto leaves an exception block
  1141. Revision 1.60 1999/12/01 12:36:23 peter
  1142. * fixed selfpointer after destroyexception
  1143. Revision 1.59 1999/11/30 10:40:42 peter
  1144. + ttype, tsymlist
  1145. Revision 1.58 1999/11/28 23:15:23 pierre
  1146. * fix for form bug 721
  1147. Revision 1.57 1999/11/15 21:49:09 peter
  1148. * push address also for raise at
  1149. Revision 1.56 1999/11/06 14:34:17 peter
  1150. * truncated log to 20 revs
  1151. Revision 1.55 1999/10/30 17:35:26 peter
  1152. * fpc_freemem fpc_getmem new callings updated
  1153. Revision 1.54 1999/10/21 16:41:37 florian
  1154. * problems with readln fixed: esi wasn't restored correctly when
  1155. reading ordinal fields of objects futher the register allocation
  1156. didn't take care of the extra register when reading ordinal values
  1157. * enumerations can now be used in constant indexes of properties
  1158. Revision 1.53 1999/10/05 22:01:52 pierre
  1159. * bug exit('test') + fail for classes
  1160. Revision 1.52 1999/09/27 23:44:46 peter
  1161. * procinfo is now a pointer
  1162. * support for result setting in sub procedure
  1163. Revision 1.51 1999/09/26 13:26:05 florian
  1164. * exception patch of Romio nevertheless the excpetion handling
  1165. needs some corections regarding register saving
  1166. * gettempansistring is again a procedure
  1167. Revision 1.50 1999/09/20 16:35:43 peter
  1168. * restored old alignment, saves 40k on ppc386
  1169. Revision 1.49 1999/09/15 20:35:37 florian
  1170. * small fix to operator overloading when in MMX mode
  1171. + the compiler uses now fldz and fld1 if possible
  1172. + some fixes to floating point registers
  1173. + some math. functions (arctan, ln, sin, cos, sqrt, sqr, pi) are now inlined
  1174. * .... ???
  1175. Revision 1.48 1999/09/07 07:56:37 peter
  1176. * reload esi in except block to allow virtual methods
  1177. Revision 1.47 1999/08/25 11:59:42 jonas
  1178. * changed pai386, paippc and paiapha (same for tai*) to paicpu (taicpu)
  1179. }