ncgcal.pas 50 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172
  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);
  126. end
  127. else
  128. reference_reset_base(href,tempcgpara.location^.reference.index,tempcgpara.location^.reference.offset);
  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);
  139. end
  140. else
  141. reference_reset_base(href,tempcgpara.location^.reference.index,tempcgpara.location^.reference.offset);
  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);
  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);
  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(location,LOC_REFERENCE,OS_NO);
  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. begin
  691. { copy all resources to the allocated registers }
  692. ppn:=tcgcallparanode(left);
  693. while assigned(ppn) do
  694. begin
  695. if (ppn.left.nodetype<>nothingn) then
  696. begin
  697. { better check for the real location of the parameter here, when stack passed parameters
  698. are saved temporary in registers, checking for the tmpparaloc.loc is wrong
  699. }
  700. paramanager.freeparaloc(current_asmdata.CurrAsmList,ppn.tempcgpara);
  701. tmpparaloc:=ppn.tempcgpara.location;
  702. sizeleft:=ppn.tempcgpara.intsize;
  703. callerparaloc:=ppn.parasym.paraloc[callerside].location;
  704. while assigned(callerparaloc) do
  705. begin
  706. { Every paraloc must have a matching tmpparaloc }
  707. if not assigned(tmpparaloc) then
  708. internalerror(200408224);
  709. if callerparaloc^.size<>tmpparaloc^.size then
  710. internalerror(200408225);
  711. case callerparaloc^.loc of
  712. LOC_REGISTER:
  713. begin
  714. if tmpparaloc^.loc<>LOC_REGISTER then
  715. internalerror(200408221);
  716. if getsupreg(callerparaloc^.register)<first_int_imreg then
  717. cg.getcpuregister(current_asmdata.CurrAsmList,callerparaloc^.register);
  718. cg.a_load_reg_reg(current_asmdata.CurrAsmList,tmpparaloc^.size,tmpparaloc^.size,
  719. tmpparaloc^.register,callerparaloc^.register);
  720. end;
  721. LOC_FPUREGISTER:
  722. begin
  723. if tmpparaloc^.loc<>LOC_FPUREGISTER then
  724. internalerror(200408222);
  725. if getsupreg(callerparaloc^.register)<first_fpu_imreg then
  726. cg.getcpuregister(current_asmdata.CurrAsmList,callerparaloc^.register);
  727. cg.a_loadfpu_reg_reg(current_asmdata.CurrAsmList,tmpparaloc^.size,ppn.tempcgpara.size,tmpparaloc^.register,callerparaloc^.register);
  728. end;
  729. LOC_MMREGISTER:
  730. begin
  731. if tmpparaloc^.loc<>LOC_MMREGISTER then
  732. internalerror(200408223);
  733. if getsupreg(callerparaloc^.register)<first_mm_imreg then
  734. cg.getcpuregister(current_asmdata.CurrAsmList,callerparaloc^.register);
  735. cg.a_loadmm_reg_reg(current_asmdata.CurrAsmList,tmpparaloc^.size,tmpparaloc^.size,
  736. tmpparaloc^.register,callerparaloc^.register,mms_movescalar);
  737. end;
  738. LOC_REFERENCE:
  739. begin
  740. if use_fixed_stack then
  741. begin
  742. { Can't have a data copied to the stack, every location
  743. must contain a valid size field }
  744. if (ppn.tempcgpara.size=OS_NO) and
  745. ((tmpparaloc^.loc<>LOC_REFERENCE) or
  746. assigned(tmpparaloc^.next)) then
  747. internalerror(200501281);
  748. reference_reset_base(href,callerparaloc^.reference.index,callerparaloc^.reference.offset);
  749. { copy parameters in case they were moved to a temp. location because we've a fixed stack }
  750. case tmpparaloc^.loc of
  751. LOC_REFERENCE:
  752. begin
  753. reference_reset_base(htempref,tmpparaloc^.reference.index,tmpparaloc^.reference.offset);
  754. { use concatcopy, because it can also be a float which fails when
  755. load_ref_ref is used }
  756. if (ppn.tempcgpara.size <> OS_NO) then
  757. cg.g_concatcopy(current_asmdata.CurrAsmList,htempref,href,tcgsize2size[tmpparaloc^.size])
  758. else
  759. cg.g_concatcopy(current_asmdata.CurrAsmList,htempref,href,sizeleft)
  760. end;
  761. LOC_REGISTER:
  762. cg.a_load_reg_ref(current_asmdata.CurrAsmList,tmpparaloc^.size,tmpparaloc^.size,tmpparaloc^.register,href);
  763. LOC_FPUREGISTER:
  764. cg.a_loadfpu_reg_ref(current_asmdata.CurrAsmList,tmpparaloc^.size,tmpparaloc^.size,tmpparaloc^.register,href);
  765. LOC_MMREGISTER:
  766. cg.a_loadmm_reg_ref(current_asmdata.CurrAsmList,tmpparaloc^.size,tmpparaloc^.size,tmpparaloc^.register,href,mms_movescalar);
  767. else
  768. internalerror(200402081);
  769. end;
  770. end;
  771. end;
  772. end;
  773. dec(sizeleft,tcgsize2size[tmpparaloc^.size]);
  774. callerparaloc:=callerparaloc^.next;
  775. tmpparaloc:=tmpparaloc^.next;
  776. end;
  777. end;
  778. ppn:=tcgcallparanode(ppn.right);
  779. end;
  780. end;
  781. procedure tcgcallnode.freeparas;
  782. var
  783. ppn : tcgcallparanode;
  784. begin
  785. { free the resources allocated for the parameters }
  786. ppn:=tcgcallparanode(left);
  787. while assigned(ppn) do
  788. begin
  789. if (ppn.left.nodetype<>nothingn) then
  790. begin
  791. if (ppn.parasym.paraloc[callerside].location^.loc <> LOC_REFERENCE) then
  792. paramanager.freeparaloc(current_asmdata.CurrAsmList,ppn.parasym.paraloc[callerside]);
  793. end;
  794. ppn:=tcgcallparanode(ppn.right);
  795. end;
  796. end;
  797. procedure tcgcallnode.pass_generate_code;
  798. var
  799. name_to_call: shortstring;
  800. regs_to_save_int,
  801. regs_to_save_fpu,
  802. regs_to_save_mm : Tcpuregisterset;
  803. href : treference;
  804. pop_size : longint;
  805. vmtoffset : aint;
  806. pvreg,
  807. vmtreg : tregister;
  808. oldaktcallnode : tcallnode;
  809. {$ifdef vtentry}
  810. sym : tasmsymbol;
  811. {$endif vtentry}
  812. {$ifdef x86_64}
  813. cgpara : tcgpara;
  814. {$endif x86_64}
  815. begin
  816. if not assigned(procdefinition) or
  817. not procdefinition.has_paraloc_info then
  818. internalerror(200305264);
  819. if assigned(callinitblock) then
  820. secondpass(callinitblock);
  821. regs_to_save_int:=paramanager.get_volatile_registers_int(procdefinition.proccalloption);
  822. regs_to_save_fpu:=paramanager.get_volatile_registers_fpu(procdefinition.proccalloption);
  823. regs_to_save_mm:=paramanager.get_volatile_registers_mm(procdefinition.proccalloption);
  824. { Include Function result registers }
  825. if (not is_void(resultdef)) then
  826. begin
  827. case procdefinition.funcretloc[callerside].loc of
  828. LOC_REGISTER,
  829. LOC_CREGISTER:
  830. include(regs_to_save_int,getsupreg(procdefinition.funcretloc[callerside].register));
  831. LOC_FPUREGISTER,
  832. LOC_CFPUREGISTER:
  833. include(regs_to_save_fpu,getsupreg(procdefinition.funcretloc[callerside].register));
  834. LOC_MMREGISTER,
  835. LOC_CMMREGISTER:
  836. include(regs_to_save_mm,getsupreg(procdefinition.funcretloc[callerside].register));
  837. LOC_REFERENCE,
  838. LOC_VOID:
  839. ;
  840. else
  841. internalerror(2004110213);
  842. end;
  843. end;
  844. { Process parameters, register parameters will be loaded
  845. in imaginary registers. The actual load to the correct
  846. register is done just before the call }
  847. oldaktcallnode:=aktcallnode;
  848. aktcallnode:=self;
  849. if assigned(left) then
  850. tcallparanode(left).secondcallparan;
  851. aktcallnode:=oldaktcallnode;
  852. { procedure variable or normal function call ? }
  853. if (right=nil) then
  854. begin
  855. name_to_call:='';
  856. { When methodpointer is typen we don't need (and can't) load
  857. a pointer. We can directly call the correct procdef (PFV) }
  858. if (po_virtualmethod in procdefinition.procoptions) and
  859. assigned(methodpointer) and
  860. (methodpointer.nodetype<>typen) and
  861. not wpoinfomanager.can_be_devirtualized(methodpointer.resultdef,procdefinition,name_to_call) then
  862. begin
  863. { virtual methods require an index }
  864. if tprocdef(procdefinition).extnumber=$ffff then
  865. internalerror(200304021);
  866. secondpass(methodpointer);
  867. { Load VMT from self }
  868. if methodpointer.resultdef.typ=objectdef then
  869. gen_load_vmt_register(current_asmdata.CurrAsmList,tobjectdef(methodpointer.resultdef),methodpointer.location,vmtreg)
  870. else
  871. begin
  872. { Load VMT value in register }
  873. location_force_reg(current_asmdata.CurrAsmList,methodpointer.location,OS_ADDR,false);
  874. vmtreg:=methodpointer.location.register;
  875. end;
  876. { test validity of VMT }
  877. if not(is_interface(tprocdef(procdefinition)._class)) and
  878. not(is_cppclass(tprocdef(procdefinition)._class)) then
  879. cg.g_maybe_testvmt(current_asmdata.CurrAsmList,vmtreg,tprocdef(procdefinition)._class);
  880. { Call through VMT, generate a VTREF symbol to notify the linker }
  881. vmtoffset:=tprocdef(procdefinition)._class.vmtmethodoffset(tprocdef(procdefinition).extnumber);
  882. {$ifdef vtentry}
  883. if not is_interface(tprocdef(procdefinition)._class) then
  884. begin
  885. inc(current_asmdata.NextVTEntryNr);
  886. 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));
  887. end;
  888. {$endif vtentry}
  889. {$ifndef x86}
  890. pvreg:=cg.getintregister(current_asmdata.CurrAsmList,OS_ADDR);
  891. {$endif not x86}
  892. reference_reset_base(href,vmtreg,vmtoffset);
  893. {$ifndef x86}
  894. cg.a_load_ref_reg(current_asmdata.CurrAsmList,OS_ADDR,OS_ADDR,href,pvreg);
  895. {$endif not x86}
  896. { Load parameters that are in temporary registers in the
  897. correct parameter register }
  898. if assigned(left) then
  899. begin
  900. pushparas;
  901. { free the resources allocated for the parameters }
  902. freeparas;
  903. end;
  904. cg.alloccpuregisters(current_asmdata.CurrAsmList,R_INTREGISTER,regs_to_save_int);
  905. if cg.uses_registers(R_FPUREGISTER) then
  906. cg.alloccpuregisters(current_asmdata.CurrAsmList,R_FPUREGISTER,regs_to_save_fpu);
  907. if cg.uses_registers(R_MMREGISTER) then
  908. cg.alloccpuregisters(current_asmdata.CurrAsmList,R_MMREGISTER,regs_to_save_mm);
  909. { call method }
  910. extra_call_code;
  911. {$ifdef x86}
  912. cg.a_call_ref(current_asmdata.CurrAsmList,href);
  913. {$else x86}
  914. cg.a_call_reg(current_asmdata.CurrAsmList,pvreg);
  915. {$endif x86}
  916. extra_post_call_code;
  917. end
  918. else
  919. begin
  920. { Load parameters that are in temporary registers in the
  921. correct parameter register }
  922. if assigned(left) then
  923. begin
  924. pushparas;
  925. { free the resources allocated for the parameters }
  926. freeparas;
  927. end;
  928. cg.alloccpuregisters(current_asmdata.CurrAsmList,R_INTREGISTER,regs_to_save_int);
  929. if cg.uses_registers(R_FPUREGISTER) then
  930. cg.alloccpuregisters(current_asmdata.CurrAsmList,R_FPUREGISTER,regs_to_save_fpu);
  931. if cg.uses_registers(R_MMREGISTER) then
  932. cg.alloccpuregisters(current_asmdata.CurrAsmList,R_MMREGISTER,regs_to_save_mm);
  933. if procdefinition.proccalloption=pocall_syscall then
  934. do_syscall
  935. else
  936. begin
  937. { Calling interrupt from the same code requires some
  938. extra code }
  939. if (po_interrupt in procdefinition.procoptions) then
  940. extra_interrupt_code;
  941. extra_call_code;
  942. if (name_to_call='') then
  943. cg.a_call_name(current_asmdata.CurrAsmList,tprocdef(procdefinition).mangledname,po_weakexternal in procdefinition.procoptions)
  944. else
  945. cg.a_call_name(current_asmdata.CurrAsmList,name_to_call,po_weakexternal in procdefinition.procoptions);
  946. extra_post_call_code;
  947. end;
  948. end;
  949. end
  950. else
  951. { now procedure variable case }
  952. begin
  953. secondpass(right);
  954. pvreg:=cg.getintregister(current_asmdata.CurrAsmList,OS_ADDR);
  955. { Only load OS_ADDR from the reference }
  956. if right.location.loc in [LOC_REFERENCE,LOC_CREFERENCE] then
  957. cg.a_load_ref_reg(current_asmdata.CurrAsmList,OS_ADDR,OS_ADDR,right.location.reference,pvreg)
  958. else
  959. cg.a_load_loc_reg(current_asmdata.CurrAsmList,OS_ADDR,right.location,pvreg);
  960. location_freetemp(current_asmdata.CurrAsmList,right.location);
  961. { Load parameters that are in temporary registers in the
  962. correct parameter register }
  963. if assigned(left) then
  964. begin
  965. pushparas;
  966. { free the resources allocated for the parameters }
  967. freeparas;
  968. end;
  969. cg.alloccpuregisters(current_asmdata.CurrAsmList,R_INTREGISTER,regs_to_save_int);
  970. if cg.uses_registers(R_FPUREGISTER) then
  971. cg.alloccpuregisters(current_asmdata.CurrAsmList,R_FPUREGISTER,regs_to_save_fpu);
  972. if cg.uses_registers(R_MMREGISTER) then
  973. cg.alloccpuregisters(current_asmdata.CurrAsmList,R_MMREGISTER,regs_to_save_mm);
  974. { Calling interrupt from the same code requires some
  975. extra code }
  976. if (po_interrupt in procdefinition.procoptions) then
  977. extra_interrupt_code;
  978. extra_call_code;
  979. cg.a_call_reg(current_asmdata.CurrAsmList,pvreg);
  980. extra_post_call_code;
  981. end;
  982. { Need to remove the parameters from the stack? }
  983. if (procdefinition.proccalloption in clearstack_pocalls) then
  984. begin
  985. pop_size:=pushedparasize;
  986. { for Cdecl functions we don't need to pop the funcret when it
  987. was pushed by para }
  988. if paramanager.ret_in_param(procdefinition.returndef,procdefinition.proccalloption) then
  989. dec(pop_size,sizeof(pint));
  990. { Remove parameters/alignment from the stack }
  991. pop_parasize(pop_size);
  992. end;
  993. { Release registers, but not the registers that contain the
  994. function result }
  995. if (not is_void(resultdef)) then
  996. begin
  997. case procdefinition.funcretloc[callerside].loc of
  998. LOC_REGISTER,
  999. LOC_CREGISTER:
  1000. begin
  1001. {$ifndef cpu64bitalu}
  1002. if procdefinition.funcretloc[callerside].size in [OS_64,OS_S64] then
  1003. begin
  1004. exclude(regs_to_save_int,getsupreg(procdefinition.funcretloc[callerside].register64.reghi));
  1005. exclude(regs_to_save_int,getsupreg(procdefinition.funcretloc[callerside].register64.reglo));
  1006. end
  1007. else
  1008. {$endif not cpu64bitalu}
  1009. exclude(regs_to_save_int,getsupreg(procdefinition.funcretloc[callerside].register));
  1010. end;
  1011. LOC_FPUREGISTER,
  1012. LOC_CFPUREGISTER:
  1013. exclude(regs_to_save_fpu,getsupreg(procdefinition.funcretloc[callerside].register));
  1014. LOC_MMREGISTER,
  1015. LOC_CMMREGISTER:
  1016. exclude(regs_to_save_mm,getsupreg(procdefinition.funcretloc[callerside].register));
  1017. LOC_REFERENCE,
  1018. LOC_VOID:
  1019. ;
  1020. else
  1021. internalerror(2004110214);
  1022. end;
  1023. end;
  1024. {$if defined(x86) or defined(arm)}
  1025. if (procdefinition.proccalloption=pocall_safecall) and
  1026. (target_info.system in system_all_windows) then
  1027. begin
  1028. {$ifdef x86_64}
  1029. cgpara.init;
  1030. paramanager.getintparaloc(pocall_default,1,cgpara);
  1031. cg.a_param_reg(current_asmdata.CurrAsmList,OS_ADDR,NR_RAX,cgpara);
  1032. cgpara.done;
  1033. {$endif x86_64}
  1034. cg.allocallcpuregisters(current_asmdata.CurrAsmList);
  1035. cg.a_call_name(current_asmdata.CurrAsmList,'FPC_SAFECALLCHECK',false);
  1036. cg.deallocallcpuregisters(current_asmdata.CurrAsmList);
  1037. end;
  1038. {$endif}
  1039. if cg.uses_registers(R_MMREGISTER) then
  1040. cg.dealloccpuregisters(current_asmdata.CurrAsmList,R_MMREGISTER,regs_to_save_mm);
  1041. if cg.uses_registers(R_FPUREGISTER) then
  1042. cg.dealloccpuregisters(current_asmdata.CurrAsmList,R_FPUREGISTER,regs_to_save_fpu);
  1043. cg.dealloccpuregisters(current_asmdata.CurrAsmList,R_INTREGISTER,regs_to_save_int);
  1044. { handle function results }
  1045. if (not is_void(resultdef)) then
  1046. handle_return_value
  1047. else
  1048. location_reset(location,LOC_VOID,OS_NO);
  1049. { convert persistent temps for parameters and function result to normal temps }
  1050. if assigned(callcleanupblock) then
  1051. secondpass(callcleanupblock);
  1052. { release temps and finalize unused return values, must be
  1053. after the callcleanupblock because that converts temps
  1054. from persistent to normal }
  1055. release_unused_return_value;
  1056. { release temps of paras }
  1057. release_para_temps;
  1058. { perhaps i/o check ? }
  1059. if (cs_check_io in current_settings.localswitches) and
  1060. (po_iocheck in procdefinition.procoptions) and
  1061. not(po_iocheck in current_procinfo.procdef.procoptions) and
  1062. { no IO check for methods and procedure variables }
  1063. (right=nil) and
  1064. not(po_virtualmethod in procdefinition.procoptions) then
  1065. begin
  1066. cg.allocallcpuregisters(current_asmdata.CurrAsmList);
  1067. cg.a_call_name(current_asmdata.CurrAsmList,'FPC_IOCHECK',false);
  1068. cg.deallocallcpuregisters(current_asmdata.CurrAsmList);
  1069. end;
  1070. end;
  1071. begin
  1072. ccallparanode:=tcgcallparanode;
  1073. ccallnode:=tcgcallnode;
  1074. end.