ncgcal.pas 45 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043
  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_loadaddr_ref_cgpara(current_asmdata.CurrAsmList,left.location.reference,tempcgpara);
  96. end;
  97. procedure tcgcallparanode.push_value_para;
  98. begin
  99. { we've nothing to push when the size of the parameter is 0 }
  100. if left.resultdef.size=0 then
  101. exit;
  102. { Move flags and jump in register to make it less complex }
  103. if left.location.loc in [LOC_FLAGS,LOC_JUMP,LOC_SUBSETREG,LOC_CSUBSETREG,LOC_SUBSETREF,LOC_CSUBSETREF] then
  104. location_force_reg(current_asmdata.CurrAsmList,left.location,def_cgsize(left.resultdef),false);
  105. { load the parameter's tlocation into its cgpara }
  106. gen_load_loc_cgpara(current_asmdata.CurrAsmList,left.resultdef,left.location,tempcgpara)
  107. end;
  108. procedure tcgcallparanode.secondcallparan;
  109. var
  110. href : treference;
  111. otlabel,
  112. oflabel : tasmlabel;
  113. begin
  114. if not(assigned(parasym)) then
  115. internalerror(200304242);
  116. { Skip nothingn nodes which are used after disabling
  117. a parameter }
  118. if (left.nodetype<>nothingn) then
  119. begin
  120. otlabel:=current_procinfo.CurrTrueLabel;
  121. oflabel:=current_procinfo.CurrFalseLabel;
  122. current_asmdata.getjumplabel(current_procinfo.CurrTrueLabel);
  123. current_asmdata.getjumplabel(current_procinfo.CurrFalseLabel);
  124. secondpass(left);
  125. maybechangeloadnodereg(current_asmdata.CurrAsmList,left,true);
  126. { release memory for refcnt out parameters }
  127. if (parasym.varspez=vs_out) and
  128. is_managed_type(left.resultdef) then
  129. begin
  130. location_get_data_ref(current_asmdata.CurrAsmList,left.location,href,false,sizeof(pint));
  131. cg.g_decrrefcount(current_asmdata.CurrAsmList,left.resultdef,href);
  132. end;
  133. paramanager.createtempparaloc(current_asmdata.CurrAsmList,aktcallnode.procdefinition.proccalloption,parasym,tempcgpara);
  134. { handle varargs first, because parasym is not valid }
  135. if (cpf_varargs_para in callparaflags) then
  136. begin
  137. if paramanager.push_addr_param(vs_value,left.resultdef,
  138. aktcallnode.procdefinition.proccalloption) then
  139. push_addr_para
  140. else
  141. push_value_para;
  142. end
  143. { hidden parameters }
  144. else if (vo_is_hidden_para in parasym.varoptions) then
  145. begin
  146. { don't push a node that already generated a pointer type
  147. by address for implicit hidden parameters }
  148. if (vo_is_funcret in parasym.varoptions) or
  149. { pass "this" in C++ classes explicitly as pointer
  150. because push_addr_param might not be true for them }
  151. (is_cppclass(parasym.vardef) and (vo_is_self in parasym.varoptions)) or
  152. (not(left.resultdef.typ in [pointerdef,classrefdef]) and
  153. paramanager.push_addr_param(parasym.varspez,parasym.vardef,
  154. aktcallnode.procdefinition.proccalloption)) then
  155. push_addr_para
  156. else
  157. push_value_para;
  158. end
  159. { formal def }
  160. else if (parasym.vardef.typ=formaldef) then
  161. begin
  162. { allow passing of a constant to a const formaldef }
  163. if (parasym.varspez=vs_const) and
  164. (left.location.loc in [LOC_CONSTANT,LOC_REGISTER]) then
  165. location_force_mem(current_asmdata.CurrAsmList,left.location);
  166. push_addr_para;
  167. end
  168. { Normal parameter }
  169. else
  170. begin
  171. { don't push a node that already generated a pointer type
  172. by address for implicit hidden parameters }
  173. if (not(
  174. (vo_is_hidden_para in parasym.varoptions) and
  175. (left.resultdef.typ in [pointerdef,classrefdef])
  176. ) and
  177. paramanager.push_addr_param(parasym.varspez,parasym.vardef,
  178. aktcallnode.procdefinition.proccalloption)) and
  179. { dyn. arrays passed to an array of const must be passed by value, see tests/webtbs/tw4219.pp }
  180. not(
  181. is_array_of_const(parasym.vardef) and
  182. is_dynamic_array(left.resultdef)
  183. ) then
  184. begin
  185. { Passing a var parameter to a var parameter, we can
  186. just push the address transparently }
  187. if (left.nodetype=loadn) and
  188. (tloadnode(left).is_addr_param_load) then
  189. begin
  190. if (left.location.reference.index<>NR_NO) or
  191. (left.location.reference.offset<>0) then
  192. internalerror(200410107);
  193. cg.a_load_reg_cgpara(current_asmdata.CurrAsmList,OS_ADDR,left.location.reference.base,tempcgpara)
  194. end
  195. else
  196. begin
  197. { Force to be in memory }
  198. if not(left.location.loc in [LOC_CREFERENCE,LOC_REFERENCE]) then
  199. location_force_mem(current_asmdata.CurrAsmList,left.location);
  200. push_addr_para;
  201. end;
  202. end
  203. else
  204. push_value_para;
  205. end;
  206. current_procinfo.CurrTrueLabel:=otlabel;
  207. current_procinfo.CurrFalseLabel:=oflabel;
  208. { update return location in callnode when this is the function
  209. result }
  210. if assigned(parasym) and
  211. (vo_is_funcret in parasym.varoptions) then
  212. location_copy(aktcallnode.location,left.location);
  213. end;
  214. { next parameter }
  215. if assigned(right) then
  216. tcallparanode(right).secondcallparan;
  217. end;
  218. {*****************************************************************************
  219. TCGCALLNODE
  220. *****************************************************************************}
  221. procedure tcgcallnode.extra_interrupt_code;
  222. begin
  223. end;
  224. procedure tcgcallnode.extra_call_code;
  225. begin
  226. end;
  227. procedure tcgcallnode.extra_post_call_code;
  228. begin
  229. end;
  230. procedure tcgcallnode.pop_parasize(pop_size:longint);
  231. begin
  232. end;
  233. procedure tcgcallnode.handle_return_value;
  234. var
  235. tmpcgsize,
  236. cgsize : tcgsize;
  237. {$ifdef cpu64bitaddr}
  238. ref : treference;
  239. {$endif cpu64bitaddr}
  240. {$ifndef x86}
  241. hregister : tregister;
  242. {$endif not x86}
  243. begin
  244. { Check that the return location is set when the result is passed in
  245. a parameter }
  246. if (procdefinition.proctypeoption<>potype_constructor) and
  247. paramanager.ret_in_param(resultdef,procdefinition.proccalloption) then
  248. begin
  249. if location.loc<>LOC_REFERENCE then
  250. internalerror(200304241);
  251. exit;
  252. end;
  253. { Load normal (ordinal,float,pointer) result value from accumulator }
  254. cgsize:=retloc.size;
  255. case retloc.loc of
  256. LOC_FPUREGISTER:
  257. begin
  258. location_reset(location,LOC_FPUREGISTER,cgsize);
  259. location.register:=retloc.register;
  260. {$ifdef x86}
  261. tcgx86(cg).inc_fpu_stack;
  262. {$else x86}
  263. { Do not move the physical register to a virtual one in case
  264. the return value is not used, because if the virtual one is
  265. then mapped to the same register as the physical one, we will
  266. end up with two deallocs of this register (one inserted here,
  267. one inserted by the register allocator), which unbalances the
  268. register allocation information. The return register(s) will
  269. be freed by location_free() in release_unused_return_value
  270. (mantis #13536). }
  271. if (cnf_return_value_used in callnodeflags) then
  272. begin
  273. if getsupreg(retloc.register)<first_fpu_imreg then
  274. cg.ungetcpuregister(current_asmdata.CurrAsmList,retloc.register);
  275. hregister:=cg.getfpuregister(current_asmdata.CurrAsmList,location.size);
  276. cg.a_loadfpu_reg_reg(current_asmdata.CurrAsmList,location.size,location.size,location.register,hregister);
  277. location.register:=hregister;
  278. end;
  279. {$endif x86}
  280. end;
  281. LOC_REGISTER:
  282. begin
  283. if cgsize<>OS_NO then
  284. begin
  285. location_reset(location,LOC_REGISTER,cgsize);
  286. {$ifdef cpu64bitaddr}
  287. { x86-64 system v abi:
  288. structs with up to 16 bytes are returned in registers }
  289. if cgsize in [OS_128,OS_S128] then
  290. begin
  291. if retloc.loc<>LOC_REGISTER then
  292. internalerror(2009042001);
  293. { See #13536 comment above. }
  294. if (cnf_return_value_used in callnodeflags) then
  295. begin
  296. tg.GetTemp(current_asmdata.CurrAsmList,16,8,tt_normal,ref);
  297. location_reset_ref(location,LOC_REFERENCE,OS_NO,0);
  298. location.reference:=ref;
  299. if getsupreg(retloc.register)<first_int_imreg then
  300. cg.ungetcpuregister(current_asmdata.CurrAsmList,retloc.register);
  301. cg.a_load_reg_ref(current_asmdata.CurrAsmList,OS_64,OS_64,retloc.register,ref);
  302. inc(ref.offset,8);
  303. if getsupreg(retloc.registerhi)<first_int_imreg then
  304. cg.ungetcpuregister(current_asmdata.CurrAsmList,retloc.registerhi);
  305. cg.a_load_reg_ref(current_asmdata.CurrAsmList,OS_64,OS_64,retloc.registerhi,ref);
  306. end
  307. else
  308. location:=retloc;
  309. end
  310. else
  311. {$else cpu64bitaddr}
  312. if cgsize in [OS_64,OS_S64] then
  313. begin
  314. if retloc.loc<>LOC_REGISTER then
  315. internalerror(200409141);
  316. { See #13536 comment above. }
  317. if (cnf_return_value_used in callnodeflags) then
  318. begin
  319. { the function result registers are already allocated }
  320. if getsupreg(retloc.register64.reglo)<first_int_imreg then
  321. cg.ungetcpuregister(current_asmdata.CurrAsmList,retloc.register64.reglo);
  322. location.register64.reglo:=cg.getintregister(current_asmdata.CurrAsmList,OS_32);
  323. cg.a_load_reg_reg(current_asmdata.CurrAsmList,OS_32,OS_32,retloc.register64.reglo,location.register64.reglo);
  324. if getsupreg(retloc.register64.reghi)<first_int_imreg then
  325. cg.ungetcpuregister(current_asmdata.CurrAsmList,retloc.register64.reghi);
  326. location.register64.reghi:=cg.getintregister(current_asmdata.CurrAsmList,OS_32);
  327. cg.a_load_reg_reg(current_asmdata.CurrAsmList,OS_32,OS_32,retloc.register64.reghi,location.register64.reghi);
  328. end
  329. else
  330. location:=retloc;
  331. end
  332. else
  333. {$endif not cpu64bitaddr}
  334. begin
  335. { change register size after the unget because the
  336. getregister was done for the full register
  337. def_cgsize(resultdef) is used here because
  338. it could be a constructor call }
  339. { See #13536 comment above. }
  340. if (cnf_return_value_used in callnodeflags) then
  341. begin
  342. if getsupreg(retloc.register)<first_int_imreg then
  343. cg.ungetcpuregister(current_asmdata.CurrAsmList,retloc.register);
  344. { but use def_size only if it returns something valid because in
  345. case of odd sized structured results in registers def_cgsize(resultdef)
  346. could return OS_NO }
  347. if def_cgsize(resultdef)<>OS_NO then
  348. tmpcgsize:=def_cgsize(resultdef)
  349. else
  350. tmpcgsize:=cgsize;
  351. location.register:=cg.getintregister(current_asmdata.CurrAsmList,tmpcgsize);
  352. cg.a_load_reg_reg(current_asmdata.CurrAsmList,cgsize,tmpcgsize,retloc.register,location.register);
  353. end
  354. else
  355. location:=retloc;
  356. end;
  357. {$ifdef arm}
  358. if (resultdef.typ=floatdef) and (current_settings.fputype in [fpu_fpa,fpu_fpa10,fpu_fpa11]) then
  359. begin
  360. location_force_mem(current_asmdata.CurrAsmList,location);
  361. end;
  362. {$endif arm}
  363. end
  364. else
  365. begin
  366. if resultdef.size>0 then
  367. internalerror(200305131);
  368. end;
  369. end;
  370. LOC_MMREGISTER:
  371. begin
  372. { See #13536 comment above. }
  373. if (cnf_return_value_used in callnodeflags) then
  374. begin
  375. location_reset(location,LOC_MMREGISTER,cgsize);
  376. if getsupreg(retloc.register)<first_mm_imreg then
  377. cg.ungetcpuregister(current_asmdata.CurrAsmList,retloc.register);
  378. location.register:=cg.getmmregister(current_asmdata.CurrAsmList,cgsize);
  379. cg.a_loadmm_reg_reg(current_asmdata.CurrAsmList,cgsize,cgsize,retloc.register,location.register,mms_movescalar);
  380. end
  381. else
  382. location:=retloc;
  383. end;
  384. else
  385. internalerror(200405023);
  386. end;
  387. { copy value to the final location if this was already provided to the
  388. callnode. This must be done after the call node, because the location can
  389. also be used as parameter and may not be finalized yet }
  390. if assigned(funcretnode) then
  391. begin
  392. funcretnode.pass_generate_code;
  393. { Decrease refcount for refcounted types, this can be skipped when
  394. we have used a temp, because then it is already done from tempcreatenode.
  395. Also no finalize is needed, because there is no risk of exceptions from the
  396. function since this is code is only executed after the function call has returned }
  397. if is_managed_type(funcretnode.resultdef) and
  398. (funcretnode.nodetype<>temprefn) then
  399. cg.g_decrrefcount(current_asmdata.CurrAsmList,funcretnode.resultdef,funcretnode.location.reference);
  400. case location.loc of
  401. LOC_REGISTER :
  402. {$ifndef cpu64bitalu}
  403. if cgsize in [OS_64,OS_S64] then
  404. cg64.a_load64_reg_loc(current_asmdata.CurrAsmList,location.register64,funcretnode.location)
  405. else
  406. {$endif}
  407. cg.a_load_reg_loc(current_asmdata.CurrAsmList,cgsize,location.register,funcretnode.location);
  408. LOC_REFERENCE:
  409. begin
  410. case funcretnode.location.loc of
  411. LOC_REGISTER:
  412. cg.a_load_ref_reg(current_asmdata.CurrAsmList,cgsize,cgsize,location.reference,funcretnode.location.register);
  413. LOC_REFERENCE:
  414. cg.g_concatcopy(current_asmdata.CurrAsmList,location.reference,funcretnode.location.reference,resultdef.size);
  415. else
  416. internalerror(200802121);
  417. end;
  418. end;
  419. else
  420. internalerror(200709085);
  421. end;
  422. location := funcretnode.location;
  423. end;
  424. end;
  425. procedure tcgcallnode.release_unused_return_value;
  426. begin
  427. { When the result is not used we need to finalize the result and
  428. can release the temp. This need to be after the callcleanupblock
  429. tree is generated, because that converts the temp from persistent to normal }
  430. if not(cnf_return_value_used in callnodeflags) then
  431. begin
  432. case location.loc of
  433. LOC_REFERENCE :
  434. begin
  435. if is_managed_type(resultdef) then
  436. cg.g_finalize(current_asmdata.CurrAsmList,resultdef,location.reference);
  437. tg.ungetiftemp(current_asmdata.CurrAsmList,location.reference);
  438. end;
  439. {$ifdef x86}
  440. LOC_FPUREGISTER :
  441. begin
  442. { release FPU stack }
  443. emit_reg(A_FSTP,S_NO,NR_FPU_RESULT_REG);
  444. tcgx86(cg).dec_fpu_stack;
  445. end;
  446. {$endif x86}
  447. end;
  448. if retloc.size<>OS_NO then
  449. location_free(current_asmdata.CurrAsmList,retloc);
  450. location_reset(location,LOC_VOID,OS_NO);
  451. end;
  452. end;
  453. procedure tcgcallnode.release_para_temps;
  454. var
  455. hp,
  456. hp2 : tnode;
  457. ppn : tcallparanode;
  458. begin
  459. { Release temps from parameters }
  460. ppn:=tcallparanode(left);
  461. while assigned(ppn) do
  462. begin
  463. if assigned(ppn.left) then
  464. begin
  465. { don't release the funcret temp }
  466. if not(assigned(ppn.parasym)) or
  467. not(vo_is_funcret in ppn.parasym.varoptions) then
  468. location_freetemp(current_asmdata.CurrAsmList,ppn.left.location);
  469. { process also all nodes of an array of const }
  470. hp:=ppn.left;
  471. while (hp.nodetype=typeconvn) do
  472. hp:=ttypeconvnode(hp).left;
  473. if (hp.nodetype=arrayconstructorn) and
  474. assigned(tarrayconstructornode(hp).left) then
  475. begin
  476. while assigned(hp) do
  477. begin
  478. hp2:=tarrayconstructornode(hp).left;
  479. { ignore typeconvs and addrn inserted by arrayconstructn for
  480. passing a shortstring }
  481. if (hp2.nodetype=typeconvn) and
  482. (tunarynode(hp2).left.nodetype=addrn) then
  483. hp2:=tunarynode(tunarynode(hp2).left).left;
  484. location_freetemp(current_asmdata.CurrAsmList,hp2.location);
  485. hp:=tarrayconstructornode(hp).right;
  486. end;
  487. end;
  488. end;
  489. ppn:=tcallparanode(ppn.right);
  490. end;
  491. end;
  492. procedure tcgcallnode.pushparas;
  493. var
  494. ppn : tcgcallparanode;
  495. callerparaloc,
  496. tmpparaloc : pcgparalocation;
  497. sizeleft: aint;
  498. htempref,
  499. href : treference;
  500. calleralignment,
  501. tmpalignment: longint;
  502. begin
  503. { copy all resources to the allocated registers }
  504. ppn:=tcgcallparanode(left);
  505. while assigned(ppn) do
  506. begin
  507. if (ppn.left.nodetype<>nothingn) then
  508. begin
  509. { better check for the real location of the parameter here, when stack passed parameters
  510. are saved temporary in registers, checking for the tmpparaloc.loc is wrong
  511. }
  512. paramanager.freeparaloc(current_asmdata.CurrAsmList,ppn.tempcgpara);
  513. tmpparaloc:=ppn.tempcgpara.location;
  514. sizeleft:=ppn.tempcgpara.intsize;
  515. calleralignment:=ppn.parasym.paraloc[callerside].alignment;
  516. tmpalignment:=ppn.tempcgpara.alignment;
  517. if (tmpalignment=0) or
  518. (calleralignment=0) then
  519. internalerror(2009020701);
  520. callerparaloc:=ppn.parasym.paraloc[callerside].location;
  521. while assigned(callerparaloc) do
  522. begin
  523. { Every paraloc must have a matching tmpparaloc }
  524. if not assigned(tmpparaloc) then
  525. internalerror(200408224);
  526. if callerparaloc^.size<>tmpparaloc^.size then
  527. internalerror(200408225);
  528. case callerparaloc^.loc of
  529. LOC_REGISTER:
  530. begin
  531. if tmpparaloc^.loc<>LOC_REGISTER then
  532. internalerror(200408221);
  533. if getsupreg(callerparaloc^.register)<first_int_imreg then
  534. cg.getcpuregister(current_asmdata.CurrAsmList,callerparaloc^.register);
  535. cg.a_load_reg_reg(current_asmdata.CurrAsmList,tmpparaloc^.size,tmpparaloc^.size,
  536. tmpparaloc^.register,callerparaloc^.register);
  537. end;
  538. LOC_FPUREGISTER:
  539. begin
  540. if tmpparaloc^.loc<>LOC_FPUREGISTER then
  541. internalerror(200408222);
  542. if getsupreg(callerparaloc^.register)<first_fpu_imreg then
  543. cg.getcpuregister(current_asmdata.CurrAsmList,callerparaloc^.register);
  544. cg.a_loadfpu_reg_reg(current_asmdata.CurrAsmList,tmpparaloc^.size,ppn.tempcgpara.size,tmpparaloc^.register,callerparaloc^.register);
  545. end;
  546. LOC_MMREGISTER:
  547. begin
  548. if tmpparaloc^.loc<>LOC_MMREGISTER then
  549. internalerror(200408223);
  550. if getsupreg(callerparaloc^.register)<first_mm_imreg then
  551. cg.getcpuregister(current_asmdata.CurrAsmList,callerparaloc^.register);
  552. cg.a_loadmm_reg_reg(current_asmdata.CurrAsmList,tmpparaloc^.size,tmpparaloc^.size,
  553. tmpparaloc^.register,callerparaloc^.register,mms_movescalar);
  554. end;
  555. LOC_REFERENCE:
  556. begin
  557. if use_fixed_stack then
  558. begin
  559. { Can't have a data copied to the stack, every location
  560. must contain a valid size field }
  561. if (ppn.tempcgpara.size=OS_NO) and
  562. ((tmpparaloc^.loc<>LOC_REFERENCE) or
  563. assigned(tmpparaloc^.next)) then
  564. internalerror(200501281);
  565. reference_reset_base(href,callerparaloc^.reference.index,callerparaloc^.reference.offset,calleralignment);
  566. { copy parameters in case they were moved to a temp. location because we've a fixed stack }
  567. case tmpparaloc^.loc of
  568. LOC_REFERENCE:
  569. begin
  570. reference_reset_base(htempref,tmpparaloc^.reference.index,tmpparaloc^.reference.offset,tmpalignment);
  571. { use concatcopy, because it can also be a float which fails when
  572. load_ref_ref is used }
  573. if (ppn.tempcgpara.size <> OS_NO) then
  574. cg.g_concatcopy(current_asmdata.CurrAsmList,htempref,href,tcgsize2size[tmpparaloc^.size])
  575. else
  576. cg.g_concatcopy(current_asmdata.CurrAsmList,htempref,href,sizeleft)
  577. end;
  578. LOC_REGISTER:
  579. cg.a_load_reg_ref(current_asmdata.CurrAsmList,tmpparaloc^.size,tmpparaloc^.size,tmpparaloc^.register,href);
  580. LOC_FPUREGISTER:
  581. cg.a_loadfpu_reg_ref(current_asmdata.CurrAsmList,tmpparaloc^.size,tmpparaloc^.size,tmpparaloc^.register,href);
  582. LOC_MMREGISTER:
  583. cg.a_loadmm_reg_ref(current_asmdata.CurrAsmList,tmpparaloc^.size,tmpparaloc^.size,tmpparaloc^.register,href,mms_movescalar);
  584. else
  585. internalerror(200402081);
  586. end;
  587. end;
  588. end;
  589. end;
  590. dec(sizeleft,tcgsize2size[tmpparaloc^.size]);
  591. callerparaloc:=callerparaloc^.next;
  592. tmpparaloc:=tmpparaloc^.next;
  593. end;
  594. end;
  595. ppn:=tcgcallparanode(ppn.right);
  596. end;
  597. end;
  598. procedure tcgcallnode.freeparas;
  599. var
  600. ppn : tcgcallparanode;
  601. begin
  602. { free the resources allocated for the parameters }
  603. ppn:=tcgcallparanode(left);
  604. while assigned(ppn) do
  605. begin
  606. if (ppn.left.nodetype<>nothingn) then
  607. begin
  608. if (ppn.parasym.paraloc[callerside].location^.loc <> LOC_REFERENCE) then
  609. paramanager.freeparaloc(current_asmdata.CurrAsmList,ppn.parasym.paraloc[callerside]);
  610. end;
  611. ppn:=tcgcallparanode(ppn.right);
  612. end;
  613. end;
  614. procedure tcgcallnode.pass_generate_code;
  615. var
  616. name_to_call: shortstring;
  617. regs_to_save_int,
  618. regs_to_save_fpu,
  619. regs_to_save_mm : Tcpuregisterset;
  620. href : treference;
  621. pop_size : longint;
  622. vmtoffset : aint;
  623. pvreg,
  624. vmtreg : tregister;
  625. oldaktcallnode : tcallnode;
  626. {$ifdef vtentry}
  627. sym : tasmsymbol;
  628. {$endif vtentry}
  629. {$ifdef x86_64}
  630. cgpara : tcgpara;
  631. {$endif x86_64}
  632. begin
  633. if not assigned(procdefinition) or
  634. not procdefinition.has_paraloc_info then
  635. internalerror(200305264);
  636. if assigned(callinitblock) then
  637. secondpass(tnode(callinitblock));
  638. regs_to_save_int:=paramanager.get_volatile_registers_int(procdefinition.proccalloption);
  639. regs_to_save_fpu:=paramanager.get_volatile_registers_fpu(procdefinition.proccalloption);
  640. regs_to_save_mm:=paramanager.get_volatile_registers_mm(procdefinition.proccalloption);
  641. { Include Function result registers }
  642. if (not is_void(resultdef)) then
  643. begin
  644. { The forced returntype may have a different size than the one
  645. declared for the procdef }
  646. if not assigned(typedef) then
  647. retloc:=procdefinition.funcretloc[callerside]
  648. else
  649. retloc:=paramanager.get_funcretloc(procdefinition,callerside,typedef);
  650. case retloc.loc of
  651. LOC_REGISTER,
  652. LOC_CREGISTER:
  653. begin
  654. {$ifdef cpu64bitaddr}
  655. { x86-64 system v abi:
  656. structs with up to 16 bytes are returned in registers }
  657. if retloc.size in [OS_128,OS_S128] then
  658. begin
  659. include(regs_to_save_int,getsupreg(retloc.register));
  660. include(regs_to_save_int,getsupreg(retloc.registerhi));
  661. end
  662. else
  663. {$else cpu64bitaddr}
  664. if retloc.size in [OS_64,OS_S64] then
  665. begin
  666. include(regs_to_save_int,getsupreg(retloc.register64.reglo));
  667. include(regs_to_save_int,getsupreg(retloc.register64.reghi));
  668. end
  669. else
  670. {$endif not cpu64bitaddr}
  671. include(regs_to_save_int,getsupreg(retloc.register));
  672. end;
  673. LOC_FPUREGISTER,
  674. LOC_CFPUREGISTER:
  675. begin
  676. include(regs_to_save_fpu,getsupreg(retloc.register));
  677. {$ifdef SPARC}
  678. { SPARC uses two successive single precision fpu registers
  679. for double-precision values }
  680. if retloc.size=OS_F64 then
  681. include(regs_to_save_fpu,succ(getsupreg(retloc.register)));
  682. {$endif SPARC}
  683. end;
  684. LOC_MMREGISTER,
  685. LOC_CMMREGISTER:
  686. include(regs_to_save_mm,getsupreg(retloc.register));
  687. LOC_REFERENCE,
  688. LOC_VOID:
  689. ;
  690. else
  691. internalerror(2004110213);
  692. end;
  693. end;
  694. { Process parameters, register parameters will be loaded
  695. in imaginary registers. The actual load to the correct
  696. register is done just before the call }
  697. oldaktcallnode:=aktcallnode;
  698. aktcallnode:=self;
  699. if assigned(left) then
  700. tcallparanode(left).secondcallparan;
  701. aktcallnode:=oldaktcallnode;
  702. { procedure variable or normal function call ? }
  703. if (right=nil) then
  704. begin
  705. { register call for WPO (must be done before wpo test below,
  706. otherwise optimised called methods are no longer registered)
  707. }
  708. if (po_virtualmethod in procdefinition.procoptions) and
  709. assigned(methodpointer) and
  710. (methodpointer.nodetype<>typen) and
  711. (not assigned(current_procinfo) or
  712. wpoinfomanager.symbol_live(current_procinfo.procdef.mangledname)) then
  713. tprocdef(procdefinition)._class.register_vmt_call(tprocdef(procdefinition).extnumber);
  714. {$ifdef vtentry}
  715. if not is_interface(tprocdef(procdefinition)._class) then
  716. begin
  717. inc(current_asmdata.NextVTEntryNr);
  718. 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));
  719. end;
  720. {$endif vtentry}
  721. name_to_call:='';
  722. if assigned(fobjcforcedprocname) then
  723. name_to_call:=fobjcforcedprocname^;
  724. { When methodpointer is typen we don't need (and can't) load
  725. a pointer. We can directly call the correct procdef (PFV) }
  726. if (name_to_call='') and
  727. (po_virtualmethod in procdefinition.procoptions) and
  728. assigned(methodpointer) and
  729. (methodpointer.nodetype<>typen) and
  730. not wpoinfomanager.can_be_devirtualized(methodpointer.resultdef,procdefinition,name_to_call) then
  731. begin
  732. { virtual methods require an index }
  733. if tprocdef(procdefinition).extnumber=$ffff then
  734. internalerror(200304021);
  735. secondpass(methodpointer);
  736. { Load VMT from self }
  737. if methodpointer.resultdef.typ=objectdef then
  738. gen_load_vmt_register(current_asmdata.CurrAsmList,tobjectdef(methodpointer.resultdef),methodpointer.location,vmtreg)
  739. else
  740. begin
  741. { Load VMT value in register }
  742. location_force_reg(current_asmdata.CurrAsmList,methodpointer.location,OS_ADDR,false);
  743. vmtreg:=methodpointer.location.register;
  744. end;
  745. { test validity of VMT }
  746. if not(is_interface(tprocdef(procdefinition)._class)) and
  747. not(is_cppclass(tprocdef(procdefinition)._class)) then
  748. cg.g_maybe_testvmt(current_asmdata.CurrAsmList,vmtreg,tprocdef(procdefinition)._class);
  749. { Call through VMT, generate a VTREF symbol to notify the linker }
  750. vmtoffset:=tprocdef(procdefinition)._class.vmtmethodoffset(tprocdef(procdefinition).extnumber);
  751. { register call for WPO }
  752. if (not assigned(current_procinfo) or
  753. wpoinfomanager.symbol_live(current_procinfo.procdef.mangledname)) then
  754. tprocdef(procdefinition)._class.register_vmt_call(tprocdef(procdefinition).extnumber);
  755. {$ifndef x86}
  756. pvreg:=cg.getintregister(current_asmdata.CurrAsmList,OS_ADDR);
  757. {$endif not x86}
  758. reference_reset_base(href,vmtreg,vmtoffset,sizeof(pint));
  759. {$ifndef x86}
  760. cg.a_load_ref_reg(current_asmdata.CurrAsmList,OS_ADDR,OS_ADDR,href,pvreg);
  761. {$endif not x86}
  762. { Load parameters that are in temporary registers in the
  763. correct parameter register }
  764. if assigned(left) then
  765. begin
  766. pushparas;
  767. { free the resources allocated for the parameters }
  768. freeparas;
  769. end;
  770. cg.alloccpuregisters(current_asmdata.CurrAsmList,R_INTREGISTER,regs_to_save_int);
  771. if cg.uses_registers(R_FPUREGISTER) then
  772. cg.alloccpuregisters(current_asmdata.CurrAsmList,R_FPUREGISTER,regs_to_save_fpu);
  773. if cg.uses_registers(R_MMREGISTER) then
  774. cg.alloccpuregisters(current_asmdata.CurrAsmList,R_MMREGISTER,regs_to_save_mm);
  775. { call method }
  776. extra_call_code;
  777. {$ifdef x86}
  778. cg.a_call_ref(current_asmdata.CurrAsmList,href);
  779. {$else x86}
  780. cg.a_call_reg(current_asmdata.CurrAsmList,pvreg);
  781. {$endif x86}
  782. extra_post_call_code;
  783. end
  784. else
  785. begin
  786. { Load parameters that are in temporary registers in the
  787. correct parameter register }
  788. if assigned(left) then
  789. begin
  790. pushparas;
  791. { free the resources allocated for the parameters }
  792. freeparas;
  793. end;
  794. cg.alloccpuregisters(current_asmdata.CurrAsmList,R_INTREGISTER,regs_to_save_int);
  795. if cg.uses_registers(R_FPUREGISTER) then
  796. cg.alloccpuregisters(current_asmdata.CurrAsmList,R_FPUREGISTER,regs_to_save_fpu);
  797. if cg.uses_registers(R_MMREGISTER) then
  798. cg.alloccpuregisters(current_asmdata.CurrAsmList,R_MMREGISTER,regs_to_save_mm);
  799. if procdefinition.proccalloption=pocall_syscall then
  800. do_syscall
  801. else
  802. begin
  803. { Calling interrupt from the same code requires some
  804. extra code }
  805. if (po_interrupt in procdefinition.procoptions) then
  806. extra_interrupt_code;
  807. extra_call_code;
  808. if (name_to_call='') then
  809. cg.a_call_name(current_asmdata.CurrAsmList,tprocdef(procdefinition).mangledname,po_weakexternal in procdefinition.procoptions)
  810. else
  811. cg.a_call_name(current_asmdata.CurrAsmList,name_to_call,po_weakexternal in procdefinition.procoptions);
  812. extra_post_call_code;
  813. end;
  814. end;
  815. end
  816. else
  817. { now procedure variable case }
  818. begin
  819. secondpass(right);
  820. pvreg:=cg.getintregister(current_asmdata.CurrAsmList,OS_ADDR);
  821. { Only load OS_ADDR from the reference }
  822. if right.location.loc in [LOC_REFERENCE,LOC_CREFERENCE] then
  823. cg.a_load_ref_reg(current_asmdata.CurrAsmList,OS_ADDR,OS_ADDR,right.location.reference,pvreg)
  824. else
  825. cg.a_load_loc_reg(current_asmdata.CurrAsmList,OS_ADDR,right.location,pvreg);
  826. location_freetemp(current_asmdata.CurrAsmList,right.location);
  827. { Load parameters that are in temporary registers in the
  828. correct parameter register }
  829. if assigned(left) then
  830. begin
  831. pushparas;
  832. { free the resources allocated for the parameters }
  833. freeparas;
  834. end;
  835. cg.alloccpuregisters(current_asmdata.CurrAsmList,R_INTREGISTER,regs_to_save_int);
  836. if cg.uses_registers(R_FPUREGISTER) then
  837. cg.alloccpuregisters(current_asmdata.CurrAsmList,R_FPUREGISTER,regs_to_save_fpu);
  838. if cg.uses_registers(R_MMREGISTER) then
  839. cg.alloccpuregisters(current_asmdata.CurrAsmList,R_MMREGISTER,regs_to_save_mm);
  840. { Calling interrupt from the same code requires some
  841. extra code }
  842. if (po_interrupt in procdefinition.procoptions) then
  843. extra_interrupt_code;
  844. extra_call_code;
  845. cg.a_call_reg(current_asmdata.CurrAsmList,pvreg);
  846. extra_post_call_code;
  847. end;
  848. { Need to remove the parameters from the stack? }
  849. if (procdefinition.proccalloption in clearstack_pocalls) then
  850. begin
  851. pop_size:=pushedparasize;
  852. { for Cdecl functions we don't need to pop the funcret when it
  853. was pushed by para }
  854. if paramanager.ret_in_param(procdefinition.returndef,procdefinition.proccalloption) then
  855. dec(pop_size,sizeof(pint));
  856. { Remove parameters/alignment from the stack }
  857. pop_parasize(pop_size);
  858. end;
  859. { Release registers, but not the registers that contain the
  860. function result }
  861. if (not is_void(resultdef)) then
  862. begin
  863. case retloc.loc of
  864. LOC_REGISTER,
  865. LOC_CREGISTER:
  866. begin
  867. {$ifndef cpu64bitalu}
  868. if retloc.size in [OS_64,OS_S64] then
  869. begin
  870. exclude(regs_to_save_int,getsupreg(retloc.register64.reghi));
  871. exclude(regs_to_save_int,getsupreg(retloc.register64.reglo));
  872. end
  873. {$else not cpu64bitalu}
  874. if retloc.size in [OS_128,OS_S128] then
  875. begin
  876. exclude(regs_to_save_int,getsupreg(retloc.register));
  877. exclude(regs_to_save_int,getsupreg(retloc.registerhi));
  878. end
  879. {$endif not cpu64bitalu}
  880. else
  881. exclude(regs_to_save_int,getsupreg(retloc.register));
  882. end;
  883. LOC_FPUREGISTER,
  884. LOC_CFPUREGISTER:
  885. exclude(regs_to_save_fpu,getsupreg(retloc.register));
  886. LOC_MMREGISTER,
  887. LOC_CMMREGISTER:
  888. exclude(regs_to_save_mm,getsupreg(retloc.register));
  889. LOC_REFERENCE,
  890. LOC_VOID:
  891. ;
  892. else
  893. internalerror(2004110214);
  894. end;
  895. end;
  896. {$if defined(x86) or defined(arm)}
  897. if (procdefinition.proccalloption=pocall_safecall) and
  898. (target_info.system in systems_all_windows) then
  899. begin
  900. {$ifdef x86_64}
  901. cgpara.init;
  902. paramanager.getintparaloc(pocall_default,1,cgpara);
  903. cg.a_load_reg_cgpara(current_asmdata.CurrAsmList,OS_ADDR,NR_RAX,cgpara);
  904. cgpara.done;
  905. {$endif x86_64}
  906. cg.allocallcpuregisters(current_asmdata.CurrAsmList);
  907. cg.a_call_name(current_asmdata.CurrAsmList,'FPC_SAFECALLCHECK',false);
  908. cg.deallocallcpuregisters(current_asmdata.CurrAsmList);
  909. end;
  910. {$endif}
  911. if cg.uses_registers(R_MMREGISTER) then
  912. cg.dealloccpuregisters(current_asmdata.CurrAsmList,R_MMREGISTER,regs_to_save_mm);
  913. if cg.uses_registers(R_FPUREGISTER) then
  914. cg.dealloccpuregisters(current_asmdata.CurrAsmList,R_FPUREGISTER,regs_to_save_fpu);
  915. cg.dealloccpuregisters(current_asmdata.CurrAsmList,R_INTREGISTER,regs_to_save_int);
  916. { handle function results }
  917. if (not is_void(resultdef)) then
  918. handle_return_value
  919. else
  920. location_reset(location,LOC_VOID,OS_NO);
  921. { convert persistent temps for parameters and function result to normal temps }
  922. if assigned(callcleanupblock) then
  923. secondpass(tnode(callcleanupblock));
  924. { release temps and finalize unused return values, must be
  925. after the callcleanupblock because that converts temps
  926. from persistent to normal }
  927. release_unused_return_value;
  928. { release temps of paras }
  929. release_para_temps;
  930. { perhaps i/o check ? }
  931. if (cs_check_io in current_settings.localswitches) and
  932. (po_iocheck in procdefinition.procoptions) and
  933. not(po_iocheck in current_procinfo.procdef.procoptions) and
  934. { no IO check for methods and procedure variables }
  935. (right=nil) and
  936. not(po_virtualmethod in procdefinition.procoptions) then
  937. begin
  938. cg.allocallcpuregisters(current_asmdata.CurrAsmList);
  939. cg.a_call_name(current_asmdata.CurrAsmList,'FPC_IOCHECK',false);
  940. cg.deallocallcpuregisters(current_asmdata.CurrAsmList);
  941. end;
  942. end;
  943. begin
  944. ccallparanode:=tcgcallparanode;
  945. ccallnode:=tcgcallnode;
  946. end.