ncgcal.pas 51 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179
  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. if getsupreg(procdefinition.funcretloc[callerside].register)<first_fpu_imreg then
  494. cg.ungetcpuregister(current_asmdata.CurrAsmList,procdefinition.funcretloc[callerside].register);
  495. hregister:=cg.getfpuregister(current_asmdata.CurrAsmList,location.size);
  496. cg.a_loadfpu_reg_reg(current_asmdata.CurrAsmList,location.size,location.size,location.register,hregister);
  497. location.register:=hregister;
  498. {$endif x86}
  499. end;
  500. LOC_REGISTER:
  501. begin
  502. if cgsize<>OS_NO then
  503. begin
  504. location_reset(location,LOC_REGISTER,cgsize);
  505. {$ifdef cpu64bitaddr}
  506. { x86-64 system v abi:
  507. structs with up to 16 bytes are returned in registers }
  508. if cgsize in [OS_128,OS_S128] then
  509. begin
  510. tg.GetTemp(current_asmdata.CurrAsmList,16,8,tt_normal,ref);
  511. location_reset_ref(location,LOC_REFERENCE,OS_NO,0);
  512. location.reference:=ref;
  513. cg.a_load_reg_ref(current_asmdata.CurrAsmList,OS_64,OS_64,procdefinition.funcretloc[callerside].register,ref);
  514. inc(ref.offset,8);
  515. cg.a_load_reg_ref(current_asmdata.CurrAsmList,OS_64,OS_64,procdefinition.funcretloc[callerside].registerhi,ref);
  516. end
  517. else
  518. {$else cpu64bitaddr}
  519. if cgsize in [OS_64,OS_S64] then
  520. begin
  521. retloc:=procdefinition.funcretloc[callerside];
  522. if retloc.loc<>LOC_REGISTER then
  523. internalerror(200409141);
  524. { the function result registers are already allocated }
  525. if getsupreg(retloc.register64.reglo)<first_int_imreg then
  526. cg.ungetcpuregister(current_asmdata.CurrAsmList,retloc.register64.reglo);
  527. location.register64.reglo:=cg.getintregister(current_asmdata.CurrAsmList,OS_32);
  528. cg.a_load_reg_reg(current_asmdata.CurrAsmList,OS_32,OS_32,retloc.register64.reglo,location.register64.reglo);
  529. if getsupreg(retloc.register64.reghi)<first_int_imreg then
  530. cg.ungetcpuregister(current_asmdata.CurrAsmList,retloc.register64.reghi);
  531. location.register64.reghi:=cg.getintregister(current_asmdata.CurrAsmList,OS_32);
  532. cg.a_load_reg_reg(current_asmdata.CurrAsmList,OS_32,OS_32,retloc.register64.reghi,location.register64.reghi);
  533. end
  534. else
  535. {$endif not cpu64bitaddr}
  536. begin
  537. { change register size after the unget because the
  538. getregister was done for the full register
  539. def_cgsize(resultdef) is used here because
  540. it could be a constructor call }
  541. if getsupreg(procdefinition.funcretloc[callerside].register)<first_int_imreg then
  542. cg.ungetcpuregister(current_asmdata.CurrAsmList,procdefinition.funcretloc[callerside].register);
  543. { but use def_size only if it returns something valid because in
  544. case of odd sized structured results in registers def_cgsize(resultdef)
  545. could return OS_NO }
  546. if def_cgsize(resultdef)<>OS_NO then
  547. tmpcgsize:=def_cgsize(resultdef)
  548. else
  549. tmpcgsize:=cgsize;
  550. location.register:=cg.getintregister(current_asmdata.CurrAsmList,tmpcgsize);
  551. cg.a_load_reg_reg(current_asmdata.CurrAsmList,cgsize,tmpcgsize,procdefinition.funcretloc[callerside].register,location.register);
  552. end;
  553. {$ifdef arm}
  554. if (resultdef.typ=floatdef) and (current_settings.fputype in [fpu_fpa,fpu_fpa10,fpu_fpa11]) then
  555. begin
  556. location_force_mem(current_asmdata.CurrAsmList,location);
  557. end;
  558. {$endif arm}
  559. end
  560. else
  561. begin
  562. if resultdef.size>0 then
  563. internalerror(200305131);
  564. end;
  565. end;
  566. LOC_MMREGISTER:
  567. begin
  568. location_reset(location,LOC_MMREGISTER,cgsize);
  569. if getsupreg(procdefinition.funcretloc[callerside].register)<first_mm_imreg then
  570. cg.ungetcpuregister(current_asmdata.CurrAsmList,procdefinition.funcretloc[callerside].register);
  571. location.register:=cg.getmmregister(current_asmdata.CurrAsmList,cgsize);
  572. cg.a_loadmm_reg_reg(current_asmdata.CurrAsmList,cgsize,cgsize,procdefinition.funcretloc[callerside].register,location.register,mms_movescalar);
  573. end;
  574. else
  575. internalerror(200405023);
  576. end;
  577. { copy value to the final location if this was already provided to the
  578. callnode. This must be done after the call node, because the location can
  579. also be used as parameter and may not be finalized yet }
  580. if assigned(funcretnode) then
  581. begin
  582. funcretnode.pass_generate_code;
  583. { Decrease refcount for refcounted types, this can be skipped when
  584. we have used a temp, because then it is already done from tempcreatenode.
  585. Also no finalize is needed, because there is no risk of exceptions from the
  586. function since this is code is only executed after the function call has returned }
  587. if funcretnode.resultdef.needs_inittable and
  588. (funcretnode.nodetype<>temprefn) then
  589. cg.g_decrrefcount(current_asmdata.CurrAsmList,funcretnode.resultdef,funcretnode.location.reference);
  590. case location.loc of
  591. LOC_REGISTER :
  592. {$ifndef cpu64bitalu}
  593. if cgsize in [OS_64,OS_S64] then
  594. cg64.a_load64_reg_loc(current_asmdata.CurrAsmList,location.register64,funcretnode.location)
  595. else
  596. {$endif}
  597. cg.a_load_reg_loc(current_asmdata.CurrAsmList,cgsize,location.register,funcretnode.location);
  598. LOC_REFERENCE:
  599. begin
  600. case funcretnode.location.loc of
  601. LOC_REGISTER:
  602. cg.a_load_ref_reg(current_asmdata.CurrAsmList,cgsize,cgsize,location.reference,funcretnode.location.register);
  603. LOC_REFERENCE:
  604. cg.g_concatcopy(current_asmdata.CurrAsmList,location.reference,funcretnode.location.reference,resultdef.size);
  605. else
  606. internalerror(200802121);
  607. end;
  608. end;
  609. else
  610. internalerror(200709085);
  611. end;
  612. location := funcretnode.location;
  613. end;
  614. end;
  615. procedure tcgcallnode.release_unused_return_value;
  616. begin
  617. { When the result is not used we need to finalize the result and
  618. can release the temp. This need to be after the callcleanupblock
  619. tree is generated, because that converts the temp from persistent to normal }
  620. if not(cnf_return_value_used in callnodeflags) then
  621. begin
  622. case location.loc of
  623. LOC_REFERENCE :
  624. begin
  625. if resultdef.needs_inittable then
  626. cg.g_finalize(current_asmdata.CurrAsmList,resultdef,location.reference);
  627. tg.ungetiftemp(current_asmdata.CurrAsmList,location.reference);
  628. end;
  629. {$ifdef x86}
  630. LOC_FPUREGISTER :
  631. begin
  632. { release FPU stack }
  633. emit_reg(A_FSTP,S_NO,NR_FPU_RESULT_REG);
  634. tcgx86(cg).dec_fpu_stack;
  635. end;
  636. {$endif x86}
  637. end;
  638. if procdefinition.funcretloc[callerside].size<>OS_NO then
  639. location_free(current_asmdata.CurrAsmList,procdefinition.funcretloc[callerside]);
  640. location_reset(location,LOC_VOID,OS_NO);
  641. end;
  642. end;
  643. procedure tcgcallnode.release_para_temps;
  644. var
  645. hp,
  646. hp2 : tnode;
  647. ppn : tcallparanode;
  648. begin
  649. { Release temps from parameters }
  650. ppn:=tcallparanode(left);
  651. while assigned(ppn) do
  652. begin
  653. if assigned(ppn.left) then
  654. begin
  655. { don't release the funcret temp }
  656. if not(assigned(ppn.parasym)) or
  657. not(vo_is_funcret in ppn.parasym.varoptions) then
  658. location_freetemp(current_asmdata.CurrAsmList,ppn.left.location);
  659. { process also all nodes of an array of const }
  660. hp:=ppn.left;
  661. while (hp.nodetype=typeconvn) do
  662. hp:=ttypeconvnode(hp).left;
  663. if (hp.nodetype=arrayconstructorn) and
  664. assigned(tarrayconstructornode(hp).left) then
  665. begin
  666. while assigned(hp) do
  667. begin
  668. hp2:=tarrayconstructornode(hp).left;
  669. { ignore typeconvs and addrn inserted by arrayconstructn for
  670. passing a shortstring }
  671. if (hp2.nodetype=typeconvn) and
  672. (tunarynode(hp2).left.nodetype=addrn) then
  673. hp2:=tunarynode(tunarynode(hp2).left).left;
  674. location_freetemp(current_asmdata.CurrAsmList,hp2.location);
  675. hp:=tarrayconstructornode(hp).right;
  676. end;
  677. end;
  678. end;
  679. ppn:=tcallparanode(ppn.right);
  680. end;
  681. end;
  682. procedure tcgcallnode.pushparas;
  683. var
  684. ppn : tcgcallparanode;
  685. callerparaloc,
  686. tmpparaloc : pcgparalocation;
  687. sizeleft: aint;
  688. htempref,
  689. href : treference;
  690. calleralignment,
  691. tmpalignment: longint;
  692. begin
  693. { copy all resources to the allocated registers }
  694. ppn:=tcgcallparanode(left);
  695. while assigned(ppn) do
  696. begin
  697. if (ppn.left.nodetype<>nothingn) then
  698. begin
  699. { better check for the real location of the parameter here, when stack passed parameters
  700. are saved temporary in registers, checking for the tmpparaloc.loc is wrong
  701. }
  702. paramanager.freeparaloc(current_asmdata.CurrAsmList,ppn.tempcgpara);
  703. tmpparaloc:=ppn.tempcgpara.location;
  704. sizeleft:=ppn.tempcgpara.intsize;
  705. calleralignment:=ppn.parasym.paraloc[callerside].alignment;
  706. tmpalignment:=ppn.tempcgpara.alignment;
  707. if (tmpalignment=0) or
  708. (calleralignment=0) then
  709. internalerror(2009020701);
  710. callerparaloc:=ppn.parasym.paraloc[callerside].location;
  711. while assigned(callerparaloc) do
  712. begin
  713. { Every paraloc must have a matching tmpparaloc }
  714. if not assigned(tmpparaloc) then
  715. internalerror(200408224);
  716. if callerparaloc^.size<>tmpparaloc^.size then
  717. internalerror(200408225);
  718. case callerparaloc^.loc of
  719. LOC_REGISTER:
  720. begin
  721. if tmpparaloc^.loc<>LOC_REGISTER then
  722. internalerror(200408221);
  723. if getsupreg(callerparaloc^.register)<first_int_imreg then
  724. cg.getcpuregister(current_asmdata.CurrAsmList,callerparaloc^.register);
  725. cg.a_load_reg_reg(current_asmdata.CurrAsmList,tmpparaloc^.size,tmpparaloc^.size,
  726. tmpparaloc^.register,callerparaloc^.register);
  727. end;
  728. LOC_FPUREGISTER:
  729. begin
  730. if tmpparaloc^.loc<>LOC_FPUREGISTER then
  731. internalerror(200408222);
  732. if getsupreg(callerparaloc^.register)<first_fpu_imreg then
  733. cg.getcpuregister(current_asmdata.CurrAsmList,callerparaloc^.register);
  734. cg.a_loadfpu_reg_reg(current_asmdata.CurrAsmList,tmpparaloc^.size,ppn.tempcgpara.size,tmpparaloc^.register,callerparaloc^.register);
  735. end;
  736. LOC_MMREGISTER:
  737. begin
  738. if tmpparaloc^.loc<>LOC_MMREGISTER then
  739. internalerror(200408223);
  740. if getsupreg(callerparaloc^.register)<first_mm_imreg then
  741. cg.getcpuregister(current_asmdata.CurrAsmList,callerparaloc^.register);
  742. cg.a_loadmm_reg_reg(current_asmdata.CurrAsmList,tmpparaloc^.size,tmpparaloc^.size,
  743. tmpparaloc^.register,callerparaloc^.register,mms_movescalar);
  744. end;
  745. LOC_REFERENCE:
  746. begin
  747. if use_fixed_stack then
  748. begin
  749. { Can't have a data copied to the stack, every location
  750. must contain a valid size field }
  751. if (ppn.tempcgpara.size=OS_NO) and
  752. ((tmpparaloc^.loc<>LOC_REFERENCE) or
  753. assigned(tmpparaloc^.next)) then
  754. internalerror(200501281);
  755. reference_reset_base(href,callerparaloc^.reference.index,callerparaloc^.reference.offset,calleralignment);
  756. { copy parameters in case they were moved to a temp. location because we've a fixed stack }
  757. case tmpparaloc^.loc of
  758. LOC_REFERENCE:
  759. begin
  760. reference_reset_base(htempref,tmpparaloc^.reference.index,tmpparaloc^.reference.offset,tmpalignment);
  761. { use concatcopy, because it can also be a float which fails when
  762. load_ref_ref is used }
  763. if (ppn.tempcgpara.size <> OS_NO) then
  764. cg.g_concatcopy(current_asmdata.CurrAsmList,htempref,href,tcgsize2size[tmpparaloc^.size])
  765. else
  766. cg.g_concatcopy(current_asmdata.CurrAsmList,htempref,href,sizeleft)
  767. end;
  768. LOC_REGISTER:
  769. cg.a_load_reg_ref(current_asmdata.CurrAsmList,tmpparaloc^.size,tmpparaloc^.size,tmpparaloc^.register,href);
  770. LOC_FPUREGISTER:
  771. cg.a_loadfpu_reg_ref(current_asmdata.CurrAsmList,tmpparaloc^.size,tmpparaloc^.size,tmpparaloc^.register,href);
  772. LOC_MMREGISTER:
  773. cg.a_loadmm_reg_ref(current_asmdata.CurrAsmList,tmpparaloc^.size,tmpparaloc^.size,tmpparaloc^.register,href,mms_movescalar);
  774. else
  775. internalerror(200402081);
  776. end;
  777. end;
  778. end;
  779. end;
  780. dec(sizeleft,tcgsize2size[tmpparaloc^.size]);
  781. callerparaloc:=callerparaloc^.next;
  782. tmpparaloc:=tmpparaloc^.next;
  783. end;
  784. end;
  785. ppn:=tcgcallparanode(ppn.right);
  786. end;
  787. end;
  788. procedure tcgcallnode.freeparas;
  789. var
  790. ppn : tcgcallparanode;
  791. begin
  792. { free the resources allocated for the parameters }
  793. ppn:=tcgcallparanode(left);
  794. while assigned(ppn) do
  795. begin
  796. if (ppn.left.nodetype<>nothingn) then
  797. begin
  798. if (ppn.parasym.paraloc[callerside].location^.loc <> LOC_REFERENCE) then
  799. paramanager.freeparaloc(current_asmdata.CurrAsmList,ppn.parasym.paraloc[callerside]);
  800. end;
  801. ppn:=tcgcallparanode(ppn.right);
  802. end;
  803. end;
  804. procedure tcgcallnode.pass_generate_code;
  805. var
  806. name_to_call: shortstring;
  807. regs_to_save_int,
  808. regs_to_save_fpu,
  809. regs_to_save_mm : Tcpuregisterset;
  810. href : treference;
  811. pop_size : longint;
  812. vmtoffset : aint;
  813. pvreg,
  814. vmtreg : tregister;
  815. oldaktcallnode : tcallnode;
  816. {$ifdef vtentry}
  817. sym : tasmsymbol;
  818. {$endif vtentry}
  819. {$ifdef x86_64}
  820. cgpara : tcgpara;
  821. {$endif x86_64}
  822. begin
  823. if not assigned(procdefinition) or
  824. not procdefinition.has_paraloc_info then
  825. internalerror(200305264);
  826. if assigned(callinitblock) then
  827. secondpass(callinitblock);
  828. regs_to_save_int:=paramanager.get_volatile_registers_int(procdefinition.proccalloption);
  829. regs_to_save_fpu:=paramanager.get_volatile_registers_fpu(procdefinition.proccalloption);
  830. regs_to_save_mm:=paramanager.get_volatile_registers_mm(procdefinition.proccalloption);
  831. { Include Function result registers }
  832. if (not is_void(resultdef)) then
  833. begin
  834. case procdefinition.funcretloc[callerside].loc of
  835. LOC_REGISTER,
  836. LOC_CREGISTER:
  837. include(regs_to_save_int,getsupreg(procdefinition.funcretloc[callerside].register));
  838. LOC_FPUREGISTER,
  839. LOC_CFPUREGISTER:
  840. include(regs_to_save_fpu,getsupreg(procdefinition.funcretloc[callerside].register));
  841. LOC_MMREGISTER,
  842. LOC_CMMREGISTER:
  843. include(regs_to_save_mm,getsupreg(procdefinition.funcretloc[callerside].register));
  844. LOC_REFERENCE,
  845. LOC_VOID:
  846. ;
  847. else
  848. internalerror(2004110213);
  849. end;
  850. end;
  851. { Process parameters, register parameters will be loaded
  852. in imaginary registers. The actual load to the correct
  853. register is done just before the call }
  854. oldaktcallnode:=aktcallnode;
  855. aktcallnode:=self;
  856. if assigned(left) then
  857. tcallparanode(left).secondcallparan;
  858. aktcallnode:=oldaktcallnode;
  859. { procedure variable or normal function call ? }
  860. if (right=nil) then
  861. begin
  862. name_to_call:='';
  863. { When methodpointer is typen we don't need (and can't) load
  864. a pointer. We can directly call the correct procdef (PFV) }
  865. if (po_virtualmethod in procdefinition.procoptions) and
  866. assigned(methodpointer) and
  867. (methodpointer.nodetype<>typen) and
  868. not wpoinfomanager.can_be_devirtualized(methodpointer.resultdef,procdefinition,name_to_call) then
  869. begin
  870. { virtual methods require an index }
  871. if tprocdef(procdefinition).extnumber=$ffff then
  872. internalerror(200304021);
  873. secondpass(methodpointer);
  874. { Load VMT from self }
  875. if methodpointer.resultdef.typ=objectdef then
  876. gen_load_vmt_register(current_asmdata.CurrAsmList,tobjectdef(methodpointer.resultdef),methodpointer.location,vmtreg)
  877. else
  878. begin
  879. { Load VMT value in register }
  880. location_force_reg(current_asmdata.CurrAsmList,methodpointer.location,OS_ADDR,false);
  881. vmtreg:=methodpointer.location.register;
  882. end;
  883. { test validity of VMT }
  884. if not(is_interface(tprocdef(procdefinition)._class)) and
  885. not(is_cppclass(tprocdef(procdefinition)._class)) then
  886. cg.g_maybe_testvmt(current_asmdata.CurrAsmList,vmtreg,tprocdef(procdefinition)._class);
  887. { Call through VMT, generate a VTREF symbol to notify the linker }
  888. vmtoffset:=tprocdef(procdefinition)._class.vmtmethodoffset(tprocdef(procdefinition).extnumber);
  889. {$ifdef vtentry}
  890. if not is_interface(tprocdef(procdefinition)._class) then
  891. begin
  892. inc(current_asmdata.NextVTEntryNr);
  893. 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));
  894. end;
  895. {$endif vtentry}
  896. {$ifndef x86}
  897. pvreg:=cg.getintregister(current_asmdata.CurrAsmList,OS_ADDR);
  898. {$endif not x86}
  899. reference_reset_base(href,vmtreg,vmtoffset,sizeof(pint));
  900. {$ifndef x86}
  901. cg.a_load_ref_reg(current_asmdata.CurrAsmList,OS_ADDR,OS_ADDR,href,pvreg);
  902. {$endif not x86}
  903. { Load parameters that are in temporary registers in the
  904. correct parameter register }
  905. if assigned(left) then
  906. begin
  907. pushparas;
  908. { free the resources allocated for the parameters }
  909. freeparas;
  910. end;
  911. cg.alloccpuregisters(current_asmdata.CurrAsmList,R_INTREGISTER,regs_to_save_int);
  912. if cg.uses_registers(R_FPUREGISTER) then
  913. cg.alloccpuregisters(current_asmdata.CurrAsmList,R_FPUREGISTER,regs_to_save_fpu);
  914. if cg.uses_registers(R_MMREGISTER) then
  915. cg.alloccpuregisters(current_asmdata.CurrAsmList,R_MMREGISTER,regs_to_save_mm);
  916. { call method }
  917. extra_call_code;
  918. {$ifdef x86}
  919. cg.a_call_ref(current_asmdata.CurrAsmList,href);
  920. {$else x86}
  921. cg.a_call_reg(current_asmdata.CurrAsmList,pvreg);
  922. {$endif x86}
  923. extra_post_call_code;
  924. end
  925. else
  926. begin
  927. { Load parameters that are in temporary registers in the
  928. correct parameter register }
  929. if assigned(left) then
  930. begin
  931. pushparas;
  932. { free the resources allocated for the parameters }
  933. freeparas;
  934. end;
  935. cg.alloccpuregisters(current_asmdata.CurrAsmList,R_INTREGISTER,regs_to_save_int);
  936. if cg.uses_registers(R_FPUREGISTER) then
  937. cg.alloccpuregisters(current_asmdata.CurrAsmList,R_FPUREGISTER,regs_to_save_fpu);
  938. if cg.uses_registers(R_MMREGISTER) then
  939. cg.alloccpuregisters(current_asmdata.CurrAsmList,R_MMREGISTER,regs_to_save_mm);
  940. if procdefinition.proccalloption=pocall_syscall then
  941. do_syscall
  942. else
  943. begin
  944. { Calling interrupt from the same code requires some
  945. extra code }
  946. if (po_interrupt in procdefinition.procoptions) then
  947. extra_interrupt_code;
  948. extra_call_code;
  949. if (name_to_call='') then
  950. cg.a_call_name(current_asmdata.CurrAsmList,tprocdef(procdefinition).mangledname,po_weakexternal in procdefinition.procoptions)
  951. else
  952. cg.a_call_name(current_asmdata.CurrAsmList,name_to_call,po_weakexternal in procdefinition.procoptions);
  953. extra_post_call_code;
  954. end;
  955. end;
  956. end
  957. else
  958. { now procedure variable case }
  959. begin
  960. secondpass(right);
  961. pvreg:=cg.getintregister(current_asmdata.CurrAsmList,OS_ADDR);
  962. { Only load OS_ADDR from the reference }
  963. if right.location.loc in [LOC_REFERENCE,LOC_CREFERENCE] then
  964. cg.a_load_ref_reg(current_asmdata.CurrAsmList,OS_ADDR,OS_ADDR,right.location.reference,pvreg)
  965. else
  966. cg.a_load_loc_reg(current_asmdata.CurrAsmList,OS_ADDR,right.location,pvreg);
  967. location_freetemp(current_asmdata.CurrAsmList,right.location);
  968. { Load parameters that are in temporary registers in the
  969. correct parameter register }
  970. if assigned(left) then
  971. begin
  972. pushparas;
  973. { free the resources allocated for the parameters }
  974. freeparas;
  975. end;
  976. cg.alloccpuregisters(current_asmdata.CurrAsmList,R_INTREGISTER,regs_to_save_int);
  977. if cg.uses_registers(R_FPUREGISTER) then
  978. cg.alloccpuregisters(current_asmdata.CurrAsmList,R_FPUREGISTER,regs_to_save_fpu);
  979. if cg.uses_registers(R_MMREGISTER) then
  980. cg.alloccpuregisters(current_asmdata.CurrAsmList,R_MMREGISTER,regs_to_save_mm);
  981. { Calling interrupt from the same code requires some
  982. extra code }
  983. if (po_interrupt in procdefinition.procoptions) then
  984. extra_interrupt_code;
  985. extra_call_code;
  986. cg.a_call_reg(current_asmdata.CurrAsmList,pvreg);
  987. extra_post_call_code;
  988. end;
  989. { Need to remove the parameters from the stack? }
  990. if (procdefinition.proccalloption in clearstack_pocalls) then
  991. begin
  992. pop_size:=pushedparasize;
  993. { for Cdecl functions we don't need to pop the funcret when it
  994. was pushed by para }
  995. if paramanager.ret_in_param(procdefinition.returndef,procdefinition.proccalloption) then
  996. dec(pop_size,sizeof(pint));
  997. { Remove parameters/alignment from the stack }
  998. pop_parasize(pop_size);
  999. end;
  1000. { Release registers, but not the registers that contain the
  1001. function result }
  1002. if (not is_void(resultdef)) then
  1003. begin
  1004. case procdefinition.funcretloc[callerside].loc of
  1005. LOC_REGISTER,
  1006. LOC_CREGISTER:
  1007. begin
  1008. {$ifndef cpu64bitalu}
  1009. if procdefinition.funcretloc[callerside].size in [OS_64,OS_S64] then
  1010. begin
  1011. exclude(regs_to_save_int,getsupreg(procdefinition.funcretloc[callerside].register64.reghi));
  1012. exclude(regs_to_save_int,getsupreg(procdefinition.funcretloc[callerside].register64.reglo));
  1013. end
  1014. else
  1015. {$endif not cpu64bitalu}
  1016. exclude(regs_to_save_int,getsupreg(procdefinition.funcretloc[callerside].register));
  1017. end;
  1018. LOC_FPUREGISTER,
  1019. LOC_CFPUREGISTER:
  1020. exclude(regs_to_save_fpu,getsupreg(procdefinition.funcretloc[callerside].register));
  1021. LOC_MMREGISTER,
  1022. LOC_CMMREGISTER:
  1023. exclude(regs_to_save_mm,getsupreg(procdefinition.funcretloc[callerside].register));
  1024. LOC_REFERENCE,
  1025. LOC_VOID:
  1026. ;
  1027. else
  1028. internalerror(2004110214);
  1029. end;
  1030. end;
  1031. {$if defined(x86) or defined(arm)}
  1032. if (procdefinition.proccalloption=pocall_safecall) and
  1033. (target_info.system in system_all_windows) then
  1034. begin
  1035. {$ifdef x86_64}
  1036. cgpara.init;
  1037. paramanager.getintparaloc(pocall_default,1,cgpara);
  1038. cg.a_param_reg(current_asmdata.CurrAsmList,OS_ADDR,NR_RAX,cgpara);
  1039. cgpara.done;
  1040. {$endif x86_64}
  1041. cg.allocallcpuregisters(current_asmdata.CurrAsmList);
  1042. cg.a_call_name(current_asmdata.CurrAsmList,'FPC_SAFECALLCHECK',false);
  1043. cg.deallocallcpuregisters(current_asmdata.CurrAsmList);
  1044. end;
  1045. {$endif}
  1046. if cg.uses_registers(R_MMREGISTER) then
  1047. cg.dealloccpuregisters(current_asmdata.CurrAsmList,R_MMREGISTER,regs_to_save_mm);
  1048. if cg.uses_registers(R_FPUREGISTER) then
  1049. cg.dealloccpuregisters(current_asmdata.CurrAsmList,R_FPUREGISTER,regs_to_save_fpu);
  1050. cg.dealloccpuregisters(current_asmdata.CurrAsmList,R_INTREGISTER,regs_to_save_int);
  1051. { handle function results }
  1052. if (not is_void(resultdef)) then
  1053. handle_return_value
  1054. else
  1055. location_reset(location,LOC_VOID,OS_NO);
  1056. { convert persistent temps for parameters and function result to normal temps }
  1057. if assigned(callcleanupblock) then
  1058. secondpass(callcleanupblock);
  1059. { release temps and finalize unused return values, must be
  1060. after the callcleanupblock because that converts temps
  1061. from persistent to normal }
  1062. release_unused_return_value;
  1063. { release temps of paras }
  1064. release_para_temps;
  1065. { perhaps i/o check ? }
  1066. if (cs_check_io in current_settings.localswitches) and
  1067. (po_iocheck in procdefinition.procoptions) and
  1068. not(po_iocheck in current_procinfo.procdef.procoptions) and
  1069. { no IO check for methods and procedure variables }
  1070. (right=nil) and
  1071. not(po_virtualmethod in procdefinition.procoptions) then
  1072. begin
  1073. cg.allocallcpuregisters(current_asmdata.CurrAsmList);
  1074. cg.a_call_name(current_asmdata.CurrAsmList,'FPC_IOCHECK',false);
  1075. cg.deallocallcpuregisters(current_asmdata.CurrAsmList);
  1076. end;
  1077. end;
  1078. begin
  1079. ccallparanode:=tcgcallparanode;
  1080. ccallnode:=tcgcallnode;
  1081. end.