ncgcal.pas 55 KB

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