cpupi.pas 45 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094
  1. {
  2. Copyright (c) 2002-2010 by Florian Klaempfl and Jonas Maebe
  3. This unit contains the CPU specific part of tprocinfo
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program; if not, write to the Free Software
  14. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  15. ****************************************************************************
  16. }
  17. unit cpupi;
  18. {$i fpcdefs.inc}
  19. interface
  20. uses
  21. cutils,globtype,aasmdata,aasmcpu,aasmtai,
  22. procinfo,cpubase,cpuinfo, symtype,aasmbase,cgbase,
  23. psub, cclasses;
  24. type
  25. { tcpuprocinfo }
  26. tcpuprocinfo=class(tcgprocinfo)
  27. private
  28. FFuncType: TWasmFuncType;
  29. FLocals: array of TWasmBasicType;
  30. FParametersCount: Integer;
  31. FFirstFreeLocal: Integer;
  32. FAllocatedLocals: array of TWasmBasicType;
  33. FGotoTargets: TFPHashObjectList;
  34. function ConvertBranchTargetNumbersToLabels(ai: tai; blockstack: twasmstruc_stack): TAsmMapFuncResult;
  35. function ConvertIfToBrIf(ai: tai; blockstack: twasmstruc_stack): TAsmMapFuncResult;
  36. function ConvertLoopToBr(ai: tai; blockstack: twasmstruc_stack): TAsmMapFuncResult;
  37. function StripBlockInstructions(ai: tai; blockstack: twasmstruc_stack): TAsmMapFuncResult;
  38. { used for allocating locals during the postprocess_code stage (i.e. after register allocation) }
  39. function AllocWasmLocal(wbt: TWasmBasicType): Integer;
  40. function GetLocalType(localidx: Integer): TWasmBasicType;
  41. public
  42. { label to the nearest local exception handler }
  43. CurrRaiseLabel : tasmlabel;
  44. constructor create(aparent: tprocinfo); override;
  45. destructor destroy; override;
  46. function calc_stackframe_size : longint;override;
  47. procedure setup_eh; override;
  48. procedure generate_exit_label(list: tasmlist); override;
  49. procedure postprocess_code; override;
  50. procedure set_first_temp_offset;override;
  51. procedure add_goto_target(l : tasmlabel);
  52. function is_goto_target(l : tasmsymbol): Boolean;
  53. end;
  54. implementation
  55. uses
  56. systems,verbose,globals,tgcpu,cgexcept,
  57. tgobj,paramgr,symconst,symdef,symtable,symcpu,cgutils,pass_2,parabase,
  58. fmodule,hlcgobj,hlcgcpu,defutil,itcpugas;
  59. {*****************************************************************************
  60. twasmexceptionstatehandler_noexceptions
  61. *****************************************************************************}
  62. type
  63. { twasmexceptionstatehandler_noexceptions }
  64. twasmexceptionstatehandler_noexceptions = class(tcgexceptionstatehandler)
  65. class procedure get_exception_temps(list:TAsmList;var t:texceptiontemps); override;
  66. class procedure unget_exception_temps(list:TAsmList;const t:texceptiontemps); override;
  67. class procedure new_exception(list:TAsmList;const t:texceptiontemps; const exceptframekind: texceptframekind; out exceptstate: texceptionstate); override;
  68. class procedure free_exception(list: TAsmList; const t: texceptiontemps; const s: texceptionstate; a: aint; endexceptlabel: tasmlabel; onlyfree:boolean); override;
  69. class procedure handle_nested_exception(list:TAsmList;var t:texceptiontemps;var entrystate: texceptionstate); override;
  70. end;
  71. class procedure twasmexceptionstatehandler_noexceptions.get_exception_temps(list:TAsmList;var t:texceptiontemps);
  72. begin
  73. if not assigned(exceptionreasontype) then
  74. exceptionreasontype:=search_system_proc('fpc_setjmp').returndef;
  75. reference_reset(t.envbuf,0,[]);
  76. reference_reset(t.jmpbuf,0,[]);
  77. tg.gethltemp(list,exceptionreasontype,exceptionreasontype.size,tt_persistent,t.reasonbuf);
  78. end;
  79. class procedure twasmexceptionstatehandler_noexceptions.unget_exception_temps(list:TAsmList;const t:texceptiontemps);
  80. begin
  81. tg.ungettemp(list,t.reasonbuf);
  82. end;
  83. class procedure twasmexceptionstatehandler_noexceptions.new_exception(list:TAsmList;const t:texceptiontemps; const exceptframekind: texceptframekind; out exceptstate: texceptionstate);
  84. begin
  85. exceptstate.exceptionlabel:=nil;
  86. exceptstate.oldflowcontrol:=flowcontrol;
  87. exceptstate.finallycodelabel:=nil;
  88. flowcontrol:=[fc_inflowcontrol,fc_catching_exceptions];
  89. end;
  90. class procedure twasmexceptionstatehandler_noexceptions.free_exception(list: TAsmList; const t: texceptiontemps; const s: texceptionstate; a: aint; endexceptlabel: tasmlabel; onlyfree:boolean);
  91. begin
  92. end;
  93. class procedure twasmexceptionstatehandler_noexceptions.handle_nested_exception(list:TAsmList;var t:texceptiontemps;var entrystate: texceptionstate);
  94. begin
  95. list.Concat(tai_comment.Create(strpnew('TODO: handle_nested_exception')));
  96. end;
  97. {*****************************************************************************
  98. twasmexceptionstatehandler_nativeexnrefexceptions
  99. *****************************************************************************}
  100. type
  101. { twasmexceptionstatehandler_nativeexnrefexceptions }
  102. twasmexceptionstatehandler_nativeexnrefexceptions = class(tcgexceptionstatehandler)
  103. class procedure new_exception(list:TAsmList;const t:texceptiontemps; const exceptframekind: texceptframekind; out exceptstate: texceptionstate); override;
  104. class procedure free_exception(list: TAsmList; const t: texceptiontemps; const s: texceptionstate; a: aint; endexceptlabel: tasmlabel; onlyfree:boolean); override;
  105. class procedure handle_nested_exception(list:TAsmList;var t:texceptiontemps;var entrystate: texceptionstate); override;
  106. { start of an "on" (catch) block }
  107. class procedure begin_catch(list: TAsmList; excepttype: tobjectdef; nextonlabel: tasmlabel; out exceptlocdef: tdef; out exceptlocreg: tregister); override;
  108. { end of an "on" (catch) block }
  109. class procedure end_catch(list: TAsmList); override;
  110. end;
  111. class procedure twasmexceptionstatehandler_nativeexnrefexceptions.new_exception(list:TAsmList;const t:texceptiontemps; const exceptframekind: texceptframekind; out exceptstate: texceptionstate);
  112. begin
  113. exceptstate.exceptionlabel:=nil;
  114. exceptstate.oldflowcontrol:=flowcontrol;
  115. exceptstate.finallycodelabel:=nil;
  116. flowcontrol:=[fc_inflowcontrol,fc_catching_exceptions];
  117. end;
  118. class procedure twasmexceptionstatehandler_nativeexnrefexceptions.free_exception(list: TAsmList; const t: texceptiontemps; const s: texceptionstate; a: aint; endexceptlabel: tasmlabel; onlyfree:boolean);
  119. begin
  120. end;
  121. class procedure twasmexceptionstatehandler_nativeexnrefexceptions.handle_nested_exception(list:TAsmList;var t:texceptiontemps;var entrystate: texceptionstate);
  122. begin
  123. Message1(parser_f_unsupported_feature,'nested exception');
  124. end;
  125. class procedure twasmexceptionstatehandler_nativeexnrefexceptions.begin_catch(list: TAsmList; excepttype: tobjectdef; nextonlabel: tasmlabel; out exceptlocdef: tdef; out exceptlocreg: tregister);
  126. var
  127. pd: tprocdef;
  128. href2: treference;
  129. fpc_catches_res,
  130. paraloc1: tcgpara;
  131. exceptloc: tlocation;
  132. indirect: boolean;
  133. otherunit: boolean;
  134. begin
  135. paraloc1.init;
  136. otherunit:=findunitsymtable(excepttype.owner).moduleid<>findunitsymtable(current_procinfo.procdef.owner).moduleid;
  137. indirect:=(tf_supports_packages in target_info.flags) and
  138. (target_info.system in systems_indirect_var_imports) and
  139. (cs_imported_data in current_settings.localswitches) and
  140. otherunit;
  141. { send the vmt parameter }
  142. pd:=search_system_proc('fpc_catches');
  143. reference_reset_symbol(href2, current_asmdata.RefAsmSymbol(excepttype.vmt_mangledname, AT_DATA, indirect), 0, sizeof(pint), []);
  144. if otherunit then
  145. current_module.add_extern_asmsym(excepttype.vmt_mangledname, AB_EXTERNAL, AT_DATA);
  146. paramanager.getcgtempparaloc(list, pd, 1, paraloc1);
  147. hlcg.a_loadaddr_ref_cgpara(list, excepttype.vmt_def, href2, paraloc1);
  148. paramanager.freecgpara(list, paraloc1);
  149. fpc_catches_res:=hlcg.g_call_system_proc(list, pd, [@paraloc1], nil);
  150. location_reset(exceptloc, LOC_REGISTER, def_cgsize(fpc_catches_res.def));
  151. exceptloc.register:=hlcg.getaddressregister(list, fpc_catches_res.def);
  152. hlcg.gen_load_cgpara_loc(list, fpc_catches_res.def, fpc_catches_res, exceptloc, true);
  153. { is it this catch? }
  154. thlcgwasm(hlcg).a_cmp_const_reg_stack(list, fpc_catches_res.def, OC_NE, 0, exceptloc.register);
  155. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_if));
  156. thlcgwasm(hlcg).decstack(current_asmdata.CurrAsmList,1);
  157. paraloc1.done;
  158. exceptlocdef:=fpc_catches_res.def;
  159. exceptlocreg:=exceptloc.register;
  160. end;
  161. class procedure twasmexceptionstatehandler_nativeexnrefexceptions.end_catch(list: TAsmList);
  162. begin
  163. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_end_if));
  164. end;
  165. {*****************************************************************************
  166. twasmexceptionstatehandler_nativelegacyexceptions
  167. *****************************************************************************}
  168. type
  169. { twasmexceptionstatehandler_nativelegacyexceptions }
  170. twasmexceptionstatehandler_nativelegacyexceptions = class(tcgexceptionstatehandler)
  171. class procedure new_exception(list:TAsmList;const t:texceptiontemps; const exceptframekind: texceptframekind; out exceptstate: texceptionstate); override;
  172. class procedure free_exception(list: TAsmList; const t: texceptiontemps; const s: texceptionstate; a: aint; endexceptlabel: tasmlabel; onlyfree:boolean); override;
  173. class procedure handle_nested_exception(list:TAsmList;var t:texceptiontemps;var entrystate: texceptionstate); override;
  174. { start of an "on" (catch) block }
  175. class procedure begin_catch(list: TAsmList; excepttype: tobjectdef; nextonlabel: tasmlabel; out exceptlocdef: tdef; out exceptlocreg: tregister); override;
  176. { end of an "on" (catch) block }
  177. class procedure end_catch(list: TAsmList); override;
  178. end;
  179. class procedure twasmexceptionstatehandler_nativelegacyexceptions.new_exception(list:TAsmList;const t:texceptiontemps; const exceptframekind: texceptframekind; out exceptstate: texceptionstate);
  180. begin
  181. exceptstate.exceptionlabel:=nil;
  182. exceptstate.oldflowcontrol:=flowcontrol;
  183. exceptstate.finallycodelabel:=nil;
  184. flowcontrol:=[fc_inflowcontrol,fc_catching_exceptions];
  185. end;
  186. class procedure twasmexceptionstatehandler_nativelegacyexceptions.free_exception(list: TAsmList; const t: texceptiontemps; const s: texceptionstate; a: aint; endexceptlabel: tasmlabel; onlyfree:boolean);
  187. begin
  188. end;
  189. class procedure twasmexceptionstatehandler_nativelegacyexceptions.handle_nested_exception(list:TAsmList;var t:texceptiontemps;var entrystate: texceptionstate);
  190. begin
  191. Message1(parser_f_unsupported_feature,'nested exception');
  192. end;
  193. class procedure twasmexceptionstatehandler_nativelegacyexceptions.begin_catch(list: TAsmList; excepttype: tobjectdef; nextonlabel: tasmlabel; out exceptlocdef: tdef; out exceptlocreg: tregister);
  194. var
  195. pd: tprocdef;
  196. href2: treference;
  197. fpc_catches_res,
  198. paraloc1: tcgpara;
  199. exceptloc: tlocation;
  200. indirect: boolean;
  201. otherunit: boolean;
  202. begin
  203. paraloc1.init;
  204. otherunit:=findunitsymtable(excepttype.owner).moduleid<>findunitsymtable(current_procinfo.procdef.owner).moduleid;
  205. indirect:=(tf_supports_packages in target_info.flags) and
  206. (target_info.system in systems_indirect_var_imports) and
  207. (cs_imported_data in current_settings.localswitches) and
  208. otherunit;
  209. { send the vmt parameter }
  210. pd:=search_system_proc('fpc_catches');
  211. reference_reset_symbol(href2, current_asmdata.RefAsmSymbol(excepttype.vmt_mangledname, AT_DATA, indirect), 0, sizeof(pint), []);
  212. if otherunit then
  213. current_module.add_extern_asmsym(excepttype.vmt_mangledname, AB_EXTERNAL, AT_DATA);
  214. paramanager.getcgtempparaloc(list, pd, 1, paraloc1);
  215. hlcg.a_loadaddr_ref_cgpara(list, excepttype.vmt_def, href2, paraloc1);
  216. paramanager.freecgpara(list, paraloc1);
  217. fpc_catches_res:=hlcg.g_call_system_proc(list, pd, [@paraloc1], nil);
  218. location_reset(exceptloc, LOC_REGISTER, def_cgsize(fpc_catches_res.def));
  219. exceptloc.register:=hlcg.getaddressregister(list, fpc_catches_res.def);
  220. hlcg.gen_load_cgpara_loc(list, fpc_catches_res.def, fpc_catches_res, exceptloc, true);
  221. { is it this catch? }
  222. thlcgwasm(hlcg).a_cmp_const_reg_stack(list, fpc_catches_res.def, OC_NE, 0, exceptloc.register);
  223. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_if));
  224. thlcgwasm(hlcg).decstack(current_asmdata.CurrAsmList,1);
  225. paraloc1.done;
  226. exceptlocdef:=fpc_catches_res.def;
  227. exceptlocreg:=exceptloc.register;
  228. end;
  229. class procedure twasmexceptionstatehandler_nativelegacyexceptions.end_catch(list: TAsmList);
  230. begin
  231. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_end_if));
  232. end;
  233. {*****************************************************************************
  234. twasmexceptionstatehandler_bfexceptions
  235. *****************************************************************************}
  236. type
  237. { twasmexceptionstatehandler_bfexceptions }
  238. twasmexceptionstatehandler_bfexceptions = class(tcgexceptionstatehandler)
  239. class procedure new_exception(list:TAsmList;const t:texceptiontemps; const exceptframekind: texceptframekind; out exceptstate: texceptionstate); override;
  240. class procedure free_exception(list: TAsmList; const t: texceptiontemps; const s: texceptionstate; a: aint; endexceptlabel: tasmlabel; onlyfree:boolean); override;
  241. class procedure handle_nested_exception(list:TAsmList;var t:texceptiontemps;var entrystate: texceptionstate); override;
  242. { start of an "on" (catch) block }
  243. class procedure begin_catch(list: TAsmList; excepttype: tobjectdef; nextonlabel: tasmlabel; out exceptlocdef: tdef; out exceptlocreg: tregister); override;
  244. { end of an "on" (catch) block }
  245. class procedure end_catch(list: TAsmList); override;
  246. end;
  247. class procedure twasmexceptionstatehandler_bfexceptions.new_exception(list:TAsmList;const t:texceptiontemps; const exceptframekind: texceptframekind; out exceptstate: texceptionstate);
  248. begin
  249. exceptstate.exceptionlabel:=nil;
  250. exceptstate.oldflowcontrol:=flowcontrol;
  251. exceptstate.finallycodelabel:=nil;
  252. flowcontrol:=[fc_inflowcontrol,fc_catching_exceptions];
  253. end;
  254. class procedure twasmexceptionstatehandler_bfexceptions.free_exception(list: TAsmList; const t: texceptiontemps; const s: texceptionstate; a: aint; endexceptlabel: tasmlabel; onlyfree:boolean);
  255. begin
  256. end;
  257. class procedure twasmexceptionstatehandler_bfexceptions.handle_nested_exception(list:TAsmList;var t:texceptiontemps;var entrystate: texceptionstate);
  258. begin
  259. Message1(parser_f_unsupported_feature,'nested exception');
  260. end;
  261. class procedure twasmexceptionstatehandler_bfexceptions.begin_catch(list: TAsmList; excepttype: tobjectdef; nextonlabel: tasmlabel; out exceptlocdef: tdef; out exceptlocreg: tregister);
  262. var
  263. pd: tprocdef;
  264. href2: treference;
  265. fpc_catches_res,
  266. paraloc1: tcgpara;
  267. exceptloc: tlocation;
  268. indirect: boolean;
  269. otherunit: boolean;
  270. begin
  271. paraloc1.init;
  272. otherunit:=findunitsymtable(excepttype.owner).moduleid<>findunitsymtable(current_procinfo.procdef.owner).moduleid;
  273. indirect:=(tf_supports_packages in target_info.flags) and
  274. (target_info.system in systems_indirect_var_imports) and
  275. (cs_imported_data in current_settings.localswitches) and
  276. otherunit;
  277. { send the vmt parameter }
  278. pd:=search_system_proc('fpc_catches');
  279. reference_reset_symbol(href2, current_asmdata.RefAsmSymbol(excepttype.vmt_mangledname, AT_DATA, indirect), 0, sizeof(pint), []);
  280. if otherunit then
  281. current_module.add_extern_asmsym(excepttype.vmt_mangledname, AB_EXTERNAL, AT_DATA);
  282. paramanager.getcgtempparaloc(list, pd, 1, paraloc1);
  283. hlcg.a_loadaddr_ref_cgpara(list, excepttype.vmt_def, href2, paraloc1);
  284. paramanager.freecgpara(list, paraloc1);
  285. fpc_catches_res:=hlcg.g_call_system_proc(list, pd, [@paraloc1], nil);
  286. location_reset(exceptloc, LOC_REGISTER, def_cgsize(fpc_catches_res.def));
  287. exceptloc.register:=hlcg.getaddressregister(list, fpc_catches_res.def);
  288. hlcg.gen_load_cgpara_loc(list, fpc_catches_res.def, fpc_catches_res, exceptloc, true);
  289. { is it this catch? }
  290. thlcgwasm(hlcg).a_cmp_const_reg_stack(list, fpc_catches_res.def, OC_NE, 0, exceptloc.register);
  291. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_if));
  292. thlcgwasm(hlcg).decstack(current_asmdata.CurrAsmList,1);
  293. paraloc1.done;
  294. exceptlocdef:=fpc_catches_res.def;
  295. exceptlocreg:=exceptloc.register;
  296. end;
  297. class procedure twasmexceptionstatehandler_bfexceptions.end_catch(list: TAsmList);
  298. begin
  299. current_asmdata.CurrAsmList.concat(taicpu.op_none(a_end_if));
  300. end;
  301. {*****************************************************************************
  302. twasmblockitem
  303. *****************************************************************************}
  304. type
  305. { twasmblockitem }
  306. twasmblockitem = class(TLinkedListItem)
  307. blockstart: taicpu;
  308. elseinstr: taicpu;
  309. constructor Create(ablockstart: taicpu);
  310. end;
  311. constructor twasmblockitem.Create(ablockstart: taicpu);
  312. begin
  313. blockstart:=ablockstart;
  314. end;
  315. {*****************************************************************************
  316. twasmblockstack
  317. *****************************************************************************}
  318. type
  319. { twasmblockstack }
  320. twasmblockstack = class(tlinkedlist)
  321. end;
  322. {*****************************************************************************
  323. tcpuprocinfo
  324. *****************************************************************************}
  325. function tcpuprocinfo.ConvertBranchTargetNumbersToLabels(ai: tai; blockstack: twasmstruc_stack): TAsmMapFuncResult;
  326. var
  327. instr: taicpu;
  328. bl: taicpu_wasm_structured_instruction;
  329. l: TAsmLabel;
  330. begin
  331. result.typ:=amfrtNoChange;
  332. if ai.typ<>ait_instruction then
  333. exit;
  334. instr:=taicpu(ai);
  335. if not (instr.opcode in [a_br,a_br_if]) then
  336. exit;
  337. if instr.ops<>1 then
  338. internalerror(2023101601);
  339. if instr.oper[0]^.typ<>top_const then
  340. exit;
  341. bl:=blockstack[instr.oper[0]^.val];
  342. l:=bl.getlabel;
  343. instr.loadsymbol(0,l,0);
  344. end;
  345. function tcpuprocinfo.ConvertIfToBrIf(ai: tai; blockstack: twasmstruc_stack): TAsmMapFuncResult;
  346. begin
  347. result.typ:=amfrtNoChange;
  348. if (ai.typ=ait_wasm_structured_instruction) and (taicpu_wasm_structured_instruction(ai).wstyp=aitws_if) then
  349. begin
  350. result.typ:=amfrtNewList;
  351. result.newlist:=TAsmList.Create;
  352. tai_wasmstruc_if(ai).ConvertToBrIf(result.newlist,@AllocWasmLocal);
  353. end;
  354. end;
  355. function tcpuprocinfo.ConvertLoopToBr(ai: tai; blockstack: twasmstruc_stack): TAsmMapFuncResult;
  356. begin
  357. result.typ:=amfrtNoChange;
  358. if (ai.typ=ait_wasm_structured_instruction) and (taicpu_wasm_structured_instruction(ai).wstyp=aitws_loop) then
  359. begin
  360. result.typ:=amfrtNewList;
  361. result.newlist:=TAsmList.Create;
  362. tai_wasmstruc_loop(ai).ConvertToBr(result.newlist);
  363. end;
  364. end;
  365. function tcpuprocinfo.StripBlockInstructions(ai: tai; blockstack: twasmstruc_stack): TAsmMapFuncResult;
  366. var
  367. instr: taicpu;
  368. begin
  369. result.typ:=amfrtNoChange;
  370. if ai.typ<>ait_instruction then
  371. exit;
  372. instr:=taicpu(ai);
  373. if instr.opcode in [a_block,a_end_block] then
  374. result.typ:=amfrtDeleteAi;
  375. end;
  376. function tcpuprocinfo.AllocWasmLocal(wbt: TWasmBasicType): Integer;
  377. begin
  378. SetLength(FAllocatedLocals,Length(FAllocatedLocals)+1);
  379. FAllocatedLocals[High(FAllocatedLocals)]:=wbt;
  380. result:=High(FAllocatedLocals)+FFirstFreeLocal;
  381. SetLength(FLocals,Length(FLocals)+1);
  382. FLocals[High(FLocals)]:=wbt;
  383. end;
  384. function tcpuprocinfo.GetLocalType(localidx: Integer): TWasmBasicType;
  385. begin
  386. if (localidx<Low(FLocals)) or (localidx>High(FLocals)) then
  387. internalerror(2024022601);
  388. result:=FLocals[localidx];
  389. end;
  390. constructor tcpuprocinfo.create(aparent: tprocinfo);
  391. begin
  392. inherited create(aparent);
  393. FGotoTargets:=TFPHashObjectList.Create(false);
  394. if ts_wasm_bf_exceptions in current_settings.targetswitches then
  395. current_asmdata.getjumplabel(CurrRaiseLabel);
  396. end;
  397. destructor tcpuprocinfo.destroy;
  398. begin
  399. FGotoTargets.Free;
  400. inherited destroy;
  401. end;
  402. function tcpuprocinfo.calc_stackframe_size: longint;
  403. begin
  404. { the stack frame in WebAssembly should always have a 16-byte alignment }
  405. Result:=Align(inherited calc_stackframe_size,16);
  406. end;
  407. procedure tcpuprocinfo.setup_eh;
  408. begin
  409. if ts_wasm_native_exnref_exceptions in current_settings.targetswitches then
  410. cexceptionstatehandler:=twasmexceptionstatehandler_nativeexnrefexceptions
  411. else if ts_wasm_native_legacy_exceptions in current_settings.targetswitches then
  412. cexceptionstatehandler:=twasmexceptionstatehandler_nativelegacyexceptions
  413. else if ts_wasm_no_exceptions in current_settings.targetswitches then
  414. cexceptionstatehandler:=twasmexceptionstatehandler_noexceptions
  415. else if ts_wasm_bf_exceptions in current_settings.targetswitches then
  416. cexceptionstatehandler:=twasmexceptionstatehandler_bfexceptions
  417. else
  418. internalerror(2021091701);
  419. end;
  420. procedure tcpuprocinfo.generate_exit_label(list: tasmlist);
  421. begin
  422. if not (po_assembler in current_procinfo.procdef.procoptions) then
  423. list.concat(taicpu.op_none(a_end_block));
  424. inherited generate_exit_label(list);
  425. end;
  426. procedure tcpuprocinfo.postprocess_code;
  427. function findfirst_tai_functype(asmlist: TAsmList): tai_functype;
  428. var
  429. hp: tai;
  430. begin
  431. result:=nil;
  432. if not assigned(asmlist) then
  433. exit;
  434. hp:=tai(asmlist.first);
  435. while assigned(hp) do
  436. begin
  437. if hp.typ=ait_functype then
  438. begin
  439. result:=tai_functype(hp);
  440. exit;
  441. end;
  442. hp:=tai(hp.Next);
  443. end;
  444. end;
  445. procedure replace_local_frame_pointer(asmlist: TAsmList);
  446. var
  447. hp: tai;
  448. instr: taicpu;
  449. l: Integer;
  450. begin
  451. if not assigned(asmlist) then
  452. exit;
  453. hp:=tai(asmlist.first);
  454. while assigned(hp) do
  455. begin
  456. if hp.typ=ait_instruction then
  457. begin
  458. instr:=taicpu(hp);
  459. for l:=0 to instr.ops-1 do
  460. if (instr.oper[l]^.typ=top_reg) and (instr.oper[l]^.reg=NR_LOCAL_FRAME_POINTER_REG) then
  461. instr.loadref(l,tcpuprocdef(current_procinfo.procdef).frame_pointer_ref);
  462. end;
  463. hp:=tai(hp.Next);
  464. end;
  465. end;
  466. function FindNextInstruction(hp: tai): taicpu;
  467. begin
  468. result:=nil;
  469. if not assigned(hp) then
  470. exit;
  471. repeat
  472. hp:=tai(hp.next);
  473. until not assigned(hp) or (hp.typ=ait_instruction);
  474. if assigned(hp) then
  475. result:=taicpu(hp);
  476. end;
  477. procedure resolve_labels_pass1(asmlist: TAsmList);
  478. var
  479. hp: tai;
  480. lastinstr, nextinstr: taicpu;
  481. cur_nesting_depth: longint;
  482. lbl: tai_label;
  483. blockstack: twasmblockstack;
  484. cblock: twasmblockitem;
  485. begin
  486. blockstack:=twasmblockstack.create;
  487. cur_nesting_depth:=0;
  488. lastinstr:=nil;
  489. hp:=tai(asmlist.first);
  490. while assigned(hp) do
  491. begin
  492. case hp.typ of
  493. ait_instruction:
  494. begin
  495. lastinstr:=taicpu(hp);
  496. case lastinstr.opcode of
  497. a_block,
  498. a_loop,
  499. a_if,
  500. a_try_table,
  501. a_legacy_try:
  502. begin
  503. blockstack.Concat(twasmblockitem.create(lastinstr));
  504. inc(cur_nesting_depth);
  505. end;
  506. a_else:
  507. begin
  508. cblock:=twasmblockitem(blockstack.Last);
  509. if (cblock=nil) or
  510. (cblock.blockstart.opcode<>a_if) or
  511. assigned(cblock.elseinstr) then
  512. Message1(parser_f_unsupported_feature,'misplaced a_else');
  513. cblock.elseinstr:=lastinstr;
  514. end;
  515. a_end_block,
  516. a_end_loop,
  517. a_end_if,
  518. a_end_try_table,
  519. a_end_legacy_try:
  520. begin
  521. dec(cur_nesting_depth);
  522. if cur_nesting_depth<0 then
  523. Message1(parser_f_unsupported_feature,'negative nesting level');
  524. cblock:=twasmblockitem(blockstack.GetLast);
  525. if (cblock=nil) or
  526. ((cblock.blockstart.opcode=a_block) and (lastinstr.opcode<>a_end_block)) or
  527. ((cblock.blockstart.opcode=a_loop) and (lastinstr.opcode<>a_end_loop)) or
  528. ((cblock.blockstart.opcode=a_if) and (lastinstr.opcode<>a_end_if)) or
  529. ((cblock.blockstart.opcode=a_try_table) and (lastinstr.opcode<>a_end_try_table)) or
  530. ((cblock.blockstart.opcode=a_legacy_try) and (lastinstr.opcode<>a_end_legacy_try)) then
  531. Message1(parser_f_unsupported_feature,'incompatible nesting level');
  532. cblock.free;
  533. end;
  534. else
  535. ;
  536. end;
  537. end;
  538. ait_label:
  539. begin
  540. lbl:=tai_label(hp);
  541. lbl.labsym.nestingdepth:=-1;
  542. nextinstr:=FindNextInstruction(hp);
  543. if assigned(nextinstr) and (nextinstr.opcode in [a_end_block,a_end_legacy_try,a_end_if]) then
  544. lbl.labsym.nestingdepth:=cur_nesting_depth
  545. else if assigned(lastinstr) and (lastinstr.opcode=a_loop) then
  546. lbl.labsym.nestingdepth:=cur_nesting_depth
  547. else if assigned(lastinstr) and (lastinstr.opcode in [a_end_block,a_end_legacy_try,a_end_if]) then
  548. lbl.labsym.nestingdepth:=cur_nesting_depth+1
  549. else if assigned(nextinstr) and (nextinstr.opcode=a_loop) then
  550. lbl.labsym.nestingdepth:=cur_nesting_depth+1;
  551. end;
  552. else
  553. ;
  554. end;
  555. hp:=tai(hp.Next);
  556. end;
  557. if cur_nesting_depth<>0 then
  558. Message1(parser_f_unsupported_feature,'unbalanced nesting level');
  559. blockstack.free;
  560. end;
  561. function resolve_labels_pass2(asmlist: TAsmList): Boolean;
  562. var
  563. hp: tai;
  564. instr: taicpu;
  565. hlabel: tasmsymbol;
  566. cur_nesting_depth: longint;
  567. begin
  568. Result:=true;
  569. cur_nesting_depth:=0;
  570. hp:=tai(asmlist.first);
  571. while assigned(hp) do
  572. begin
  573. if hp.typ=ait_instruction then
  574. begin
  575. instr:=taicpu(hp);
  576. case instr.opcode of
  577. a_block,
  578. a_loop,
  579. a_if,
  580. a_legacy_try:
  581. inc(cur_nesting_depth);
  582. a_end_block,
  583. a_end_loop,
  584. a_end_if,
  585. a_end_legacy_try:
  586. begin
  587. dec(cur_nesting_depth);
  588. if cur_nesting_depth<0 then
  589. Message1(parser_f_unsupported_feature,'negative nesting level');
  590. end;
  591. a_br,
  592. a_br_if:
  593. begin
  594. if instr.ops<>1 then
  595. Message1(parser_f_unsupported_feature,'a_br or a_br_if with wrong operand count');
  596. if instr.oper[0]^.typ=top_ref then
  597. begin
  598. if not assigned(instr.oper[0]^.ref^.symbol) then
  599. Message1(parser_f_unsupported_feature,'a_br or a_br_if with wrong ref operand');
  600. if (instr.oper[0]^.ref^.base<>NR_NO) or
  601. (instr.oper[0]^.ref^.index<>NR_NO) or
  602. (instr.oper[0]^.ref^.offset<>0) then
  603. Message1(parser_f_unsupported_feature,'a_br or a_br_if with wrong ref type');
  604. if (instr.oper[0]^.ref^.symbol.nestingdepth<>-1) and
  605. (cur_nesting_depth>=instr.oper[0]^.ref^.symbol.nestingdepth) then
  606. instr.loadconst(0,cur_nesting_depth-instr.oper[0]^.ref^.symbol.nestingdepth)
  607. else
  608. begin
  609. result:=false;
  610. hlabel:=tasmsymbol(instr.oper[0]^.ref^.symbol);
  611. asmlist.insertafter(tai_comment.create(strpnew('Unable to find destination of label '+hlabel.name)),hp);
  612. end;
  613. end;
  614. end;
  615. else
  616. ;
  617. end;
  618. end;
  619. hp:=tai(hp.Next);
  620. end;
  621. if cur_nesting_depth<>0 then
  622. Message1(parser_f_unsupported_feature,'unbalanced nesting level');
  623. end;
  624. function resolve_labels_simple(asmlist: TAsmList): Boolean;
  625. begin
  626. if not assigned(asmlist) then
  627. exit(true);
  628. resolve_labels_pass1(asmlist);
  629. result:=resolve_labels_pass2(asmlist);
  630. end;
  631. procedure resolve_labels_via_state_machine(asmlist: TAsmList);
  632. var
  633. blocks: TFPHashObjectList;
  634. curr_block, tmplist: TAsmList;
  635. hp, hpnext: tai;
  636. block_nr, machine_state, target_block_index: Integer;
  637. state_machine_loop_start_label, state_machine_exit: TAsmLabel;
  638. begin
  639. blocks:=TFPHashObjectList.Create;
  640. curr_block:=TAsmList.Create;
  641. blocks.Add('.start',curr_block);
  642. repeat
  643. hp:=tai(asmlist.First);
  644. if assigned(hp) then
  645. begin
  646. asmlist.Remove(hp);
  647. if hp.typ=ait_label then
  648. begin
  649. if (tai_label(hp).labsym.is_used) then
  650. begin
  651. curr_block:=TAsmList.Create;
  652. blocks.Add(tai_label(hp).labsym.Name,curr_block);
  653. end;
  654. end
  655. else
  656. curr_block.Concat(hp);
  657. end;
  658. until not assigned(hp);
  659. { asmlist is now empty }
  660. asmlist.Concat(tai_comment.Create(strpnew('labels resolved via state machine')));
  661. machine_state:=AllocWasmLocal(wbt_i32);
  662. asmlist.Concat(tai_comment.Create(strpnew('machine state is in local '+tostr(machine_state))));
  663. asmlist.Concat(taicpu.op_const(a_i32_const,0));
  664. asmlist.Concat(taicpu.op_const(a_local_set,machine_state));
  665. asmlist.Concat(taicpu.op_none(a_block));
  666. asmlist.Concat(taicpu.op_none(a_loop));
  667. current_asmdata.getjumplabel(state_machine_loop_start_label);
  668. asmlist.concat(tai_label.create(state_machine_loop_start_label));
  669. current_asmdata.getjumplabel(state_machine_exit);
  670. for block_nr:=0 to blocks.Count-1 do
  671. asmlist.Concat(taicpu.op_none(a_block));
  672. for block_nr:=0 to blocks.Count-1 do
  673. begin
  674. { TODO: this sequence can be replaced with a single br_table instruction }
  675. asmlist.Concat(taicpu.op_const(a_local_get,machine_state));
  676. asmlist.Concat(taicpu.op_const(a_i32_const,block_nr));
  677. asmlist.Concat(taicpu.op_none(a_i32_eq));
  678. asmlist.Concat(taicpu.op_const(a_br_if,block_nr));
  679. end;
  680. asmlist.Concat(taicpu.op_none(a_unreachable));
  681. tmplist:=TAsmList.Create;
  682. for block_nr:=0 to blocks.Count-1 do
  683. begin
  684. asmlist.Concat(taicpu.op_none(a_end_block));
  685. asmlist.Concat(tai_comment.Create(strpnew('block '+tostr(block_nr)+' for label '+blocks.NameOfIndex(block_nr))));
  686. curr_block:=TAsmList(blocks[block_nr]);
  687. hp:=tai(curr_block.First);
  688. while assigned(hp) do
  689. begin
  690. hpnext:=tai(hp.next);
  691. if (hp.typ=ait_instruction) and (taicpu(hp).opcode in [a_br,a_br_if]) and
  692. (taicpu(hp).ops=1) and
  693. (taicpu(hp).oper[0]^.typ=top_ref) and
  694. assigned(taicpu(hp).oper[0]^.ref^.symbol) then
  695. begin
  696. target_block_index:=blocks.FindIndexOf(taicpu(hp).oper[0]^.ref^.symbol.Name);
  697. curr_block.InsertBefore(tai_comment.Create(strpnew(
  698. 'branch '+gas_op2str[taicpu(hp).opcode]+
  699. ' '+taicpu(hp).oper[0]^.ref^.symbol.Name+
  700. ' target_block_index='+tostr(target_block_index))),hp);
  701. if target_block_index<>-1 then
  702. begin
  703. tmplist.Clear;
  704. if taicpu(hp).opcode=a_br_if then
  705. tmplist.Concat(taicpu.op_none(a_if));
  706. tmplist.Concat(taicpu.op_const(a_i32_const,target_block_index));
  707. tmplist.Concat(taicpu.op_const(a_local_set,machine_state));
  708. tmplist.Concat(taicpu.op_sym(a_br,state_machine_loop_start_label));
  709. if taicpu(hp).opcode=a_br_if then
  710. tmplist.Concat(taicpu.op_none(a_end_if));
  711. curr_block.insertListAfter(hp,tmplist);
  712. curr_block.Remove(hp);
  713. end;
  714. end;
  715. hp:=hpnext;
  716. end;
  717. if block_nr<(blocks.Count-1) then
  718. begin
  719. curr_block.Concat(taicpu.op_const(a_i32_const,block_nr+1));
  720. curr_block.Concat(taicpu.op_const(a_local_set,machine_state));
  721. curr_block.Concat(taicpu.op_sym(a_br,state_machine_loop_start_label));
  722. end
  723. else
  724. curr_block.Concat(taicpu.op_sym(a_br,state_machine_exit));
  725. asmlist.concatList(curr_block);
  726. end;
  727. tmplist.Free;
  728. asmlist.Concat(taicpu.op_none(a_end_loop));
  729. asmlist.Concat(taicpu.op_none(a_end_block));
  730. asmlist.concat(tai_label.create(state_machine_exit));
  731. end;
  732. procedure filter_start_exit_code(asmlist: TAsmList; out entry_code, proc_body, exit_code: TAsmList);
  733. var
  734. hp, hpnext, hpprev: tai;
  735. begin
  736. entry_code:=TAsmList.Create;
  737. proc_body:=TAsmList.Create;
  738. exit_code:=TAsmList.Create;
  739. repeat
  740. hp:=tai(asmlist.First);
  741. if assigned(hp) then
  742. begin
  743. hpnext:=tai(hp.next);
  744. if (hp.typ=ait_instruction) and (taicpu(hp).opcode=a_block) then
  745. break;
  746. asmlist.Remove(hp);
  747. entry_code.Concat(hp);
  748. hp:=hpnext;
  749. end;
  750. until not assigned(hp);
  751. repeat
  752. hp:=tai(asmlist.Last);
  753. if assigned(hp) then
  754. begin
  755. hpprev:=tai(hp.Previous);
  756. if (hp.typ=ait_instruction) and (taicpu(hp).opcode=a_end_block) then
  757. break;
  758. asmlist.Remove(hp);
  759. exit_code.Insert(hp);
  760. hp:=hpprev;
  761. end;
  762. until not assigned(hp);
  763. proc_body.insertList(asmlist);
  764. end;
  765. procedure resolve_labels_of_asmlist_with_try_blocks_recursive(asmlist: TAsmList);
  766. var
  767. hp: tai;
  768. i: Integer;
  769. begin
  770. if not assigned(asmlist) then
  771. exit;
  772. hp:=tai(asmlist.First);
  773. while assigned(hp) do
  774. begin
  775. if hp.typ=ait_wasm_structured_instruction then
  776. begin
  777. if not (taicpu_wasm_structured_instruction(hp).wstyp in [aitws_try_catch,aitws_try_delegate]) then
  778. internalerror(2023102201);
  779. resolve_labels_of_asmlist_with_try_blocks_recursive(tai_wasmstruc_try(hp).try_asmlist);
  780. if taicpu_wasm_structured_instruction(hp).wstyp=aitws_try_catch then
  781. with tai_wasmstruc_try_catch(hp) do
  782. begin
  783. for i:=low(catch_list) to high(catch_list) do
  784. resolve_labels_of_asmlist_with_try_blocks_recursive(catch_list[i].asmlist);
  785. resolve_labels_of_asmlist_with_try_blocks_recursive(catch_all_asmlist);
  786. end
  787. else if taicpu_wasm_structured_instruction(hp).wstyp=aitws_try_delegate then
  788. {nothing}
  789. else
  790. internalerror(2023102202);
  791. end;
  792. hp:=tai(hp.next);
  793. end;
  794. resolve_labels_via_state_machine(asmlist);
  795. end;
  796. procedure resolve_labels_complex(var asmlist: TAsmList);
  797. var
  798. entry_code, proc_body, exit_code: TAsmList;
  799. begin
  800. filter_start_exit_code(asmlist,entry_code,proc_body,exit_code);
  801. asmlist.Free;
  802. asmlist:=proc_body;
  803. proc_body:=nil;
  804. wasm_convert_to_structured_asmlist(asmlist);
  805. map_structured_asmlist(asmlist,@ConvertBranchTargetNumbersToLabels);
  806. map_structured_asmlist(asmlist,@ConvertIfToBrIf);
  807. map_structured_asmlist(asmlist,@ConvertLoopToBr);
  808. wasm_convert_to_flat_asmlist(asmlist);
  809. map_structured_asmlist(asmlist,@StripBlockInstructions);
  810. wasm_convert_to_structured_asmlist(asmlist);
  811. resolve_labels_of_asmlist_with_try_blocks_recursive(asmlist);
  812. wasm_convert_to_flat_asmlist(asmlist);
  813. asmlist.insertList(entry_code);
  814. entry_code.free;
  815. asmlist.concatList(exit_code);
  816. exit_code.free;
  817. if not resolve_labels_simple(asmlist) then
  818. internalerror(2023102101);
  819. end;
  820. function prepare_locals: TAsmList;
  821. var
  822. local: tai_local;
  823. l : TWasmLocal;
  824. begin
  825. result:=TAsmList.create;
  826. local:=tai_local.create([]);
  827. result.Concat(local);
  828. l:=ttgwasm(tg).localvars.first;
  829. FFuncType:=findfirst_tai_functype(aktproccode).functype;
  830. FLocals:=Copy(FFuncType.params);
  831. FParametersCount:=Length(FLocals);
  832. FFirstFreeLocal:=FParametersCount;
  833. while Assigned(l) do
  834. begin
  835. SetLength(FLocals,Length(FLocals)+1);
  836. FLocals[High(FLocals)]:=l.typ;
  837. local.AddLocal(l.typ);
  838. l:=l.nextseq;
  839. Inc(FFirstFreeLocal);
  840. end;
  841. end;
  842. procedure add_extra_allocated_locals(localslist: TAsmList);
  843. begin
  844. if tai(localslist.First).typ<>ait_local then
  845. internalerror(2024081501);
  846. tai_local(localslist.First).AddLocals(FAllocatedLocals);
  847. end;
  848. procedure insert_localslist(destlist,localslist: TAsmList);
  849. begin
  850. if assigned(localslist) then
  851. destlist.insertListAfter(findfirst_tai_functype(destlist),localslist);
  852. end;
  853. procedure check_goto_br_instructions(list: TAsmList; out HasGotoBrInstructions: boolean);
  854. var
  855. hp: tai;
  856. begin
  857. HasGotoBrInstructions:=False;
  858. hp:=tai(list.first);
  859. while assigned(hp) do
  860. begin
  861. if (hp.typ=ait_instruction) and (taicpu(hp).is_br_generated_by_goto) then
  862. begin
  863. HasGotoBrInstructions:=True;
  864. if (taicpu(hp).opcode<>a_br) or
  865. (taicpu(hp).ops<>1) or
  866. (taicpu(hp).oper[0]^.typ<>top_ref) or
  867. (taicpu(hp).oper[0]^.ref^.offset<>0) or
  868. (taicpu(hp).oper[0]^.ref^.base<>NR_NO) or
  869. (taicpu(hp).oper[0]^.ref^.index<>NR_NO) or
  870. (taicpu(hp).oper[0]^.ref^.symbol=nil) then
  871. internalerror(2023102203);
  872. if not is_goto_target(taicpu(hp).oper[0]^.ref^.symbol) then
  873. internalerror(2023102204);
  874. end;
  875. hp:=tai(hp.next);
  876. end;
  877. end;
  878. procedure validate_code;
  879. var
  880. vs: TWasmValidationStacks;
  881. hp: tai;
  882. begin
  883. vs:=TWasmValidationStacks.Create(@GetLocalType,FFuncType);
  884. hp:=tai(aktproccode.first);
  885. while assigned(hp) do
  886. begin
  887. if hp.typ=ait_instruction then
  888. vs.Validate(taicpu(hp));
  889. hp:=tai(hp.next);
  890. end;
  891. vs.Free;
  892. end;
  893. procedure postprocess_code_assembler;
  894. begin
  895. aktproccode.InsertAfter(tai_local.create([]),findfirst_tai_functype(aktproccode));
  896. end;
  897. var
  898. localslist: TAsmList;
  899. labels_resolved, has_goto: Boolean;
  900. begin
  901. if po_assembler in procdef.procoptions then
  902. begin
  903. postprocess_code_assembler;
  904. exit;
  905. end;
  906. check_goto_br_instructions(aktproccode,has_goto);
  907. localslist:=prepare_locals;
  908. replace_local_frame_pointer(aktproccode);
  909. labels_resolved:=false;
  910. if not has_goto then
  911. { TODO: make resolve_labels_simple handle goto labels correctly }
  912. labels_resolved:=resolve_labels_simple(aktproccode);
  913. {$ifndef DEBUG_WASM_GOTO}
  914. if not labels_resolved then
  915. {$endif DEBUG_WASM_GOTO}
  916. resolve_labels_complex(aktproccode);
  917. add_extra_allocated_locals(localslist);
  918. insert_localslist(aktproccode,localslist);
  919. localslist.Free;
  920. {$ifdef DEBUG_WASM_VALIDATION}
  921. validate_code;
  922. {$endif DEBUG_WASM_VALIDATION}
  923. inherited postprocess_code;
  924. end;
  925. procedure tcpuprocinfo.set_first_temp_offset;
  926. var
  927. sz : integer;
  928. i : integer;
  929. sym: tsym;
  930. begin
  931. {
  932. Stackframe layout:
  933. sp:
  934. <incoming parameters>
  935. sp+first_temp_offset:
  936. <locals>
  937. <temp>
  938. }
  939. procdef.init_paraloc_info(calleeside);
  940. sz := procdef.calleeargareasize;
  941. tg.setfirsttemp(sz);
  942. end;
  943. procedure tcpuprocinfo.add_goto_target(l: tasmlabel);
  944. begin
  945. FGotoTargets.Add(l.Name,l);
  946. end;
  947. function tcpuprocinfo.is_goto_target(l: tasmsymbol): Boolean;
  948. begin
  949. result:=FGotoTargets.FindIndexOf(l.Name)<>-1;
  950. end;
  951. initialization
  952. cprocinfo:=tcpuprocinfo;
  953. end.