cg386flw.pas 44 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317
  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. label
  352. do_jmp;
  353. begin
  354. include(flowcontrol,fc_exit);
  355. if assigned(p^.left) then
  356. if p^.left^.treetype=assignn then
  357. begin
  358. { just do a normal assignment followed by exit }
  359. secondpass(p^.left);
  360. emitjmp(C_None,aktexitlabel);
  361. end
  362. else
  363. begin
  364. otlabel:=truelabel;
  365. oflabel:=falselabel;
  366. getlabel(truelabel);
  367. getlabel(falselabel);
  368. secondpass(p^.left);
  369. case p^.left^.location.loc of
  370. LOC_FPU : goto do_jmp;
  371. LOC_MEM,
  372. LOC_REFERENCE : is_mem:=true;
  373. LOC_CREGISTER,
  374. LOC_REGISTER : is_mem:=false;
  375. LOC_FLAGS : begin
  376. emit_flag2reg(p^.left^.location.resflags,R_AL);
  377. goto do_jmp;
  378. end;
  379. LOC_JUMP : begin
  380. emitlab(truelabel);
  381. emit_const_reg(A_MOV,S_B,1,R_AL);
  382. emitjmp(C_None,aktexit2label);
  383. emitlab(falselabel);
  384. emit_reg_reg(A_XOR,S_B,R_AL,R_AL);
  385. goto do_jmp;
  386. end;
  387. else
  388. internalerror(2001);
  389. end;
  390. case procinfo^.returntype.def^.deftype of
  391. pointerdef,
  392. procvardef : begin
  393. if is_mem then
  394. emit_ref_reg(A_MOV,S_L,
  395. newreference(p^.left^.location.reference),R_EAX)
  396. else
  397. emit_reg_reg(A_MOV,S_L,
  398. p^.left^.location.register,R_EAX);
  399. end;
  400. floatdef : begin
  401. if pfloatdef(procinfo^.returntype.def)^.typ=f32bit then
  402. begin
  403. if is_mem then
  404. emit_ref_reg(A_MOV,S_L,
  405. newreference(p^.left^.location.reference),R_EAX)
  406. else
  407. emit_reg_reg(A_MOV,S_L,p^.left^.location.register,R_EAX);
  408. end
  409. else
  410. if is_mem then
  411. floatload(pfloatdef(procinfo^.returntype.def)^.typ,p^.left^.location.reference);
  412. end;
  413. { orddef,
  414. enumdef : }
  415. else
  416. { it can be anything shorter than 4 bytes PM
  417. this caused form bug 711 }
  418. begin
  419. case procinfo^.returntype.def^.size of
  420. { if its 3 bytes only we can still
  421. copy one of garbage ! PM }
  422. 4,3 : if is_mem then
  423. emit_ref_reg(A_MOV,S_L,
  424. newreference(p^.left^.location.reference),R_EAX)
  425. else
  426. emit_reg_reg(A_MOV,S_L,p^.left^.location.register,R_EAX);
  427. 2 : if is_mem then
  428. emit_ref_reg(A_MOV,S_W,
  429. newreference(p^.left^.location.reference),R_AX)
  430. else
  431. emit_reg_reg(A_MOV,S_W,makereg16(p^.left^.location.register),R_AX);
  432. 1 : if is_mem then
  433. emit_ref_reg(A_MOV,S_B,
  434. newreference(p^.left^.location.reference),R_AL)
  435. else
  436. emit_reg_reg(A_MOV,S_B,makereg8(p^.left^.location.register),R_AL);
  437. end;
  438. end;
  439. end;
  440. do_jmp:
  441. truelabel:=otlabel;
  442. falselabel:=oflabel;
  443. emitjmp(C_None,aktexit2label);
  444. end
  445. else
  446. begin
  447. emitjmp(C_None,aktexitlabel);
  448. end;
  449. end;
  450. {*****************************************************************************
  451. SecondBreakN
  452. *****************************************************************************}
  453. procedure secondbreakn(var p : ptree);
  454. begin
  455. include(flowcontrol,fc_break);
  456. if aktbreaklabel<>nil then
  457. emitjmp(C_None,aktbreaklabel)
  458. else
  459. CGMessage(cg_e_break_not_allowed);
  460. end;
  461. {*****************************************************************************
  462. SecondContinueN
  463. *****************************************************************************}
  464. procedure secondcontinuen(var p : ptree);
  465. begin
  466. include(flowcontrol,fc_continue);
  467. if aktcontinuelabel<>nil then
  468. emitjmp(C_None,aktcontinuelabel)
  469. else
  470. CGMessage(cg_e_continue_not_allowed);
  471. end;
  472. {*****************************************************************************
  473. SecondGoto
  474. *****************************************************************************}
  475. procedure secondgoto(var p : ptree);
  476. begin
  477. emitjmp(C_None,p^.labelnr);
  478. { the assigned avoids only crashes if the label isn't defined }
  479. if assigned(p^.labsym) and
  480. assigned(p^.labsym^.code) and
  481. (aktexceptblock<>ptree(p^.labsym^.code)^.exceptionblock) then
  482. CGMessage(cg_e_goto_inout_of_exception_block);
  483. end;
  484. {*****************************************************************************
  485. SecondLabel
  486. *****************************************************************************}
  487. procedure secondlabel(var p : ptree);
  488. begin
  489. emitlab(p^.labelnr);
  490. cleartempgen;
  491. secondpass(p^.left);
  492. end;
  493. {*****************************************************************************
  494. SecondRaise
  495. *****************************************************************************}
  496. procedure secondraise(var p : ptree);
  497. var
  498. a : pasmlabel;
  499. begin
  500. if assigned(p^.left) then
  501. begin
  502. { multiple parameters? }
  503. if assigned(p^.right) then
  504. begin
  505. { push frame }
  506. if assigned(p^.frametree) then
  507. begin
  508. secondpass(p^.frametree);
  509. if codegenerror then
  510. exit;
  511. emit_push_loc(p^.frametree^.location);
  512. end
  513. else
  514. emit_const(A_PUSH,S_L,0);
  515. { push address }
  516. secondpass(p^.right);
  517. if codegenerror then
  518. exit;
  519. emit_push_loc(p^.right^.location);
  520. end
  521. else
  522. begin
  523. getlabel(a);
  524. emitlab(a);
  525. emit_const(A_PUSH,S_L,0);
  526. emit_sym(A_PUSH,S_L,a);
  527. end;
  528. { push object }
  529. secondpass(p^.left);
  530. if codegenerror then
  531. exit;
  532. emit_push_loc(p^.left^.location);
  533. emitcall('FPC_RAISEEXCEPTION');
  534. end
  535. else
  536. begin
  537. emitcall('FPC_POPADDRSTACK');
  538. emitcall('FPC_RERAISE');
  539. end;
  540. end;
  541. {*****************************************************************************
  542. SecondTryExcept
  543. *****************************************************************************}
  544. var
  545. endexceptlabel : pasmlabel;
  546. { does the necessary things to clean up the object stack }
  547. { in the except block }
  548. procedure cleanupobjectstack;
  549. begin
  550. emitcall('FPC_POPOBJECTSTACK');
  551. exprasmlist^.concat(new(pairegalloc,alloc(R_EAX)));
  552. emit_reg(A_PUSH,S_L,R_EAX);
  553. emitcall('FPC_DESTROYEXCEPTION');
  554. exprasmlist^.concat(new(pairegalloc,dealloc(R_EAX)));
  555. maybe_loadesi;
  556. end;
  557. { pops one element from the exception address stack }
  558. { and removes the flag }
  559. procedure cleanupaddrstack;
  560. begin
  561. emitcall('FPC_POPADDRSTACK');
  562. { allocate eax }
  563. exprasmlist^.concat(new(pairegalloc,alloc(R_EAX)));
  564. emit_reg(A_POP,S_L,R_EAX);
  565. { deallocate eax }
  566. exprasmlist^.concat(new(pairegalloc,dealloc(R_EAX)));
  567. end;
  568. procedure secondtryexcept(var p : ptree);
  569. var
  570. exceptlabel,doexceptlabel,oldendexceptlabel,
  571. lastonlabel,
  572. exitexceptlabel,
  573. continueexceptlabel,
  574. breakexceptlabel,
  575. exittrylabel,
  576. continuetrylabel,
  577. breaktrylabel,
  578. doobjectdestroy,
  579. doobjectdestroyandreraise,
  580. oldaktexitlabel,
  581. oldaktexit2label,
  582. oldaktcontinuelabel,
  583. oldaktbreaklabel : pasmlabel;
  584. oldexceptblock : ptree;
  585. oldflowcontrol,tryflowcontrol,
  586. exceptflowcontrol : tflowcontrol;
  587. begin
  588. oldflowcontrol:=flowcontrol;
  589. flowcontrol:=[];
  590. { this can be called recursivly }
  591. oldendexceptlabel:=endexceptlabel;
  592. { we modify EAX }
  593. usedinproc:=usedinproc or ($80 shr byte(R_EAX));
  594. { save the old labels for control flow statements }
  595. oldaktexitlabel:=aktexitlabel;
  596. oldaktexit2label:=aktexit2label;
  597. if assigned(aktbreaklabel) then
  598. begin
  599. oldaktcontinuelabel:=aktcontinuelabel;
  600. oldaktbreaklabel:=aktbreaklabel;
  601. end;
  602. { get new labels for the control flow statements }
  603. getlabel(exittrylabel);
  604. getlabel(exitexceptlabel);
  605. if assigned(aktbreaklabel) then
  606. begin
  607. getlabel(breaktrylabel);
  608. getlabel(continuetrylabel);
  609. getlabel(breakexceptlabel);
  610. getlabel(continueexceptlabel);
  611. end;
  612. getlabel(exceptlabel);
  613. getlabel(doexceptlabel);
  614. getlabel(endexceptlabel);
  615. getlabel(lastonlabel);
  616. push_int (1); { push type of exceptionframe }
  617. emitcall('FPC_PUSHEXCEPTADDR');
  618. { allocate eax }
  619. exprasmlist^.concat(new(pairegalloc,alloc(R_EAX)));
  620. emit_reg(A_PUSH,S_L,R_EAX);
  621. emitcall('FPC_SETJMP');
  622. emit_reg(A_PUSH,S_L,R_EAX);
  623. emit_reg_reg(A_TEST,S_L,R_EAX,R_EAX);
  624. { deallocate eax }
  625. exprasmlist^.concat(new(pairegalloc,dealloc(R_EAX)));
  626. emitjmp(C_NE,exceptlabel);
  627. { try block }
  628. { set control flow labels for the try block }
  629. aktexitlabel:=exittrylabel;
  630. aktexit2label:=exittrylabel;
  631. if assigned(oldaktbreaklabel) then
  632. begin
  633. aktcontinuelabel:=continuetrylabel;
  634. aktbreaklabel:=breaktrylabel;
  635. end;
  636. oldexceptblock:=aktexceptblock;
  637. aktexceptblock:=p^.left;
  638. flowcontrol:=[];
  639. secondpass(p^.left);
  640. tryflowcontrol:=flowcontrol;
  641. aktexceptblock:=oldexceptblock;
  642. if codegenerror then
  643. exit;
  644. emitlab(exceptlabel);
  645. emitcall('FPC_POPADDRSTACK');
  646. exprasmlist^.concat(new(pairegalloc,alloc(R_EAX)));
  647. emit_reg(A_POP,S_L,R_EAX);
  648. emit_reg_reg(A_TEST,S_L,R_EAX,R_EAX);
  649. exprasmlist^.concat(new(pairegalloc,dealloc(R_EAX)));
  650. emitjmp(C_E,endexceptlabel);
  651. emitlab(doexceptlabel);
  652. { set control flow labels for the except block }
  653. { and the on statements }
  654. aktexitlabel:=exitexceptlabel;
  655. aktexit2label:=exitexceptlabel;
  656. if assigned(oldaktbreaklabel) then
  657. begin
  658. aktcontinuelabel:=continueexceptlabel;
  659. aktbreaklabel:=breakexceptlabel;
  660. end;
  661. flowcontrol:=[];
  662. { on statements }
  663. if assigned(p^.right) then
  664. begin
  665. oldexceptblock:=aktexceptblock;
  666. aktexceptblock:=p^.right;
  667. secondpass(p^.right);
  668. aktexceptblock:=oldexceptblock;
  669. end;
  670. emitlab(lastonlabel);
  671. { default handling except handling }
  672. if assigned(p^.t1) then
  673. begin
  674. { FPC_CATCHES must be called with
  675. 'default handler' flag (=-1)
  676. }
  677. push_int (-1);
  678. emitcall('FPC_CATCHES');
  679. maybe_loadesi;
  680. { the destruction of the exception object must be also }
  681. { guarded by an exception frame }
  682. getlabel(doobjectdestroy);
  683. getlabel(doobjectdestroyandreraise);
  684. exprasmlist^.concat(new(paicpu,op_const(A_PUSH,S_L,1)));
  685. emitcall('FPC_PUSHEXCEPTADDR');
  686. exprasmlist^.concat(new(pairegalloc,alloc(R_EAX)));
  687. exprasmlist^.concat(new(paicpu,
  688. op_reg(A_PUSH,S_L,R_EAX)));
  689. exprasmlist^.concat(new(pairegalloc,dealloc(R_EAX)));
  690. emitcall('FPC_SETJMP');
  691. exprasmlist^.concat(new(pairegalloc,alloc(R_EAX)));
  692. exprasmlist^.concat(new(paicpu,
  693. op_reg(A_PUSH,S_L,R_EAX)));
  694. exprasmlist^.concat(new(paicpu,
  695. op_reg_reg(A_TEST,S_L,R_EAX,R_EAX)));
  696. exprasmlist^.concat(new(pairegalloc,dealloc(R_EAX)));
  697. emitjmp(C_NE,doobjectdestroyandreraise);
  698. oldexceptblock:=aktexceptblock;
  699. aktexceptblock:=p^.t1;
  700. { here we don't have to reset flowcontrol }
  701. { the default and on flowcontrols are handled equal }
  702. secondpass(p^.t1);
  703. exceptflowcontrol:=flowcontrol;
  704. aktexceptblock:=oldexceptblock;
  705. emitlab(doobjectdestroyandreraise);
  706. emitcall('FPC_POPADDRSTACK');
  707. exprasmlist^.concat(new(pairegalloc,alloc(R_EAX)));
  708. exprasmlist^.concat(new(paicpu,
  709. op_reg(A_POP,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_E,doobjectdestroy);
  714. emitcall('FPC_POPSECONDOBJECTSTACK');
  715. exprasmlist^.concat(new(pairegalloc,alloc(R_EAX)));
  716. emit_reg(A_PUSH,S_L,R_EAX);
  717. emitcall('FPC_DESTROYEXCEPTION');
  718. exprasmlist^.concat(new(pairegalloc,dealloc(R_EAX)));
  719. { we don't need to restore esi here because reraise never }
  720. { returns }
  721. emitcall('FPC_RERAISE');
  722. emitlab(doobjectdestroy);
  723. cleanupobjectstack;
  724. emitjmp(C_None,endexceptlabel);
  725. end
  726. else
  727. begin
  728. emitcall('FPC_RERAISE');
  729. exceptflowcontrol:=flowcontrol;
  730. end;
  731. if fc_exit in exceptflowcontrol then
  732. begin
  733. { do some magic for exit in the try block }
  734. emitlab(exitexceptlabel);
  735. { we must also destroy the address frame which guards }
  736. { exception object }
  737. cleanupaddrstack;
  738. cleanupobjectstack;
  739. emitjmp(C_None,oldaktexitlabel);
  740. end;
  741. if fc_break in exceptflowcontrol then
  742. begin
  743. emitlab(breakexceptlabel);
  744. { we must also destroy the address frame which guards }
  745. { exception object }
  746. cleanupaddrstack;
  747. cleanupobjectstack;
  748. emitjmp(C_None,oldaktbreaklabel);
  749. end;
  750. if fc_continue in exceptflowcontrol then
  751. begin
  752. emitlab(continueexceptlabel);
  753. { we must also destroy the address frame which guards }
  754. { exception object }
  755. cleanupaddrstack;
  756. cleanupobjectstack;
  757. emitjmp(C_None,oldaktcontinuelabel);
  758. end;
  759. if fc_exit in tryflowcontrol then
  760. begin
  761. { do some magic for exit in the try block }
  762. emitlab(exittrylabel);
  763. cleanupaddrstack;
  764. emitjmp(C_None,oldaktexitlabel);
  765. end;
  766. if fc_break in tryflowcontrol then
  767. begin
  768. emitlab(breaktrylabel);
  769. cleanupaddrstack;
  770. emitjmp(C_None,oldaktbreaklabel);
  771. end;
  772. if fc_continue in tryflowcontrol then
  773. begin
  774. emitlab(continuetrylabel);
  775. cleanupaddrstack;
  776. emitjmp(C_None,oldaktcontinuelabel);
  777. end;
  778. emitlab(endexceptlabel);
  779. endexceptlabel:=oldendexceptlabel;
  780. { restore the control flow labels }
  781. aktexitlabel:=oldaktexitlabel;
  782. aktexit2label:=oldaktexit2label;
  783. if assigned(oldaktbreaklabel) then
  784. begin
  785. aktcontinuelabel:=oldaktcontinuelabel;
  786. aktbreaklabel:=oldaktbreaklabel;
  787. end;
  788. { return all used control flow statements }
  789. flowcontrol:=oldflowcontrol+exceptflowcontrol+
  790. tryflowcontrol;
  791. end;
  792. procedure secondon(var p : ptree);
  793. var
  794. nextonlabel,
  795. exitonlabel,
  796. continueonlabel,
  797. breakonlabel,
  798. oldaktexitlabel,
  799. oldaktexit2label,
  800. oldaktcontinuelabel,
  801. doobjectdestroyandreraise,
  802. doobjectdestroy,
  803. oldaktbreaklabel : pasmlabel;
  804. ref : treference;
  805. oldexceptblock : ptree;
  806. oldflowcontrol : tflowcontrol;
  807. begin
  808. oldflowcontrol:=flowcontrol;
  809. flowcontrol:=[];
  810. getlabel(nextonlabel);
  811. { push the vmt }
  812. emit_sym(A_PUSH,S_L,
  813. newasmsymbol(p^.excepttype^.vmt_mangledname));
  814. emitcall('FPC_CATCHES');
  815. { allocate eax }
  816. exprasmlist^.concat(new(pairegalloc,alloc(R_EAX)));
  817. emit_reg_reg(A_TEST,S_L,R_EAX,R_EAX);
  818. emitjmp(C_E,nextonlabel);
  819. ref.symbol:=nil;
  820. gettempofsizereference(4,ref);
  821. { what a hack ! }
  822. if assigned(p^.exceptsymtable) then
  823. pvarsym(p^.exceptsymtable^.symindex^.first)^.address:=ref.offset;
  824. emit_reg_ref(A_MOV,S_L,
  825. R_EAX,newreference(ref));
  826. { deallocate eax }
  827. exprasmlist^.concat(new(pairegalloc,dealloc(R_EAX)));
  828. { in the case that another exception is risen }
  829. { we've to destroy the old one }
  830. getlabel(doobjectdestroyandreraise);
  831. exprasmlist^.concat(new(paicpu,op_const(A_PUSH,S_L,1)));
  832. emitcall('FPC_PUSHEXCEPTADDR');
  833. exprasmlist^.concat(new(pairegalloc,alloc(R_EAX)));
  834. exprasmlist^.concat(new(paicpu,
  835. op_reg(A_PUSH,S_L,R_EAX)));
  836. exprasmlist^.concat(new(pairegalloc,dealloc(R_EAX)));
  837. emitcall('FPC_SETJMP');
  838. exprasmlist^.concat(new(pairegalloc,alloc(R_EAX)));
  839. exprasmlist^.concat(new(paicpu,
  840. op_reg(A_PUSH,S_L,R_EAX)));
  841. exprasmlist^.concat(new(paicpu,
  842. op_reg_reg(A_TEST,S_L,R_EAX,R_EAX)));
  843. exprasmlist^.concat(new(pairegalloc,dealloc(R_EAX)));
  844. emitjmp(C_NE,doobjectdestroyandreraise);
  845. if assigned(p^.right) then
  846. begin
  847. oldaktexitlabel:=aktexitlabel;
  848. oldaktexit2label:=aktexit2label;
  849. getlabel(exitonlabel);
  850. aktexitlabel:=exitonlabel;
  851. aktexit2label:=exitonlabel;
  852. if assigned(aktbreaklabel) then
  853. begin
  854. oldaktcontinuelabel:=aktcontinuelabel;
  855. oldaktbreaklabel:=aktbreaklabel;
  856. getlabel(breakonlabel);
  857. getlabel(continueonlabel);
  858. aktcontinuelabel:=continueonlabel;
  859. aktbreaklabel:=breakonlabel;
  860. end;
  861. { esi is destroyed by FPC_CATCHES }
  862. maybe_loadesi;
  863. oldexceptblock:=aktexceptblock;
  864. aktexceptblock:=p^.right;
  865. secondpass(p^.right);
  866. aktexceptblock:=oldexceptblock;
  867. end;
  868. getlabel(doobjectdestroy);
  869. emitlab(doobjectdestroyandreraise);
  870. emitcall('FPC_POPADDRSTACK');
  871. exprasmlist^.concat(new(pairegalloc,alloc(R_EAX)));
  872. exprasmlist^.concat(new(paicpu,
  873. op_reg(A_POP,S_L,R_EAX)));
  874. exprasmlist^.concat(new(paicpu,
  875. op_reg_reg(A_TEST,S_L,R_EAX,R_EAX)));
  876. exprasmlist^.concat(new(pairegalloc,dealloc(R_EAX)));
  877. emitjmp(C_E,doobjectdestroy);
  878. emitcall('FPC_POPSECONDOBJECTSTACK');
  879. exprasmlist^.concat(new(pairegalloc,alloc(R_EAX)));
  880. emit_reg(A_PUSH,S_L,R_EAX);
  881. emitcall('FPC_DESTROYEXCEPTION');
  882. exprasmlist^.concat(new(pairegalloc,dealloc(R_EAX)));
  883. { we don't need to restore esi here because reraise never }
  884. { returns }
  885. emitcall('FPC_RERAISE');
  886. emitlab(doobjectdestroy);
  887. cleanupobjectstack;
  888. { clear some stuff }
  889. ungetiftemp(ref);
  890. emitjmp(C_None,endexceptlabel);
  891. if assigned(p^.right) then
  892. begin
  893. { special handling for control flow instructions }
  894. if fc_exit in flowcontrol then
  895. begin
  896. { the address and object pop does secondtryexcept }
  897. emitlab(exitonlabel);
  898. emitjmp(C_None,oldaktexitlabel);
  899. end;
  900. if fc_break in flowcontrol then
  901. begin
  902. { the address and object pop does secondtryexcept }
  903. emitlab(breakonlabel);
  904. emitjmp(C_None,oldaktbreaklabel);
  905. end;
  906. if fc_continue in flowcontrol then
  907. begin
  908. { the address and object pop does secondtryexcept }
  909. emitlab(continueonlabel);
  910. emitjmp(C_None,oldaktcontinuelabel);
  911. end;
  912. aktexitlabel:=oldaktexitlabel;
  913. aktexit2label:=oldaktexit2label;
  914. if assigned(oldaktbreaklabel) then
  915. begin
  916. aktcontinuelabel:=oldaktcontinuelabel;
  917. aktbreaklabel:=oldaktbreaklabel;
  918. end;
  919. end;
  920. emitlab(nextonlabel);
  921. flowcontrol:=oldflowcontrol+flowcontrol;
  922. { next on node }
  923. if assigned(p^.left) then
  924. secondpass(p^.left);
  925. end;
  926. {*****************************************************************************
  927. SecondTryFinally
  928. *****************************************************************************}
  929. procedure secondtryfinally(var p : ptree);
  930. var
  931. reraiselabel,
  932. finallylabel,
  933. endfinallylabel,
  934. exitfinallylabel,
  935. continuefinallylabel,
  936. breakfinallylabel,
  937. oldaktexitlabel,
  938. oldaktexit2label,
  939. oldaktcontinuelabel,
  940. oldaktbreaklabel : pasmlabel;
  941. oldexceptblock : ptree;
  942. oldflowcontrol,tryflowcontrol : tflowcontrol;
  943. decconst : longint;
  944. begin
  945. { check if child nodes do a break/continue/exit }
  946. oldflowcontrol:=flowcontrol;
  947. flowcontrol:=[];
  948. { we modify EAX }
  949. usedinproc:=usedinproc or ($80 shr byte(R_EAX));
  950. getlabel(finallylabel);
  951. getlabel(endfinallylabel);
  952. getlabel(reraiselabel);
  953. { the finally block must catch break, continue and exit }
  954. { statements }
  955. oldaktexitlabel:=aktexitlabel;
  956. oldaktexit2label:=aktexit2label;
  957. getlabel(exitfinallylabel);
  958. aktexitlabel:=exitfinallylabel;
  959. aktexit2label:=exitfinallylabel;
  960. if assigned(aktbreaklabel) then
  961. begin
  962. oldaktcontinuelabel:=aktcontinuelabel;
  963. oldaktbreaklabel:=aktbreaklabel;
  964. getlabel(breakfinallylabel);
  965. getlabel(continuefinallylabel);
  966. aktcontinuelabel:=continuefinallylabel;
  967. aktbreaklabel:=breakfinallylabel;
  968. end;
  969. push_int(1); { Type of stack-frame must be pushed}
  970. emitcall('FPC_PUSHEXCEPTADDR');
  971. { allocate eax }
  972. exprasmlist^.concat(new(pairegalloc,alloc(R_EAX)));
  973. emit_reg(A_PUSH,S_L,R_EAX);
  974. emitcall('FPC_SETJMP');
  975. emit_reg(A_PUSH,S_L,R_EAX);
  976. emit_reg_reg(A_TEST,S_L,R_EAX,R_EAX);
  977. { deallocate eax }
  978. exprasmlist^.concat(new(pairegalloc,dealloc(R_EAX)));
  979. emitjmp(C_NE,finallylabel);
  980. { try code }
  981. if assigned(p^.left) then
  982. begin
  983. oldexceptblock:=aktexceptblock;
  984. aktexceptblock:=p^.left;
  985. secondpass(p^.left);
  986. tryflowcontrol:=flowcontrol;
  987. if codegenerror then
  988. exit;
  989. aktexceptblock:=oldexceptblock;
  990. end;
  991. emitlab(finallylabel);
  992. emitcall('FPC_POPADDRSTACK');
  993. { finally code }
  994. oldexceptblock:=aktexceptblock;
  995. aktexceptblock:=p^.right;
  996. flowcontrol:=[];
  997. secondpass(p^.right);
  998. if flowcontrol<>[] then
  999. CGMessage(cg_e_control_flow_outside_finally);
  1000. aktexceptblock:=oldexceptblock;
  1001. if codegenerror then
  1002. exit;
  1003. { allocate eax }
  1004. exprasmlist^.concat(new(pairegalloc,alloc(R_EAX)));
  1005. emit_reg(A_POP,S_L,R_EAX);
  1006. emit_reg_reg(A_TEST,S_L,R_EAX,R_EAX);
  1007. emitjmp(C_E,endfinallylabel);
  1008. emit_reg(A_DEC,S_L,R_EAX);
  1009. emitjmp(C_Z,reraiselabel);
  1010. if fc_exit in tryflowcontrol then
  1011. begin
  1012. emit_reg(A_DEC,S_L,R_EAX);
  1013. emitjmp(C_Z,oldaktexitlabel);
  1014. decconst:=1;
  1015. end
  1016. else
  1017. decconst:=2;
  1018. if fc_break in tryflowcontrol then
  1019. begin
  1020. emit_const_reg(A_SUB,S_L,decconst,R_EAX);
  1021. emitjmp(C_Z,oldaktbreaklabel);
  1022. decconst:=1;
  1023. end
  1024. else
  1025. inc(decconst);
  1026. if fc_continue in tryflowcontrol then
  1027. begin
  1028. emit_const_reg(A_SUB,S_L,decconst,R_EAX);
  1029. emitjmp(C_Z,oldaktcontinuelabel);
  1030. end;
  1031. { deallocate eax }
  1032. exprasmlist^.concat(new(pairegalloc,dealloc(R_EAX)));
  1033. emitlab(reraiselabel);
  1034. emitcall('FPC_RERAISE');
  1035. { do some magic for exit,break,continue in the try block }
  1036. if fc_exit in tryflowcontrol then
  1037. begin
  1038. emitlab(exitfinallylabel);
  1039. { allocate eax }
  1040. exprasmlist^.concat(new(pairegalloc,alloc(R_EAX)));
  1041. emit_reg(A_POP,S_L,R_EAX);
  1042. exprasmlist^.concat(new(pairegalloc,alloc(R_EAX)));
  1043. emit_const(A_PUSH,S_L,2);
  1044. emitjmp(C_NONE,finallylabel);
  1045. end;
  1046. if fc_break in tryflowcontrol then
  1047. begin
  1048. emitlab(breakfinallylabel);
  1049. { allocate eax }
  1050. exprasmlist^.concat(new(pairegalloc,alloc(R_EAX)));
  1051. emit_reg(A_POP,S_L,R_EAX);
  1052. { deallocate eax }
  1053. exprasmlist^.concat(new(pairegalloc,dealloc(R_EAX)));
  1054. emit_const(A_PUSH,S_L,3);
  1055. emitjmp(C_NONE,finallylabel);
  1056. end;
  1057. if fc_continue in tryflowcontrol then
  1058. begin
  1059. emitlab(continuefinallylabel);
  1060. exprasmlist^.concat(new(pairegalloc,alloc(R_EAX)));
  1061. emit_reg(A_POP,S_L,R_EAX);
  1062. exprasmlist^.concat(new(pairegalloc,alloc(R_EAX)));
  1063. emit_const(A_PUSH,S_L,4);
  1064. emitjmp(C_NONE,finallylabel);
  1065. end;
  1066. emitlab(endfinallylabel);
  1067. aktexitlabel:=oldaktexitlabel;
  1068. aktexit2label:=oldaktexit2label;
  1069. if assigned(aktbreaklabel) then
  1070. begin
  1071. aktcontinuelabel:=oldaktcontinuelabel;
  1072. aktbreaklabel:=oldaktbreaklabel;
  1073. end;
  1074. flowcontrol:=oldflowcontrol+tryflowcontrol;
  1075. end;
  1076. {*****************************************************************************
  1077. SecondFail
  1078. *****************************************************************************}
  1079. procedure secondfail(var p : ptree);
  1080. begin
  1081. emitjmp(C_None,faillabel);
  1082. end;
  1083. end.
  1084. {
  1085. $Log$
  1086. Revision 1.73 2000-04-24 11:11:50 peter
  1087. * backtraces for exceptions are now only generated from the place of the
  1088. exception
  1089. * frame is also pushed for exceptions
  1090. * raise statement enhanced with [,<frame>]
  1091. Revision 1.72 2000/04/22 15:29:26 jonas
  1092. * cleaner register (de)allocation in secondfor (for optimizer)
  1093. Revision 1.71 2000/04/16 08:08:44 jonas
  1094. * release register used in for-loop before end label (for better
  1095. optimizations)
  1096. Revision 1.70 2000/02/29 23:58:19 pierre
  1097. Use $GOTO ON
  1098. Revision 1.69 2000/02/10 23:44:42 florian
  1099. * big update for exception handling code generation: possible mem holes
  1100. fixed, break/continue/exit should work always now as expected
  1101. Revision 1.68 2000/02/09 13:22:47 peter
  1102. * log truncated
  1103. Revision 1.67 2000/01/21 12:17:42 jonas
  1104. * regallocation fixes
  1105. Revision 1.66 2000/01/07 01:14:20 peter
  1106. * updated copyright to 2000
  1107. Revision 1.65 1999/12/22 23:30:06 peter
  1108. * nested try blocks work again
  1109. Revision 1.64 1999/12/22 01:01:46 peter
  1110. - removed freelabel()
  1111. * added undefined label detection in internal assembler, this prevents
  1112. a lot of ld crashes and wrong .o files
  1113. * .o files aren't written anymore if errors have occured
  1114. * inlining of assembler labels is now correct
  1115. Revision 1.63 1999/12/19 17:02:45 peter
  1116. * support exit,break,continue in try...except
  1117. * support break,continue in try...finally
  1118. Revision 1.62 1999/12/17 11:20:06 florian
  1119. * made the goto checking for excpetions more fool proof against errors
  1120. Revision 1.61 1999/12/14 09:58:41 florian
  1121. + compiler checks now if a goto leaves an exception block
  1122. Revision 1.60 1999/12/01 12:36:23 peter
  1123. * fixed selfpointer after destroyexception
  1124. Revision 1.59 1999/11/30 10:40:42 peter
  1125. + ttype, tsymlist
  1126. Revision 1.58 1999/11/28 23:15:23 pierre
  1127. * fix for form bug 721
  1128. Revision 1.57 1999/11/15 21:49:09 peter
  1129. * push address also for raise at
  1130. Revision 1.56 1999/11/06 14:34:17 peter
  1131. * truncated log to 20 revs
  1132. Revision 1.55 1999/10/30 17:35:26 peter
  1133. * fpc_freemem fpc_getmem new callings updated
  1134. Revision 1.54 1999/10/21 16:41:37 florian
  1135. * problems with readln fixed: esi wasn't restored correctly when
  1136. reading ordinal fields of objects futher the register allocation
  1137. didn't take care of the extra register when reading ordinal values
  1138. * enumerations can now be used in constant indexes of properties
  1139. Revision 1.53 1999/10/05 22:01:52 pierre
  1140. * bug exit('test') + fail for classes
  1141. Revision 1.52 1999/09/27 23:44:46 peter
  1142. * procinfo is now a pointer
  1143. * support for result setting in sub procedure
  1144. Revision 1.51 1999/09/26 13:26:05 florian
  1145. * exception patch of Romio nevertheless the excpetion handling
  1146. needs some corections regarding register saving
  1147. * gettempansistring is again a procedure
  1148. Revision 1.50 1999/09/20 16:35:43 peter
  1149. * restored old alignment, saves 40k on ppc386
  1150. Revision 1.49 1999/09/15 20:35:37 florian
  1151. * small fix to operator overloading when in MMX mode
  1152. + the compiler uses now fldz and fld1 if possible
  1153. + some fixes to floating point registers
  1154. + some math. functions (arctan, ln, sin, cos, sqrt, sqr, pi) are now inlined
  1155. * .... ???
  1156. Revision 1.48 1999/09/07 07:56:37 peter
  1157. * reload esi in except block to allow virtual methods
  1158. Revision 1.47 1999/08/25 11:59:42 jonas
  1159. * changed pai386, paippc and paiapha (same for tai*) to paicpu (taicpu)
  1160. }