cg386flw.pas 43 KB

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