ncgcal.pas 54 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272
  1. {
  2. Copyright (c) 1998-2002 by Florian Klaempfl
  3. Generate assembler for call nodes
  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 ncgcal;
  18. {$i fpcdefs.inc}
  19. interface
  20. uses
  21. cpubase,
  22. globtype,
  23. parabase,cgbase,cgutils,
  24. symdef,node,ncal;
  25. type
  26. tcgcallparanode = class(tcallparanode)
  27. protected
  28. procedure push_addr_para;
  29. procedure push_value_para;virtual;
  30. procedure push_formal_para;virtual;
  31. procedure push_copyout_para;virtual;abstract;
  32. public
  33. tempcgpara : tcgpara;
  34. constructor create(expr,next : tnode);override;
  35. destructor destroy;override;
  36. procedure secondcallparan;override;
  37. end;
  38. { tcgcallnode }
  39. tcgcallnode = class(tcallnode)
  40. private
  41. procedure handle_return_value;
  42. procedure release_unused_return_value;
  43. procedure copy_back_paras;
  44. procedure release_para_temps;
  45. procedure reorder_parameters;
  46. procedure freeparas;
  47. protected
  48. retloc: tcgpara;
  49. paralocs: array of pcgpara;
  50. framepointer_paraloc : tcgpara;
  51. {# This routine is used to push the current frame pointer
  52. on the stack. This is used in nested routines where the
  53. value of the frame pointer is always pushed as an extra
  54. parameter.
  55. The default handling is the standard handling used on
  56. most stack based machines, where the frame pointer is
  57. the first invisible parameter.
  58. }
  59. procedure pop_parasize(pop_size:longint);virtual;
  60. procedure extra_interrupt_code;virtual;
  61. procedure extra_pre_call_code;virtual;
  62. procedure extra_call_code;virtual;
  63. procedure extra_post_call_code;virtual;
  64. procedure do_syscall;virtual;abstract;
  65. { The function result is returned in a tcgpara. This tcgpara has to
  66. be translated into a tlocation so the rest of the code generator
  67. can work with it. This routine decides what the most appropriate
  68. tlocation is and sets self.location based on that. }
  69. procedure set_result_location(realresdef: tstoreddef);virtual;
  70. { if an unused return value is in another location than a
  71. LOC_REFERENCE, this method will be called to perform the necessary
  72. cleanups. By default it does not do anything }
  73. procedure do_release_unused_return_value;virtual;
  74. { Override the following three methods to support calls to address in
  75. 'ref' without loading it into register (only x86 targets probably).
  76. If can_call_ref returns true, it should do required simplification
  77. on ref. }
  78. function can_call_ref(var ref: treference):boolean;virtual;
  79. procedure extra_call_ref_code(var ref: treference);virtual;
  80. function do_call_ref(ref: treference): tcgpara;virtual;
  81. { store all the parameters in the temporary paralocs in their final
  82. location, and create the paralocs array that will be passed to
  83. hlcg.a_call_* }
  84. procedure pushparas;virtual;
  85. { loads the code pointer of a complex procvar (one with a self/
  86. parentfp/... and a procedure address) into a register and returns it }
  87. function load_complex_procvar_codeptr: tregister; virtual;
  88. { loads the procvar code pointer into a register }
  89. function load_procvar_codeptr: tregister;
  90. procedure load_block_invoke(toreg: tregister);virtual;
  91. public
  92. procedure pass_generate_code;override;
  93. destructor destroy;override;
  94. end;
  95. implementation
  96. uses
  97. systems,
  98. cutils,verbose,globals,
  99. cpuinfo,
  100. symconst,symbase,symtable,symtype,symsym,defutil,paramgr,
  101. pass_2,
  102. aasmbase,aasmtai,aasmdata,
  103. nbas,nmem,nld,ncnv,nutils,
  104. ncgutil,blockutl,
  105. cgobj,tgobj,hlcgobj,
  106. procinfo,
  107. wpobase;
  108. {*****************************************************************************
  109. TCGCALLPARANODE
  110. *****************************************************************************}
  111. constructor tcgcallparanode.create(expr,next : tnode);
  112. begin
  113. inherited create(expr,next);
  114. tempcgpara.init;
  115. end;
  116. destructor tcgcallparanode.destroy;
  117. begin
  118. tempcgpara.done;
  119. inherited destroy;
  120. end;
  121. procedure tcgcallparanode.push_addr_para;
  122. begin
  123. if not(left.location.loc in [LOC_CREFERENCE,LOC_REFERENCE]) then
  124. internalerror(200304235);
  125. hlcg.a_loadaddr_ref_cgpara(current_asmdata.CurrAsmList,left.resultdef,left.location.reference,tempcgpara);
  126. end;
  127. procedure tcgcallnode.reorder_parameters;
  128. var
  129. hpcurr,hpprev,hpnext,hpreversestart : tcgcallparanode;
  130. begin
  131. { All parameters are now in temporary locations. If we move them to
  132. their regular locations in the same order, then we get the
  133. following pattern for register parameters:
  134. mov para1, tempreg1
  135. mov para2, tempreg2
  136. mov para3, tempreg3
  137. mov tempreg1, parareg1
  138. mov tempreg2, parareg2
  139. mov tempreg3, parareg3
  140. The result is that all tempregs conflict with all pararegs.
  141. A better solution is to use:
  142. mov para1, tempreg1
  143. mov para2, tempreg2
  144. mov para3, tempreg3
  145. mov tempreg3, parareg3
  146. mov tempreg2, parareg2
  147. mov tempreg1, parareg1
  148. This way, tempreg2 can be the same as parareg1 etc.
  149. To achieve this, we invert the order of all LOC_XREGISTER
  150. paras (JM).
  151. }
  152. hpcurr:=tcgcallparanode(left);
  153. { assume all LOC_REFERENCE parameters come first
  154. (see tcallnode.order_parameters)
  155. }
  156. hpreversestart:=nil;
  157. while assigned(hpcurr) do
  158. begin
  159. if not(hpcurr.parasym.paraloc[callerside].location^.loc in [LOC_REFERENCE,LOC_CREFERENCE]) then
  160. hpreversestart:=hpcurr;
  161. hpcurr:=tcgcallparanode(hpcurr.right);
  162. end;
  163. { since all register tempparalocs have basically a complexity of 1,
  164. (unless there are large stack offsets that require a temp register on
  165. some architectures, but that's minor), we don't have to care about
  166. the internal relative order of different register type parameters
  167. }
  168. hpprev:=nil;
  169. hpcurr:=tcgcallparanode(left);
  170. while (hpcurr<>hpreversestart) do
  171. begin
  172. hpnext:=tcgcallparanode(hpcurr.right);
  173. if not(hpcurr.parasym.paraloc[callerside].location^.loc in [LOC_REFERENCE,LOC_CREFERENCE]) then
  174. begin
  175. { remove hpcurr from chain }
  176. if assigned(hpprev) then
  177. hpprev.right:=hpnext
  178. else
  179. left:=hpnext;
  180. { insert right after hpreversestart, so every element will
  181. be inserted right before the previously moved one ->
  182. reverse order; hpreversestart itself is the last register
  183. parameter }
  184. hpcurr.right:=hpreversestart.right;
  185. hpreversestart.right:=hpcurr;
  186. end
  187. else
  188. hpprev:=hpcurr;
  189. hpcurr:=hpnext;
  190. end;
  191. end;
  192. procedure tcgcallparanode.push_value_para;
  193. begin
  194. { we've nothing to push when the size of the parameter is 0
  195. -- except in case of the self parameter of an emptry record on e.g.
  196. the JVM target }
  197. if (left.resultdef.size=0) and
  198. not(vo_is_self in parasym.varoptions) then
  199. exit;
  200. { Move flags and jump in register to make it less complex }
  201. if left.location.loc in [LOC_FLAGS,LOC_JUMP,LOC_SUBSETREG,LOC_CSUBSETREG,LOC_SUBSETREF,LOC_CSUBSETREF] then
  202. hlcg.location_force_reg(current_asmdata.CurrAsmList,left.location,left.resultdef,left.resultdef,false);
  203. { load the parameter's tlocation into its cgpara }
  204. hlcg.gen_load_loc_cgpara(current_asmdata.CurrAsmList,left.resultdef,left.location,tempcgpara)
  205. end;
  206. procedure tcgcallparanode.push_formal_para;
  207. begin
  208. { allow passing of a constant to a const formaldef }
  209. if (parasym.varspez=vs_const) and
  210. (left.location.loc in [LOC_CONSTANT,LOC_REGISTER]) then
  211. hlcg.location_force_mem(current_asmdata.CurrAsmList,left.location,left.resultdef);
  212. push_addr_para;
  213. end;
  214. procedure tcgcallparanode.secondcallparan;
  215. var
  216. href : treference;
  217. otlabel,
  218. oflabel : tasmlabel;
  219. pushaddr: boolean;
  220. begin
  221. if not(assigned(parasym)) then
  222. internalerror(200304242);
  223. { Skip nothingn nodes which are used after disabling
  224. a parameter }
  225. if (left.nodetype<>nothingn) then
  226. begin
  227. otlabel:=current_procinfo.CurrTrueLabel;
  228. oflabel:=current_procinfo.CurrFalseLabel;
  229. current_asmdata.getjumplabel(current_procinfo.CurrTrueLabel);
  230. current_asmdata.getjumplabel(current_procinfo.CurrFalseLabel);
  231. if assigned(fparainit) then
  232. secondpass(fparainit);
  233. secondpass(left);
  234. hlcg.maybe_change_load_node_reg(current_asmdata.CurrAsmList,left,true);
  235. { release memory for refcnt out parameters }
  236. if (parasym.varspez=vs_out) and
  237. is_managed_type(left.resultdef) and
  238. not(target_info.system in systems_garbage_collected_managed_types) then
  239. begin
  240. hlcg.location_get_data_ref(current_asmdata.CurrAsmList,left.resultdef,left.location,href,false,sizeof(pint));
  241. if is_open_array(resultdef) then
  242. begin
  243. { if elementdef is not managed, omit fpc_decref_array
  244. because it won't do anything anyway }
  245. if is_managed_type(tarraydef(resultdef).elementdef) then
  246. begin
  247. if third=nil then
  248. InternalError(201103063);
  249. secondpass(third);
  250. hlcg.g_array_rtti_helper(current_asmdata.CurrAsmList,tarraydef(resultdef).elementdef,
  251. href,third.location,'fpc_finalize_array');
  252. end;
  253. end
  254. else
  255. hlcg.g_finalize(current_asmdata.CurrAsmList,left.resultdef,href)
  256. end;
  257. paramanager.createtempparaloc(current_asmdata.CurrAsmList,aktcallnode.procdefinition.proccalloption,parasym,not followed_by_stack_tainting_call_cached,tempcgpara);
  258. { handle varargs first, because parasym is not valid }
  259. if (cpf_varargs_para in callparaflags) then
  260. begin
  261. if paramanager.push_addr_param(vs_value,left.resultdef,
  262. aktcallnode.procdefinition.proccalloption) then
  263. push_addr_para
  264. else
  265. push_value_para;
  266. end
  267. { hidden parameters }
  268. else if (vo_is_hidden_para in parasym.varoptions) then
  269. begin
  270. { don't push a node that already generated a pointer type
  271. by address for implicit hidden parameters }
  272. pushaddr:=(vo_is_funcret in parasym.varoptions) or
  273. { pass "this" in C++ classes explicitly as pointer
  274. because push_addr_param might not be true for them }
  275. (is_cppclass(parasym.vardef) and (vo_is_self in parasym.varoptions)) or
  276. (
  277. (
  278. not(left.resultdef.typ in [pointerdef,classrefdef]) or
  279. (
  280. { allow pointerdefs (as self) to be passed as addr
  281. param if the method is part of a type helper which
  282. extends a pointer type }
  283. (vo_is_self in parasym.varoptions) and
  284. (aktcallnode.procdefinition.owner.symtabletype=objectsymtable) and
  285. (is_objectpascal_helper(tdef(aktcallnode.procdefinition.owner.defowner))) and
  286. (tobjectdef(aktcallnode.procdefinition.owner.defowner).extendeddef.typ=pointerdef)
  287. )
  288. ) and
  289. paramanager.push_addr_param(parasym.varspez,parasym.vardef,
  290. aktcallnode.procdefinition.proccalloption));
  291. if pushaddr then
  292. begin
  293. { objects or advanced records could be located in registers if they are the result of a type case, see e.g. webtbs\tw26075.pp }
  294. if not(left.location.loc in [LOC_CREFERENCE,LOC_REFERENCE]) then
  295. hlcg.location_force_mem(current_asmdata.CurrAsmList,left.location,left.resultdef);
  296. push_addr_para
  297. end
  298. else
  299. push_value_para;
  300. end
  301. { formal def }
  302. else if (parasym.vardef.typ=formaldef) then
  303. push_formal_para
  304. { Normal parameter }
  305. else if paramanager.push_copyout_param(parasym.varspez,parasym.vardef,
  306. aktcallnode.procdefinition.proccalloption) then
  307. push_copyout_para
  308. else
  309. begin
  310. { don't push a node that already generated a pointer type
  311. by address for implicit hidden parameters }
  312. if (not(
  313. (vo_is_hidden_para in parasym.varoptions) and
  314. (left.resultdef.typ in [pointerdef,classrefdef])
  315. ) and
  316. paramanager.push_addr_param(parasym.varspez,parasym.vardef,
  317. aktcallnode.procdefinition.proccalloption)) and
  318. { dyn. arrays passed to an array of const must be passed by value, see tests/webtbs/tw4219.pp }
  319. not(
  320. is_array_of_const(parasym.vardef) and
  321. is_dynamic_array(left.resultdef)
  322. ) then
  323. begin
  324. { Passing a var parameter to a var parameter, we can
  325. just push the address transparently }
  326. if (left.nodetype=loadn) and
  327. (tloadnode(left).is_addr_param_load) then
  328. begin
  329. if (left.location.reference.index<>NR_NO) or
  330. (left.location.reference.offset<>0) then
  331. internalerror(200410107);
  332. hlcg.a_load_reg_cgpara(current_asmdata.CurrAsmList,voidpointertype,left.location.reference.base,tempcgpara)
  333. end
  334. else
  335. begin
  336. { Force to be in memory }
  337. if not(left.location.loc in [LOC_CREFERENCE,LOC_REFERENCE]) then
  338. hlcg.location_force_mem(current_asmdata.CurrAsmList,left.location,left.resultdef);
  339. push_addr_para;
  340. end;
  341. end
  342. else
  343. push_value_para;
  344. end;
  345. current_procinfo.CurrTrueLabel:=otlabel;
  346. current_procinfo.CurrFalseLabel:=oflabel;
  347. { update return location in callnode when this is the function
  348. result }
  349. if assigned(parasym) and
  350. (
  351. { for type helper/record constructor check that it is self parameter }
  352. (
  353. (vo_is_self in parasym.varoptions) and
  354. (aktcallnode.procdefinition.proctypeoption=potype_constructor) and
  355. (parasym.vardef.typ<>objectdef)
  356. ) or
  357. (vo_is_funcret in parasym.varoptions)
  358. ) then
  359. location_copy(aktcallnode.location,left.location);
  360. end;
  361. { next parameter }
  362. if assigned(right) then
  363. tcallparanode(right).secondcallparan;
  364. end;
  365. {*****************************************************************************
  366. TCGCALLNODE
  367. *****************************************************************************}
  368. {$if first_mm_imreg = 0}
  369. {$WARN 4044 OFF} { Comparison might be always false ... }
  370. {$endif}
  371. procedure tcgcallnode.extra_interrupt_code;
  372. begin
  373. end;
  374. procedure tcgcallnode.extra_pre_call_code;
  375. begin
  376. end;
  377. procedure tcgcallnode.extra_call_code;
  378. begin
  379. end;
  380. procedure tcgcallnode.extra_post_call_code;
  381. begin
  382. end;
  383. function tcgcallnode.can_call_ref(var ref: treference): boolean;
  384. begin
  385. result:=false;
  386. end;
  387. procedure tcgcallnode.extra_call_ref_code(var ref: treference);
  388. begin
  389. { no action by default }
  390. end;
  391. function tcgcallnode.do_call_ref(ref: treference): tcgpara;
  392. begin
  393. InternalError(2014012901);
  394. { silence warning }
  395. result.init;
  396. end;
  397. procedure tcgcallnode.load_block_invoke(toreg: tregister);
  398. var
  399. href: treference;
  400. srsym: tsym;
  401. srsymtable: tsymtable;
  402. literaldef: trecorddef;
  403. begin
  404. literaldef:=get_block_literal_type_for_proc(tabstractprocdef(right.resultdef));
  405. hlcg.location_force_reg(current_asmdata.CurrAsmList,right.location,right.resultdef,getpointerdef(literaldef),true);
  406. { load the invoke pointer }
  407. hlcg.reference_reset_base(href,right.resultdef,right.location.register,0,right.resultdef.alignment);
  408. if not searchsym_in_record(literaldef,'INVOKE',srsym,srsymtable) or
  409. (srsym.typ<>fieldvarsym) or
  410. (tfieldvarsym(srsym).vardef<>voidpointertype) then
  411. internalerror(2014071506);
  412. href.offset:=tfieldvarsym(srsym).fieldoffset;
  413. hlcg.a_load_ref_reg(current_asmdata.CurrAsmList,tfieldvarsym(srsym).vardef,procdefinition,href,toreg);
  414. end;
  415. procedure tcgcallnode.set_result_location(realresdef: tstoreddef);
  416. begin
  417. if realresdef.is_intregable or
  418. realresdef.is_fpuregable or
  419. { avoid temporarily storing pointer-sized entities that can't be
  420. regvars, such as reference-counted pointers, to memory --
  421. no exception can occur right now (except in case of existing
  422. memory corruption), and we'd store them to a regular temp
  423. anyway and that is not safer than keeping them in a register }
  424. ((realresdef.size=sizeof(aint)) and
  425. (retloc.location^.loc=LOC_REGISTER) and
  426. not assigned(retloc.location^.next)) then
  427. location_allocate_register(current_asmdata.CurrAsmList,location,realresdef,false)
  428. else
  429. begin
  430. location_reset_ref(location,LOC_REFERENCE,def_cgsize(realresdef),0);
  431. tg.gethltemp(current_asmdata.CurrAsmList,realresdef,retloc.intsize,tt_normal,location.reference);
  432. end;
  433. end;
  434. procedure tcgcallnode.do_release_unused_return_value;
  435. begin
  436. case location.loc of
  437. LOC_REFERENCE :
  438. begin
  439. if is_managed_type(resultdef) then
  440. hlcg.g_finalize(current_asmdata.CurrAsmList,resultdef,location.reference);
  441. tg.ungetiftemp(current_asmdata.CurrAsmList,location.reference);
  442. end;
  443. end;
  444. end;
  445. procedure tcgcallnode.pop_parasize(pop_size:longint);
  446. begin
  447. end;
  448. procedure tcgcallnode.handle_return_value;
  449. var
  450. realresdef: tstoreddef;
  451. begin
  452. { Check that the return location is set when the result is passed in
  453. a parameter }
  454. if paramanager.ret_in_param(resultdef,procdefinition) then
  455. begin
  456. { self.location is set near the end of secondcallparan so it
  457. refers to the implicit result parameter }
  458. if location.loc<>LOC_REFERENCE then
  459. internalerror(200304241);
  460. exit;
  461. end;
  462. if not assigned(typedef) then
  463. realresdef:=tstoreddef(resultdef)
  464. else
  465. realresdef:=tstoreddef(typedef);
  466. { get a tlocation that can hold the return value that's currently in
  467. the return value's tcgpara }
  468. set_result_location(realresdef);
  469. { Do not move the physical register to a virtual one in case
  470. the return value is not used, because if the virtual one is
  471. then mapped to the same register as the physical one, we will
  472. end up with two deallocs of this register (one inserted here,
  473. one inserted by the register allocator), which unbalances the
  474. register allocation information. The return register(s) will
  475. be freed by location_free() in release_unused_return_value
  476. (mantis #13536). }
  477. if (cnf_return_value_used in callnodeflags) or
  478. assigned(funcretnode) then
  479. hlcg.gen_load_cgpara_loc(current_asmdata.CurrAsmList,realresdef,retloc,location,false);
  480. { copy value to the final location if this was already provided to the
  481. callnode. This must be done after the call node, because the location can
  482. also be used as parameter and may not be finalized yet }
  483. if assigned(funcretnode) then
  484. begin
  485. funcretnode.pass_generate_code;
  486. { Decrease refcount for refcounted types, this can be skipped when
  487. we have used a temp, because then it is already done from tempcreatenode.
  488. Also no finalize is needed, because there is no risk of exceptions from the
  489. function since this is code is only executed after the function call has returned }
  490. if is_managed_type(funcretnode.resultdef) and
  491. (funcretnode.nodetype<>temprefn) then
  492. hlcg.g_finalize(current_asmdata.CurrAsmList,funcretnode.resultdef,funcretnode.location.reference);
  493. case location.loc of
  494. LOC_REGISTER :
  495. begin
  496. {$ifndef cpu64bitalu}
  497. if location.size in [OS_64,OS_S64] then
  498. cg64.a_load64_reg_loc(current_asmdata.CurrAsmList,location.register64,funcretnode.location)
  499. else
  500. {$endif}
  501. hlcg.a_load_reg_loc(current_asmdata.CurrAsmList,resultdef,resultdef,location.register,funcretnode.location);
  502. location_free(current_asmdata.CurrAsmList,location);
  503. end;
  504. LOC_REFERENCE:
  505. begin
  506. case funcretnode.location.loc of
  507. LOC_REGISTER:
  508. hlcg.a_load_ref_reg(current_asmdata.CurrAsmList,resultdef,resultdef,location.reference,funcretnode.location.register);
  509. LOC_REFERENCE:
  510. hlcg.g_concatcopy(current_asmdata.CurrAsmList,resultdef,location.reference,funcretnode.location.reference);
  511. else
  512. internalerror(200802121);
  513. end;
  514. location_freetemp(current_asmdata.CurrAsmList,location);
  515. end;
  516. else
  517. internalerror(200709085);
  518. end;
  519. location := funcretnode.location;
  520. end;
  521. end;
  522. procedure tcgcallnode.release_unused_return_value;
  523. begin
  524. { When the result is not used we need to finalize the result and
  525. can release the temp. This need to be after the callcleanupblock
  526. tree is generated, because that converts the temp from persistent to normal }
  527. if not(cnf_return_value_used in callnodeflags) then
  528. begin
  529. do_release_unused_return_value;
  530. if (retloc.intsize<>0) then
  531. paramanager.freecgpara(current_asmdata.CurrAsmList,retloc);
  532. location_reset(location,LOC_VOID,OS_NO);
  533. end;
  534. end;
  535. procedure tcgcallnode.copy_back_paras;
  536. var
  537. ppn : tcallparanode;
  538. begin
  539. ppn:=tcallparanode(left);
  540. while assigned(ppn) do
  541. begin
  542. if assigned(ppn.paracopyback) then
  543. secondpass(ppn.paracopyback);
  544. ppn:=tcallparanode(ppn.right);
  545. end;
  546. end;
  547. procedure tcgcallnode.release_para_temps;
  548. var
  549. hp,
  550. hp2 : tnode;
  551. ppn : tcallparanode;
  552. begin
  553. { Release temps from parameters }
  554. ppn:=tcallparanode(left);
  555. while assigned(ppn) do
  556. begin
  557. if assigned(ppn.left) then
  558. begin
  559. { don't release the funcret temp }
  560. if not(assigned(ppn.parasym)) or
  561. not(vo_is_funcret in ppn.parasym.varoptions) then
  562. location_freetemp(current_asmdata.CurrAsmList,ppn.left.location);
  563. { process also all nodes of an array of const }
  564. hp:=ppn.left;
  565. while (hp.nodetype=typeconvn) do
  566. hp:=ttypeconvnode(hp).left;
  567. if (hp.nodetype=arrayconstructorn) and
  568. assigned(tarrayconstructornode(hp).left) then
  569. begin
  570. while assigned(hp) do
  571. begin
  572. hp2:=tarrayconstructornode(hp).left;
  573. { ignore typeconvs and addrn inserted by arrayconstructn for
  574. passing a shortstring }
  575. if (hp2.nodetype=typeconvn) and
  576. (tunarynode(hp2).left.nodetype=addrn) then
  577. hp2:=tunarynode(tunarynode(hp2).left).left
  578. else if hp2.nodetype=addrn then
  579. hp2:=tunarynode(hp2).left;
  580. location_freetemp(current_asmdata.CurrAsmList,hp2.location);
  581. hp:=tarrayconstructornode(hp).right;
  582. end;
  583. end;
  584. end;
  585. ppn:=tcallparanode(ppn.right);
  586. end;
  587. setlength(paralocs,0);
  588. end;
  589. procedure tcgcallnode.pushparas;
  590. var
  591. ppn : tcgcallparanode;
  592. callerparaloc,
  593. tmpparaloc : pcgparalocation;
  594. sizeleft: aint;
  595. htempref,
  596. href : treference;
  597. calleralignment,
  598. tmpalignment, i: longint;
  599. skipiffinalloc: boolean;
  600. begin
  601. { copy all resources to the allocated registers }
  602. ppn:=tcgcallparanode(left);
  603. while assigned(ppn) do
  604. begin
  605. if (ppn.left.nodetype<>nothingn) then
  606. begin
  607. { better check for the real location of the parameter here, when stack passed parameters
  608. are saved temporary in registers, checking for the tmpparaloc.loc is wrong
  609. }
  610. paramanager.freecgpara(current_asmdata.CurrAsmList,ppn.tempcgpara);
  611. tmpparaloc:=ppn.tempcgpara.location;
  612. sizeleft:=ppn.tempcgpara.intsize;
  613. calleralignment:=ppn.parasym.paraloc[callerside].alignment;
  614. tmpalignment:=ppn.tempcgpara.alignment;
  615. if (tmpalignment=0) or
  616. (calleralignment=0) then
  617. internalerror(2009020701);
  618. callerparaloc:=ppn.parasym.paraloc[callerside].location;
  619. skipiffinalloc:=
  620. not paramanager.use_fixed_stack or
  621. not(ppn.followed_by_stack_tainting_call_cached);
  622. while assigned(callerparaloc) do
  623. begin
  624. { Every paraloc must have a matching tmpparaloc }
  625. if not assigned(tmpparaloc) then
  626. internalerror(200408224);
  627. if callerparaloc^.size<>tmpparaloc^.size then
  628. internalerror(200408225);
  629. case callerparaloc^.loc of
  630. LOC_REGISTER:
  631. begin
  632. if tmpparaloc^.loc<>LOC_REGISTER then
  633. internalerror(200408221);
  634. if getsupreg(callerparaloc^.register)<first_int_imreg then
  635. cg.getcpuregister(current_asmdata.CurrAsmList,callerparaloc^.register);
  636. cg.a_load_reg_reg(current_asmdata.CurrAsmList,tmpparaloc^.size,tmpparaloc^.size,
  637. tmpparaloc^.register,callerparaloc^.register);
  638. end;
  639. LOC_FPUREGISTER:
  640. begin
  641. if tmpparaloc^.loc<>LOC_FPUREGISTER then
  642. internalerror(200408222);
  643. if getsupreg(callerparaloc^.register)<first_fpu_imreg then
  644. cg.getcpuregister(current_asmdata.CurrAsmList,callerparaloc^.register);
  645. cg.a_loadfpu_reg_reg(current_asmdata.CurrAsmList,tmpparaloc^.size,ppn.tempcgpara.size,tmpparaloc^.register,callerparaloc^.register);
  646. end;
  647. LOC_MMREGISTER:
  648. begin
  649. if tmpparaloc^.loc<>LOC_MMREGISTER then
  650. internalerror(200408223);
  651. if getsupreg(callerparaloc^.register)<first_mm_imreg then
  652. cg.getcpuregister(current_asmdata.CurrAsmList,callerparaloc^.register);
  653. cg.a_loadmm_reg_reg(current_asmdata.CurrAsmList,tmpparaloc^.size,tmpparaloc^.size,
  654. tmpparaloc^.register,callerparaloc^.register,mms_movescalar);
  655. end;
  656. LOC_REFERENCE:
  657. begin
  658. if not(skipiffinalloc and
  659. paramanager.is_stack_paraloc(callerparaloc)) then
  660. begin
  661. { Can't have a data copied to the stack, every location
  662. must contain a valid size field }
  663. if (tmpparaloc^.size=OS_NO) and
  664. ((tmpparaloc^.loc<>LOC_REFERENCE) or
  665. assigned(tmpparaloc^.next)) then
  666. internalerror(200501281);
  667. reference_reset_base(href,callerparaloc^.reference.index,callerparaloc^.reference.offset,calleralignment);
  668. { copy parameters in case they were moved to a temp. location because we've a fixed stack }
  669. case tmpparaloc^.loc of
  670. LOC_REFERENCE:
  671. begin
  672. reference_reset_base(htempref,tmpparaloc^.reference.index,tmpparaloc^.reference.offset,tmpalignment);
  673. { use concatcopy, because it can also be a float which fails when
  674. load_ref_ref is used }
  675. if (ppn.tempcgpara.size <> OS_NO) then
  676. cg.g_concatcopy(current_asmdata.CurrAsmList,htempref,href,tcgsize2size[tmpparaloc^.size])
  677. else
  678. cg.g_concatcopy(current_asmdata.CurrAsmList,htempref,href,sizeleft)
  679. end;
  680. LOC_REGISTER:
  681. cg.a_load_reg_ref(current_asmdata.CurrAsmList,tmpparaloc^.size,tmpparaloc^.size,tmpparaloc^.register,href);
  682. LOC_FPUREGISTER:
  683. cg.a_loadfpu_reg_ref(current_asmdata.CurrAsmList,tmpparaloc^.size,tmpparaloc^.size,tmpparaloc^.register,href);
  684. LOC_MMREGISTER:
  685. cg.a_loadmm_reg_ref(current_asmdata.CurrAsmList,tmpparaloc^.size,tmpparaloc^.size,tmpparaloc^.register,href,mms_movescalar);
  686. else
  687. internalerror(200402081);
  688. end;
  689. end;
  690. end;
  691. end;
  692. dec(sizeleft,tcgsize2size[tmpparaloc^.size]);
  693. callerparaloc:=callerparaloc^.next;
  694. tmpparaloc:=tmpparaloc^.next;
  695. end;
  696. end;
  697. ppn:=tcgcallparanode(ppn.right);
  698. end;
  699. setlength(paralocs,procdefinition.paras.count);
  700. for i:=0 to procdefinition.paras.count-1 do
  701. paralocs[i]:=@tparavarsym(procdefinition.paras[i]).paraloc[callerside];
  702. end;
  703. function tcgcallnode.load_complex_procvar_codeptr: tregister;
  704. var
  705. srcreg: tregister;
  706. codeprocdef: tabstractprocdef;
  707. begin
  708. { this is safe even on i8086, because procvardef code pointers are
  709. always far there (so the current state of far calls vs the state
  710. of far calls where the procvardef was defined does not matter,
  711. even though the procvardef constructor called by getcopyas looks at
  712. it) }
  713. codeprocdef:=tabstractprocdef(procdefinition.getcopyas(procvardef,pc_address_only));
  714. result:=hlcg.getaddressregister(current_asmdata.CurrAsmList,codeprocdef);
  715. { in case we have a method pointer on a big endian target in registers,
  716. the method address is stored in registerhi (it's the first field
  717. in the tmethod record) }
  718. if (right.location.loc in [LOC_REGISTER,LOC_CREGISTER]) then
  719. begin
  720. if not(right.location.size in [OS_PAIR,OS_SPAIR]) then
  721. internalerror(2014081401);
  722. if (target_info.endian=endian_big) then
  723. srcreg:=right.location.registerhi
  724. else
  725. srcreg:=right.location.register;
  726. hlcg.a_load_reg_reg(current_asmdata.CurrAsmList,codeprocdef,codeprocdef,srcreg,result)
  727. end
  728. else
  729. begin
  730. hlcg.location_force_mem(current_asmdata.CurrAsmList,right.location,procdefinition);
  731. hlcg.g_ptrtypecast_ref(current_asmdata.CurrAsmList,getpointerdef(procdefinition),getpointerdef(codeprocdef),right.location.reference);
  732. hlcg.a_load_ref_reg(current_asmdata.CurrAsmList,codeprocdef,codeprocdef,right.location.reference,result);
  733. end;
  734. end;
  735. function tcgcallnode.load_procvar_codeptr: tregister;
  736. begin
  737. if po_is_block in procdefinition.procoptions then
  738. begin
  739. result:=hlcg.getaddressregister(current_asmdata.CurrAsmList,procdefinition);
  740. load_block_invoke(result);
  741. end
  742. else if not(procdefinition.is_addressonly) then
  743. result:=load_complex_procvar_codeptr
  744. else
  745. begin
  746. result:=hlcg.getaddressregister(current_asmdata.CurrAsmList,procdefinition);
  747. hlcg.a_load_loc_reg(current_asmdata.CurrAsmList,procdefinition,procdefinition,right.location,result);
  748. end;
  749. end;
  750. procedure tcgcallnode.freeparas;
  751. var
  752. ppn : tcgcallparanode;
  753. begin
  754. { free the resources allocated for the parameters }
  755. ppn:=tcgcallparanode(left);
  756. while assigned(ppn) do
  757. begin
  758. if (ppn.left.nodetype<>nothingn) then
  759. begin
  760. if (ppn.parasym.paraloc[callerside].location^.loc <> LOC_REFERENCE) then
  761. paramanager.freecgpara(current_asmdata.CurrAsmList,ppn.parasym.paraloc[callerside]);
  762. end;
  763. ppn:=tcgcallparanode(ppn.right);
  764. end;
  765. end;
  766. procedure tcgcallnode.pass_generate_code;
  767. var
  768. name_to_call: TSymStr;
  769. regs_to_save_int,
  770. regs_to_save_address,
  771. regs_to_save_fpu,
  772. regs_to_save_mm : Tcpuregisterset;
  773. href : treference;
  774. pop_size : longint;
  775. vmtoffset : aint;
  776. pvreg,
  777. vmtreg : tregister;
  778. oldaktcallnode : tcallnode;
  779. retlocitem: pcgparalocation;
  780. pd : tprocdef;
  781. proc_addr_size: TCgSize;
  782. proc_addr_voidptrdef: tdef;
  783. callref: boolean;
  784. {$ifdef vtentry}
  785. sym : tasmsymbol;
  786. {$endif vtentry}
  787. {$ifdef SUPPORT_SAFECALL}
  788. cgpara : tcgpara;
  789. {$endif}
  790. begin
  791. if not assigned(procdefinition) or
  792. not(procdefinition.has_paraloc_info in [callerside,callbothsides]) then
  793. internalerror(200305264);
  794. extra_pre_call_code;
  795. if assigned(callinitblock) then
  796. secondpass(tnode(callinitblock));
  797. regs_to_save_int:=paramanager.get_volatile_registers_int(procdefinition.proccalloption);
  798. regs_to_save_address:=paramanager.get_volatile_registers_address(procdefinition.proccalloption);
  799. regs_to_save_fpu:=paramanager.get_volatile_registers_fpu(procdefinition.proccalloption);
  800. regs_to_save_mm:=paramanager.get_volatile_registers_mm(procdefinition.proccalloption);
  801. proc_addr_voidptrdef:=procdefinition.address_type;
  802. proc_addr_size:=def_cgsize(proc_addr_voidptrdef);
  803. { Include Function result registers }
  804. if (not is_void(resultdef)) then
  805. begin
  806. { The forced returntype may have a different size than the one
  807. declared for the procdef }
  808. retloc:=hlcg.get_call_result_cgpara(procdefinition,typedef);
  809. retlocitem:=retloc.location;
  810. while assigned(retlocitem) do
  811. begin
  812. case retlocitem^.loc of
  813. LOC_REGISTER:
  814. case getregtype(retlocitem^.register) of
  815. R_INTREGISTER:
  816. include(regs_to_save_int,getsupreg(retlocitem^.register));
  817. R_ADDRESSREGISTER:
  818. include(regs_to_save_address,getsupreg(retlocitem^.register));
  819. R_TEMPREGISTER:
  820. ;
  821. else
  822. internalerror(2014020102);
  823. end;
  824. LOC_FPUREGISTER:
  825. include(regs_to_save_fpu,getsupreg(retlocitem^.register));
  826. LOC_MMREGISTER:
  827. include(regs_to_save_mm,getsupreg(retlocitem^.register));
  828. LOC_REFERENCE,
  829. LOC_VOID:
  830. ;
  831. else
  832. internalerror(2004110213);
  833. end;
  834. retlocitem:=retlocitem^.next;
  835. end;
  836. end;
  837. { Process parameters, register parameters will be loaded
  838. in imaginary registers. The actual load to the correct
  839. register is done just before the call }
  840. oldaktcallnode:=aktcallnode;
  841. aktcallnode:=self;
  842. if assigned(left) then
  843. tcallparanode(left).secondcallparan;
  844. aktcallnode:=oldaktcallnode;
  845. { procedure variable or normal function call ? }
  846. if (right=nil) then
  847. begin
  848. { register call for WPO (must be done before wpo test below,
  849. otherwise optimised called methods are no longer registered)
  850. }
  851. if (po_virtualmethod in procdefinition.procoptions) and
  852. not is_objectpascal_helper(tprocdef(procdefinition).struct) and
  853. assigned(methodpointer) and
  854. (methodpointer.nodetype<>typen) and
  855. (not assigned(current_procinfo) or
  856. wpoinfomanager.symbol_live(current_procinfo.procdef.mangledname)) then
  857. tobjectdef(tprocdef(procdefinition).struct).register_vmt_call(tprocdef(procdefinition).extnumber);
  858. {$ifdef vtentry}
  859. if not is_interface(tprocdef(procdefinition)._class) then
  860. begin
  861. inc(current_asmdata.NextVTEntryNr);
  862. current_asmdata.CurrAsmList.Concat(tai_symbol.CreateName('VTREF'+tostr(current_asmdata.NextVTEntryNr)+'_'+tprocdef(procdefinition).struct.vmt_mangledname+'$$'+tostr(vmtoffset div sizeof(pint)),AT_FUNCTION,0));
  863. end;
  864. {$endif vtentry}
  865. {$ifdef symansistr}
  866. name_to_call:=fforcedprocname;
  867. {$else symansistr}
  868. name_to_call:='';
  869. if assigned(fforcedprocname) then
  870. name_to_call:=fforcedprocname^;
  871. {$endif symansistr}
  872. { When methodpointer is typen we don't need (and can't) load
  873. a pointer. We can directly call the correct procdef (PFV) }
  874. if (name_to_call='') and
  875. (po_virtualmethod in procdefinition.procoptions) and
  876. not is_objectpascal_helper(tprocdef(procdefinition).struct) and
  877. assigned(methodpointer) and
  878. (methodpointer.nodetype<>typen) and
  879. not wpoinfomanager.can_be_devirtualized(methodpointer.resultdef,procdefinition,name_to_call) then
  880. begin
  881. { virtual methods require an index }
  882. if tprocdef(procdefinition).extnumber=$ffff then
  883. internalerror(200304021);
  884. secondpass(methodpointer);
  885. { Load VMT from self }
  886. if methodpointer.resultdef.typ=objectdef then
  887. gen_load_vmt_register(current_asmdata.CurrAsmList,tobjectdef(methodpointer.resultdef),methodpointer.location,vmtreg)
  888. else
  889. begin
  890. { Load VMT value in register }
  891. hlcg.location_force_reg(current_asmdata.CurrAsmList,methodpointer.location,methodpointer.resultdef,methodpointer.resultdef,false);
  892. vmtreg:=methodpointer.location.register;
  893. { test validity of VMT }
  894. if not(is_interface(tprocdef(procdefinition).struct)) and
  895. not(is_cppclass(tprocdef(procdefinition).struct)) then
  896. cg.g_maybe_testvmt(current_asmdata.CurrAsmList,vmtreg,tobjectdef(tprocdef(procdefinition).struct));
  897. end;
  898. { Call through VMT, generate a VTREF symbol to notify the linker }
  899. vmtoffset:=tobjectdef(tprocdef(procdefinition).struct).vmtmethodoffset(tprocdef(procdefinition).extnumber);
  900. { register call for WPO }
  901. if (not assigned(current_procinfo) or
  902. wpoinfomanager.symbol_live(current_procinfo.procdef.mangledname)) then
  903. tobjectdef(tprocdef(procdefinition).struct).register_vmt_call(tprocdef(procdefinition).extnumber);
  904. reference_reset_base(href,vmtreg,vmtoffset,proc_addr_voidptrdef.alignment);
  905. pvreg:=NR_NO;
  906. callref:=can_call_ref(href);
  907. if not callref then
  908. begin
  909. pvreg:=hlcg.getaddressregister(current_asmdata.CurrAsmList,proc_addr_voidptrdef);
  910. cg.a_load_ref_reg(current_asmdata.CurrAsmList,proc_addr_size,proc_addr_size,href,pvreg);
  911. end;
  912. { Load parameters that are in temporary registers in the
  913. correct parameter register }
  914. if assigned(left) then
  915. begin
  916. reorder_parameters;
  917. pushparas;
  918. { free the resources allocated for the parameters }
  919. freeparas;
  920. end;
  921. if callref then
  922. extra_call_ref_code(href);
  923. cg.alloccpuregisters(current_asmdata.CurrAsmList,R_INTREGISTER,regs_to_save_int);
  924. if cg.uses_registers(R_ADDRESSREGISTER) then
  925. cg.alloccpuregisters(current_asmdata.CurrAsmList,R_ADDRESSREGISTER,regs_to_save_address);
  926. if cg.uses_registers(R_FPUREGISTER) then
  927. cg.alloccpuregisters(current_asmdata.CurrAsmList,R_FPUREGISTER,regs_to_save_fpu);
  928. if cg.uses_registers(R_MMREGISTER) then
  929. cg.alloccpuregisters(current_asmdata.CurrAsmList,R_MMREGISTER,regs_to_save_mm);
  930. { call method }
  931. extra_call_code;
  932. retloc.resetiftemp;
  933. if callref then
  934. retloc:=do_call_ref(href)
  935. else
  936. retloc:=hlcg.a_call_reg(current_asmdata.CurrAsmList,tabstractprocdef(procdefinition),pvreg,paralocs);
  937. extra_post_call_code;
  938. end
  939. else
  940. begin
  941. { Load parameters that are in temporary registers in the
  942. correct parameter register }
  943. if assigned(left) then
  944. begin
  945. reorder_parameters;
  946. pushparas;
  947. { free the resources allocated for the parameters }
  948. freeparas;
  949. end;
  950. cg.alloccpuregisters(current_asmdata.CurrAsmList,R_INTREGISTER,regs_to_save_int);
  951. if cg.uses_registers(R_ADDRESSREGISTER) then
  952. cg.alloccpuregisters(current_asmdata.CurrAsmList,R_ADDRESSREGISTER,regs_to_save_address);
  953. if cg.uses_registers(R_FPUREGISTER) then
  954. cg.alloccpuregisters(current_asmdata.CurrAsmList,R_FPUREGISTER,regs_to_save_fpu);
  955. if cg.uses_registers(R_MMREGISTER) then
  956. cg.alloccpuregisters(current_asmdata.CurrAsmList,R_MMREGISTER,regs_to_save_mm);
  957. if procdefinition.proccalloption=pocall_syscall then
  958. do_syscall
  959. else
  960. begin
  961. { Calling interrupt from the same code requires some
  962. extra code }
  963. if (po_interrupt in procdefinition.procoptions) then
  964. extra_interrupt_code;
  965. extra_call_code;
  966. retloc.resetiftemp;
  967. if (name_to_call='') then
  968. name_to_call:=tprocdef(procdefinition).mangledname;
  969. if cnf_inherited in callnodeflags then
  970. retloc:=hlcg.a_call_name_inherited(current_asmdata.CurrAsmList,tprocdef(procdefinition),name_to_call,paralocs)
  971. else
  972. retloc:=hlcg.a_call_name(current_asmdata.CurrAsmList,tprocdef(procdefinition),name_to_call,paralocs,typedef,po_weakexternal in procdefinition.procoptions);
  973. extra_post_call_code;
  974. end;
  975. end;
  976. end
  977. else
  978. { now procedure variable case }
  979. begin
  980. secondpass(right);
  981. { can we directly call the procvar in a memory location? }
  982. callref:=false;
  983. if not(po_is_block in procdefinition.procoptions) and
  984. (right.location.loc in [LOC_REFERENCE,LOC_CREFERENCE]) then
  985. begin
  986. href:=right.location.reference;
  987. callref:=can_call_ref(href);
  988. end;
  989. if not callref then
  990. pvreg:=load_procvar_codeptr
  991. else
  992. pvreg:=NR_INVALID;
  993. location_freetemp(current_asmdata.CurrAsmList,right.location);
  994. { Load parameters that are in temporary registers in the
  995. correct parameter register }
  996. if assigned(left) then
  997. begin
  998. reorder_parameters;
  999. pushparas;
  1000. { free the resources allocated for the parameters }
  1001. freeparas;
  1002. end;
  1003. if callref then
  1004. extra_call_ref_code(href);
  1005. cg.alloccpuregisters(current_asmdata.CurrAsmList,R_INTREGISTER,regs_to_save_int);
  1006. if cg.uses_registers(R_ADDRESSREGISTER) then
  1007. cg.alloccpuregisters(current_asmdata.CurrAsmList,R_ADDRESSREGISTER,regs_to_save_address);
  1008. if cg.uses_registers(R_FPUREGISTER) then
  1009. cg.alloccpuregisters(current_asmdata.CurrAsmList,R_FPUREGISTER,regs_to_save_fpu);
  1010. if cg.uses_registers(R_MMREGISTER) then
  1011. cg.alloccpuregisters(current_asmdata.CurrAsmList,R_MMREGISTER,regs_to_save_mm);
  1012. { Calling interrupt from the same code requires some
  1013. extra code }
  1014. if (po_interrupt in procdefinition.procoptions) then
  1015. extra_interrupt_code;
  1016. extra_call_code;
  1017. retloc.resetiftemp;
  1018. if callref then
  1019. retloc:=do_call_ref(href)
  1020. else
  1021. retloc:=hlcg.a_call_reg(current_asmdata.CurrAsmList,procdefinition,pvreg,paralocs);
  1022. extra_post_call_code;
  1023. end;
  1024. { Need to remove the parameters from the stack? }
  1025. if (procdefinition.proccalloption in clearstack_pocalls) then
  1026. begin
  1027. pop_size:=pushedparasize;
  1028. { for Cdecl functions we don't need to pop the funcret when it
  1029. was pushed by para. Except for safecall functions with
  1030. safecall-exceptions enabled. In that case the funcret is always
  1031. returned as a para which is considered a normal para on the
  1032. c-side, so the funcret has to be pop'ed normally. }
  1033. if not ((procdefinition.proccalloption=pocall_safecall) and
  1034. (tf_safecall_exceptions in target_info.flags)) and
  1035. paramanager.ret_in_param(procdefinition.returndef,procdefinition) then
  1036. dec(pop_size,sizeof(pint));
  1037. { Remove parameters/alignment from the stack }
  1038. pop_parasize(pop_size);
  1039. end
  1040. { frame pointer parameter is popped by the caller when it's passed the
  1041. Delphi way }
  1042. else if (po_delphi_nested_cc in procdefinition.procoptions) and
  1043. not paramanager.use_fixed_stack then
  1044. pop_parasize(sizeof(pint));
  1045. { Release registers, but not the registers that contain the
  1046. function result }
  1047. if (not is_void(resultdef)) then
  1048. begin
  1049. retlocitem:=retloc.location;
  1050. while assigned(retlocitem) do
  1051. begin
  1052. case retlocitem^.loc of
  1053. LOC_REGISTER:
  1054. case getregtype(retlocitem^.register) of
  1055. R_INTREGISTER:
  1056. exclude(regs_to_save_int,getsupreg(retlocitem^.register));
  1057. R_ADDRESSREGISTER:
  1058. exclude(regs_to_save_address,getsupreg(retlocitem^.register));
  1059. R_TEMPREGISTER:
  1060. ;
  1061. else
  1062. internalerror(2014020103);
  1063. end;
  1064. LOC_FPUREGISTER:
  1065. exclude(regs_to_save_fpu,getsupreg(retlocitem^.register));
  1066. LOC_MMREGISTER:
  1067. exclude(regs_to_save_mm,getsupreg(retlocitem^.register));
  1068. LOC_REFERENCE,
  1069. LOC_VOID:
  1070. ;
  1071. else
  1072. internalerror(2004110214);
  1073. end;
  1074. retlocitem:=retlocitem^.next;
  1075. end;
  1076. end;
  1077. if cg.uses_registers(R_MMREGISTER) then
  1078. cg.dealloccpuregisters(current_asmdata.CurrAsmList,R_MMREGISTER,regs_to_save_mm);
  1079. if cg.uses_registers(R_FPUREGISTER) then
  1080. cg.dealloccpuregisters(current_asmdata.CurrAsmList,R_FPUREGISTER,regs_to_save_fpu);
  1081. if cg.uses_registers(R_ADDRESSREGISTER) then
  1082. cg.dealloccpuregisters(current_asmdata.CurrAsmList,R_ADDRESSREGISTER,regs_to_save_address);
  1083. cg.dealloccpuregisters(current_asmdata.CurrAsmList,R_INTREGISTER,regs_to_save_int);
  1084. {$ifdef SUPPORT_SAFECALL}
  1085. if (procdefinition.proccalloption=pocall_safecall) and
  1086. (tf_safecall_exceptions in target_info.flags) then
  1087. begin
  1088. pd:=search_system_proc('fpc_safecallcheck');
  1089. cgpara.init;
  1090. paramanager.getintparaloc(pd,1,cgpara);
  1091. cg.a_load_reg_cgpara(current_asmdata.CurrAsmList,OS_INT,NR_FUNCTION_RESULT_REG,cgpara);
  1092. paramanager.freecgpara(current_asmdata.CurrAsmList,cgpara);
  1093. cg.g_call(current_asmdata.CurrAsmList,'FPC_SAFECALLCHECK');
  1094. cgpara.done;
  1095. end;
  1096. {$endif}
  1097. { handle function results }
  1098. if (not is_void(resultdef)) then
  1099. handle_return_value
  1100. else
  1101. location_reset(location,LOC_VOID,OS_NO);
  1102. { convert persistent temps for parameters and function result to normal temps }
  1103. if assigned(callcleanupblock) then
  1104. secondpass(tnode(callcleanupblock));
  1105. { copy back copy-out parameters if any }
  1106. copy_back_paras;
  1107. { release temps and finalize unused return values, must be
  1108. after the callcleanupblock because that converts temps
  1109. from persistent to normal }
  1110. release_unused_return_value;
  1111. { release temps of paras }
  1112. release_para_temps;
  1113. { perhaps i/o check ? }
  1114. if (cs_check_io in current_settings.localswitches) and
  1115. (po_iocheck in procdefinition.procoptions) and
  1116. not(po_iocheck in current_procinfo.procdef.procoptions) and
  1117. { no IO check for methods and procedure variables }
  1118. (right=nil) and
  1119. not(po_virtualmethod in procdefinition.procoptions) then
  1120. begin
  1121. hlcg.g_call_system_proc(current_asmdata.CurrAsmList,'fpc_iocheck',[],nil).resetiftemp;
  1122. end;
  1123. end;
  1124. destructor tcgcallnode.destroy;
  1125. begin
  1126. retloc.resetiftemp;
  1127. inherited destroy;
  1128. end;
  1129. begin
  1130. ccallparanode:=tcgcallparanode;
  1131. ccallnode:=tcgcallnode;
  1132. end.