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