ncgcal.pas 55 KB

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