cgflw.pas 43 KB

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