ncgflw.pas 44 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125
  1. {
  2. Copyright (c) 1998-2002 by Florian Klaempfl
  3. Generate assembler for nodes that influence the flow which are
  4. the same for all (most?) processors
  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 ncgflw;
  19. {$i fpcdefs.inc}
  20. interface
  21. uses
  22. aasmbase,node,nflw,ncgutil;
  23. type
  24. tcgwhilerepeatnode = class(twhilerepeatnode)
  25. usedregvars: tusedregvars;
  26. procedure pass_generate_code;override;
  27. procedure sync_regvars(checkusedregvars: boolean);
  28. end;
  29. tcgifnode = class(tifnode)
  30. procedure pass_generate_code;override;
  31. end;
  32. tcgfornode = class(tfornode)
  33. procedure pass_generate_code;override;
  34. end;
  35. tcgexitnode = class(texitnode)
  36. procedure pass_generate_code;override;
  37. end;
  38. tcgbreaknode = class(tbreaknode)
  39. procedure pass_generate_code;override;
  40. end;
  41. tcgcontinuenode = class(tcontinuenode)
  42. procedure pass_generate_code;override;
  43. end;
  44. tcggotonode = class(tgotonode)
  45. procedure pass_generate_code;override;
  46. end;
  47. tcglabelnode = class(tlabelnode)
  48. protected
  49. asmlabel : tasmlabel;
  50. public
  51. function getasmlabel : tasmlabel; virtual;
  52. procedure pass_generate_code;override;
  53. end;
  54. tcgraisenode = class(traisenode)
  55. end;
  56. tcgtryexceptnode = class(ttryexceptnode)
  57. procedure pass_generate_code;override;
  58. end;
  59. tcgtryfinallynode = class(ttryfinallynode)
  60. procedure handle_safecall_exception;
  61. procedure pass_generate_code;override;
  62. end;
  63. tcgonnode = class(tonnode)
  64. procedure pass_generate_code;override;
  65. end;
  66. implementation
  67. uses
  68. cutils,
  69. verbose,globals,systems,globtype,constexp,
  70. symconst,symdef,symsym,symtable,symtype,aasmtai,aasmdata,aasmcpu,defutil,
  71. procinfo,cgbase,pass_2,parabase,
  72. fmodule,
  73. cpubase,ncon,
  74. tgobj,paramgr,
  75. cgutils,cgobj,hlcgobj,nutils
  76. ;
  77. {*****************************************************************************
  78. Second_While_RepeatN
  79. *****************************************************************************}
  80. procedure tcgwhilerepeatnode.sync_regvars(checkusedregvars: boolean);
  81. begin
  82. if (cs_opt_regvar in current_settings.optimizerswitches) and
  83. not(pi_has_label in current_procinfo.flags) then
  84. begin
  85. if checkusedregvars then
  86. begin
  87. usedregvars.intregvars.init;
  88. usedregvars.addrregvars.init;
  89. usedregvars.fpuregvars.init;
  90. usedregvars.mmregvars.init;
  91. { we have to synchronise both the regvars used in the loop }
  92. { and the ones in the while/until condition }
  93. get_used_regvars(self,usedregvars);
  94. gen_sync_regvars(current_asmdata.CurrAsmList,usedregvars);
  95. end
  96. else
  97. begin
  98. gen_sync_regvars(current_asmdata.CurrAsmList,usedregvars);
  99. usedregvars.intregvars.done;
  100. usedregvars.addrregvars.done;
  101. usedregvars.fpuregvars.done;
  102. usedregvars.mmregvars.done;
  103. end;
  104. end;
  105. end;
  106. procedure tcgwhilerepeatnode.pass_generate_code;
  107. var
  108. lcont,lbreak,lloop,
  109. oldclabel,oldblabel : tasmlabel;
  110. truelabel,falselabel : tasmlabel;
  111. oldflowcontrol : tflowcontrol;
  112. oldexecutionweight : longint;
  113. begin
  114. location_reset(location,LOC_VOID,OS_NO);
  115. current_asmdata.getjumplabel(lloop);
  116. current_asmdata.getjumplabel(lcont);
  117. current_asmdata.getjumplabel(lbreak);
  118. { arrange continue and breaklabels: }
  119. oldflowcontrol:=flowcontrol;
  120. oldclabel:=current_procinfo.CurrContinueLabel;
  121. oldblabel:=current_procinfo.CurrBreakLabel;
  122. include(flowcontrol,fc_inflowcontrol);
  123. exclude(flowcontrol,fc_unwind_loop);
  124. sync_regvars(true);
  125. {$ifdef OLDREGVARS}
  126. load_all_regvars(current_asmdata.CurrAsmList);
  127. {$endif OLDREGVARS}
  128. { handling code at the end as it is much more efficient, and makes
  129. while equal to repeat loop, only the end true/false is swapped (PFV) }
  130. if lnf_testatbegin in loopflags then
  131. hlcg.a_jmp_always(current_asmdata.CurrAsmList,lcont);
  132. if not(cs_opt_size in current_settings.optimizerswitches) then
  133. { align loop target }
  134. current_asmdata.CurrAsmList.concat(Tai_align.Create(current_settings.alignment.loopalign));
  135. hlcg.a_label(current_asmdata.CurrAsmList,lloop);
  136. current_procinfo.CurrContinueLabel:=lcont;
  137. current_procinfo.CurrBreakLabel:=lbreak;
  138. { calc register weight }
  139. oldexecutionweight:=cg.executionweight;
  140. cg.executionweight:=max(cg.executionweight,1)*8;
  141. if assigned(right) then
  142. secondpass(right);
  143. {$ifdef OLDREGVARS}
  144. load_all_regvars(current_asmdata.CurrAsmList);
  145. {$endif OLDREGVARS}
  146. hlcg.a_label(current_asmdata.CurrAsmList,lcont);
  147. if lnf_checknegate in loopflags then
  148. begin
  149. truelabel:=lbreak;
  150. falselabel:=lloop;
  151. end
  152. else
  153. begin
  154. truelabel:=lloop;
  155. falselabel:=lbreak;
  156. end;
  157. secondpass(left);
  158. hlcg.maketojumpboollabels(current_asmdata.CurrAsmList,left,truelabel,falselabel);
  159. cg.executionweight:=oldexecutionweight;
  160. hlcg.a_label(current_asmdata.CurrAsmList,lbreak);
  161. sync_regvars(false);
  162. current_procinfo.CurrContinueLabel:=oldclabel;
  163. current_procinfo.CurrBreakLabel:=oldblabel;
  164. { a break/continue in a while/repeat block can't be seen outside }
  165. flowcontrol:=oldflowcontrol+(flowcontrol-[fc_break,fc_continue,fc_inflowcontrol]);
  166. end;
  167. {*****************************************************************************
  168. tcgIFNODE
  169. *****************************************************************************}
  170. procedure tcgifnode.pass_generate_code;
  171. var
  172. hl : tasmlabel;
  173. oldflowcontrol: tflowcontrol;
  174. oldexecutionweight : longint;
  175. (*
  176. org_regvar_loaded_other,
  177. then_regvar_loaded_other,
  178. else_regvar_loaded_other : regvarother_booleanarray;
  179. org_regvar_loaded_int,
  180. then_regvar_loaded_int,
  181. else_regvar_loaded_int : Tsuperregisterset;
  182. org_list,
  183. then_list,
  184. else_list : TAsmList;
  185. *)
  186. begin
  187. location_reset(location,LOC_VOID,OS_NO);
  188. hl:=nil;
  189. oldflowcontrol := flowcontrol;
  190. include(flowcontrol,fc_inflowcontrol);
  191. secondpass(left);
  192. (*
  193. { save regvars loaded in the beginning so that we can restore them }
  194. { when processing the else-block }
  195. if cs_opt_regvar in current_settings.optimizerswitches then
  196. begin
  197. org_list := current_asmdata.CurrAsmList;
  198. current_asmdata.CurrAsmList := TAsmList.create;
  199. end;
  200. *)
  201. hlcg.maketojumpbool(current_asmdata.CurrAsmList,left);
  202. (*
  203. if cs_opt_regvar in current_settings.optimizerswitches then
  204. begin
  205. org_regvar_loaded_int := rg.regvar_loaded_int;
  206. org_regvar_loaded_other := rg.regvar_loaded_other;
  207. end;
  208. *)
  209. { determines registers weigths }
  210. oldexecutionweight:=cg.executionweight;
  211. cg.executionweight:=cg.executionweight div 2;
  212. if cg.executionweight<1 then
  213. cg.executionweight:=1;
  214. if assigned(right) then
  215. begin
  216. hlcg.a_label(current_asmdata.CurrAsmList,left.location.truelabel);
  217. secondpass(right);
  218. end;
  219. { save current asmlist (previous instructions + then-block) and }
  220. { loaded regvar state and create new clean ones }
  221. {
  222. if cs_opt_regvar in current_settings.optimizerswitches then
  223. begin
  224. then_regvar_loaded_int := rg.regvar_loaded_int;
  225. then_regvar_loaded_other := rg.regvar_loaded_other;
  226. rg.regvar_loaded_int := org_regvar_loaded_int;
  227. rg.regvar_loaded_other := org_regvar_loaded_other;
  228. then_list := current_asmdata.CurrAsmList;
  229. current_asmdata.CurrAsmList := TAsmList.create;
  230. end;
  231. }
  232. if assigned(t1) then
  233. begin
  234. if assigned(right) then
  235. begin
  236. current_asmdata.getjumplabel(hl);
  237. { do go back to if line !! }
  238. (*
  239. if not(cs_opt_regvar in current_settings.optimizerswitches) then
  240. *)
  241. current_filepos:=current_asmdata.CurrAsmList.getlasttaifilepos^
  242. (*
  243. else
  244. current_filepos:=then_list.getlasttaifilepos^
  245. *)
  246. ;
  247. hlcg.a_jmp_always(current_asmdata.CurrAsmList,hl);
  248. end;
  249. hlcg.a_label(current_asmdata.CurrAsmList,left.location.falselabel);
  250. secondpass(t1);
  251. (*
  252. { save current asmlist (previous instructions + else-block) }
  253. { and loaded regvar state and create a new clean list }
  254. if cs_opt_regvar in current_settings.optimizerswitches then
  255. begin
  256. { else_regvar_loaded_int := rg.regvar_loaded_int;
  257. else_regvar_loaded_other := rg.regvar_loaded_other;}
  258. else_list := current_asmdata.CurrAsmList;
  259. current_asmdata.CurrAsmList := TAsmList.create;
  260. end;
  261. *)
  262. if assigned(right) then
  263. hlcg.a_label(current_asmdata.CurrAsmList,hl);
  264. end
  265. else
  266. begin
  267. (*
  268. if cs_opt_regvar in current_settings.optimizerswitches then
  269. begin
  270. { else_regvar_loaded_int := rg.regvar_loaded_int;
  271. else_regvar_loaded_other := rg.regvar_loaded_other;}
  272. else_list := current_asmdata.CurrAsmList;
  273. current_asmdata.CurrAsmList := TAsmList.create;
  274. end;
  275. *)
  276. hlcg.a_label(current_asmdata.CurrAsmList,left.location.falselabel);
  277. end;
  278. if not(assigned(right)) then
  279. begin
  280. hlcg.a_label(current_asmdata.CurrAsmList,left.location.truelabel);
  281. end;
  282. (*
  283. if cs_opt_regvar in current_settings.optimizerswitches then
  284. begin
  285. { add loads of regvars at the end of the then- and else-blocks }
  286. { so that at the end of both blocks the same regvars are loaded }
  287. { no else block? }
  288. if not assigned(t1) then
  289. begin
  290. sync_regvars_int(org_list,then_list,org_regvar_loaded_int,then_regvar_loaded_int);
  291. sync_regvars_other(org_list,then_list,org_regvar_loaded_other,then_regvar_loaded_other);
  292. end
  293. { no then block? }
  294. else if not assigned(right) then
  295. begin
  296. sync_regvars_int(org_list,else_list,org_regvar_loaded_int,else_regvar_loaded_int);
  297. sync_regvars_other(org_list,else_list,org_regvar_loaded_other,else_regvar_loaded_other);
  298. end
  299. { both else and then blocks }
  300. else
  301. begin
  302. sync_regvars_int(then_list,else_list,then_regvar_loaded_int,else_regvar_loaded_int);
  303. sync_regvars_other(then_list,else_list,then_regvar_loaded_other,else_regvar_loaded_other);
  304. end;
  305. { add all lists together }
  306. org_list.concatlist(then_list);
  307. then_list.free;
  308. org_list.concatlist(else_list);
  309. else_list.free;
  310. org_list.concatlist(current_asmdata.CurrAsmList);
  311. current_asmdata.CurrAsmList.free;
  312. current_asmdata.CurrAsmList := org_list;
  313. end;
  314. *)
  315. cg.executionweight:=oldexecutionweight;
  316. flowcontrol := oldflowcontrol + (flowcontrol - [fc_inflowcontrol]);
  317. end;
  318. {*****************************************************************************
  319. SecondFor
  320. *****************************************************************************}
  321. procedure tcgfornode.pass_generate_code;
  322. begin
  323. { for nodes are converted in pass_1 in a while loop }
  324. internalerror(2015082501);
  325. end;
  326. {*****************************************************************************
  327. SecondExitN
  328. *****************************************************************************}
  329. procedure tcgexitnode.pass_generate_code;
  330. begin
  331. location_reset(location,LOC_VOID,OS_NO);
  332. include(flowcontrol,fc_exit);
  333. if assigned(left) then
  334. secondpass(left);
  335. if (fc_unwind_exit in flowcontrol) then
  336. hlcg.g_local_unwind(current_asmdata.CurrAsmList,current_procinfo.CurrExitLabel)
  337. else
  338. hlcg.a_jmp_always(current_asmdata.CurrAsmList,current_procinfo.CurrExitLabel);
  339. end;
  340. {*****************************************************************************
  341. SecondBreakN
  342. *****************************************************************************}
  343. procedure tcgbreaknode.pass_generate_code;
  344. begin
  345. location_reset(location,LOC_VOID,OS_NO);
  346. include(flowcontrol,fc_break);
  347. if current_procinfo.CurrBreakLabel<>nil then
  348. begin
  349. {$ifdef OLDREGVARS}
  350. load_all_regvars(current_asmdata.CurrAsmList);
  351. {$endif OLDREGVARS}
  352. if (fc_unwind_loop in flowcontrol) then
  353. hlcg.g_local_unwind(current_asmdata.CurrAsmList,current_procinfo.CurrBreakLabel)
  354. else
  355. hlcg.a_jmp_always(current_asmdata.CurrAsmList,current_procinfo.CurrBreakLabel)
  356. end
  357. else
  358. CGMessage(cg_e_break_not_allowed);
  359. end;
  360. {*****************************************************************************
  361. SecondContinueN
  362. *****************************************************************************}
  363. procedure tcgcontinuenode.pass_generate_code;
  364. begin
  365. location_reset(location,LOC_VOID,OS_NO);
  366. include(flowcontrol,fc_continue);
  367. if current_procinfo.CurrContinueLabel<>nil then
  368. begin
  369. {$ifdef OLDREGVARS}
  370. load_all_regvars(current_asmdata.CurrAsmList);
  371. {$endif OLDREGVARS}
  372. if (fc_unwind_loop in flowcontrol) then
  373. hlcg.g_local_unwind(current_asmdata.CurrAsmList,current_procinfo.CurrContinueLabel)
  374. else
  375. hlcg.a_jmp_always(current_asmdata.CurrAsmList,current_procinfo.CurrContinueLabel)
  376. end
  377. else
  378. CGMessage(cg_e_continue_not_allowed);
  379. end;
  380. {*****************************************************************************
  381. SecondGoto
  382. *****************************************************************************}
  383. procedure tcggotonode.pass_generate_code;
  384. begin
  385. location_reset(location,LOC_VOID,OS_NO);
  386. include(flowcontrol,fc_gotolabel);
  387. {$ifdef OLDREGVARS}
  388. load_all_regvars(current_asmdata.CurrAsmList);
  389. {$endif OLDREGVARS}
  390. hlcg.a_jmp_always(current_asmdata.CurrAsmList,tcglabelnode(labelnode).getasmlabel)
  391. end;
  392. {*****************************************************************************
  393. SecondLabel
  394. *****************************************************************************}
  395. function tcglabelnode.getasmlabel : tasmlabel;
  396. begin
  397. if not(assigned(asmlabel)) then
  398. { labsym is not set in inlined procedures, but since assembler }
  399. { routines can't be inlined, that shouldn't matter }
  400. if assigned(labsym) and
  401. labsym.nonlocal then
  402. current_asmdata.getglobaljumplabel(asmlabel)
  403. else
  404. current_asmdata.getjumplabel(asmlabel);
  405. result:=asmlabel
  406. end;
  407. procedure tcglabelnode.pass_generate_code;
  408. begin
  409. location_reset(location,LOC_VOID,OS_NO);
  410. include(flowcontrol,fc_gotolabel);
  411. {$ifdef OLDREGVARS}
  412. load_all_regvars(current_asmdata.CurrAsmList);
  413. {$endif OLDREGVARS}
  414. hlcg.a_label(current_asmdata.CurrAsmList,getasmlabel);
  415. { Write also extra label if this label was referenced from
  416. assembler block }
  417. if assigned(labsym) and
  418. assigned(labsym.asmblocklabel) then
  419. hlcg.a_label(current_asmdata.CurrAsmList,labsym.asmblocklabel);
  420. secondpass(left);
  421. end;
  422. {*****************************************************************************
  423. SecondTryExcept
  424. *****************************************************************************}
  425. var
  426. endexceptlabel : tasmlabel;
  427. { does the necessary things to clean up the object stack }
  428. { in the except block }
  429. procedure cleanupobjectstack;
  430. begin
  431. hlcg.g_call_system_proc(current_asmdata.CurrAsmList,'fpc_doneexception',[],nil);
  432. end;
  433. { generates code to be executed when another exeception is raised while
  434. control is inside except block }
  435. procedure handle_nested_exception(list:TAsmList;const t:texceptiontemps;entrylabel:TAsmLabel);
  436. var
  437. exitlabel: tasmlabel;
  438. begin
  439. { don't generate line info for internal cleanup }
  440. list.concat(tai_marker.create(mark_NoLineInfoStart));
  441. current_asmdata.getjumplabel(exitlabel);
  442. hlcg.a_label(list,entrylabel);
  443. free_exception(list,t,0,exitlabel,false);
  444. { we don't need to save/restore registers here because reraise never }
  445. { returns }
  446. hlcg.g_call_system_proc(list,'fpc_raise_nested',[],nil);
  447. hlcg.a_label(list,exitlabel);
  448. cleanupobjectstack;
  449. end;
  450. procedure tcgtryexceptnode.pass_generate_code;
  451. var
  452. exceptlabel,doexceptlabel,oldendexceptlabel,
  453. lastonlabel,
  454. exitexceptlabel,
  455. continueexceptlabel,
  456. breakexceptlabel,
  457. exittrylabel,
  458. continuetrylabel,
  459. breaktrylabel,
  460. doobjectdestroyandreraise,
  461. oldCurrExitLabel,
  462. oldContinueLabel,
  463. oldBreakLabel : tasmlabel;
  464. oldflowcontrol,tryflowcontrol,
  465. exceptflowcontrol : tflowcontrol;
  466. destroytemps,
  467. excepttemps : texceptiontemps;
  468. label
  469. errorexit;
  470. begin
  471. location_reset(location,LOC_VOID,OS_NO);
  472. exceptflowcontrol:=[];
  473. continuetrylabel:=nil;
  474. breaktrylabel:=nil;
  475. continueexceptlabel:=nil;
  476. breakexceptlabel:=nil;
  477. oldflowcontrol:=flowcontrol;
  478. flowcontrol:=[fc_inflowcontrol];
  479. { this can be called recursivly }
  480. oldBreakLabel:=nil;
  481. oldContinueLabel:=nil;
  482. oldendexceptlabel:=endexceptlabel;
  483. { save the old labels for control flow statements }
  484. oldCurrExitLabel:=current_procinfo.CurrExitLabel;
  485. if assigned(current_procinfo.CurrBreakLabel) then
  486. begin
  487. oldContinueLabel:=current_procinfo.CurrContinueLabel;
  488. oldBreakLabel:=current_procinfo.CurrBreakLabel;
  489. end;
  490. { get new labels for the control flow statements }
  491. current_asmdata.getjumplabel(exittrylabel);
  492. current_asmdata.getjumplabel(exitexceptlabel);
  493. if assigned(current_procinfo.CurrBreakLabel) then
  494. begin
  495. current_asmdata.getjumplabel(breaktrylabel);
  496. current_asmdata.getjumplabel(continuetrylabel);
  497. current_asmdata.getjumplabel(breakexceptlabel);
  498. current_asmdata.getjumplabel(continueexceptlabel);
  499. end;
  500. current_asmdata.getjumplabel(exceptlabel);
  501. current_asmdata.getjumplabel(doexceptlabel);
  502. current_asmdata.getjumplabel(endexceptlabel);
  503. current_asmdata.getjumplabel(lastonlabel);
  504. get_exception_temps(current_asmdata.CurrAsmList,excepttemps);
  505. new_exception(current_asmdata.CurrAsmList,excepttemps,exceptlabel);
  506. { try block }
  507. { set control flow labels for the try block }
  508. current_procinfo.CurrExitLabel:=exittrylabel;
  509. if assigned(oldBreakLabel) then
  510. begin
  511. current_procinfo.CurrContinueLabel:=continuetrylabel;
  512. current_procinfo.CurrBreakLabel:=breaktrylabel;
  513. end;
  514. flowcontrol:=[fc_inflowcontrol];
  515. secondpass(left);
  516. tryflowcontrol:=flowcontrol;
  517. if codegenerror then
  518. goto errorexit;
  519. { don't generate line info for internal cleanup }
  520. current_asmdata.CurrAsmList.concat(tai_marker.create(mark_NoLineInfoStart));
  521. hlcg.a_label(current_asmdata.CurrAsmList,exceptlabel);
  522. free_exception(current_asmdata.CurrAsmList, excepttemps, 0, endexceptlabel, false);
  523. hlcg.a_label(current_asmdata.CurrAsmList,doexceptlabel);
  524. { end cleanup }
  525. current_asmdata.CurrAsmList.concat(tai_marker.create(mark_NoLineInfoEnd));
  526. { set control flow labels for the except block }
  527. { and the on statements }
  528. current_procinfo.CurrExitLabel:=exitexceptlabel;
  529. if assigned(oldBreakLabel) then
  530. begin
  531. current_procinfo.CurrContinueLabel:=continueexceptlabel;
  532. current_procinfo.CurrBreakLabel:=breakexceptlabel;
  533. end;
  534. flowcontrol:=[fc_inflowcontrol];
  535. { on statements }
  536. if assigned(right) then
  537. secondpass(right);
  538. { don't generate line info for internal cleanup }
  539. current_asmdata.CurrAsmList.concat(tai_marker.create(mark_NoLineInfoStart));
  540. hlcg.a_label(current_asmdata.CurrAsmList,lastonlabel);
  541. { default handling except handling }
  542. if assigned(t1) then
  543. begin
  544. { FPC_CATCHES with 'default handler' flag (=-1) need no longer be called,
  545. it doesn't change any state and its return value is ignored (Sergei)
  546. }
  547. { the destruction of the exception object must be also }
  548. { guarded by an exception frame, but it can be omitted }
  549. { if there's no user code in 'except' block }
  550. if not (has_no_code(t1)) then
  551. begin
  552. current_asmdata.getjumplabel(doobjectdestroyandreraise);
  553. get_exception_temps(current_asmdata.CurrAsmList,destroytemps);
  554. new_exception(current_asmdata.CurrAsmList,destroytemps,doobjectdestroyandreraise);
  555. { except block needs line info }
  556. current_asmdata.CurrAsmList.concat(tai_marker.create(mark_NoLineInfoEnd));
  557. { here we don't have to reset flowcontrol }
  558. { the default and on flowcontrols are handled equal }
  559. secondpass(t1);
  560. exceptflowcontrol:=flowcontrol;
  561. handle_nested_exception(current_asmdata.CurrAsmList,destroytemps,doobjectdestroyandreraise);
  562. unget_exception_temps(current_asmdata.CurrAsmList,destroytemps);
  563. hlcg.a_jmp_always(current_asmdata.CurrAsmList,endexceptlabel);
  564. end
  565. else
  566. begin
  567. exceptflowcontrol:=flowcontrol;
  568. cleanupobjectstack;
  569. hlcg.a_jmp_always(current_asmdata.CurrAsmList,endexceptlabel);
  570. end;
  571. end
  572. else
  573. begin
  574. hlcg.g_call_system_proc(current_asmdata.CurrAsmList,'fpc_reraise',[],nil);
  575. exceptflowcontrol:=flowcontrol;
  576. end;
  577. if fc_exit in exceptflowcontrol then
  578. begin
  579. { do some magic for exit in the try block }
  580. hlcg.a_label(current_asmdata.CurrAsmList,exitexceptlabel);
  581. { we must also destroy the address frame which guards }
  582. { exception object }
  583. hlcg.g_call_system_proc(current_asmdata.CurrAsmList,'fpc_popaddrstack',[],nil);
  584. hlcg.g_exception_reason_discard(current_asmdata.CurrAsmList,osuinttype,excepttemps.reasonbuf);
  585. cleanupobjectstack;
  586. hlcg.a_jmp_always(current_asmdata.CurrAsmList,oldCurrExitLabel);
  587. end;
  588. if fc_break in exceptflowcontrol then
  589. begin
  590. hlcg.a_label(current_asmdata.CurrAsmList,breakexceptlabel);
  591. { we must also destroy the address frame which guards }
  592. { exception object }
  593. hlcg.g_call_system_proc(current_asmdata.CurrAsmList,'fpc_popaddrstack',[],nil);
  594. hlcg.g_exception_reason_discard(current_asmdata.CurrAsmList,osuinttype,excepttemps.reasonbuf);
  595. cleanupobjectstack;
  596. cg.a_jmp_always(current_asmdata.CurrAsmList,oldBreakLabel);
  597. end;
  598. if fc_continue in exceptflowcontrol then
  599. begin
  600. hlcg.a_label(current_asmdata.CurrAsmList,continueexceptlabel);
  601. { we must also destroy the address frame which guards }
  602. { exception object }
  603. hlcg.g_call_system_proc(current_asmdata.CurrAsmList,'fpc_popaddrstack',[],nil);
  604. hlcg.g_exception_reason_discard(current_asmdata.CurrAsmList,osuinttype,excepttemps.reasonbuf);
  605. cleanupobjectstack;
  606. hlcg.a_jmp_always(current_asmdata.CurrAsmList,oldContinueLabel);
  607. end;
  608. if fc_exit in tryflowcontrol then
  609. begin
  610. { do some magic for exit in the try block }
  611. hlcg.a_label(current_asmdata.CurrAsmList,exittrylabel);
  612. hlcg.g_call_system_proc(current_asmdata.CurrAsmList,'fpc_popaddrstack',[],nil);
  613. hlcg.g_exception_reason_discard(current_asmdata.CurrAsmList,osuinttype,excepttemps.reasonbuf);
  614. hlcg.a_jmp_always(current_asmdata.CurrAsmList,oldCurrExitLabel);
  615. end;
  616. if fc_break in tryflowcontrol then
  617. begin
  618. hlcg.a_label(current_asmdata.CurrAsmList,breaktrylabel);
  619. hlcg.g_call_system_proc(current_asmdata.CurrAsmList,'fpc_popaddrstack',[],nil);
  620. hlcg.g_exception_reason_discard(current_asmdata.CurrAsmList,osuinttype,excepttemps.reasonbuf);
  621. cg.a_jmp_always(current_asmdata.CurrAsmList,oldBreakLabel);
  622. end;
  623. if fc_continue in tryflowcontrol then
  624. begin
  625. hlcg.a_label(current_asmdata.CurrAsmList,continuetrylabel);
  626. hlcg.g_call_system_proc(current_asmdata.CurrAsmList,'fpc_popaddrstack',[],nil);
  627. hlcg.g_exception_reason_discard(current_asmdata.CurrAsmList,osuinttype,excepttemps.reasonbuf);
  628. cg.a_jmp_always(current_asmdata.CurrAsmList,oldContinueLabel);
  629. end;
  630. unget_exception_temps(current_asmdata.CurrAsmList,excepttemps);
  631. hlcg.a_label(current_asmdata.CurrAsmList,endexceptlabel);
  632. { end cleanup }
  633. current_asmdata.CurrAsmList.concat(tai_marker.create(mark_NoLineInfoEnd));
  634. errorexit:
  635. { restore all saved labels }
  636. endexceptlabel:=oldendexceptlabel;
  637. { restore the control flow labels }
  638. current_procinfo.CurrExitLabel:=oldCurrExitLabel;
  639. if assigned(oldBreakLabel) then
  640. begin
  641. current_procinfo.CurrContinueLabel:=oldContinueLabel;
  642. current_procinfo.CurrBreakLabel:=oldBreakLabel;
  643. end;
  644. { return all used control flow statements }
  645. flowcontrol:=oldflowcontrol+(exceptflowcontrol +
  646. tryflowcontrol - [fc_inflowcontrol]);
  647. end;
  648. procedure tcgonnode.pass_generate_code;
  649. var
  650. nextonlabel,
  651. exitonlabel,
  652. continueonlabel,
  653. breakonlabel,
  654. oldCurrExitLabel,
  655. oldContinueLabel,
  656. doobjectdestroyandreraise,
  657. oldBreakLabel : tasmlabel;
  658. oldflowcontrol : tflowcontrol;
  659. excepttemps : texceptiontemps;
  660. href2: treference;
  661. paraloc1 : tcgpara;
  662. exceptvarsym : tlocalvarsym;
  663. pd : tprocdef;
  664. fpc_catches_res: TCGPara;
  665. fpc_catches_resloc: tlocation;
  666. otherunit,
  667. indirect : boolean;
  668. begin
  669. paraloc1.init;
  670. location_reset(location,LOC_VOID,OS_NO);
  671. oldCurrExitLabel:=nil;
  672. continueonlabel:=nil;
  673. breakonlabel:=nil;
  674. exitonlabel:=nil;
  675. oldflowcontrol:=flowcontrol;
  676. flowcontrol:=[fc_inflowcontrol];
  677. current_asmdata.getjumplabel(nextonlabel);
  678. otherunit:=findunitsymtable(excepttype.owner).moduleid<>findunitsymtable(current_procinfo.procdef.owner).moduleid;
  679. indirect:=(tf_supports_packages in target_info.flags) and
  680. (target_info.system in systems_indirect_var_imports) and
  681. (cs_imported_data in current_settings.localswitches) and
  682. otherunit;
  683. { send the vmt parameter }
  684. pd:=search_system_proc('fpc_catches');
  685. reference_reset_symbol(href2,current_asmdata.RefAsmSymbol(excepttype.vmt_mangledname,AT_DATA,indirect),0,sizeof(pint),[]);
  686. if otherunit then
  687. current_module.add_extern_asmsym(excepttype.vmt_mangledname,AB_EXTERNAL,AT_DATA);
  688. paramanager.getintparaloc(current_asmdata.CurrAsmList,pd,1,paraloc1);
  689. hlcg.a_loadaddr_ref_cgpara(current_asmdata.CurrAsmList,excepttype.vmt_def,href2,paraloc1);
  690. paramanager.freecgpara(current_asmdata.CurrAsmList,paraloc1);
  691. fpc_catches_res:=hlcg.g_call_system_proc(current_asmdata.CurrAsmList,pd,[@paraloc1],nil);
  692. location_reset(fpc_catches_resloc,LOC_REGISTER,def_cgsize(fpc_catches_res.def));
  693. fpc_catches_resloc.register:=hlcg.getaddressregister(current_asmdata.CurrAsmList,fpc_catches_res.def);
  694. hlcg.gen_load_cgpara_loc(current_asmdata.CurrAsmList,fpc_catches_res.def,fpc_catches_res,fpc_catches_resloc,true);
  695. { is it this catch? No. go to next onlabel }
  696. hlcg.a_cmp_const_reg_label(current_asmdata.CurrAsmList,fpc_catches_res.def,OC_EQ,0,fpc_catches_resloc.register,nextonlabel);
  697. { Retrieve exception variable }
  698. if assigned(excepTSymtable) then
  699. exceptvarsym:=tlocalvarsym(excepTSymtable.SymList[0])
  700. else
  701. internalerror(2011020401);
  702. if assigned(exceptvarsym) then
  703. begin
  704. location_reset_ref(exceptvarsym.localloc,LOC_REFERENCE,def_cgsize(voidpointertype),voidpointertype.alignment,[]);
  705. tg.GetLocal(current_asmdata.CurrAsmList,exceptvarsym.vardef.size,exceptvarsym.vardef,exceptvarsym.localloc.reference);
  706. hlcg.a_load_reg_ref(current_asmdata.CurrAsmList,fpc_catches_res.def,exceptvarsym.vardef,fpc_catches_resloc.register,exceptvarsym.localloc.reference);
  707. end;
  708. { in the case that another exception is risen
  709. we've to destroy the old one }
  710. current_asmdata.getjumplabel(doobjectdestroyandreraise);
  711. { call setjmp, and jump to finally label on non-zero result }
  712. get_exception_temps(current_asmdata.CurrAsmList,excepttemps);
  713. new_exception(current_asmdata.CurrAsmList,excepttemps,doobjectdestroyandreraise);
  714. oldBreakLabel:=nil;
  715. oldContinueLabel:=nil;
  716. if assigned(right) then
  717. begin
  718. oldCurrExitLabel:=current_procinfo.CurrExitLabel;
  719. current_asmdata.getjumplabel(exitonlabel);
  720. current_procinfo.CurrExitLabel:=exitonlabel;
  721. if assigned(current_procinfo.CurrBreakLabel) then
  722. begin
  723. oldContinueLabel:=current_procinfo.CurrContinueLabel;
  724. oldBreakLabel:=current_procinfo.CurrBreakLabel;
  725. current_asmdata.getjumplabel(breakonlabel);
  726. current_asmdata.getjumplabel(continueonlabel);
  727. current_procinfo.CurrContinueLabel:=continueonlabel;
  728. current_procinfo.CurrBreakLabel:=breakonlabel;
  729. end;
  730. secondpass(right);
  731. end;
  732. handle_nested_exception(current_asmdata.CurrAsmList,excepttemps,doobjectdestroyandreraise);
  733. { clear some stuff }
  734. if assigned(exceptvarsym) then
  735. begin
  736. tg.UngetLocal(current_asmdata.CurrAsmList,exceptvarsym.localloc.reference);
  737. exceptvarsym.localloc.loc:=LOC_INVALID;
  738. end;
  739. cg.a_jmp_always(current_asmdata.CurrAsmList,endexceptlabel);
  740. if assigned(right) then
  741. begin
  742. { special handling for control flow instructions }
  743. if fc_exit in flowcontrol then
  744. begin
  745. { the address and object pop does secondtryexcept }
  746. cg.a_label(current_asmdata.CurrAsmList,exitonlabel);
  747. cg.a_jmp_always(current_asmdata.CurrAsmList,oldCurrExitLabel);
  748. end;
  749. if fc_break in flowcontrol then
  750. begin
  751. { the address and object pop does secondtryexcept }
  752. cg.a_label(current_asmdata.CurrAsmList,breakonlabel);
  753. cg.a_jmp_always(current_asmdata.CurrAsmList,oldBreakLabel);
  754. end;
  755. if fc_continue in flowcontrol then
  756. begin
  757. { the address and object pop does secondtryexcept }
  758. cg.a_label(current_asmdata.CurrAsmList,continueonlabel);
  759. cg.a_jmp_always(current_asmdata.CurrAsmList,oldContinueLabel);
  760. end;
  761. current_procinfo.CurrExitLabel:=oldCurrExitLabel;
  762. if assigned(oldBreakLabel) then
  763. begin
  764. current_procinfo.CurrContinueLabel:=oldContinueLabel;
  765. current_procinfo.CurrBreakLabel:=oldBreakLabel;
  766. end;
  767. end;
  768. unget_exception_temps(current_asmdata.CurrAsmList,excepttemps);
  769. cg.a_label(current_asmdata.CurrAsmList,nextonlabel);
  770. flowcontrol:=oldflowcontrol+(flowcontrol-[fc_inflowcontrol]);
  771. paraloc1.done;
  772. current_asmdata.CurrAsmList.concat(tai_marker.create(mark_NoLineInfoEnd));
  773. { next on node }
  774. if assigned(left) then
  775. secondpass(left);
  776. end;
  777. {*****************************************************************************
  778. SecondTryFinally
  779. *****************************************************************************}
  780. procedure tcgtryfinallynode.handle_safecall_exception;
  781. var
  782. cgpara: tcgpara;
  783. selfsym: tparavarsym;
  784. pd: tprocdef;
  785. begin
  786. { call fpc_safecallhandler, passing self for methods of classes,
  787. nil otherwise. }
  788. pd:=search_system_proc('fpc_safecallhandler');
  789. cgpara.init;
  790. paramanager.getintparaloc(current_asmdata.CurrAsmList,pd,1,cgpara);
  791. if is_class(current_procinfo.procdef.struct) then
  792. begin
  793. selfsym:=tparavarsym(current_procinfo.procdef.parast.Find('self'));
  794. if (selfsym=nil) or (selfsym.typ<>paravarsym) then
  795. InternalError(2011123101);
  796. cg.a_load_loc_cgpara(current_asmdata.CurrAsmList,selfsym.localloc,cgpara);
  797. end
  798. else
  799. cg.a_load_const_cgpara(current_asmdata.CurrAsmList,OS_ADDR,0,cgpara);
  800. paramanager.freecgpara(current_asmdata.CurrAsmList,cgpara);
  801. cgpara.done;
  802. cg.g_call(current_asmdata.CurrAsmList,'FPC_SAFECALLHANDLER');
  803. cg.a_load_reg_reg(current_asmdata.CurrAsmList,OS_INT,OS_INT,NR_FUNCTION_RESULT_REG, NR_FUNCTION_RETURN_REG);
  804. end;
  805. procedure tcgtryfinallynode.pass_generate_code;
  806. var
  807. finallylabel,
  808. endfinallylabel,
  809. exitfinallylabel,
  810. continuefinallylabel,
  811. breakfinallylabel,
  812. oldCurrExitLabel,
  813. oldContinueLabel,
  814. oldBreakLabel : tasmlabel;
  815. oldflowcontrol,tryflowcontrol : tflowcontrol;
  816. excepttemps : texceptiontemps;
  817. reasonreg : tregister;
  818. begin
  819. location_reset(location,LOC_VOID,OS_NO);
  820. tryflowcontrol:=[];
  821. oldBreakLabel:=nil;
  822. oldContinueLabel:=nil;
  823. continuefinallylabel:=nil;
  824. breakfinallylabel:=nil;
  825. { check if child nodes do a break/continue/exit }
  826. oldflowcontrol:=flowcontrol;
  827. flowcontrol:=[fc_inflowcontrol];
  828. current_asmdata.getjumplabel(finallylabel);
  829. current_asmdata.getjumplabel(endfinallylabel);
  830. { the finally block must catch break, continue and exit }
  831. { statements }
  832. oldCurrExitLabel:=current_procinfo.CurrExitLabel;
  833. if implicitframe then
  834. exitfinallylabel:=finallylabel
  835. else
  836. current_asmdata.getjumplabel(exitfinallylabel);
  837. current_procinfo.CurrExitLabel:=exitfinallylabel;
  838. if assigned(current_procinfo.CurrBreakLabel) then
  839. begin
  840. oldContinueLabel:=current_procinfo.CurrContinueLabel;
  841. oldBreakLabel:=current_procinfo.CurrBreakLabel;
  842. if implicitframe then
  843. begin
  844. breakfinallylabel:=finallylabel;
  845. continuefinallylabel:=finallylabel;
  846. end
  847. else
  848. begin
  849. current_asmdata.getjumplabel(breakfinallylabel);
  850. current_asmdata.getjumplabel(continuefinallylabel);
  851. end;
  852. current_procinfo.CurrContinueLabel:=continuefinallylabel;
  853. current_procinfo.CurrBreakLabel:=breakfinallylabel;
  854. end;
  855. { call setjmp, and jump to finally label on non-zero result }
  856. get_exception_temps(current_asmdata.CurrAsmList,excepttemps);
  857. new_exception(current_asmdata.CurrAsmList,excepttemps,finallylabel);
  858. { try code }
  859. if assigned(left) then
  860. begin
  861. secondpass(left);
  862. tryflowcontrol:=flowcontrol;
  863. if codegenerror then
  864. exit;
  865. end;
  866. { don't generate line info for internal cleanup }
  867. current_asmdata.CurrAsmList.concat(tai_marker.create(mark_NoLineInfoStart));
  868. hlcg.a_label(current_asmdata.CurrAsmList,finallylabel);
  869. { just free the frame information }
  870. free_exception(current_asmdata.CurrAsmList,excepttemps,1,finallylabel,true);
  871. { end cleanup }
  872. current_asmdata.CurrAsmList.concat(tai_marker.create(mark_NoLineInfoEnd));
  873. { finally code }
  874. flowcontrol:=[fc_inflowcontrol];
  875. secondpass(right);
  876. { goto is allowed if it stays inside the finally block,
  877. this is checked using the exception block number }
  878. if (flowcontrol-[fc_gotolabel])<>[fc_inflowcontrol] then
  879. CGMessage(cg_e_control_flow_outside_finally);
  880. if codegenerror then
  881. exit;
  882. { don't generate line info for internal cleanup }
  883. current_asmdata.CurrAsmList.concat(tai_marker.create(mark_NoLineInfoStart));
  884. { the value should now be in the exception handler }
  885. reasonreg:=hlcg.getintregister(current_asmdata.CurrAsmList,osuinttype);
  886. hlcg.g_exception_reason_load(current_asmdata.CurrAsmList,osuinttype,osuinttype,excepttemps.reasonbuf,reasonreg);
  887. if implicitframe then
  888. begin
  889. hlcg.a_cmp_const_reg_label(current_asmdata.CurrAsmList,osuinttype,OC_EQ,0,reasonreg,endfinallylabel);
  890. { finally code only needed to be executed on exception }
  891. flowcontrol:=[fc_inflowcontrol];
  892. secondpass(t1);
  893. if flowcontrol<>[fc_inflowcontrol] then
  894. CGMessage(cg_e_control_flow_outside_finally);
  895. if codegenerror then
  896. exit;
  897. if (tf_safecall_exceptions in target_info.flags) and
  898. (current_procinfo.procdef.proccalloption=pocall_safecall) then
  899. handle_safecall_exception
  900. else
  901. hlcg.g_call_system_proc(current_asmdata.CurrAsmList,'fpc_reraise',[],nil);
  902. end
  903. else
  904. begin
  905. hlcg.a_cmp_const_reg_label(current_asmdata.CurrAsmList,osuinttype,OC_EQ,0,reasonreg,endfinallylabel);
  906. if fc_exit in tryflowcontrol then
  907. hlcg.a_cmp_const_reg_label(current_asmdata.CurrAsmList,osuinttype,OC_EQ,2,reasonreg,oldCurrExitLabel);
  908. if fc_break in tryflowcontrol then
  909. hlcg.a_cmp_const_reg_label(current_asmdata.CurrAsmList,osuinttype,OC_EQ,3,reasonreg,oldBreakLabel);
  910. if fc_continue in tryflowcontrol then
  911. hlcg.a_cmp_const_reg_label(current_asmdata.CurrAsmList,osuinttype,OC_EQ,4,reasonreg,oldContinueLabel);
  912. hlcg.g_call_system_proc(current_asmdata.CurrAsmList,'fpc_reraise',[],nil);
  913. { do some magic for exit,break,continue in the try block }
  914. if fc_exit in tryflowcontrol then
  915. begin
  916. hlcg.a_label(current_asmdata.CurrAsmList,exitfinallylabel);
  917. hlcg.g_exception_reason_discard(current_asmdata.CurrAsmList,osuinttype,excepttemps.reasonbuf);
  918. hlcg.g_exception_reason_save_const(current_asmdata.CurrAsmList,osuinttype,2,excepttemps.reasonbuf);
  919. hlcg.a_jmp_always(current_asmdata.CurrAsmList,finallylabel);
  920. end;
  921. if fc_break in tryflowcontrol then
  922. begin
  923. hlcg.a_label(current_asmdata.CurrAsmList,breakfinallylabel);
  924. hlcg.g_exception_reason_discard(current_asmdata.CurrAsmList,osuinttype,excepttemps.reasonbuf);
  925. hlcg.g_exception_reason_save_const(current_asmdata.CurrAsmList,osuinttype,3,excepttemps.reasonbuf);
  926. hlcg.a_jmp_always(current_asmdata.CurrAsmList,finallylabel);
  927. end;
  928. if fc_continue in tryflowcontrol then
  929. begin
  930. hlcg.a_label(current_asmdata.CurrAsmList,continuefinallylabel);
  931. hlcg.g_exception_reason_discard(current_asmdata.CurrAsmList,osuinttype,excepttemps.reasonbuf);
  932. hlcg.g_exception_reason_save_const(current_asmdata.CurrAsmList,osuinttype,4,excepttemps.reasonbuf);
  933. hlcg.a_jmp_always(current_asmdata.CurrAsmList,finallylabel);
  934. end;
  935. end;
  936. unget_exception_temps(current_asmdata.CurrAsmList,excepttemps);
  937. hlcg.a_label(current_asmdata.CurrAsmList,endfinallylabel);
  938. { end cleanup }
  939. current_asmdata.CurrAsmList.concat(tai_marker.create(mark_NoLineInfoEnd));
  940. current_procinfo.CurrExitLabel:=oldCurrExitLabel;
  941. if assigned(current_procinfo.CurrBreakLabel) then
  942. begin
  943. current_procinfo.CurrContinueLabel:=oldContinueLabel;
  944. current_procinfo.CurrBreakLabel:=oldBreakLabel;
  945. end;
  946. flowcontrol:=oldflowcontrol+(tryflowcontrol-[fc_inflowcontrol]);
  947. end;
  948. begin
  949. cwhilerepeatnode:=tcgwhilerepeatnode;
  950. cifnode:=tcgifnode;
  951. cfornode:=tcgfornode;
  952. cexitnode:=tcgexitnode;
  953. cbreaknode:=tcgbreaknode;
  954. ccontinuenode:=tcgcontinuenode;
  955. cgotonode:=tcggotonode;
  956. clabelnode:=tcglabelnode;
  957. craisenode:=tcgraisenode;
  958. ctryexceptnode:=tcgtryexceptnode;
  959. ctryfinallynode:=tcgtryfinallynode;
  960. connode:=tcgonnode;
  961. end.