ncgcal.pas 54 KB

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