ncgflw.pas 60 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553
  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. usedregvars: tusedregvars;
  34. procedure pass_generate_code;override;
  35. procedure sync_regvars(checkusedregvars: boolean);
  36. end;
  37. tcgexitnode = class(texitnode)
  38. procedure pass_generate_code;override;
  39. end;
  40. tcgbreaknode = class(tbreaknode)
  41. procedure pass_generate_code;override;
  42. end;
  43. tcgcontinuenode = class(tcontinuenode)
  44. procedure pass_generate_code;override;
  45. end;
  46. tcggotonode = class(tgotonode)
  47. procedure pass_generate_code;override;
  48. end;
  49. tcglabelnode = class(tlabelnode)
  50. private
  51. asmlabel : tasmlabel;
  52. public
  53. function getasmlabel : tasmlabel;
  54. procedure pass_generate_code;override;
  55. end;
  56. tcgraisenode = class(traisenode)
  57. end;
  58. tcgtryexceptnode = class(ttryexceptnode)
  59. procedure pass_generate_code;override;
  60. end;
  61. tcgtryfinallynode = class(ttryfinallynode)
  62. procedure handle_safecall_exception;
  63. procedure pass_generate_code;override;
  64. end;
  65. tcgonnode = class(tonnode)
  66. procedure pass_generate_code;override;
  67. end;
  68. implementation
  69. uses
  70. verbose,globals,systems,globtype,constexp,
  71. symconst,symdef,symsym,symtable,symtype,aasmtai,aasmdata,aasmcpu,defutil,
  72. procinfo,cgbase,pass_2,parabase,
  73. fmodule,
  74. cpubase,ncon,
  75. tgobj,paramgr,
  76. cgutils,cgobj,hlcgobj,nutils
  77. ;
  78. {*****************************************************************************
  79. Second_While_RepeatN
  80. *****************************************************************************}
  81. procedure tcgwhilerepeatnode.sync_regvars(checkusedregvars: boolean);
  82. begin
  83. if (cs_opt_regvar in current_settings.optimizerswitches) and
  84. not(pi_has_label in current_procinfo.flags) then
  85. begin
  86. if checkusedregvars then
  87. begin
  88. usedregvars.intregvars.init;
  89. usedregvars.addrregvars.init;
  90. usedregvars.fpuregvars.init;
  91. usedregvars.mmregvars.init;
  92. { we have to synchronise both the regvars used in the loop }
  93. { and the ones in the while/until condition }
  94. get_used_regvars(self,usedregvars);
  95. gen_sync_regvars(current_asmdata.CurrAsmList,usedregvars);
  96. end
  97. else
  98. begin
  99. gen_sync_regvars(current_asmdata.CurrAsmList,usedregvars);
  100. usedregvars.intregvars.done;
  101. usedregvars.addrregvars.done;
  102. usedregvars.fpuregvars.done;
  103. usedregvars.mmregvars.done;
  104. end;
  105. end;
  106. end;
  107. procedure tcgwhilerepeatnode.pass_generate_code;
  108. var
  109. lcont,lbreak,lloop,
  110. oldclabel,oldblabel : tasmlabel;
  111. truelabel,falselabel : tasmlabel;
  112. oldflowcontrol : tflowcontrol;
  113. oldexecutionweight : longint;
  114. begin
  115. location_reset(location,LOC_VOID,OS_NO);
  116. current_asmdata.getjumplabel(lloop);
  117. current_asmdata.getjumplabel(lcont);
  118. current_asmdata.getjumplabel(lbreak);
  119. { arrange continue and breaklabels: }
  120. oldflowcontrol:=flowcontrol;
  121. oldclabel:=current_procinfo.CurrContinueLabel;
  122. oldblabel:=current_procinfo.CurrBreakLabel;
  123. include(flowcontrol,fc_inflowcontrol);
  124. exclude(flowcontrol,fc_unwind_loop);
  125. sync_regvars(true);
  126. {$ifdef OLDREGVARS}
  127. load_all_regvars(current_asmdata.CurrAsmList);
  128. {$endif OLDREGVARS}
  129. { handling code at the end as it is much more efficient, and makes
  130. while equal to repeat loop, only the end true/false is swapped (PFV) }
  131. if lnf_testatbegin in loopflags then
  132. hlcg.a_jmp_always(current_asmdata.CurrAsmList,lcont);
  133. if not(cs_opt_size in current_settings.optimizerswitches) then
  134. { align loop target }
  135. current_asmdata.CurrAsmList.concat(Tai_align.Create(current_settings.alignment.loopalign));
  136. hlcg.a_label(current_asmdata.CurrAsmList,lloop);
  137. current_procinfo.CurrContinueLabel:=lcont;
  138. current_procinfo.CurrBreakLabel:=lbreak;
  139. if assigned(right) then
  140. begin
  141. { calc register weight }
  142. oldexecutionweight:=cg.executionweight;
  143. cg.executionweight:=cg.executionweight*8;
  144. secondpass(right);
  145. cg.executionweight:=oldexecutionweight;
  146. end;
  147. {$ifdef OLDREGVARS}
  148. load_all_regvars(current_asmdata.CurrAsmList);
  149. {$endif OLDREGVARS}
  150. hlcg.a_label(current_asmdata.CurrAsmList,lcont);
  151. if lnf_checknegate in loopflags then
  152. begin
  153. truelabel:=lbreak;
  154. falselabel:=lloop;
  155. end
  156. else
  157. begin
  158. truelabel:=lloop;
  159. falselabel:=lbreak;
  160. end;
  161. secondpass(left);
  162. hlcg.maketojumpboollabels(current_asmdata.CurrAsmList,left,truelabel,falselabel);
  163. hlcg.a_label(current_asmdata.CurrAsmList,lbreak);
  164. sync_regvars(false);
  165. current_procinfo.CurrContinueLabel:=oldclabel;
  166. current_procinfo.CurrBreakLabel:=oldblabel;
  167. { a break/continue in a while/repeat block can't be seen outside }
  168. flowcontrol:=oldflowcontrol+(flowcontrol-[fc_break,fc_continue,fc_inflowcontrol]);
  169. end;
  170. {*****************************************************************************
  171. tcgIFNODE
  172. *****************************************************************************}
  173. procedure tcgifnode.pass_generate_code;
  174. var
  175. hl : tasmlabel;
  176. oldflowcontrol: tflowcontrol;
  177. oldexecutionweight : longint;
  178. (*
  179. org_regvar_loaded_other,
  180. then_regvar_loaded_other,
  181. else_regvar_loaded_other : regvarother_booleanarray;
  182. org_regvar_loaded_int,
  183. then_regvar_loaded_int,
  184. else_regvar_loaded_int : Tsuperregisterset;
  185. org_list,
  186. then_list,
  187. else_list : TAsmList;
  188. *)
  189. begin
  190. location_reset(location,LOC_VOID,OS_NO);
  191. hl:=nil;
  192. oldflowcontrol := flowcontrol;
  193. include(flowcontrol,fc_inflowcontrol);
  194. secondpass(left);
  195. (*
  196. { save regvars loaded in the beginning so that we can restore them }
  197. { when processing the else-block }
  198. if cs_opt_regvar in current_settings.optimizerswitches then
  199. begin
  200. org_list := current_asmdata.CurrAsmList;
  201. current_asmdata.CurrAsmList := TAsmList.create;
  202. end;
  203. *)
  204. hlcg.maketojumpbool(current_asmdata.CurrAsmList,left);
  205. (*
  206. if cs_opt_regvar in current_settings.optimizerswitches then
  207. begin
  208. org_regvar_loaded_int := rg.regvar_loaded_int;
  209. org_regvar_loaded_other := rg.regvar_loaded_other;
  210. end;
  211. *)
  212. { determines registers weigths }
  213. oldexecutionweight:=cg.executionweight;
  214. cg.executionweight:=cg.executionweight div 2;
  215. if cg.executionweight<1 then
  216. cg.executionweight:=1;
  217. if assigned(right) then
  218. begin
  219. hlcg.a_label(current_asmdata.CurrAsmList,left.location.truelabel);
  220. secondpass(right);
  221. end;
  222. { save current asmlist (previous instructions + then-block) and }
  223. { loaded regvar state and create new clean ones }
  224. {
  225. if cs_opt_regvar in current_settings.optimizerswitches then
  226. begin
  227. then_regvar_loaded_int := rg.regvar_loaded_int;
  228. then_regvar_loaded_other := rg.regvar_loaded_other;
  229. rg.regvar_loaded_int := org_regvar_loaded_int;
  230. rg.regvar_loaded_other := org_regvar_loaded_other;
  231. then_list := current_asmdata.CurrAsmList;
  232. current_asmdata.CurrAsmList := TAsmList.create;
  233. end;
  234. }
  235. if assigned(t1) then
  236. begin
  237. if assigned(right) then
  238. begin
  239. current_asmdata.getjumplabel(hl);
  240. { do go back to if line !! }
  241. (*
  242. if not(cs_opt_regvar in current_settings.optimizerswitches) then
  243. *)
  244. current_filepos:=current_asmdata.CurrAsmList.getlasttaifilepos^
  245. (*
  246. else
  247. current_filepos:=then_list.getlasttaifilepos^
  248. *)
  249. ;
  250. hlcg.a_jmp_always(current_asmdata.CurrAsmList,hl);
  251. end;
  252. hlcg.a_label(current_asmdata.CurrAsmList,left.location.falselabel);
  253. secondpass(t1);
  254. (*
  255. { save current asmlist (previous instructions + else-block) }
  256. { and loaded regvar state and create a new clean list }
  257. if cs_opt_regvar in current_settings.optimizerswitches then
  258. begin
  259. { else_regvar_loaded_int := rg.regvar_loaded_int;
  260. else_regvar_loaded_other := rg.regvar_loaded_other;}
  261. else_list := current_asmdata.CurrAsmList;
  262. current_asmdata.CurrAsmList := TAsmList.create;
  263. end;
  264. *)
  265. if assigned(right) then
  266. hlcg.a_label(current_asmdata.CurrAsmList,hl);
  267. end
  268. else
  269. begin
  270. (*
  271. if cs_opt_regvar in current_settings.optimizerswitches then
  272. begin
  273. { else_regvar_loaded_int := rg.regvar_loaded_int;
  274. else_regvar_loaded_other := rg.regvar_loaded_other;}
  275. else_list := current_asmdata.CurrAsmList;
  276. current_asmdata.CurrAsmList := TAsmList.create;
  277. end;
  278. *)
  279. hlcg.a_label(current_asmdata.CurrAsmList,left.location.falselabel);
  280. end;
  281. if not(assigned(right)) then
  282. begin
  283. hlcg.a_label(current_asmdata.CurrAsmList,left.location.truelabel);
  284. end;
  285. (*
  286. if cs_opt_regvar in current_settings.optimizerswitches then
  287. begin
  288. { add loads of regvars at the end of the then- and else-blocks }
  289. { so that at the end of both blocks the same regvars are loaded }
  290. { no else block? }
  291. if not assigned(t1) then
  292. begin
  293. sync_regvars_int(org_list,then_list,org_regvar_loaded_int,then_regvar_loaded_int);
  294. sync_regvars_other(org_list,then_list,org_regvar_loaded_other,then_regvar_loaded_other);
  295. end
  296. { no then block? }
  297. else if not assigned(right) then
  298. begin
  299. sync_regvars_int(org_list,else_list,org_regvar_loaded_int,else_regvar_loaded_int);
  300. sync_regvars_other(org_list,else_list,org_regvar_loaded_other,else_regvar_loaded_other);
  301. end
  302. { both else and then blocks }
  303. else
  304. begin
  305. sync_regvars_int(then_list,else_list,then_regvar_loaded_int,else_regvar_loaded_int);
  306. sync_regvars_other(then_list,else_list,then_regvar_loaded_other,else_regvar_loaded_other);
  307. end;
  308. { add all lists together }
  309. org_list.concatlist(then_list);
  310. then_list.free;
  311. org_list.concatlist(else_list);
  312. else_list.free;
  313. org_list.concatlist(current_asmdata.CurrAsmList);
  314. current_asmdata.CurrAsmList.free;
  315. current_asmdata.CurrAsmList := org_list;
  316. end;
  317. *)
  318. cg.executionweight:=oldexecutionweight;
  319. flowcontrol := oldflowcontrol + (flowcontrol - [fc_inflowcontrol]);
  320. end;
  321. {*****************************************************************************
  322. SecondFor
  323. *****************************************************************************}
  324. procedure tcgfornode.sync_regvars(checkusedregvars: boolean);
  325. begin
  326. if (cs_opt_regvar in current_settings.optimizerswitches) and
  327. not(pi_has_label in current_procinfo.flags) then
  328. begin
  329. if checkusedregvars then
  330. begin
  331. usedregvars.intregvars.init;
  332. usedregvars.addrregvars.init;
  333. usedregvars.fpuregvars.init;
  334. usedregvars.mmregvars.init;
  335. { We have to synchronise the loop variable and loop body. }
  336. { The loop end is not necessary, unless it's a register }
  337. { variable. The start value also doesn't matter. }
  338. { loop var }
  339. get_used_regvars(left,usedregvars);
  340. { loop body }
  341. get_used_regvars(t2,usedregvars);
  342. { end value can't be a regvar, but may be a temp in register }
  343. get_used_regvars(t1,usedregvars);
  344. gen_sync_regvars(current_asmdata.CurrAsmList,usedregvars);
  345. end
  346. else
  347. begin
  348. gen_sync_regvars(current_asmdata.CurrAsmList,usedregvars);
  349. usedregvars.intregvars.done;
  350. usedregvars.addrregvars.done;
  351. usedregvars.fpuregvars.done;
  352. usedregvars.mmregvars.done;
  353. end;
  354. end;
  355. end;
  356. procedure tcgfornode.pass_generate_code;
  357. var
  358. l3,oldclabel,oldblabel : tasmlabel;
  359. temptovalue : boolean;
  360. hop : topcg;
  361. hcond : topcmp;
  362. opsize : tcgsize;
  363. count_var_is_signed,do_loopvar_at_end : boolean;
  364. cmp_const:Tconstexprint;
  365. oldflowcontrol : tflowcontrol;
  366. oldexecutionweight : longint;
  367. begin
  368. location_reset(location,LOC_VOID,OS_NO);
  369. oldclabel:=current_procinfo.CurrContinueLabel;
  370. oldblabel:=current_procinfo.CurrBreakLabel;
  371. current_asmdata.getjumplabel(current_procinfo.CurrContinueLabel);
  372. current_asmdata.getjumplabel(current_procinfo.CurrBreakLabel);
  373. current_asmdata.getjumplabel(l3);
  374. { only calculate reference }
  375. opsize := def_cgsize(left.resultdef);
  376. count_var_is_signed:=is_signed(left.resultdef);
  377. { first set the to value
  378. because the count var can be in the expression ! }
  379. do_loopvar_at_end:=(lnf_dont_mind_loopvar_on_exit in loopflags)
  380. { if the loop is unrolled and there is a jump into the loop,
  381. then we can't do the trick with incrementing the loop var only at the
  382. end
  383. }
  384. and not(assigned(entrylabel));
  385. secondpass(t1);
  386. if t1.location.loc in [LOC_FLAGS,LOC_JUMP] then
  387. hlcg.location_force_reg(current_asmdata.CurrAsmList,t1.location,t1.resultdef,t1.resultdef,false);
  388. { calculate pointer value and check if changeable and if so }
  389. { load into temporary variable }
  390. if t1.nodetype<>ordconstn then
  391. begin
  392. do_loopvar_at_end:=false;
  393. temptovalue:=true;
  394. end
  395. else
  396. temptovalue:=false;
  397. { load loopvar, prefer loopvar being a register variable }
  398. oldexecutionweight:=cg.executionweight;
  399. inc(cg.executionweight,8);
  400. secondpass(left);
  401. cg.executionweight:=oldexecutionweight;
  402. { load from value }
  403. secondpass(right);
  404. if right.location.loc in [LOC_FLAGS,LOC_JUMP] then
  405. hlcg.location_force_reg(current_asmdata.CurrAsmList,right.location,right.resultdef,right.resultdef,false);
  406. hlcg.maybe_change_load_node_reg(current_asmdata.CurrAsmList,left,false);
  407. oldflowcontrol:=flowcontrol;
  408. include(flowcontrol,fc_inflowcontrol);
  409. exclude(flowcontrol,fc_unwind_loop);
  410. { produce start assignment }
  411. case left.location.loc of
  412. LOC_REFERENCE,
  413. LOC_CREFERENCE :
  414. hlcg.a_load_loc_ref(current_asmdata.CurrAsmList,right.resultdef,left.resultdef,right.location,left.location.reference);
  415. LOC_REGISTER,
  416. LOC_CREGISTER:
  417. hlcg.a_load_loc_reg(current_asmdata.CurrAsmList,right.resultdef,left.resultdef,right.location,left.location.register);
  418. LOC_SUBSETREG,
  419. LOC_CSUBSETREG :
  420. hlcg.a_load_loc_subsetreg(current_asmdata.CurrAsmList,right.resultdef,left.resultdef,right.location,left.location.sreg);
  421. else
  422. internalerror(200501311);
  423. end;
  424. if lnf_backward in loopflags then
  425. if count_var_is_signed then
  426. hcond:=OC_LT
  427. else
  428. hcond:=OC_B
  429. else
  430. if count_var_is_signed then
  431. hcond:=OC_GT
  432. else
  433. hcond:=OC_A;
  434. sync_regvars(true);
  435. {$ifdef OLDREGVARS}
  436. load_all_regvars(current_asmdata.CurrAsmList);
  437. {$endif OLDREGVARS}
  438. if temptovalue then
  439. begin
  440. case t1.location.loc of
  441. LOC_REGISTER,LOC_CREGISTER:
  442. hlcg.a_cmp_reg_loc_label(current_asmdata.CurrAsmList,left.resultdef,hcond,
  443. t1.location.register,left.location,current_procinfo.CurrBreakLabel);
  444. LOC_REFERENCE,LOC_CREFERENCE:
  445. hlcg.a_cmp_ref_loc_label(current_asmdata.CurrAsmList,left.resultdef,hcond,
  446. t1.location.reference,left.location,current_procinfo.CurrBreakLabel);
  447. else
  448. InternalError(2013051601);
  449. end;
  450. end
  451. else
  452. begin
  453. if lnf_testatbegin in loopflags then
  454. begin
  455. hlcg.a_cmp_const_loc_label(current_asmdata.CurrAsmList,left.resultdef,hcond,
  456. tordconstnode(t1).value.svalue,
  457. left.location,current_procinfo.CurrBreakLabel);
  458. end;
  459. end;
  460. {If the loopvar doesn't mind on exit, we avoid this ugly
  461. dec instruction and do the loopvar inc/dec after the loop
  462. body.}
  463. if not do_loopvar_at_end then
  464. begin
  465. if lnf_backward in loopflags then
  466. hop:=OP_ADD
  467. else
  468. hop:=OP_SUB;
  469. hlcg.a_op_const_loc(current_asmdata.CurrAsmList,hop,left.resultdef,1,left.location);
  470. end;
  471. if assigned(entrylabel) then
  472. hlcg.a_jmp_always(current_asmdata.CurrAsmList,tcglabelnode(entrylabel).getasmlabel);
  473. { align loop target }
  474. if not(cs_opt_size in current_settings.optimizerswitches) then
  475. current_asmdata.CurrAsmList.concat(Tai_align.Create(current_settings.alignment.loopalign));
  476. hlcg.a_label(current_asmdata.CurrAsmList,l3);
  477. {If the loopvar doesn't mind on exit, we avoid the loopvar inc/dec
  478. after the loop body instead of here.}
  479. if not do_loopvar_at_end then
  480. begin
  481. { according to count direction DEC or INC... }
  482. if lnf_backward in loopflags then
  483. hop:=OP_SUB
  484. else
  485. hop:=OP_ADD;
  486. hlcg.a_op_const_loc(current_asmdata.CurrAsmList,hop,left.resultdef,1,left.location);
  487. end;
  488. if assigned(t2) then
  489. begin
  490. { Calc register weight }
  491. oldexecutionweight:=cg.executionweight;
  492. cg.executionweight:=cg.executionweight*8;
  493. secondpass(t2);
  494. cg.executionweight:=oldexecutionweight;
  495. {$ifdef OLDREGVARS}
  496. load_all_regvars(current_asmdata.CurrAsmList);
  497. {$endif OLDREGVARS}
  498. end;
  499. {If the loopvar doesn't mind on exit, we do the loopvar inc/dec
  500. after the loop body instead of here.}
  501. if do_loopvar_at_end then
  502. begin
  503. { according to count direction DEC or INC... }
  504. if lnf_backward in loopflags then
  505. hop:=OP_SUB
  506. else
  507. hop:=OP_ADD;
  508. hlcg.a_op_const_loc(current_asmdata.CurrAsmList,hop,left.resultdef,1,left.location);
  509. end;
  510. hlcg.a_label(current_asmdata.CurrAsmList,current_procinfo.CurrContinueLabel);
  511. if do_loopvar_at_end then
  512. if lnf_backward in loopflags then
  513. if count_var_is_signed then
  514. hcond:=OC_GTE
  515. else
  516. hcond:=OC_AE
  517. else
  518. if count_var_is_signed then
  519. hcond:=OC_LTE
  520. else
  521. hcond:=OC_BE
  522. else
  523. if lnf_backward in loopflags then
  524. if count_var_is_signed then
  525. hcond:=OC_GT
  526. else
  527. hcond:=OC_A
  528. else
  529. if count_var_is_signed then
  530. hcond:=OC_LT
  531. else
  532. hcond:=OC_B;
  533. {$ifdef OLDREGVARS}
  534. load_all_regvars(current_asmdata.CurrAsmList);
  535. {$endif OLDREGVARS}
  536. { produce comparison and the corresponding }
  537. { jump }
  538. if temptovalue then
  539. begin
  540. case t1.location.loc of
  541. LOC_REGISTER,LOC_CREGISTER:
  542. hlcg.a_cmp_reg_loc_label(current_asmdata.CurrAsmList,left.resultdef,hcond,t1.location.register,
  543. left.location,l3);
  544. LOC_REFERENCE,LOC_CREFERENCE:
  545. hlcg.a_cmp_ref_loc_label(current_asmdata.CurrAsmList,left.resultdef,hcond,t1.location.reference,
  546. left.location,l3);
  547. else
  548. InternalError(2013051602);
  549. end;
  550. end
  551. else
  552. begin
  553. cmp_const:=Tordconstnode(t1).value;
  554. if do_loopvar_at_end then
  555. begin
  556. {Watch out for wrap around 255 -> 0.}
  557. {Ugly: This code is way to long... Use tables?}
  558. case opsize of
  559. OS_8:
  560. begin
  561. if lnf_backward in loopflags then
  562. begin
  563. if byte(cmp_const.svalue)=low(byte) then
  564. begin
  565. hcond:=OC_NE;
  566. cmp_const:=high(byte);
  567. end
  568. end
  569. else
  570. begin
  571. if byte(cmp_const.svalue)=high(byte) then
  572. begin
  573. hcond:=OC_NE;
  574. cmp_const:=low(byte);
  575. end
  576. end
  577. end;
  578. OS_16:
  579. begin
  580. if lnf_backward in loopflags then
  581. begin
  582. if word(cmp_const.svalue)=high(word) then
  583. begin
  584. hcond:=OC_NE;
  585. cmp_const:=low(word);
  586. end
  587. end
  588. else
  589. begin
  590. if word(cmp_const.svalue)=low(word) then
  591. begin
  592. hcond:=OC_NE;
  593. cmp_const:=high(word);
  594. end
  595. end
  596. end;
  597. OS_32:
  598. begin
  599. if lnf_backward in loopflags then
  600. begin
  601. if cardinal(cmp_const.svalue)=high(cardinal) then
  602. begin
  603. hcond:=OC_NE;
  604. cmp_const:=low(cardinal);
  605. end
  606. end
  607. else
  608. begin
  609. if cardinal(cmp_const.svalue)=low(cardinal) then
  610. begin
  611. hcond:=OC_NE;
  612. cmp_const:=high(cardinal);
  613. end
  614. end
  615. end;
  616. OS_64:
  617. begin
  618. if lnf_backward in loopflags then
  619. begin
  620. if qword(cmp_const.uvalue)=high(qword) then
  621. begin
  622. hcond:=OC_NE;
  623. cmp_const:=low(qword);
  624. end
  625. end
  626. else
  627. begin
  628. if qword(cmp_const.uvalue)=low(qword) then
  629. begin
  630. hcond:=OC_NE;
  631. cmp_const:=high(qword);
  632. end
  633. end
  634. end;
  635. OS_S8:
  636. begin
  637. if lnf_backward in loopflags then
  638. begin
  639. if shortint(cmp_const.svalue)=low(shortint) then
  640. begin
  641. hcond:=OC_NE;
  642. cmp_const:=high(shortint);
  643. end
  644. end
  645. else
  646. begin
  647. if shortint(cmp_const.svalue)=high(shortint) then
  648. begin
  649. hcond:=OC_NE;
  650. cmp_const:=int64(low(shortint));
  651. end
  652. end
  653. end;
  654. OS_S16:
  655. begin
  656. if lnf_backward in loopflags then
  657. begin
  658. if integer(cmp_const.svalue)=high(smallint) then
  659. begin
  660. hcond:=OC_NE;
  661. cmp_const:=int64(low(smallint));
  662. end
  663. end
  664. else
  665. begin
  666. if integer(cmp_const.svalue)=low(smallint) then
  667. begin
  668. hcond:=OC_NE;
  669. cmp_const:=int64(high(smallint));
  670. end
  671. end
  672. end;
  673. OS_S32:
  674. begin
  675. if lnf_backward in loopflags then
  676. begin
  677. if longint(cmp_const.svalue)=high(longint) then
  678. begin
  679. hcond:=OC_NE;
  680. cmp_const:=int64(low(longint));
  681. end
  682. end
  683. else
  684. begin
  685. if longint(cmp_const.svalue)=low(longint) then
  686. begin
  687. hcond:=OC_NE;
  688. cmp_const:=int64(high(longint));
  689. end
  690. end
  691. end;
  692. OS_S64:
  693. begin
  694. if lnf_backward in loopflags then
  695. begin
  696. if int64(cmp_const.svalue)=high(int64) then
  697. begin
  698. hcond:=OC_NE;
  699. cmp_const:=low(int64);
  700. end
  701. end
  702. else
  703. begin
  704. if int64(cmp_const.svalue)=low(int64) then
  705. begin
  706. hcond:=OC_NE;
  707. cmp_const:=high(int64);
  708. end
  709. end
  710. end;
  711. else
  712. internalerror(200201021);
  713. end;
  714. end;
  715. hlcg.a_cmp_const_loc_label(current_asmdata.CurrAsmList,left.resultdef,hcond,
  716. tcgint(cmp_const.svalue),left.location,l3);
  717. end;
  718. { this is the break label: }
  719. hlcg.a_label(current_asmdata.CurrAsmList,current_procinfo.CurrBreakLabel);
  720. sync_regvars(false);
  721. current_procinfo.CurrContinueLabel:=oldclabel;
  722. current_procinfo.CurrBreakLabel:=oldblabel;
  723. { a break/continue in a while/repeat block can't be seen outside }
  724. flowcontrol:=oldflowcontrol+(flowcontrol-[fc_break,fc_continue,fc_inflowcontrol]);
  725. end;
  726. {*****************************************************************************
  727. SecondExitN
  728. *****************************************************************************}
  729. procedure tcgexitnode.pass_generate_code;
  730. begin
  731. location_reset(location,LOC_VOID,OS_NO);
  732. include(flowcontrol,fc_exit);
  733. if assigned(left) then
  734. secondpass(left);
  735. if (fc_unwind_exit in flowcontrol) then
  736. hlcg.g_local_unwind(current_asmdata.CurrAsmList,current_procinfo.CurrExitLabel)
  737. else
  738. hlcg.a_jmp_always(current_asmdata.CurrAsmList,current_procinfo.CurrExitLabel);
  739. end;
  740. {*****************************************************************************
  741. SecondBreakN
  742. *****************************************************************************}
  743. procedure tcgbreaknode.pass_generate_code;
  744. begin
  745. location_reset(location,LOC_VOID,OS_NO);
  746. include(flowcontrol,fc_break);
  747. if current_procinfo.CurrBreakLabel<>nil then
  748. begin
  749. {$ifdef OLDREGVARS}
  750. load_all_regvars(current_asmdata.CurrAsmList);
  751. {$endif OLDREGVARS}
  752. if (fc_unwind_loop in flowcontrol) then
  753. hlcg.g_local_unwind(current_asmdata.CurrAsmList,current_procinfo.CurrBreakLabel)
  754. else
  755. hlcg.a_jmp_always(current_asmdata.CurrAsmList,current_procinfo.CurrBreakLabel)
  756. end
  757. else
  758. CGMessage(cg_e_break_not_allowed);
  759. end;
  760. {*****************************************************************************
  761. SecondContinueN
  762. *****************************************************************************}
  763. procedure tcgcontinuenode.pass_generate_code;
  764. begin
  765. location_reset(location,LOC_VOID,OS_NO);
  766. include(flowcontrol,fc_continue);
  767. if current_procinfo.CurrContinueLabel<>nil then
  768. begin
  769. {$ifdef OLDREGVARS}
  770. load_all_regvars(current_asmdata.CurrAsmList);
  771. {$endif OLDREGVARS}
  772. if (fc_unwind_loop in flowcontrol) then
  773. hlcg.g_local_unwind(current_asmdata.CurrAsmList,current_procinfo.CurrContinueLabel)
  774. else
  775. hlcg.a_jmp_always(current_asmdata.CurrAsmList,current_procinfo.CurrContinueLabel)
  776. end
  777. else
  778. CGMessage(cg_e_continue_not_allowed);
  779. end;
  780. {*****************************************************************************
  781. SecondGoto
  782. *****************************************************************************}
  783. procedure tcggotonode.pass_generate_code;
  784. begin
  785. location_reset(location,LOC_VOID,OS_NO);
  786. include(flowcontrol,fc_gotolabel);
  787. {$ifdef OLDREGVARS}
  788. load_all_regvars(current_asmdata.CurrAsmList);
  789. {$endif OLDREGVARS}
  790. hlcg.a_jmp_always(current_asmdata.CurrAsmList,tcglabelnode(labelnode).getasmlabel)
  791. end;
  792. {*****************************************************************************
  793. SecondLabel
  794. *****************************************************************************}
  795. function tcglabelnode.getasmlabel : tasmlabel;
  796. begin
  797. if not(assigned(asmlabel)) then
  798. { labsym is not set in inlined procedures, but since assembler }
  799. { routines can't be inlined, that shouldn't matter }
  800. if assigned(labsym) and
  801. labsym.nonlocal then
  802. current_asmdata.getglobaljumplabel(asmlabel)
  803. else
  804. current_asmdata.getjumplabel(asmlabel);
  805. result:=asmlabel
  806. end;
  807. procedure tcglabelnode.pass_generate_code;
  808. begin
  809. location_reset(location,LOC_VOID,OS_NO);
  810. include(flowcontrol,fc_gotolabel);
  811. {$ifdef OLDREGVARS}
  812. load_all_regvars(current_asmdata.CurrAsmList);
  813. {$endif OLDREGVARS}
  814. hlcg.a_label(current_asmdata.CurrAsmList,getasmlabel);
  815. { Write also extra label if this label was referenced from
  816. assembler block }
  817. if assigned(labsym) and
  818. assigned(labsym.asmblocklabel) then
  819. hlcg.a_label(current_asmdata.CurrAsmList,labsym.asmblocklabel);
  820. secondpass(left);
  821. end;
  822. {*****************************************************************************
  823. SecondTryExcept
  824. *****************************************************************************}
  825. var
  826. endexceptlabel : tasmlabel;
  827. { does the necessary things to clean up the object stack }
  828. { in the except block }
  829. procedure cleanupobjectstack;
  830. begin
  831. hlcg.g_call_system_proc(current_asmdata.CurrAsmList,'fpc_doneexception',[],nil);
  832. end;
  833. { generates code to be executed when another exeception is raised while
  834. control is inside except block }
  835. procedure handle_nested_exception(list:TAsmList;const t:texceptiontemps;entrylabel:TAsmLabel);
  836. var
  837. exitlabel: tasmlabel;
  838. begin
  839. { don't generate line info for internal cleanup }
  840. list.concat(tai_marker.create(mark_NoLineInfoStart));
  841. current_asmdata.getjumplabel(exitlabel);
  842. hlcg.a_label(list,entrylabel);
  843. free_exception(list,t,0,exitlabel,false);
  844. { we don't need to save/restore registers here because reraise never }
  845. { returns }
  846. hlcg.g_call_system_proc(list,'fpc_raise_nested',[],nil);
  847. hlcg.a_label(list,exitlabel);
  848. cleanupobjectstack;
  849. end;
  850. procedure tcgtryexceptnode.pass_generate_code;
  851. var
  852. exceptlabel,doexceptlabel,oldendexceptlabel,
  853. lastonlabel,
  854. exitexceptlabel,
  855. continueexceptlabel,
  856. breakexceptlabel,
  857. exittrylabel,
  858. continuetrylabel,
  859. breaktrylabel,
  860. doobjectdestroyandreraise,
  861. oldCurrExitLabel,
  862. oldContinueLabel,
  863. oldBreakLabel : tasmlabel;
  864. oldflowcontrol,tryflowcontrol,
  865. exceptflowcontrol : tflowcontrol;
  866. destroytemps,
  867. excepttemps : texceptiontemps;
  868. label
  869. errorexit;
  870. begin
  871. location_reset(location,LOC_VOID,OS_NO);
  872. exceptflowcontrol:=[];
  873. continuetrylabel:=nil;
  874. breaktrylabel:=nil;
  875. continueexceptlabel:=nil;
  876. breakexceptlabel:=nil;
  877. oldflowcontrol:=flowcontrol;
  878. flowcontrol:=[fc_inflowcontrol];
  879. { this can be called recursivly }
  880. oldBreakLabel:=nil;
  881. oldContinueLabel:=nil;
  882. oldendexceptlabel:=endexceptlabel;
  883. { save the old labels for control flow statements }
  884. oldCurrExitLabel:=current_procinfo.CurrExitLabel;
  885. if assigned(current_procinfo.CurrBreakLabel) then
  886. begin
  887. oldContinueLabel:=current_procinfo.CurrContinueLabel;
  888. oldBreakLabel:=current_procinfo.CurrBreakLabel;
  889. end;
  890. { get new labels for the control flow statements }
  891. current_asmdata.getjumplabel(exittrylabel);
  892. current_asmdata.getjumplabel(exitexceptlabel);
  893. if assigned(current_procinfo.CurrBreakLabel) then
  894. begin
  895. current_asmdata.getjumplabel(breaktrylabel);
  896. current_asmdata.getjumplabel(continuetrylabel);
  897. current_asmdata.getjumplabel(breakexceptlabel);
  898. current_asmdata.getjumplabel(continueexceptlabel);
  899. end;
  900. current_asmdata.getjumplabel(exceptlabel);
  901. current_asmdata.getjumplabel(doexceptlabel);
  902. current_asmdata.getjumplabel(endexceptlabel);
  903. current_asmdata.getjumplabel(lastonlabel);
  904. get_exception_temps(current_asmdata.CurrAsmList,excepttemps);
  905. new_exception(current_asmdata.CurrAsmList,excepttemps,exceptlabel);
  906. { try block }
  907. { set control flow labels for the try block }
  908. current_procinfo.CurrExitLabel:=exittrylabel;
  909. if assigned(oldBreakLabel) then
  910. begin
  911. current_procinfo.CurrContinueLabel:=continuetrylabel;
  912. current_procinfo.CurrBreakLabel:=breaktrylabel;
  913. end;
  914. flowcontrol:=[fc_inflowcontrol];
  915. secondpass(left);
  916. tryflowcontrol:=flowcontrol;
  917. if codegenerror then
  918. goto errorexit;
  919. { don't generate line info for internal cleanup }
  920. current_asmdata.CurrAsmList.concat(tai_marker.create(mark_NoLineInfoStart));
  921. hlcg.a_label(current_asmdata.CurrAsmList,exceptlabel);
  922. free_exception(current_asmdata.CurrAsmList, excepttemps, 0, endexceptlabel, false);
  923. hlcg.a_label(current_asmdata.CurrAsmList,doexceptlabel);
  924. { end cleanup }
  925. current_asmdata.CurrAsmList.concat(tai_marker.create(mark_NoLineInfoEnd));
  926. { set control flow labels for the except block }
  927. { and the on statements }
  928. current_procinfo.CurrExitLabel:=exitexceptlabel;
  929. if assigned(oldBreakLabel) then
  930. begin
  931. current_procinfo.CurrContinueLabel:=continueexceptlabel;
  932. current_procinfo.CurrBreakLabel:=breakexceptlabel;
  933. end;
  934. flowcontrol:=[fc_inflowcontrol];
  935. { on statements }
  936. if assigned(right) then
  937. secondpass(right);
  938. { don't generate line info for internal cleanup }
  939. current_asmdata.CurrAsmList.concat(tai_marker.create(mark_NoLineInfoStart));
  940. hlcg.a_label(current_asmdata.CurrAsmList,lastonlabel);
  941. { default handling except handling }
  942. if assigned(t1) then
  943. begin
  944. { FPC_CATCHES with 'default handler' flag (=-1) need no longer be called,
  945. it doesn't change any state and its return value is ignored (Sergei)
  946. }
  947. { the destruction of the exception object must be also }
  948. { guarded by an exception frame, but it can be omitted }
  949. { if there's no user code in 'except' block }
  950. if not (has_no_code(t1)) then
  951. begin
  952. current_asmdata.getjumplabel(doobjectdestroyandreraise);
  953. get_exception_temps(current_asmdata.CurrAsmList,destroytemps);
  954. new_exception(current_asmdata.CurrAsmList,destroytemps,doobjectdestroyandreraise);
  955. { except block needs line info }
  956. current_asmdata.CurrAsmList.concat(tai_marker.create(mark_NoLineInfoEnd));
  957. { here we don't have to reset flowcontrol }
  958. { the default and on flowcontrols are handled equal }
  959. secondpass(t1);
  960. exceptflowcontrol:=flowcontrol;
  961. handle_nested_exception(current_asmdata.CurrAsmList,destroytemps,doobjectdestroyandreraise);
  962. unget_exception_temps(current_asmdata.CurrAsmList,destroytemps);
  963. hlcg.a_jmp_always(current_asmdata.CurrAsmList,endexceptlabel);
  964. end
  965. else
  966. begin
  967. exceptflowcontrol:=flowcontrol;
  968. cleanupobjectstack;
  969. hlcg.a_jmp_always(current_asmdata.CurrAsmList,endexceptlabel);
  970. end;
  971. end
  972. else
  973. begin
  974. hlcg.g_call_system_proc(current_asmdata.CurrAsmList,'fpc_reraise',[],nil);
  975. exceptflowcontrol:=flowcontrol;
  976. end;
  977. if fc_exit in exceptflowcontrol then
  978. begin
  979. { do some magic for exit in the try block }
  980. hlcg.a_label(current_asmdata.CurrAsmList,exitexceptlabel);
  981. { we must also destroy the address frame which guards }
  982. { exception object }
  983. hlcg.g_call_system_proc(current_asmdata.CurrAsmList,'fpc_popaddrstack',[],nil);
  984. hlcg.g_exception_reason_discard(current_asmdata.CurrAsmList,osuinttype,excepttemps.reasonbuf);
  985. cleanupobjectstack;
  986. hlcg.a_jmp_always(current_asmdata.CurrAsmList,oldCurrExitLabel);
  987. end;
  988. if fc_break in exceptflowcontrol then
  989. begin
  990. hlcg.a_label(current_asmdata.CurrAsmList,breakexceptlabel);
  991. { we must also destroy the address frame which guards }
  992. { exception object }
  993. hlcg.g_call_system_proc(current_asmdata.CurrAsmList,'fpc_popaddrstack',[],nil);
  994. hlcg.g_exception_reason_discard(current_asmdata.CurrAsmList,osuinttype,excepttemps.reasonbuf);
  995. cleanupobjectstack;
  996. cg.a_jmp_always(current_asmdata.CurrAsmList,oldBreakLabel);
  997. end;
  998. if fc_continue in exceptflowcontrol then
  999. begin
  1000. hlcg.a_label(current_asmdata.CurrAsmList,continueexceptlabel);
  1001. { we must also destroy the address frame which guards }
  1002. { exception object }
  1003. hlcg.g_call_system_proc(current_asmdata.CurrAsmList,'fpc_popaddrstack',[],nil);
  1004. hlcg.g_exception_reason_discard(current_asmdata.CurrAsmList,osuinttype,excepttemps.reasonbuf);
  1005. cleanupobjectstack;
  1006. hlcg.a_jmp_always(current_asmdata.CurrAsmList,oldContinueLabel);
  1007. end;
  1008. if fc_exit in tryflowcontrol then
  1009. begin
  1010. { do some magic for exit in the try block }
  1011. hlcg.a_label(current_asmdata.CurrAsmList,exittrylabel);
  1012. hlcg.g_call_system_proc(current_asmdata.CurrAsmList,'fpc_popaddrstack',[],nil);
  1013. hlcg.g_exception_reason_discard(current_asmdata.CurrAsmList,osuinttype,excepttemps.reasonbuf);
  1014. hlcg.a_jmp_always(current_asmdata.CurrAsmList,oldCurrExitLabel);
  1015. end;
  1016. if fc_break in tryflowcontrol then
  1017. begin
  1018. hlcg.a_label(current_asmdata.CurrAsmList,breaktrylabel);
  1019. hlcg.g_call_system_proc(current_asmdata.CurrAsmList,'fpc_popaddrstack',[],nil);
  1020. hlcg.g_exception_reason_discard(current_asmdata.CurrAsmList,osuinttype,excepttemps.reasonbuf);
  1021. cg.a_jmp_always(current_asmdata.CurrAsmList,oldBreakLabel);
  1022. end;
  1023. if fc_continue in tryflowcontrol then
  1024. begin
  1025. hlcg.a_label(current_asmdata.CurrAsmList,continuetrylabel);
  1026. hlcg.g_call_system_proc(current_asmdata.CurrAsmList,'fpc_popaddrstack',[],nil);
  1027. hlcg.g_exception_reason_discard(current_asmdata.CurrAsmList,osuinttype,excepttemps.reasonbuf);
  1028. cg.a_jmp_always(current_asmdata.CurrAsmList,oldContinueLabel);
  1029. end;
  1030. unget_exception_temps(current_asmdata.CurrAsmList,excepttemps);
  1031. hlcg.a_label(current_asmdata.CurrAsmList,endexceptlabel);
  1032. { end cleanup }
  1033. current_asmdata.CurrAsmList.concat(tai_marker.create(mark_NoLineInfoEnd));
  1034. errorexit:
  1035. { restore all saved labels }
  1036. endexceptlabel:=oldendexceptlabel;
  1037. { restore the control flow labels }
  1038. current_procinfo.CurrExitLabel:=oldCurrExitLabel;
  1039. if assigned(oldBreakLabel) then
  1040. begin
  1041. current_procinfo.CurrContinueLabel:=oldContinueLabel;
  1042. current_procinfo.CurrBreakLabel:=oldBreakLabel;
  1043. end;
  1044. { return all used control flow statements }
  1045. flowcontrol:=oldflowcontrol+(exceptflowcontrol +
  1046. tryflowcontrol - [fc_inflowcontrol]);
  1047. end;
  1048. procedure tcgonnode.pass_generate_code;
  1049. var
  1050. nextonlabel,
  1051. exitonlabel,
  1052. continueonlabel,
  1053. breakonlabel,
  1054. oldCurrExitLabel,
  1055. oldContinueLabel,
  1056. doobjectdestroyandreraise,
  1057. oldBreakLabel : tasmlabel;
  1058. oldflowcontrol : tflowcontrol;
  1059. excepttemps : texceptiontemps;
  1060. href2: treference;
  1061. paraloc1 : tcgpara;
  1062. exceptvarsym : tlocalvarsym;
  1063. pd : tprocdef;
  1064. fpc_catches_res: TCGPara;
  1065. fpc_catches_resloc: tlocation;
  1066. otherunit,
  1067. indirect : boolean;
  1068. begin
  1069. paraloc1.init;
  1070. location_reset(location,LOC_VOID,OS_NO);
  1071. oldCurrExitLabel:=nil;
  1072. continueonlabel:=nil;
  1073. breakonlabel:=nil;
  1074. exitonlabel:=nil;
  1075. oldflowcontrol:=flowcontrol;
  1076. flowcontrol:=[fc_inflowcontrol];
  1077. current_asmdata.getjumplabel(nextonlabel);
  1078. otherunit:=findunitsymtable(excepttype.owner).moduleid<>findunitsymtable(current_procinfo.procdef.owner).moduleid;
  1079. indirect:=(tf_supports_packages in target_info.flags) and
  1080. (target_info.system in systems_indirect_var_imports) and
  1081. (cs_imported_data in current_settings.localswitches) and
  1082. otherunit;
  1083. { send the vmt parameter }
  1084. pd:=search_system_proc('fpc_catches');
  1085. reference_reset_symbol(href2,current_asmdata.RefAsmSymbol(excepttype.vmt_mangledname,AT_DATA,indirect),0,sizeof(pint));
  1086. if otherunit then
  1087. current_module.add_extern_asmsym(excepttype.vmt_mangledname,AB_EXTERNAL,AT_DATA);
  1088. paramanager.getintparaloc(current_asmdata.CurrAsmList,pd,1,paraloc1);
  1089. hlcg.a_loadaddr_ref_cgpara(current_asmdata.CurrAsmList,excepttype.vmt_def,href2,paraloc1);
  1090. paramanager.freecgpara(current_asmdata.CurrAsmList,paraloc1);
  1091. fpc_catches_res:=hlcg.g_call_system_proc(current_asmdata.CurrAsmList,pd,[@paraloc1],nil);
  1092. location_reset(fpc_catches_resloc,LOC_REGISTER,def_cgsize(fpc_catches_res.def));
  1093. fpc_catches_resloc.register:=hlcg.getaddressregister(current_asmdata.CurrAsmList,fpc_catches_res.def);
  1094. hlcg.gen_load_cgpara_loc(current_asmdata.CurrAsmList,fpc_catches_res.def,fpc_catches_res,fpc_catches_resloc,true);
  1095. { is it this catch? No. go to next onlabel }
  1096. hlcg.a_cmp_const_reg_label(current_asmdata.CurrAsmList,fpc_catches_res.def,OC_EQ,0,fpc_catches_resloc.register,nextonlabel);
  1097. { Retrieve exception variable }
  1098. if assigned(excepTSymtable) then
  1099. exceptvarsym:=tlocalvarsym(excepTSymtable.SymList[0])
  1100. else
  1101. internalerror(2011020401);
  1102. if assigned(exceptvarsym) then
  1103. begin
  1104. location_reset_ref(exceptvarsym.localloc,LOC_REFERENCE,def_cgsize(voidpointertype),voidpointertype.alignment);
  1105. tg.GetLocal(current_asmdata.CurrAsmList,exceptvarsym.vardef.size,exceptvarsym.vardef,exceptvarsym.localloc.reference);
  1106. hlcg.a_load_reg_ref(current_asmdata.CurrAsmList,fpc_catches_res.def,exceptvarsym.vardef,fpc_catches_resloc.register,exceptvarsym.localloc.reference);
  1107. end;
  1108. { in the case that another exception is risen
  1109. we've to destroy the old one }
  1110. current_asmdata.getjumplabel(doobjectdestroyandreraise);
  1111. { call setjmp, and jump to finally label on non-zero result }
  1112. get_exception_temps(current_asmdata.CurrAsmList,excepttemps);
  1113. new_exception(current_asmdata.CurrAsmList,excepttemps,doobjectdestroyandreraise);
  1114. oldBreakLabel:=nil;
  1115. oldContinueLabel:=nil;
  1116. if assigned(right) then
  1117. begin
  1118. oldCurrExitLabel:=current_procinfo.CurrExitLabel;
  1119. current_asmdata.getjumplabel(exitonlabel);
  1120. current_procinfo.CurrExitLabel:=exitonlabel;
  1121. if assigned(current_procinfo.CurrBreakLabel) then
  1122. begin
  1123. oldContinueLabel:=current_procinfo.CurrContinueLabel;
  1124. oldBreakLabel:=current_procinfo.CurrBreakLabel;
  1125. current_asmdata.getjumplabel(breakonlabel);
  1126. current_asmdata.getjumplabel(continueonlabel);
  1127. current_procinfo.CurrContinueLabel:=continueonlabel;
  1128. current_procinfo.CurrBreakLabel:=breakonlabel;
  1129. end;
  1130. secondpass(right);
  1131. end;
  1132. handle_nested_exception(current_asmdata.CurrAsmList,excepttemps,doobjectdestroyandreraise);
  1133. { clear some stuff }
  1134. if assigned(exceptvarsym) then
  1135. begin
  1136. tg.UngetLocal(current_asmdata.CurrAsmList,exceptvarsym.localloc.reference);
  1137. exceptvarsym.localloc.loc:=LOC_INVALID;
  1138. end;
  1139. cg.a_jmp_always(current_asmdata.CurrAsmList,endexceptlabel);
  1140. if assigned(right) then
  1141. begin
  1142. { special handling for control flow instructions }
  1143. if fc_exit in flowcontrol then
  1144. begin
  1145. { the address and object pop does secondtryexcept }
  1146. cg.a_label(current_asmdata.CurrAsmList,exitonlabel);
  1147. cg.a_jmp_always(current_asmdata.CurrAsmList,oldCurrExitLabel);
  1148. end;
  1149. if fc_break in flowcontrol then
  1150. begin
  1151. { the address and object pop does secondtryexcept }
  1152. cg.a_label(current_asmdata.CurrAsmList,breakonlabel);
  1153. cg.a_jmp_always(current_asmdata.CurrAsmList,oldBreakLabel);
  1154. end;
  1155. if fc_continue in flowcontrol then
  1156. begin
  1157. { the address and object pop does secondtryexcept }
  1158. cg.a_label(current_asmdata.CurrAsmList,continueonlabel);
  1159. cg.a_jmp_always(current_asmdata.CurrAsmList,oldContinueLabel);
  1160. end;
  1161. current_procinfo.CurrExitLabel:=oldCurrExitLabel;
  1162. if assigned(oldBreakLabel) then
  1163. begin
  1164. current_procinfo.CurrContinueLabel:=oldContinueLabel;
  1165. current_procinfo.CurrBreakLabel:=oldBreakLabel;
  1166. end;
  1167. end;
  1168. unget_exception_temps(current_asmdata.CurrAsmList,excepttemps);
  1169. cg.a_label(current_asmdata.CurrAsmList,nextonlabel);
  1170. flowcontrol:=oldflowcontrol+(flowcontrol-[fc_inflowcontrol]);
  1171. paraloc1.done;
  1172. current_asmdata.CurrAsmList.concat(tai_marker.create(mark_NoLineInfoEnd));
  1173. { next on node }
  1174. if assigned(left) then
  1175. secondpass(left);
  1176. end;
  1177. {*****************************************************************************
  1178. SecondTryFinally
  1179. *****************************************************************************}
  1180. procedure tcgtryfinallynode.handle_safecall_exception;
  1181. var
  1182. cgpara: tcgpara;
  1183. selfsym: tparavarsym;
  1184. pd: tprocdef;
  1185. begin
  1186. { call fpc_safecallhandler, passing self for methods of classes,
  1187. nil otherwise. }
  1188. pd:=search_system_proc('fpc_safecallhandler');
  1189. cgpara.init;
  1190. paramanager.getintparaloc(current_asmdata.CurrAsmList,pd,1,cgpara);
  1191. if is_class(current_procinfo.procdef.struct) then
  1192. begin
  1193. selfsym:=tparavarsym(current_procinfo.procdef.parast.Find('self'));
  1194. if (selfsym=nil) or (selfsym.typ<>paravarsym) then
  1195. InternalError(2011123101);
  1196. cg.a_load_loc_cgpara(current_asmdata.CurrAsmList,selfsym.localloc,cgpara);
  1197. end
  1198. else
  1199. cg.a_load_const_cgpara(current_asmdata.CurrAsmList,OS_ADDR,0,cgpara);
  1200. paramanager.freecgpara(current_asmdata.CurrAsmList,cgpara);
  1201. cgpara.done;
  1202. cg.g_call(current_asmdata.CurrAsmList,'FPC_SAFECALLHANDLER');
  1203. cg.a_load_reg_reg(current_asmdata.CurrAsmList,OS_INT,OS_INT,NR_FUNCTION_RESULT_REG, NR_FUNCTION_RETURN_REG);
  1204. end;
  1205. procedure tcgtryfinallynode.pass_generate_code;
  1206. var
  1207. finallylabel,
  1208. endfinallylabel,
  1209. exitfinallylabel,
  1210. continuefinallylabel,
  1211. breakfinallylabel,
  1212. oldCurrExitLabel,
  1213. oldContinueLabel,
  1214. oldBreakLabel : tasmlabel;
  1215. oldflowcontrol,tryflowcontrol : tflowcontrol;
  1216. excepttemps : texceptiontemps;
  1217. reasonreg : tregister;
  1218. begin
  1219. location_reset(location,LOC_VOID,OS_NO);
  1220. tryflowcontrol:=[];
  1221. oldBreakLabel:=nil;
  1222. oldContinueLabel:=nil;
  1223. continuefinallylabel:=nil;
  1224. breakfinallylabel:=nil;
  1225. { check if child nodes do a break/continue/exit }
  1226. oldflowcontrol:=flowcontrol;
  1227. flowcontrol:=[fc_inflowcontrol];
  1228. current_asmdata.getjumplabel(finallylabel);
  1229. current_asmdata.getjumplabel(endfinallylabel);
  1230. { the finally block must catch break, continue and exit }
  1231. { statements }
  1232. oldCurrExitLabel:=current_procinfo.CurrExitLabel;
  1233. if implicitframe then
  1234. exitfinallylabel:=finallylabel
  1235. else
  1236. current_asmdata.getjumplabel(exitfinallylabel);
  1237. current_procinfo.CurrExitLabel:=exitfinallylabel;
  1238. if assigned(current_procinfo.CurrBreakLabel) then
  1239. begin
  1240. oldContinueLabel:=current_procinfo.CurrContinueLabel;
  1241. oldBreakLabel:=current_procinfo.CurrBreakLabel;
  1242. if implicitframe then
  1243. begin
  1244. breakfinallylabel:=finallylabel;
  1245. continuefinallylabel:=finallylabel;
  1246. end
  1247. else
  1248. begin
  1249. current_asmdata.getjumplabel(breakfinallylabel);
  1250. current_asmdata.getjumplabel(continuefinallylabel);
  1251. end;
  1252. current_procinfo.CurrContinueLabel:=continuefinallylabel;
  1253. current_procinfo.CurrBreakLabel:=breakfinallylabel;
  1254. end;
  1255. { call setjmp, and jump to finally label on non-zero result }
  1256. get_exception_temps(current_asmdata.CurrAsmList,excepttemps);
  1257. new_exception(current_asmdata.CurrAsmList,excepttemps,finallylabel);
  1258. { try code }
  1259. if assigned(left) then
  1260. begin
  1261. secondpass(left);
  1262. tryflowcontrol:=flowcontrol;
  1263. if codegenerror then
  1264. exit;
  1265. end;
  1266. { don't generate line info for internal cleanup }
  1267. current_asmdata.CurrAsmList.concat(tai_marker.create(mark_NoLineInfoStart));
  1268. hlcg.a_label(current_asmdata.CurrAsmList,finallylabel);
  1269. { just free the frame information }
  1270. free_exception(current_asmdata.CurrAsmList,excepttemps,1,finallylabel,true);
  1271. { end cleanup }
  1272. current_asmdata.CurrAsmList.concat(tai_marker.create(mark_NoLineInfoEnd));
  1273. { finally code }
  1274. flowcontrol:=[fc_inflowcontrol];
  1275. secondpass(right);
  1276. { goto is allowed if it stays inside the finally block,
  1277. this is checked using the exception block number }
  1278. if (flowcontrol-[fc_gotolabel])<>[fc_inflowcontrol] then
  1279. CGMessage(cg_e_control_flow_outside_finally);
  1280. if codegenerror then
  1281. exit;
  1282. { don't generate line info for internal cleanup }
  1283. current_asmdata.CurrAsmList.concat(tai_marker.create(mark_NoLineInfoStart));
  1284. { the value should now be in the exception handler }
  1285. reasonreg:=hlcg.getintregister(current_asmdata.CurrAsmList,osuinttype);
  1286. hlcg.g_exception_reason_load(current_asmdata.CurrAsmList,osuinttype,osuinttype,excepttemps.reasonbuf,reasonreg);
  1287. if implicitframe then
  1288. begin
  1289. hlcg.a_cmp_const_reg_label(current_asmdata.CurrAsmList,osuinttype,OC_EQ,0,reasonreg,endfinallylabel);
  1290. { finally code only needed to be executed on exception }
  1291. flowcontrol:=[fc_inflowcontrol];
  1292. secondpass(t1);
  1293. if flowcontrol<>[fc_inflowcontrol] then
  1294. CGMessage(cg_e_control_flow_outside_finally);
  1295. if codegenerror then
  1296. exit;
  1297. if (tf_safecall_exceptions in target_info.flags) and
  1298. (current_procinfo.procdef.proccalloption=pocall_safecall) then
  1299. handle_safecall_exception
  1300. else
  1301. hlcg.g_call_system_proc(current_asmdata.CurrAsmList,'fpc_reraise',[],nil);
  1302. end
  1303. else
  1304. begin
  1305. hlcg.a_cmp_const_reg_label(current_asmdata.CurrAsmList,osuinttype,OC_EQ,0,reasonreg,endfinallylabel);
  1306. if fc_exit in tryflowcontrol then
  1307. hlcg.a_cmp_const_reg_label(current_asmdata.CurrAsmList,osuinttype,OC_EQ,2,reasonreg,oldCurrExitLabel);
  1308. if fc_break in tryflowcontrol then
  1309. hlcg.a_cmp_const_reg_label(current_asmdata.CurrAsmList,osuinttype,OC_EQ,3,reasonreg,oldBreakLabel);
  1310. if fc_continue in tryflowcontrol then
  1311. hlcg.a_cmp_const_reg_label(current_asmdata.CurrAsmList,osuinttype,OC_EQ,4,reasonreg,oldContinueLabel);
  1312. hlcg.g_call_system_proc(current_asmdata.CurrAsmList,'fpc_reraise',[],nil);
  1313. { do some magic for exit,break,continue in the try block }
  1314. if fc_exit in tryflowcontrol then
  1315. begin
  1316. hlcg.a_label(current_asmdata.CurrAsmList,exitfinallylabel);
  1317. hlcg.g_exception_reason_discard(current_asmdata.CurrAsmList,osuinttype,excepttemps.reasonbuf);
  1318. hlcg.g_exception_reason_save_const(current_asmdata.CurrAsmList,osuinttype,2,excepttemps.reasonbuf);
  1319. hlcg.a_jmp_always(current_asmdata.CurrAsmList,finallylabel);
  1320. end;
  1321. if fc_break in tryflowcontrol then
  1322. begin
  1323. hlcg.a_label(current_asmdata.CurrAsmList,breakfinallylabel);
  1324. hlcg.g_exception_reason_discard(current_asmdata.CurrAsmList,osuinttype,excepttemps.reasonbuf);
  1325. hlcg.g_exception_reason_save_const(current_asmdata.CurrAsmList,osuinttype,3,excepttemps.reasonbuf);
  1326. hlcg.a_jmp_always(current_asmdata.CurrAsmList,finallylabel);
  1327. end;
  1328. if fc_continue in tryflowcontrol then
  1329. begin
  1330. hlcg.a_label(current_asmdata.CurrAsmList,continuefinallylabel);
  1331. hlcg.g_exception_reason_discard(current_asmdata.CurrAsmList,osuinttype,excepttemps.reasonbuf);
  1332. hlcg.g_exception_reason_save_const(current_asmdata.CurrAsmList,osuinttype,4,excepttemps.reasonbuf);
  1333. hlcg.a_jmp_always(current_asmdata.CurrAsmList,finallylabel);
  1334. end;
  1335. end;
  1336. unget_exception_temps(current_asmdata.CurrAsmList,excepttemps);
  1337. hlcg.a_label(current_asmdata.CurrAsmList,endfinallylabel);
  1338. { end cleanup }
  1339. current_asmdata.CurrAsmList.concat(tai_marker.create(mark_NoLineInfoEnd));
  1340. current_procinfo.CurrExitLabel:=oldCurrExitLabel;
  1341. if assigned(current_procinfo.CurrBreakLabel) then
  1342. begin
  1343. current_procinfo.CurrContinueLabel:=oldContinueLabel;
  1344. current_procinfo.CurrBreakLabel:=oldBreakLabel;
  1345. end;
  1346. flowcontrol:=oldflowcontrol+(tryflowcontrol-[fc_inflowcontrol]);
  1347. end;
  1348. begin
  1349. cwhilerepeatnode:=tcgwhilerepeatnode;
  1350. cifnode:=tcgifnode;
  1351. cfornode:=tcgfornode;
  1352. cexitnode:=tcgexitnode;
  1353. cbreaknode:=tcgbreaknode;
  1354. ccontinuenode:=tcgcontinuenode;
  1355. cgotonode:=tcggotonode;
  1356. clabelnode:=tcglabelnode;
  1357. craisenode:=tcgraisenode;
  1358. ctryexceptnode:=tcgtryexceptnode;
  1359. ctryfinallynode:=tcgtryfinallynode;
  1360. connode:=tcgonnode;
  1361. end.