ncgcal.pas 53 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243
  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,cgutils,
  24. symdef,node,ncal;
  25. type
  26. tcgcallparanode = class(tcallparanode)
  27. private
  28. tempcgpara : tcgpara;
  29. procedure push_addr_para;
  30. procedure push_value_para;
  31. public
  32. constructor create(expr,next : tnode);override;
  33. destructor destroy;override;
  34. procedure secondcallparan;override;
  35. end;
  36. tcgcallnode = class(tcallnode)
  37. private
  38. retloc: tlocation;
  39. procedure handle_return_value;
  40. procedure release_unused_return_value;
  41. procedure release_para_temps;
  42. procedure pushparas;
  43. procedure freeparas;
  44. protected
  45. framepointer_paraloc : tcgpara;
  46. {# This routine is used to push the current frame pointer
  47. on the stack. This is used in nested routines where the
  48. value of the frame pointer is always pushed as an extra
  49. parameter.
  50. The default handling is the standard handling used on
  51. most stack based machines, where the frame pointer is
  52. the first invisible parameter.
  53. }
  54. procedure pop_parasize(pop_size:longint);virtual;
  55. procedure extra_interrupt_code;virtual;
  56. procedure extra_call_code;virtual;
  57. procedure extra_post_call_code;virtual;
  58. procedure do_syscall;virtual;abstract;
  59. public
  60. procedure pass_generate_code;override;
  61. end;
  62. implementation
  63. uses
  64. systems,
  65. cutils,verbose,globals,
  66. cpuinfo,
  67. symconst,symtable,defutil,paramgr,
  68. cgbase,pass_2,
  69. aasmbase,aasmtai,aasmdata,
  70. nbas,nmem,nld,ncnv,nutils,
  71. {$ifdef x86}
  72. cga,cgx86,aasmcpu,
  73. {$endif x86}
  74. ncgutil,
  75. cgobj,tgobj,
  76. procinfo,
  77. wpobase;
  78. {*****************************************************************************
  79. TCGCALLPARANODE
  80. *****************************************************************************}
  81. constructor tcgcallparanode.create(expr,next : tnode);
  82. begin
  83. inherited create(expr,next);
  84. tempcgpara.init;
  85. end;
  86. destructor tcgcallparanode.destroy;
  87. begin
  88. tempcgpara.done;
  89. inherited destroy;
  90. end;
  91. procedure tcgcallparanode.push_addr_para;
  92. begin
  93. if not(left.location.loc in [LOC_CREFERENCE,LOC_REFERENCE]) then
  94. internalerror(200304235);
  95. cg.a_loadaddr_ref_cgpara(current_asmdata.CurrAsmList,left.location.reference,tempcgpara);
  96. end;
  97. procedure tcgcallparanode.push_value_para;
  98. {$ifdef i386}
  99. var
  100. href : treference;
  101. size : longint;
  102. {$endif i386}
  103. begin
  104. { we've nothing to push when the size of the parameter is 0 }
  105. if left.resultdef.size=0 then
  106. exit;
  107. { Move flags and jump in register to make it less complex }
  108. if left.location.loc in [LOC_FLAGS,LOC_JUMP,LOC_SUBSETREG,LOC_CSUBSETREG,LOC_SUBSETREF,LOC_CSUBSETREF] then
  109. location_force_reg(current_asmdata.CurrAsmList,left.location,def_cgsize(left.resultdef),false);
  110. { Handle Floating point types differently
  111. This doesn't depend on emulator settings, emulator settings should
  112. be handled by cpupara }
  113. if left.resultdef.typ=floatdef then
  114. begin
  115. {$ifdef i386}
  116. if tempcgpara.location^.loc<>LOC_REFERENCE then
  117. internalerror(200309291);
  118. case left.location.loc of
  119. LOC_FPUREGISTER,
  120. LOC_CFPUREGISTER:
  121. begin
  122. size:=align(TCGSize2Size[left.location.size],tempcgpara.alignment);
  123. if tempcgpara.location^.reference.index=NR_STACK_POINTER_REG then
  124. begin
  125. cg.g_stackpointer_alloc(current_asmdata.CurrAsmList,size);
  126. reference_reset_base(href,NR_STACK_POINTER_REG,0,sizeof(pint));
  127. end
  128. else
  129. reference_reset_base(href,tempcgpara.location^.reference.index,tempcgpara.location^.reference.offset,tempcgpara.alignment);
  130. cg.a_loadfpu_reg_ref(current_asmdata.CurrAsmList,left.location.size,left.location.size,left.location.register,href);
  131. end;
  132. LOC_MMREGISTER,
  133. LOC_CMMREGISTER:
  134. begin
  135. size:=align(tfloatdef(left.resultdef).size,tempcgpara.alignment);
  136. if tempcgpara.location^.reference.index=NR_STACK_POINTER_REG then
  137. begin
  138. cg.g_stackpointer_alloc(current_asmdata.CurrAsmList,size);
  139. reference_reset_base(href,NR_STACK_POINTER_REG,0,sizeof(pint));
  140. end
  141. else
  142. reference_reset_base(href,tempcgpara.location^.reference.index,tempcgpara.location^.reference.offset,tempcgpara.alignment);
  143. cg.a_loadmm_reg_ref(current_asmdata.CurrAsmList,left.location.size,left.location.size,left.location.register,href,mms_movescalar);
  144. end;
  145. LOC_REFERENCE,
  146. LOC_CREFERENCE :
  147. begin
  148. size:=align(left.resultdef.size,tempcgpara.alignment);
  149. if (not use_fixed_stack) and
  150. (tempcgpara.location^.reference.index=NR_STACK_POINTER_REG) then
  151. cg.a_load_ref_cgpara(current_asmdata.CurrAsmList,left.location.size,left.location.reference,tempcgpara)
  152. else
  153. begin
  154. reference_reset_base(href,tempcgpara.location^.reference.index,tempcgpara.location^.reference.offset,tempcgpara.alignment);
  155. cg.g_concatcopy(current_asmdata.CurrAsmList,left.location.reference,href,size);
  156. end;
  157. end;
  158. else
  159. internalerror(2002042430);
  160. end;
  161. {$else i386}
  162. case left.location.loc of
  163. LOC_MMREGISTER,
  164. LOC_CMMREGISTER:
  165. case tempcgpara.location^.loc of
  166. LOC_REFERENCE,
  167. LOC_CREFERENCE,
  168. LOC_MMREGISTER,
  169. LOC_CMMREGISTER,
  170. LOC_REGISTER,
  171. LOC_CREGISTER :
  172. cg.a_loadmm_reg_cgpara(current_asmdata.CurrAsmList,left.location.size,left.location.register,tempcgpara,mms_movescalar);
  173. LOC_FPUREGISTER,
  174. LOC_CFPUREGISTER:
  175. begin
  176. location_force_fpureg(current_asmdata.CurrAsmList,left.location,false);
  177. cg.a_loadfpu_reg_cgpara(current_asmdata.CurrAsmList,left.location.size,left.location.register,tempcgpara);
  178. end;
  179. else
  180. internalerror(200204249);
  181. end;
  182. LOC_FPUREGISTER,
  183. LOC_CFPUREGISTER:
  184. case tempcgpara.location^.loc of
  185. LOC_MMREGISTER,
  186. LOC_CMMREGISTER:
  187. begin
  188. location_force_mmregscalar(current_asmdata.CurrAsmList,left.location,false);
  189. cg.a_loadmm_reg_cgpara(current_asmdata.CurrAsmList,left.location.size,left.location.register,tempcgpara,mms_movescalar);
  190. end;
  191. { Some targets pass floats in normal registers }
  192. LOC_REGISTER,
  193. LOC_CREGISTER,
  194. LOC_REFERENCE,
  195. LOC_CREFERENCE,
  196. LOC_FPUREGISTER,
  197. LOC_CFPUREGISTER:
  198. cg.a_loadfpu_reg_cgpara(current_asmdata.CurrAsmList,left.location.size,left.location.register,tempcgpara);
  199. else
  200. internalerror(2002042433);
  201. end;
  202. LOC_REFERENCE,
  203. LOC_CREFERENCE:
  204. case tempcgpara.location^.loc of
  205. LOC_MMREGISTER,
  206. LOC_CMMREGISTER:
  207. cg.a_loadmm_ref_cgpara(current_asmdata.CurrAsmList,left.location.size,left.location.reference,tempcgpara,mms_movescalar);
  208. {$ifdef cpu64bitalu}
  209. LOC_REGISTER,
  210. LOC_CREGISTER :
  211. begin
  212. { force integer size }
  213. left.location.size:=int_cgsize(tcgsize2size[left.location.size]);
  214. cg.a_load_ref_cgpara(current_asmdata.CurrAsmList,left.location.size,left.location.reference,tempcgpara);
  215. end;
  216. {$endif cpu64bitalu}
  217. {$ifdef powerpc}
  218. { x86_64 pushes s64comp in normal register }
  219. LOC_REGISTER,
  220. LOC_CREGISTER :
  221. begin
  222. { force integer size }
  223. left.location.size:=int_cgsize(tcgsize2size[left.location.size]);
  224. if (left.location.size in [OS_32,OS_S32]) then
  225. cg.a_load_ref_cgpara(current_asmdata.CurrAsmList,left.location.size,left.location.reference,tempcgpara)
  226. else
  227. cg64.a_load64_ref_cgpara(current_asmdata.CurrAsmList,left.location.reference,tempcgpara);
  228. end;
  229. {$endif powerpc}
  230. {$if defined(sparc) or defined(arm) or defined(m68k)}
  231. { sparc and arm pass floats in normal registers }
  232. LOC_REGISTER,
  233. LOC_CREGISTER,
  234. {$endif}
  235. LOC_REFERENCE,
  236. LOC_CREFERENCE,
  237. LOC_FPUREGISTER,
  238. LOC_CFPUREGISTER:
  239. cg.a_loadfpu_ref_cgpara(current_asmdata.CurrAsmList,left.location.size,left.location.reference,tempcgpara);
  240. else
  241. internalerror(2002042431);
  242. end;
  243. LOC_REGISTER,
  244. LOC_CREGISTER :
  245. begin
  246. {$ifndef cpu64bitalu}
  247. { use cg64 only for int64, not for 8 byte records }
  248. if is_64bit(left.resultdef) then
  249. cg64.a_load64_loc_cgpara(current_asmdata.CurrAsmList,left.location,tempcgpara)
  250. else
  251. {$endif not cpu64bitalu}
  252. begin
  253. {$ifndef cpu64bitalu}
  254. { Only a_load_ref_cgpara supports multiple locations, when the
  255. value is still a const or in a register then write it
  256. to a reference first. This situation can be triggered
  257. by typecasting an int64 constant to a record of 8 bytes }
  258. if left.location.size in [OS_64,OS_S64] then
  259. location_force_mem(current_asmdata.CurrAsmList,left.location);
  260. {$endif not cpu64bitalu}
  261. cg.a_load_loc_cgpara(current_asmdata.CurrAsmList,left.location,tempcgpara);
  262. end;
  263. end;
  264. else
  265. internalerror(2002042432);
  266. end;
  267. {$endif i386}
  268. end
  269. else
  270. begin
  271. case left.location.loc of
  272. LOC_CONSTANT,
  273. LOC_REGISTER,
  274. LOC_CREGISTER,
  275. LOC_REFERENCE,
  276. LOC_CREFERENCE :
  277. begin
  278. {$ifndef cpu64bitalu}
  279. { use cg64 only for int64, not for 8 byte records }
  280. if is_64bit(left.resultdef) then
  281. cg64.a_load64_loc_cgpara(current_asmdata.CurrAsmList,left.location,tempcgpara)
  282. else
  283. {$endif not cpu64bitalu}
  284. begin
  285. {$ifndef cpu64bitalu}
  286. { Only a_load_ref_cgpara supports multiple locations, when the
  287. value is still a const or in a register then write it
  288. to a reference first. This situation can be triggered
  289. by typecasting an int64 constant to a record of 8 bytes }
  290. if left.location.size in [OS_64,OS_S64] then
  291. location_force_mem(current_asmdata.CurrAsmList,left.location);
  292. {$endif not cpu64bitalu}
  293. cg.a_load_loc_cgpara(current_asmdata.CurrAsmList,left.location,tempcgpara);
  294. end;
  295. end;
  296. {$ifdef SUPPORT_MMX}
  297. LOC_MMXREGISTER,
  298. LOC_CMMXREGISTER:
  299. cg.a_loadmm_reg_cgpara(current_asmdata.CurrAsmList,OS_M64,left.location.register,tempcgpara,nil);
  300. {$endif SUPPORT_MMX}
  301. else
  302. internalerror(200204241);
  303. end;
  304. end;
  305. end;
  306. procedure tcgcallparanode.secondcallparan;
  307. var
  308. href : treference;
  309. otlabel,
  310. oflabel : tasmlabel;
  311. begin
  312. if not(assigned(parasym)) then
  313. internalerror(200304242);
  314. { Skip nothingn nodes which are used after disabling
  315. a parameter }
  316. if (left.nodetype<>nothingn) then
  317. begin
  318. otlabel:=current_procinfo.CurrTrueLabel;
  319. oflabel:=current_procinfo.CurrFalseLabel;
  320. current_asmdata.getjumplabel(current_procinfo.CurrTrueLabel);
  321. current_asmdata.getjumplabel(current_procinfo.CurrFalseLabel);
  322. secondpass(left);
  323. maybechangeloadnodereg(current_asmdata.CurrAsmList,left,true);
  324. { release memory for refcnt out parameters }
  325. if (parasym.varspez=vs_out) and
  326. (left.resultdef.needs_inittable) then
  327. begin
  328. location_get_data_ref(current_asmdata.CurrAsmList,left.location,href,false,sizeof(pint));
  329. cg.g_decrrefcount(current_asmdata.CurrAsmList,left.resultdef,href);
  330. end;
  331. paramanager.createtempparaloc(current_asmdata.CurrAsmList,aktcallnode.procdefinition.proccalloption,parasym,tempcgpara);
  332. { handle varargs first, because parasym is not valid }
  333. if (cpf_varargs_para in callparaflags) then
  334. begin
  335. if paramanager.push_addr_param(vs_value,left.resultdef,
  336. aktcallnode.procdefinition.proccalloption) then
  337. push_addr_para
  338. else
  339. push_value_para;
  340. end
  341. { hidden parameters }
  342. else if (vo_is_hidden_para in parasym.varoptions) then
  343. begin
  344. { don't push a node that already generated a pointer type
  345. by address for implicit hidden parameters }
  346. if (vo_is_funcret in parasym.varoptions) or
  347. { pass "this" in C++ classes explicitly as pointer
  348. because push_addr_param might not be true for them }
  349. (is_cppclass(parasym.vardef) and (vo_is_self in parasym.varoptions)) or
  350. (not(left.resultdef.typ in [pointerdef,classrefdef]) and
  351. paramanager.push_addr_param(parasym.varspez,parasym.vardef,
  352. aktcallnode.procdefinition.proccalloption)) then
  353. push_addr_para
  354. else
  355. push_value_para;
  356. end
  357. { formal def }
  358. else if (parasym.vardef.typ=formaldef) then
  359. begin
  360. { allow passing of a constant to a const formaldef }
  361. if (parasym.varspez=vs_const) and
  362. (left.location.loc in [LOC_CONSTANT,LOC_REGISTER]) then
  363. location_force_mem(current_asmdata.CurrAsmList,left.location);
  364. push_addr_para;
  365. end
  366. { Normal parameter }
  367. else
  368. begin
  369. { don't push a node that already generated a pointer type
  370. by address for implicit hidden parameters }
  371. if (not(
  372. (vo_is_hidden_para in parasym.varoptions) and
  373. (left.resultdef.typ in [pointerdef,classrefdef])
  374. ) and
  375. paramanager.push_addr_param(parasym.varspez,parasym.vardef,
  376. aktcallnode.procdefinition.proccalloption)) and
  377. { dyn. arrays passed to an array of const must be passed by value, see tests/webtbs/tw4219.pp }
  378. not(
  379. is_array_of_const(parasym.vardef) and
  380. is_dynamic_array(left.resultdef)
  381. ) then
  382. begin
  383. { Passing a var parameter to a var parameter, we can
  384. just push the address transparently }
  385. if (left.nodetype=loadn) and
  386. (tloadnode(left).is_addr_param_load) then
  387. begin
  388. if (left.location.reference.index<>NR_NO) or
  389. (left.location.reference.offset<>0) then
  390. internalerror(200410107);
  391. cg.a_load_reg_cgpara(current_asmdata.CurrAsmList,OS_ADDR,left.location.reference.base,tempcgpara)
  392. end
  393. else
  394. begin
  395. { Force to be in memory }
  396. if not(left.location.loc in [LOC_CREFERENCE,LOC_REFERENCE]) then
  397. location_force_mem(current_asmdata.CurrAsmList,left.location);
  398. push_addr_para;
  399. end;
  400. end
  401. else
  402. push_value_para;
  403. end;
  404. current_procinfo.CurrTrueLabel:=otlabel;
  405. current_procinfo.CurrFalseLabel:=oflabel;
  406. { update return location in callnode when this is the function
  407. result }
  408. if assigned(parasym) and
  409. (vo_is_funcret in parasym.varoptions) then
  410. location_copy(aktcallnode.location,left.location);
  411. end;
  412. { next parameter }
  413. if assigned(right) then
  414. tcallparanode(right).secondcallparan;
  415. end;
  416. {*****************************************************************************
  417. TCGCALLNODE
  418. *****************************************************************************}
  419. procedure tcgcallnode.extra_interrupt_code;
  420. begin
  421. end;
  422. procedure tcgcallnode.extra_call_code;
  423. begin
  424. end;
  425. procedure tcgcallnode.extra_post_call_code;
  426. begin
  427. end;
  428. procedure tcgcallnode.pop_parasize(pop_size:longint);
  429. begin
  430. end;
  431. procedure tcgcallnode.handle_return_value;
  432. var
  433. tmpcgsize,
  434. cgsize : tcgsize;
  435. {$ifdef cpu64bitaddr}
  436. ref : treference;
  437. {$endif cpu64bitaddr}
  438. {$ifndef x86}
  439. hregister : tregister;
  440. {$endif not x86}
  441. begin
  442. { Check that the return location is set when the result is passed in
  443. a parameter }
  444. if (procdefinition.proctypeoption<>potype_constructor) and
  445. paramanager.ret_in_param(resultdef,procdefinition.proccalloption) then
  446. begin
  447. if location.loc<>LOC_REFERENCE then
  448. internalerror(200304241);
  449. exit;
  450. end;
  451. { Load normal (ordinal,float,pointer) result value from accumulator }
  452. cgsize:=retloc.size;
  453. case retloc.loc of
  454. LOC_FPUREGISTER:
  455. begin
  456. location_reset(location,LOC_FPUREGISTER,cgsize);
  457. location.register:=retloc.register;
  458. {$ifdef x86}
  459. tcgx86(cg).inc_fpu_stack;
  460. {$else x86}
  461. { Do not move the physical register to a virtual one in case
  462. the return value is not used, because if the virtual one is
  463. then mapped to the same register as the physical one, we will
  464. end up with two deallocs of this register (one inserted here,
  465. one inserted by the register allocator), which unbalances the
  466. register allocation information. The return register(s) will
  467. be freed by location_free() in release_unused_return_value
  468. (mantis #13536). }
  469. if (cnf_return_value_used in callnodeflags) then
  470. begin
  471. if getsupreg(retloc.register)<first_fpu_imreg then
  472. cg.ungetcpuregister(current_asmdata.CurrAsmList,retloc.register);
  473. hregister:=cg.getfpuregister(current_asmdata.CurrAsmList,location.size);
  474. cg.a_loadfpu_reg_reg(current_asmdata.CurrAsmList,location.size,location.size,location.register,hregister);
  475. location.register:=hregister;
  476. end;
  477. {$endif x86}
  478. end;
  479. LOC_REGISTER:
  480. begin
  481. if cgsize<>OS_NO then
  482. begin
  483. location_reset(location,LOC_REGISTER,cgsize);
  484. {$ifdef cpu64bitaddr}
  485. { x86-64 system v abi:
  486. structs with up to 16 bytes are returned in registers }
  487. if cgsize in [OS_128,OS_S128] then
  488. begin
  489. if retloc.loc<>LOC_REGISTER then
  490. internalerror(2009042001);
  491. { See #13536 comment above. }
  492. if (cnf_return_value_used in callnodeflags) then
  493. begin
  494. tg.GetTemp(current_asmdata.CurrAsmList,16,8,tt_normal,ref);
  495. location_reset_ref(location,LOC_REFERENCE,OS_NO,0);
  496. location.reference:=ref;
  497. if getsupreg(retloc.register)<first_int_imreg then
  498. cg.ungetcpuregister(current_asmdata.CurrAsmList,retloc.register);
  499. cg.a_load_reg_ref(current_asmdata.CurrAsmList,OS_64,OS_64,retloc.register,ref);
  500. inc(ref.offset,8);
  501. if getsupreg(retloc.registerhi)<first_int_imreg then
  502. cg.ungetcpuregister(current_asmdata.CurrAsmList,retloc.registerhi);
  503. cg.a_load_reg_ref(current_asmdata.CurrAsmList,OS_64,OS_64,retloc.registerhi,ref);
  504. end
  505. else
  506. location:=retloc;
  507. end
  508. else
  509. {$else cpu64bitaddr}
  510. if cgsize in [OS_64,OS_S64] then
  511. begin
  512. if retloc.loc<>LOC_REGISTER then
  513. internalerror(200409141);
  514. { See #13536 comment above. }
  515. if (cnf_return_value_used in callnodeflags) then
  516. begin
  517. { the function result registers are already allocated }
  518. if getsupreg(retloc.register64.reglo)<first_int_imreg then
  519. cg.ungetcpuregister(current_asmdata.CurrAsmList,retloc.register64.reglo);
  520. location.register64.reglo:=cg.getintregister(current_asmdata.CurrAsmList,OS_32);
  521. cg.a_load_reg_reg(current_asmdata.CurrAsmList,OS_32,OS_32,retloc.register64.reglo,location.register64.reglo);
  522. if getsupreg(retloc.register64.reghi)<first_int_imreg then
  523. cg.ungetcpuregister(current_asmdata.CurrAsmList,retloc.register64.reghi);
  524. location.register64.reghi:=cg.getintregister(current_asmdata.CurrAsmList,OS_32);
  525. cg.a_load_reg_reg(current_asmdata.CurrAsmList,OS_32,OS_32,retloc.register64.reghi,location.register64.reghi);
  526. end
  527. else
  528. location:=retloc;
  529. end
  530. else
  531. {$endif not cpu64bitaddr}
  532. begin
  533. { change register size after the unget because the
  534. getregister was done for the full register
  535. def_cgsize(resultdef) is used here because
  536. it could be a constructor call }
  537. { See #13536 comment above. }
  538. if (cnf_return_value_used in callnodeflags) then
  539. begin
  540. if getsupreg(retloc.register)<first_int_imreg then
  541. cg.ungetcpuregister(current_asmdata.CurrAsmList,retloc.register);
  542. { but use def_size only if it returns something valid because in
  543. case of odd sized structured results in registers def_cgsize(resultdef)
  544. could return OS_NO }
  545. if def_cgsize(resultdef)<>OS_NO then
  546. tmpcgsize:=def_cgsize(resultdef)
  547. else
  548. tmpcgsize:=cgsize;
  549. location.register:=cg.getintregister(current_asmdata.CurrAsmList,tmpcgsize);
  550. cg.a_load_reg_reg(current_asmdata.CurrAsmList,cgsize,tmpcgsize,retloc.register,location.register);
  551. end
  552. else
  553. location:=retloc;
  554. end;
  555. {$ifdef arm}
  556. if (resultdef.typ=floatdef) and (current_settings.fputype in [fpu_fpa,fpu_fpa10,fpu_fpa11]) then
  557. begin
  558. location_force_mem(current_asmdata.CurrAsmList,location);
  559. end;
  560. {$endif arm}
  561. end
  562. else
  563. begin
  564. if resultdef.size>0 then
  565. internalerror(200305131);
  566. end;
  567. end;
  568. LOC_MMREGISTER:
  569. begin
  570. { See #13536 comment above. }
  571. if (cnf_return_value_used in callnodeflags) then
  572. begin
  573. location_reset(location,LOC_MMREGISTER,cgsize);
  574. if getsupreg(retloc.register)<first_mm_imreg then
  575. cg.ungetcpuregister(current_asmdata.CurrAsmList,retloc.register);
  576. location.register:=cg.getmmregister(current_asmdata.CurrAsmList,cgsize);
  577. cg.a_loadmm_reg_reg(current_asmdata.CurrAsmList,cgsize,cgsize,retloc.register,location.register,mms_movescalar);
  578. end
  579. else
  580. location:=retloc;
  581. end;
  582. else
  583. internalerror(200405023);
  584. end;
  585. { copy value to the final location if this was already provided to the
  586. callnode. This must be done after the call node, because the location can
  587. also be used as parameter and may not be finalized yet }
  588. if assigned(funcretnode) then
  589. begin
  590. funcretnode.pass_generate_code;
  591. { Decrease refcount for refcounted types, this can be skipped when
  592. we have used a temp, because then it is already done from tempcreatenode.
  593. Also no finalize is needed, because there is no risk of exceptions from the
  594. function since this is code is only executed after the function call has returned }
  595. if funcretnode.resultdef.needs_inittable and
  596. (funcretnode.nodetype<>temprefn) then
  597. cg.g_decrrefcount(current_asmdata.CurrAsmList,funcretnode.resultdef,funcretnode.location.reference);
  598. case location.loc of
  599. LOC_REGISTER :
  600. {$ifndef cpu64bitalu}
  601. if cgsize in [OS_64,OS_S64] then
  602. cg64.a_load64_reg_loc(current_asmdata.CurrAsmList,location.register64,funcretnode.location)
  603. else
  604. {$endif}
  605. cg.a_load_reg_loc(current_asmdata.CurrAsmList,cgsize,location.register,funcretnode.location);
  606. LOC_REFERENCE:
  607. begin
  608. case funcretnode.location.loc of
  609. LOC_REGISTER:
  610. cg.a_load_ref_reg(current_asmdata.CurrAsmList,cgsize,cgsize,location.reference,funcretnode.location.register);
  611. LOC_REFERENCE:
  612. cg.g_concatcopy(current_asmdata.CurrAsmList,location.reference,funcretnode.location.reference,resultdef.size);
  613. else
  614. internalerror(200802121);
  615. end;
  616. end;
  617. else
  618. internalerror(200709085);
  619. end;
  620. location := funcretnode.location;
  621. end;
  622. end;
  623. procedure tcgcallnode.release_unused_return_value;
  624. begin
  625. { When the result is not used we need to finalize the result and
  626. can release the temp. This need to be after the callcleanupblock
  627. tree is generated, because that converts the temp from persistent to normal }
  628. if not(cnf_return_value_used in callnodeflags) then
  629. begin
  630. case location.loc of
  631. LOC_REFERENCE :
  632. begin
  633. if resultdef.needs_inittable then
  634. cg.g_finalize(current_asmdata.CurrAsmList,resultdef,location.reference);
  635. tg.ungetiftemp(current_asmdata.CurrAsmList,location.reference);
  636. end;
  637. {$ifdef x86}
  638. LOC_FPUREGISTER :
  639. begin
  640. { release FPU stack }
  641. emit_reg(A_FSTP,S_NO,NR_FPU_RESULT_REG);
  642. tcgx86(cg).dec_fpu_stack;
  643. end;
  644. {$endif x86}
  645. end;
  646. if retloc.size<>OS_NO then
  647. location_free(current_asmdata.CurrAsmList,retloc);
  648. location_reset(location,LOC_VOID,OS_NO);
  649. end;
  650. end;
  651. procedure tcgcallnode.release_para_temps;
  652. var
  653. hp,
  654. hp2 : tnode;
  655. ppn : tcallparanode;
  656. begin
  657. { Release temps from parameters }
  658. ppn:=tcallparanode(left);
  659. while assigned(ppn) do
  660. begin
  661. if assigned(ppn.left) then
  662. begin
  663. { don't release the funcret temp }
  664. if not(assigned(ppn.parasym)) or
  665. not(vo_is_funcret in ppn.parasym.varoptions) then
  666. location_freetemp(current_asmdata.CurrAsmList,ppn.left.location);
  667. { process also all nodes of an array of const }
  668. hp:=ppn.left;
  669. while (hp.nodetype=typeconvn) do
  670. hp:=ttypeconvnode(hp).left;
  671. if (hp.nodetype=arrayconstructorn) and
  672. assigned(tarrayconstructornode(hp).left) then
  673. begin
  674. while assigned(hp) do
  675. begin
  676. hp2:=tarrayconstructornode(hp).left;
  677. { ignore typeconvs and addrn inserted by arrayconstructn for
  678. passing a shortstring }
  679. if (hp2.nodetype=typeconvn) and
  680. (tunarynode(hp2).left.nodetype=addrn) then
  681. hp2:=tunarynode(tunarynode(hp2).left).left;
  682. location_freetemp(current_asmdata.CurrAsmList,hp2.location);
  683. hp:=tarrayconstructornode(hp).right;
  684. end;
  685. end;
  686. end;
  687. ppn:=tcallparanode(ppn.right);
  688. end;
  689. end;
  690. procedure tcgcallnode.pushparas;
  691. var
  692. ppn : tcgcallparanode;
  693. callerparaloc,
  694. tmpparaloc : pcgparalocation;
  695. sizeleft: aint;
  696. htempref,
  697. href : treference;
  698. calleralignment,
  699. tmpalignment: longint;
  700. begin
  701. { copy all resources to the allocated registers }
  702. ppn:=tcgcallparanode(left);
  703. while assigned(ppn) do
  704. begin
  705. if (ppn.left.nodetype<>nothingn) then
  706. begin
  707. { better check for the real location of the parameter here, when stack passed parameters
  708. are saved temporary in registers, checking for the tmpparaloc.loc is wrong
  709. }
  710. paramanager.freeparaloc(current_asmdata.CurrAsmList,ppn.tempcgpara);
  711. tmpparaloc:=ppn.tempcgpara.location;
  712. sizeleft:=ppn.tempcgpara.intsize;
  713. calleralignment:=ppn.parasym.paraloc[callerside].alignment;
  714. tmpalignment:=ppn.tempcgpara.alignment;
  715. if (tmpalignment=0) or
  716. (calleralignment=0) then
  717. internalerror(2009020701);
  718. callerparaloc:=ppn.parasym.paraloc[callerside].location;
  719. while assigned(callerparaloc) do
  720. begin
  721. { Every paraloc must have a matching tmpparaloc }
  722. if not assigned(tmpparaloc) then
  723. internalerror(200408224);
  724. if callerparaloc^.size<>tmpparaloc^.size then
  725. internalerror(200408225);
  726. case callerparaloc^.loc of
  727. LOC_REGISTER:
  728. begin
  729. if tmpparaloc^.loc<>LOC_REGISTER then
  730. internalerror(200408221);
  731. if getsupreg(callerparaloc^.register)<first_int_imreg then
  732. cg.getcpuregister(current_asmdata.CurrAsmList,callerparaloc^.register);
  733. cg.a_load_reg_reg(current_asmdata.CurrAsmList,tmpparaloc^.size,tmpparaloc^.size,
  734. tmpparaloc^.register,callerparaloc^.register);
  735. end;
  736. LOC_FPUREGISTER:
  737. begin
  738. if tmpparaloc^.loc<>LOC_FPUREGISTER then
  739. internalerror(200408222);
  740. if getsupreg(callerparaloc^.register)<first_fpu_imreg then
  741. cg.getcpuregister(current_asmdata.CurrAsmList,callerparaloc^.register);
  742. cg.a_loadfpu_reg_reg(current_asmdata.CurrAsmList,tmpparaloc^.size,ppn.tempcgpara.size,tmpparaloc^.register,callerparaloc^.register);
  743. end;
  744. LOC_MMREGISTER:
  745. begin
  746. if tmpparaloc^.loc<>LOC_MMREGISTER then
  747. internalerror(200408223);
  748. if getsupreg(callerparaloc^.register)<first_mm_imreg then
  749. cg.getcpuregister(current_asmdata.CurrAsmList,callerparaloc^.register);
  750. cg.a_loadmm_reg_reg(current_asmdata.CurrAsmList,tmpparaloc^.size,tmpparaloc^.size,
  751. tmpparaloc^.register,callerparaloc^.register,mms_movescalar);
  752. end;
  753. LOC_REFERENCE:
  754. begin
  755. if use_fixed_stack then
  756. begin
  757. { Can't have a data copied to the stack, every location
  758. must contain a valid size field }
  759. if (ppn.tempcgpara.size=OS_NO) and
  760. ((tmpparaloc^.loc<>LOC_REFERENCE) or
  761. assigned(tmpparaloc^.next)) then
  762. internalerror(200501281);
  763. reference_reset_base(href,callerparaloc^.reference.index,callerparaloc^.reference.offset,calleralignment);
  764. { copy parameters in case they were moved to a temp. location because we've a fixed stack }
  765. case tmpparaloc^.loc of
  766. LOC_REFERENCE:
  767. begin
  768. reference_reset_base(htempref,tmpparaloc^.reference.index,tmpparaloc^.reference.offset,tmpalignment);
  769. { use concatcopy, because it can also be a float which fails when
  770. load_ref_ref is used }
  771. if (ppn.tempcgpara.size <> OS_NO) then
  772. cg.g_concatcopy(current_asmdata.CurrAsmList,htempref,href,tcgsize2size[tmpparaloc^.size])
  773. else
  774. cg.g_concatcopy(current_asmdata.CurrAsmList,htempref,href,sizeleft)
  775. end;
  776. LOC_REGISTER:
  777. cg.a_load_reg_ref(current_asmdata.CurrAsmList,tmpparaloc^.size,tmpparaloc^.size,tmpparaloc^.register,href);
  778. LOC_FPUREGISTER:
  779. cg.a_loadfpu_reg_ref(current_asmdata.CurrAsmList,tmpparaloc^.size,tmpparaloc^.size,tmpparaloc^.register,href);
  780. LOC_MMREGISTER:
  781. cg.a_loadmm_reg_ref(current_asmdata.CurrAsmList,tmpparaloc^.size,tmpparaloc^.size,tmpparaloc^.register,href,mms_movescalar);
  782. else
  783. internalerror(200402081);
  784. end;
  785. end;
  786. end;
  787. end;
  788. dec(sizeleft,tcgsize2size[tmpparaloc^.size]);
  789. callerparaloc:=callerparaloc^.next;
  790. tmpparaloc:=tmpparaloc^.next;
  791. end;
  792. end;
  793. ppn:=tcgcallparanode(ppn.right);
  794. end;
  795. end;
  796. procedure tcgcallnode.freeparas;
  797. var
  798. ppn : tcgcallparanode;
  799. begin
  800. { free the resources allocated for the parameters }
  801. ppn:=tcgcallparanode(left);
  802. while assigned(ppn) do
  803. begin
  804. if (ppn.left.nodetype<>nothingn) then
  805. begin
  806. if (ppn.parasym.paraloc[callerside].location^.loc <> LOC_REFERENCE) then
  807. paramanager.freeparaloc(current_asmdata.CurrAsmList,ppn.parasym.paraloc[callerside]);
  808. end;
  809. ppn:=tcgcallparanode(ppn.right);
  810. end;
  811. end;
  812. procedure tcgcallnode.pass_generate_code;
  813. var
  814. name_to_call: shortstring;
  815. regs_to_save_int,
  816. regs_to_save_fpu,
  817. regs_to_save_mm : Tcpuregisterset;
  818. href : treference;
  819. pop_size : longint;
  820. vmtoffset : aint;
  821. pvreg,
  822. vmtreg : tregister;
  823. oldaktcallnode : tcallnode;
  824. {$ifdef vtentry}
  825. sym : tasmsymbol;
  826. {$endif vtentry}
  827. {$ifdef x86_64}
  828. cgpara : tcgpara;
  829. {$endif x86_64}
  830. begin
  831. if not assigned(procdefinition) or
  832. not procdefinition.has_paraloc_info then
  833. internalerror(200305264);
  834. if assigned(callinitblock) then
  835. secondpass(tnode(callinitblock));
  836. regs_to_save_int:=paramanager.get_volatile_registers_int(procdefinition.proccalloption);
  837. regs_to_save_fpu:=paramanager.get_volatile_registers_fpu(procdefinition.proccalloption);
  838. regs_to_save_mm:=paramanager.get_volatile_registers_mm(procdefinition.proccalloption);
  839. { Include Function result registers }
  840. if (not is_void(resultdef)) then
  841. begin
  842. { The forced returntype may have a different size than the one
  843. declared for the procdef }
  844. if not assigned(typedef) then
  845. retloc:=procdefinition.funcretloc[callerside]
  846. else
  847. retloc:=paramanager.get_funcretloc(procdefinition,callerside,typedef);
  848. case retloc.loc of
  849. LOC_REGISTER,
  850. LOC_CREGISTER:
  851. begin
  852. {$ifdef cpu64bitaddr}
  853. { x86-64 system v abi:
  854. structs with up to 16 bytes are returned in registers }
  855. if retloc.size in [OS_128,OS_S128] then
  856. begin
  857. include(regs_to_save_int,getsupreg(retloc.register));
  858. include(regs_to_save_int,getsupreg(retloc.registerhi));
  859. end
  860. else
  861. {$else cpu64bitaddr}
  862. if retloc.size in [OS_64,OS_S64] then
  863. begin
  864. include(regs_to_save_int,getsupreg(retloc.register64.reglo));
  865. include(regs_to_save_int,getsupreg(retloc.register64.reghi));
  866. end
  867. else
  868. {$endif not cpu64bitaddr}
  869. include(regs_to_save_int,getsupreg(retloc.register));
  870. end;
  871. LOC_FPUREGISTER,
  872. LOC_CFPUREGISTER:
  873. begin
  874. include(regs_to_save_fpu,getsupreg(retloc.register));
  875. {$ifdef SPARC}
  876. { SPARC uses two successive single precision fpu registers
  877. for double-precision values }
  878. if retloc.size=OS_F64 then
  879. include(regs_to_save_fpu,succ(getsupreg(retloc.register)));
  880. {$endif SPARC}
  881. end;
  882. LOC_MMREGISTER,
  883. LOC_CMMREGISTER:
  884. include(regs_to_save_mm,getsupreg(retloc.register));
  885. LOC_REFERENCE,
  886. LOC_VOID:
  887. ;
  888. else
  889. internalerror(2004110213);
  890. end;
  891. end;
  892. { Process parameters, register parameters will be loaded
  893. in imaginary registers. The actual load to the correct
  894. register is done just before the call }
  895. oldaktcallnode:=aktcallnode;
  896. aktcallnode:=self;
  897. if assigned(left) then
  898. tcallparanode(left).secondcallparan;
  899. aktcallnode:=oldaktcallnode;
  900. { procedure variable or normal function call ? }
  901. if (right=nil) then
  902. begin
  903. { register call for WPO (must be done before wpo test below,
  904. otherwise optimised called methods are no longer registered)
  905. }
  906. if (po_virtualmethod in procdefinition.procoptions) and
  907. assigned(methodpointer) and
  908. (methodpointer.nodetype<>typen) and
  909. (not assigned(current_procinfo) or
  910. wpoinfomanager.symbol_live(current_procinfo.procdef.mangledname)) then
  911. tprocdef(procdefinition)._class.register_vmt_call(tprocdef(procdefinition).extnumber);
  912. {$ifdef vtentry}
  913. if not is_interface(tprocdef(procdefinition)._class) then
  914. begin
  915. inc(current_asmdata.NextVTEntryNr);
  916. current_asmdata.CurrAsmList.Concat(tai_symbol.CreateName('VTREF'+tostr(current_asmdata.NextVTEntryNr)+'_'+tprocdef(procdefinition)._class.vmt_mangledname+'$$'+tostr(vmtoffset div sizeof(pint)),AT_FUNCTION,0));
  917. end;
  918. {$endif vtentry}
  919. name_to_call:='';
  920. if assigned(fobjcforcedprocname) then
  921. name_to_call:=fobjcforcedprocname^;
  922. { When methodpointer is typen we don't need (and can't) load
  923. a pointer. We can directly call the correct procdef (PFV) }
  924. if (name_to_call='') and
  925. (po_virtualmethod in procdefinition.procoptions) and
  926. assigned(methodpointer) and
  927. (methodpointer.nodetype<>typen) and
  928. not wpoinfomanager.can_be_devirtualized(methodpointer.resultdef,procdefinition,name_to_call) then
  929. begin
  930. { virtual methods require an index }
  931. if tprocdef(procdefinition).extnumber=$ffff then
  932. internalerror(200304021);
  933. secondpass(methodpointer);
  934. { Load VMT from self }
  935. if methodpointer.resultdef.typ=objectdef then
  936. gen_load_vmt_register(current_asmdata.CurrAsmList,tobjectdef(methodpointer.resultdef),methodpointer.location,vmtreg)
  937. else
  938. begin
  939. { Load VMT value in register }
  940. location_force_reg(current_asmdata.CurrAsmList,methodpointer.location,OS_ADDR,false);
  941. vmtreg:=methodpointer.location.register;
  942. end;
  943. { test validity of VMT }
  944. if not(is_interface(tprocdef(procdefinition)._class)) and
  945. not(is_cppclass(tprocdef(procdefinition)._class)) then
  946. cg.g_maybe_testvmt(current_asmdata.CurrAsmList,vmtreg,tprocdef(procdefinition)._class);
  947. { Call through VMT, generate a VTREF symbol to notify the linker }
  948. vmtoffset:=tprocdef(procdefinition)._class.vmtmethodoffset(tprocdef(procdefinition).extnumber);
  949. { register call for WPO }
  950. if (not assigned(current_procinfo) or
  951. wpoinfomanager.symbol_live(current_procinfo.procdef.mangledname)) then
  952. tprocdef(procdefinition)._class.register_vmt_call(tprocdef(procdefinition).extnumber);
  953. {$ifndef x86}
  954. pvreg:=cg.getintregister(current_asmdata.CurrAsmList,OS_ADDR);
  955. {$endif not x86}
  956. reference_reset_base(href,vmtreg,vmtoffset,sizeof(pint));
  957. {$ifndef x86}
  958. cg.a_load_ref_reg(current_asmdata.CurrAsmList,OS_ADDR,OS_ADDR,href,pvreg);
  959. {$endif not x86}
  960. { Load parameters that are in temporary registers in the
  961. correct parameter register }
  962. if assigned(left) then
  963. begin
  964. pushparas;
  965. { free the resources allocated for the parameters }
  966. freeparas;
  967. end;
  968. cg.alloccpuregisters(current_asmdata.CurrAsmList,R_INTREGISTER,regs_to_save_int);
  969. if cg.uses_registers(R_FPUREGISTER) then
  970. cg.alloccpuregisters(current_asmdata.CurrAsmList,R_FPUREGISTER,regs_to_save_fpu);
  971. if cg.uses_registers(R_MMREGISTER) then
  972. cg.alloccpuregisters(current_asmdata.CurrAsmList,R_MMREGISTER,regs_to_save_mm);
  973. { call method }
  974. extra_call_code;
  975. {$ifdef x86}
  976. cg.a_call_ref(current_asmdata.CurrAsmList,href);
  977. {$else x86}
  978. cg.a_call_reg(current_asmdata.CurrAsmList,pvreg);
  979. {$endif x86}
  980. extra_post_call_code;
  981. end
  982. else
  983. begin
  984. { Load parameters that are in temporary registers in the
  985. correct parameter register }
  986. if assigned(left) then
  987. begin
  988. pushparas;
  989. { free the resources allocated for the parameters }
  990. freeparas;
  991. end;
  992. cg.alloccpuregisters(current_asmdata.CurrAsmList,R_INTREGISTER,regs_to_save_int);
  993. if cg.uses_registers(R_FPUREGISTER) then
  994. cg.alloccpuregisters(current_asmdata.CurrAsmList,R_FPUREGISTER,regs_to_save_fpu);
  995. if cg.uses_registers(R_MMREGISTER) then
  996. cg.alloccpuregisters(current_asmdata.CurrAsmList,R_MMREGISTER,regs_to_save_mm);
  997. if procdefinition.proccalloption=pocall_syscall then
  998. do_syscall
  999. else
  1000. begin
  1001. { Calling interrupt from the same code requires some
  1002. extra code }
  1003. if (po_interrupt in procdefinition.procoptions) then
  1004. extra_interrupt_code;
  1005. extra_call_code;
  1006. if (name_to_call='') then
  1007. cg.a_call_name(current_asmdata.CurrAsmList,tprocdef(procdefinition).mangledname,po_weakexternal in procdefinition.procoptions)
  1008. else
  1009. cg.a_call_name(current_asmdata.CurrAsmList,name_to_call,po_weakexternal in procdefinition.procoptions);
  1010. extra_post_call_code;
  1011. end;
  1012. end;
  1013. end
  1014. else
  1015. { now procedure variable case }
  1016. begin
  1017. secondpass(right);
  1018. pvreg:=cg.getintregister(current_asmdata.CurrAsmList,OS_ADDR);
  1019. { Only load OS_ADDR from the reference }
  1020. if right.location.loc in [LOC_REFERENCE,LOC_CREFERENCE] then
  1021. cg.a_load_ref_reg(current_asmdata.CurrAsmList,OS_ADDR,OS_ADDR,right.location.reference,pvreg)
  1022. else
  1023. cg.a_load_loc_reg(current_asmdata.CurrAsmList,OS_ADDR,right.location,pvreg);
  1024. location_freetemp(current_asmdata.CurrAsmList,right.location);
  1025. { Load parameters that are in temporary registers in the
  1026. correct parameter register }
  1027. if assigned(left) then
  1028. begin
  1029. pushparas;
  1030. { free the resources allocated for the parameters }
  1031. freeparas;
  1032. end;
  1033. cg.alloccpuregisters(current_asmdata.CurrAsmList,R_INTREGISTER,regs_to_save_int);
  1034. if cg.uses_registers(R_FPUREGISTER) then
  1035. cg.alloccpuregisters(current_asmdata.CurrAsmList,R_FPUREGISTER,regs_to_save_fpu);
  1036. if cg.uses_registers(R_MMREGISTER) then
  1037. cg.alloccpuregisters(current_asmdata.CurrAsmList,R_MMREGISTER,regs_to_save_mm);
  1038. { Calling interrupt from the same code requires some
  1039. extra code }
  1040. if (po_interrupt in procdefinition.procoptions) then
  1041. extra_interrupt_code;
  1042. extra_call_code;
  1043. cg.a_call_reg(current_asmdata.CurrAsmList,pvreg);
  1044. extra_post_call_code;
  1045. end;
  1046. { Need to remove the parameters from the stack? }
  1047. if (procdefinition.proccalloption in clearstack_pocalls) then
  1048. begin
  1049. pop_size:=pushedparasize;
  1050. { for Cdecl functions we don't need to pop the funcret when it
  1051. was pushed by para }
  1052. if paramanager.ret_in_param(procdefinition.returndef,procdefinition.proccalloption) then
  1053. dec(pop_size,sizeof(pint));
  1054. { Remove parameters/alignment from the stack }
  1055. pop_parasize(pop_size);
  1056. end;
  1057. { Release registers, but not the registers that contain the
  1058. function result }
  1059. if (not is_void(resultdef)) then
  1060. begin
  1061. case retloc.loc of
  1062. LOC_REGISTER,
  1063. LOC_CREGISTER:
  1064. begin
  1065. {$ifndef cpu64bitalu}
  1066. if retloc.size in [OS_64,OS_S64] then
  1067. begin
  1068. exclude(regs_to_save_int,getsupreg(retloc.register64.reghi));
  1069. exclude(regs_to_save_int,getsupreg(retloc.register64.reglo));
  1070. end
  1071. {$else not cpu64bitalu}
  1072. if retloc.size in [OS_128,OS_S128] then
  1073. begin
  1074. exclude(regs_to_save_int,getsupreg(retloc.register));
  1075. exclude(regs_to_save_int,getsupreg(retloc.registerhi));
  1076. end
  1077. {$endif not cpu64bitalu}
  1078. else
  1079. exclude(regs_to_save_int,getsupreg(retloc.register));
  1080. end;
  1081. LOC_FPUREGISTER,
  1082. LOC_CFPUREGISTER:
  1083. exclude(regs_to_save_fpu,getsupreg(retloc.register));
  1084. LOC_MMREGISTER,
  1085. LOC_CMMREGISTER:
  1086. exclude(regs_to_save_mm,getsupreg(retloc.register));
  1087. LOC_REFERENCE,
  1088. LOC_VOID:
  1089. ;
  1090. else
  1091. internalerror(2004110214);
  1092. end;
  1093. end;
  1094. {$if defined(x86) or defined(arm)}
  1095. if (procdefinition.proccalloption=pocall_safecall) and
  1096. (target_info.system in systems_all_windows) then
  1097. begin
  1098. {$ifdef x86_64}
  1099. cgpara.init;
  1100. paramanager.getintparaloc(pocall_default,1,cgpara);
  1101. cg.a_load_reg_cgpara(current_asmdata.CurrAsmList,OS_ADDR,NR_RAX,cgpara);
  1102. cgpara.done;
  1103. {$endif x86_64}
  1104. cg.allocallcpuregisters(current_asmdata.CurrAsmList);
  1105. cg.a_call_name(current_asmdata.CurrAsmList,'FPC_SAFECALLCHECK',false);
  1106. cg.deallocallcpuregisters(current_asmdata.CurrAsmList);
  1107. end;
  1108. {$endif}
  1109. if cg.uses_registers(R_MMREGISTER) then
  1110. cg.dealloccpuregisters(current_asmdata.CurrAsmList,R_MMREGISTER,regs_to_save_mm);
  1111. if cg.uses_registers(R_FPUREGISTER) then
  1112. cg.dealloccpuregisters(current_asmdata.CurrAsmList,R_FPUREGISTER,regs_to_save_fpu);
  1113. cg.dealloccpuregisters(current_asmdata.CurrAsmList,R_INTREGISTER,regs_to_save_int);
  1114. { handle function results }
  1115. if (not is_void(resultdef)) then
  1116. handle_return_value
  1117. else
  1118. location_reset(location,LOC_VOID,OS_NO);
  1119. { convert persistent temps for parameters and function result to normal temps }
  1120. if assigned(callcleanupblock) then
  1121. secondpass(tnode(callcleanupblock));
  1122. { release temps and finalize unused return values, must be
  1123. after the callcleanupblock because that converts temps
  1124. from persistent to normal }
  1125. release_unused_return_value;
  1126. { release temps of paras }
  1127. release_para_temps;
  1128. { perhaps i/o check ? }
  1129. if (cs_check_io in current_settings.localswitches) and
  1130. (po_iocheck in procdefinition.procoptions) and
  1131. not(po_iocheck in current_procinfo.procdef.procoptions) and
  1132. { no IO check for methods and procedure variables }
  1133. (right=nil) and
  1134. not(po_virtualmethod in procdefinition.procoptions) then
  1135. begin
  1136. cg.allocallcpuregisters(current_asmdata.CurrAsmList);
  1137. cg.a_call_name(current_asmdata.CurrAsmList,'FPC_IOCHECK',false);
  1138. cg.deallocallcpuregisters(current_asmdata.CurrAsmList);
  1139. end;
  1140. end;
  1141. begin
  1142. ccallparanode:=tcgcallparanode;
  1143. ccallnode:=tcgcallnode;
  1144. end.