ncgcal.pas 43 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030
  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 release_para_temps;
  39. procedure pushparas;
  40. procedure freeparas;
  41. protected
  42. framepointer_paraloc : tcgpara;
  43. refcountedtemp : treference;
  44. procedure handle_return_value;
  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_2;override;
  60. end;
  61. implementation
  62. uses
  63. systems,
  64. cutils,verbose,globals,
  65. symconst,symtable,defutil,paramgr,
  66. cgbase,pass_2,
  67. aasmbase,aasmtai,
  68. nbas,nmem,nld,ncnv,nutils,
  69. {$ifdef x86}
  70. cga,cgx86,
  71. {$endif x86}
  72. ncgutil,
  73. cgobj,tgobj,
  74. procinfo;
  75. {*****************************************************************************
  76. TCGCALLPARANODE
  77. *****************************************************************************}
  78. constructor tcgcallparanode.create(expr,next : tnode);
  79. begin
  80. inherited create(expr,next);
  81. tempcgpara.init;
  82. end;
  83. destructor tcgcallparanode.destroy;
  84. begin
  85. tempcgpara.done;
  86. inherited destroy;
  87. end;
  88. procedure tcgcallparanode.push_addr_para;
  89. begin
  90. if not(left.location.loc in [LOC_CREFERENCE,LOC_REFERENCE]) then
  91. internalerror(200304235);
  92. cg.a_paramaddr_ref(exprasmlist,left.location.reference,tempcgpara);
  93. end;
  94. procedure tcgcallparanode.push_value_para;
  95. {$ifdef i386}
  96. var
  97. href : treference;
  98. size : longint;
  99. {$endif i386}
  100. begin
  101. { we've nothing to push when the size of the parameter is 0 }
  102. if left.resulttype.def.size=0 then
  103. exit;
  104. { Move flags and jump in register to make it less complex }
  105. if left.location.loc in [LOC_FLAGS,LOC_JUMP] then
  106. location_force_reg(exprasmlist,left.location,def_cgsize(left.resulttype.def),false);
  107. { Handle Floating point types differently }
  108. if (left.resulttype.def.deftype=floatdef) and not(cs_fp_emulation in aktmoduleswitches) then
  109. begin
  110. {$ifdef i386}
  111. if tempcgpara.location^.loc<>LOC_REFERENCE then
  112. internalerror(200309291);
  113. case left.location.loc of
  114. LOC_FPUREGISTER,
  115. LOC_CFPUREGISTER:
  116. begin
  117. size:=align(TCGSize2Size[left.location.size],tempcgpara.alignment);
  118. if tempcgpara.location^.reference.index=NR_STACK_POINTER_REG then
  119. begin
  120. cg.g_stackpointer_alloc(exprasmlist,size);
  121. reference_reset_base(href,NR_STACK_POINTER_REG,0);
  122. end
  123. else
  124. reference_reset_base(href,tempcgpara.location^.reference.index,tempcgpara.location^.reference.offset);
  125. cg.a_loadfpu_reg_ref(exprasmlist,left.location.size,left.location.register,href);
  126. end;
  127. LOC_MMREGISTER,
  128. LOC_CMMREGISTER:
  129. begin
  130. size:=align(tfloatdef(left.resulttype.def).size,tempcgpara.alignment);
  131. if tempcgpara.location^.reference.index=NR_STACK_POINTER_REG then
  132. begin
  133. cg.g_stackpointer_alloc(exprasmlist,size);
  134. reference_reset_base(href,NR_STACK_POINTER_REG,0);
  135. end
  136. else
  137. reference_reset_base(href,tempcgpara.location^.reference.index,tempcgpara.location^.reference.offset);
  138. cg.a_loadmm_reg_ref(exprasmlist,left.location.size,left.location.size,left.location.register,href,mms_movescalar);
  139. end;
  140. LOC_REFERENCE,
  141. LOC_CREFERENCE :
  142. begin
  143. size:=align(left.resulttype.def.size,tempcgpara.alignment);
  144. if tempcgpara.location^.reference.index=NR_STACK_POINTER_REG then
  145. cg.a_param_ref(exprasmlist,left.location.size,left.location.reference,tempcgpara)
  146. else
  147. begin
  148. reference_reset_base(href,tempcgpara.location^.reference.index,tempcgpara.location^.reference.offset);
  149. cg.g_concatcopy(exprasmlist,left.location.reference,href,size);
  150. end;
  151. end;
  152. else
  153. internalerror(2002042430);
  154. end;
  155. {$else i386}
  156. case left.location.loc of
  157. LOC_MMREGISTER,
  158. LOC_CMMREGISTER:
  159. case tempcgpara.location^.loc of
  160. LOC_REFERENCE,
  161. LOC_CREFERENCE,
  162. LOC_MMREGISTER,
  163. LOC_CMMREGISTER:
  164. cg.a_parammm_reg(exprasmlist,left.location.size,left.location.register,tempcgpara,mms_movescalar);
  165. LOC_FPUREGISTER,
  166. LOC_CFPUREGISTER:
  167. begin
  168. location_force_fpureg(exprasmlist,left.location,false);
  169. cg.a_paramfpu_reg(exprasmlist,left.location.size,left.location.register,tempcgpara);
  170. end;
  171. else
  172. internalerror(200204249);
  173. end;
  174. LOC_FPUREGISTER,
  175. LOC_CFPUREGISTER:
  176. case tempcgpara.location^.loc of
  177. LOC_MMREGISTER,
  178. LOC_CMMREGISTER:
  179. begin
  180. location_force_mmregscalar(exprasmlist,left.location,false);
  181. cg.a_parammm_reg(exprasmlist,left.location.size,left.location.register,tempcgpara,mms_movescalar);
  182. end;
  183. {$ifdef x86_64}
  184. { x86_64 pushes s64comp in normal register }
  185. LOC_REGISTER,
  186. LOC_CREGISTER :
  187. begin
  188. location_force_mem(exprasmlist,left.location);
  189. { force integer size }
  190. left.location.size:=int_cgsize(tcgsize2size[left.location.size]);
  191. cg.a_param_ref(exprasmlist,left.location.size,left.location.reference,tempcgpara);
  192. end;
  193. {$endif x86_64}
  194. {$if defined(sparc) or defined(arm)}
  195. { sparc and arm pass floats in normal registers }
  196. LOC_REGISTER,
  197. LOC_CREGISTER,
  198. {$endif sparc}
  199. LOC_REFERENCE,
  200. LOC_CREFERENCE,
  201. LOC_FPUREGISTER,
  202. LOC_CFPUREGISTER:
  203. cg.a_paramfpu_reg(exprasmlist,left.location.size,left.location.register,tempcgpara);
  204. else
  205. internalerror(2002042433);
  206. end;
  207. LOC_REFERENCE,
  208. LOC_CREFERENCE:
  209. case tempcgpara.location^.loc of
  210. LOC_MMREGISTER,
  211. LOC_CMMREGISTER:
  212. cg.a_parammm_ref(exprasmlist,left.location.size,left.location.reference,tempcgpara,mms_movescalar);
  213. {$ifdef x86_64}
  214. { x86_64 pushes s64comp in normal register }
  215. LOC_REGISTER,
  216. LOC_CREGISTER :
  217. begin
  218. { force integer size }
  219. left.location.size:=int_cgsize(tcgsize2size[left.location.size]);
  220. cg.a_param_ref(exprasmlist,left.location.size,left.location.reference,tempcgpara);
  221. end;
  222. {$endif x86_64}
  223. {$if defined(sparc) or defined(arm) }
  224. { sparc and arm pass floats in normal registers }
  225. LOC_REGISTER,
  226. LOC_CREGISTER,
  227. {$endif sparc}
  228. LOC_REFERENCE,
  229. LOC_CREFERENCE,
  230. LOC_FPUREGISTER,
  231. LOC_CFPUREGISTER:
  232. cg.a_paramfpu_ref(exprasmlist,left.location.size,left.location.reference,tempcgpara);
  233. else
  234. internalerror(2002042431);
  235. end;
  236. else
  237. internalerror(2002042432);
  238. end;
  239. {$endif i386}
  240. end
  241. else
  242. begin
  243. case left.location.loc of
  244. LOC_CONSTANT,
  245. LOC_REGISTER,
  246. LOC_CREGISTER,
  247. LOC_REFERENCE,
  248. LOC_CREFERENCE :
  249. begin
  250. {$ifndef cpu64bit}
  251. { use cg64 only for int64, not for 8 byte records }
  252. if is_64bit(left.resulttype.def) then
  253. cg64.a_param64_loc(exprasmlist,left.location,tempcgpara)
  254. else
  255. {$endif cpu64bit}
  256. begin
  257. {$ifndef cpu64bit}
  258. { Only a_param_ref supports multiple locations, when the
  259. value is still a const or in a register then write it
  260. to a reference first. This situation can be triggered
  261. by typecasting an int64 constant to a record of 8 bytes }
  262. if left.location.size in [OS_64,OS_S64] then
  263. location_force_mem(exprasmlist,left.location);
  264. {$endif cpu64bit}
  265. cg.a_param_loc(exprasmlist,left.location,tempcgpara);
  266. end;
  267. end;
  268. {$ifdef SUPPORT_MMX}
  269. LOC_MMXREGISTER,
  270. LOC_CMMXREGISTER:
  271. cg.a_parammm_reg(exprasmlist,OS_M64,left.location.register,tempcgpara,nil);
  272. {$endif SUPPORT_MMX}
  273. else
  274. internalerror(200204241);
  275. end;
  276. end;
  277. end;
  278. procedure tcgcallparanode.secondcallparan;
  279. var
  280. href : treference;
  281. otlabel,
  282. oflabel : tasmlabel;
  283. begin
  284. if not(assigned(parasym)) then
  285. internalerror(200304242);
  286. { Skip nothingn nodes which are used after disabling
  287. a parameter }
  288. if (left.nodetype<>nothingn) then
  289. begin
  290. otlabel:=truelabel;
  291. oflabel:=falselabel;
  292. objectlibrary.getjumplabel(truelabel);
  293. objectlibrary.getjumplabel(falselabel);
  294. secondpass(left);
  295. { release memory for refcnt out parameters }
  296. if (parasym.varspez=vs_out) and
  297. (left.resulttype.def.needs_inittable) then
  298. begin
  299. location_get_data_ref(exprasmlist,left.location,href,false);
  300. cg.g_decrrefcount(exprasmlist,left.resulttype.def,href);
  301. end;
  302. paramanager.createtempparaloc(exprasmlist,aktcallnode.procdefinition.proccalloption,parasym,tempcgpara);
  303. { handle varargs first, because parasym is not valid }
  304. if (cpf_varargs_para in callparaflags) then
  305. begin
  306. if paramanager.push_addr_param(vs_value,left.resulttype.def,
  307. aktcallnode.procdefinition.proccalloption) then
  308. push_addr_para
  309. else
  310. push_value_para;
  311. end
  312. { hidden parameters }
  313. else if (vo_is_hidden_para in parasym.varoptions) then
  314. begin
  315. { don't push a node that already generated a pointer type
  316. by address for implicit hidden parameters }
  317. if (vo_is_funcret in parasym.varoptions) or
  318. (not(left.resulttype.def.deftype in [pointerdef,classrefdef]) and
  319. paramanager.push_addr_param(parasym.varspez,parasym.vartype.def,
  320. aktcallnode.procdefinition.proccalloption)) then
  321. push_addr_para
  322. else
  323. push_value_para;
  324. end
  325. { formal def }
  326. else if (parasym.vartype.def.deftype=formaldef) then
  327. begin
  328. { allow passing of a constant to a const formaldef }
  329. if (parasym.varspez=vs_const) and
  330. (left.location.loc=LOC_CONSTANT) then
  331. location_force_mem(exprasmlist,left.location);
  332. push_addr_para;
  333. end
  334. { Normal parameter }
  335. else
  336. begin
  337. { don't push a node that already generated a pointer type
  338. by address for implicit hidden parameters }
  339. if (not(
  340. (vo_is_hidden_para in parasym.varoptions) and
  341. (left.resulttype.def.deftype in [pointerdef,classrefdef])
  342. ) and
  343. paramanager.push_addr_param(parasym.varspez,parasym.vartype.def,
  344. aktcallnode.procdefinition.proccalloption)) and
  345. { dyn. arrays passed to an array of const must be passed by value, see tests/webtbs/tw4219.pp }
  346. not(
  347. is_array_of_const(parasym.vartype.def) and
  348. is_dynamic_array(left.resulttype.def)
  349. ) then
  350. begin
  351. { Passing a var parameter to a var parameter, we can
  352. just push the address transparently }
  353. if (left.nodetype=loadn) and
  354. (tloadnode(left).is_addr_param_load) then
  355. begin
  356. if (left.location.reference.index<>NR_NO) or
  357. (left.location.reference.offset<>0) then
  358. internalerror(200410107);
  359. cg.a_param_reg(exprasmlist,OS_ADDR,left.location.reference.base,tempcgpara)
  360. end
  361. else
  362. begin
  363. { Check for passing a constant to var,out parameter }
  364. if (parasym.varspez in [vs_var,vs_out]) and
  365. (left.location.loc<>LOC_REFERENCE) then
  366. begin
  367. { passing self to a var parameter is allowed in
  368. TP and delphi }
  369. if not((left.location.loc=LOC_CREFERENCE) and
  370. is_self_node(left)) then
  371. internalerror(200106041);
  372. end;
  373. { Force to be in memory }
  374. if not(left.location.loc in [LOC_CREFERENCE,LOC_REFERENCE]) then
  375. location_force_mem(exprasmlist,left.location);
  376. push_addr_para;
  377. end;
  378. end
  379. else
  380. push_value_para;
  381. end;
  382. truelabel:=otlabel;
  383. falselabel:=oflabel;
  384. { update return location in callnode when this is the function
  385. result }
  386. if assigned(parasym) and
  387. (vo_is_funcret in parasym.varoptions) then
  388. location_copy(aktcallnode.location,left.location);
  389. end;
  390. { next parameter }
  391. if assigned(right) then
  392. tcallparanode(right).secondcallparan;
  393. end;
  394. {*****************************************************************************
  395. TCGCALLNODE
  396. *****************************************************************************}
  397. procedure tcgcallnode.extra_interrupt_code;
  398. begin
  399. end;
  400. procedure tcgcallnode.extra_call_code;
  401. begin
  402. end;
  403. procedure tcgcallnode.extra_post_call_code;
  404. begin
  405. end;
  406. procedure tcgcallnode.pop_parasize(pop_size:longint);
  407. begin
  408. end;
  409. procedure tcgcallnode.handle_return_value;
  410. var
  411. cgsize : tcgsize;
  412. retloc : tlocation;
  413. hregister : tregister;
  414. tempnode : tnode;
  415. begin
  416. cgsize:=procdefinition.funcretloc[callerside].size;
  417. { structured results are easy to handle....
  418. needed also when result_no_used !! }
  419. if (procdefinition.proctypeoption<>potype_constructor) and
  420. paramanager.ret_in_param(resulttype.def,procdefinition.proccalloption) then
  421. begin
  422. { Location should be setup by the funcret para }
  423. if location.loc<>LOC_REFERENCE then
  424. internalerror(200304241);
  425. end
  426. else
  427. { ansi/widestrings must be registered, so we can dispose them }
  428. if resulttype.def.needs_inittable then
  429. begin
  430. if procdefinition.funcretloc[callerside].loc<>LOC_REGISTER then
  431. internalerror(200409261);
  432. { the FUNCTION_RESULT_REG is already allocated }
  433. if getsupreg(procdefinition.funcretloc[callerside].register)<first_int_imreg then
  434. cg.ungetcpuregister(exprasmlist,procdefinition.funcretloc[callerside].register);
  435. if not assigned(funcretnode) then
  436. begin
  437. { reg_ref could generate two instrcutions and allocate a register so we've to
  438. save the result first before releasing it }
  439. hregister:=cg.getaddressregister(exprasmlist);
  440. cg.a_load_reg_reg(exprasmlist,OS_ADDR,OS_ADDR,procdefinition.funcretloc[callerside].register,hregister);
  441. location_reset(location,LOC_REFERENCE,OS_ADDR);
  442. location.reference:=refcountedtemp;
  443. cg.a_load_reg_ref(exprasmlist,OS_ADDR,OS_ADDR,hregister,location.reference);
  444. end
  445. else
  446. begin
  447. hregister := cg.getaddressregister(exprasmlist);
  448. cg.a_load_reg_reg(exprasmlist,OS_ADDR,OS_ADDR,procdefinition.funcretloc[callerside].register,hregister);
  449. { in case of a regular funcretnode with ret_in_param, the }
  450. { original funcretnode isn't touched -> make sure it's }
  451. { the same here (not sure if it's necessary) }
  452. tempnode := funcretnode.getcopy;
  453. tempnode.pass_2;
  454. location := tempnode.location;
  455. tempnode.free;
  456. cg.g_decrrefcount(exprasmlist,resulttype.def,location.reference);
  457. cg.a_load_reg_ref(exprasmlist,OS_ADDR,OS_ADDR,hregister,location.reference);
  458. end;
  459. end
  460. else
  461. { normal (ordinal,float,pointer) result value }
  462. begin
  463. { we have only to handle the result if it is used }
  464. if (cnf_return_value_used in callnodeflags) then
  465. begin
  466. location.loc:=procdefinition.funcretloc[callerside].loc;
  467. case procdefinition.funcretloc[callerside].loc of
  468. LOC_FPUREGISTER:
  469. begin
  470. location_reset(location,LOC_FPUREGISTER,cgsize);
  471. location.register:=procdefinition.funcretloc[callerside].register;
  472. {$ifdef x86}
  473. tcgx86(cg).inc_fpu_stack;
  474. {$else x86}
  475. if getsupreg(procdefinition.funcretloc[callerside].register)<first_fpu_imreg then
  476. cg.ungetcpuregister(exprasmlist,procdefinition.funcretloc[callerside].register);
  477. hregister:=cg.getfpuregister(exprasmlist,location.size);
  478. cg.a_loadfpu_reg_reg(exprasmlist,location.size,location.register,hregister);
  479. location.register:=hregister;
  480. {$endif x86}
  481. end;
  482. LOC_REGISTER:
  483. begin
  484. if cgsize<>OS_NO then
  485. begin
  486. location_reset(location,LOC_REGISTER,cgsize);
  487. {$ifndef cpu64bit}
  488. if cgsize in [OS_64,OS_S64] then
  489. begin
  490. retloc:=procdefinition.funcretloc[callerside];
  491. if retloc.loc<>LOC_REGISTER then
  492. internalerror(200409141);
  493. { the function result registers are already allocated }
  494. if getsupreg(retloc.register64.reglo)<first_int_imreg then
  495. cg.ungetcpuregister(exprasmlist,retloc.register64.reglo);
  496. location.register64.reglo:=cg.getintregister(exprasmlist,OS_32);
  497. cg.a_load_reg_reg(exprasmlist,OS_32,OS_32,retloc.register64.reglo,location.register64.reglo);
  498. if getsupreg(retloc.register64.reghi)<first_int_imreg then
  499. cg.ungetcpuregister(exprasmlist,retloc.register64.reghi);
  500. location.register64.reghi:=cg.getintregister(exprasmlist,OS_32);
  501. cg.a_load_reg_reg(exprasmlist,OS_32,OS_32,retloc.register64.reghi,location.register64.reghi);
  502. end
  503. else
  504. {$endif cpu64bit}
  505. begin
  506. { change register size after the unget because the
  507. getregister was done for the full register
  508. def_cgsize(resulttype.def) is used here because
  509. it could be a constructor call }
  510. if getsupreg(procdefinition.funcretloc[callerside].register)<first_int_imreg then
  511. cg.ungetcpuregister(exprasmlist,procdefinition.funcretloc[callerside].register);
  512. location.register:=cg.getintregister(exprasmlist,def_cgsize(resulttype.def));
  513. cg.a_load_reg_reg(exprasmlist,cgsize,def_cgsize(resulttype.def),procdefinition.funcretloc[callerside].register,location.register);
  514. end;
  515. end
  516. else
  517. begin
  518. if resulttype.def.size>0 then
  519. internalerror(200305131);
  520. end;
  521. end;
  522. LOC_MMREGISTER:
  523. begin
  524. location_reset(location,LOC_MMREGISTER,cgsize);
  525. if getsupreg(procdefinition.funcretloc[callerside].register)<first_mm_imreg then
  526. cg.ungetcpuregister(exprasmlist,procdefinition.funcretloc[callerside].register);
  527. location.register:=cg.getmmregister(exprasmlist,cgsize);
  528. cg.a_loadmm_reg_reg(exprasmlist,cgsize,cgsize,procdefinition.funcretloc[callerside].register,location.register,mms_movescalar);
  529. end;
  530. else
  531. internalerror(200405023);
  532. end;
  533. end
  534. else
  535. begin
  536. {$ifdef x86}
  537. { release FPU stack }
  538. if procdefinition.funcretloc[callerside].loc=LOC_FPUREGISTER then
  539. emit_reg(A_FSTP,S_NO,NR_FPU_RESULT_REG);
  540. {$endif x86}
  541. if cgsize<>OS_NO then
  542. location_free(exprasmlist,procdefinition.funcretloc[callerside]);
  543. location_reset(location,LOC_VOID,OS_NO);
  544. end;
  545. end;
  546. { When the result is not used we need to finalize the result and
  547. can release the temp }
  548. if not(cnf_return_value_used in callnodeflags) then
  549. begin
  550. if location.loc=LOC_REFERENCE then
  551. begin
  552. if resulttype.def.needs_inittable then
  553. cg.g_finalize(exprasmlist,resulttype.def,location.reference);
  554. tg.ungetiftemp(exprasmlist,location.reference)
  555. end;
  556. end;
  557. end;
  558. procedure tcgcallnode.release_para_temps;
  559. var
  560. hp : tnode;
  561. ppn : tcallparanode;
  562. begin
  563. { Release temps from parameters }
  564. ppn:=tcallparanode(left);
  565. while assigned(ppn) do
  566. begin
  567. if assigned(ppn.left) then
  568. begin
  569. { don't release the funcret temp }
  570. if not(assigned(ppn.parasym)) or
  571. not(vo_is_funcret in ppn.parasym.varoptions) then
  572. location_freetemp(exprasmlist,ppn.left.location);
  573. { process also all nodes of an array of const }
  574. hp:=ppn.left;
  575. while (hp.nodetype=typeconvn) do
  576. hp:=ttypeconvnode(hp).left;
  577. if (hp.nodetype=arrayconstructorn) and
  578. assigned(tarrayconstructornode(hp).left) then
  579. begin
  580. while assigned(hp) do
  581. begin
  582. location_freetemp(exprasmlist,tarrayconstructornode(hp).left.location);
  583. hp:=tarrayconstructornode(hp).right;
  584. end;
  585. end;
  586. end;
  587. ppn:=tcallparanode(ppn.right);
  588. end;
  589. end;
  590. procedure tcgcallnode.pushparas;
  591. var
  592. ppn : tcgcallparanode;
  593. callerparaloc,
  594. tmpparaloc : pcgparalocation;
  595. sizeleft: aint;
  596. {$ifdef cputargethasfixedstack}
  597. htempref,
  598. href : treference;
  599. {$endif cputargethasfixedstack}
  600. begin
  601. { copy all resources to the allocated registers }
  602. ppn:=tcgcallparanode(left);
  603. while assigned(ppn) do
  604. begin
  605. if (ppn.left.nodetype<>nothingn) then
  606. begin
  607. { better check for the real location of the parameter here, when stack passed parameters
  608. are saved temporary in registers, checking for the tmpparaloc.loc is wrong
  609. }
  610. paramanager.freeparaloc(exprasmlist,ppn.tempcgpara);
  611. tmpparaloc:=ppn.tempcgpara.location;
  612. sizeleft:=ppn.tempcgpara.intsize;
  613. callerparaloc:=ppn.parasym.paraloc[callerside].location;
  614. while assigned(callerparaloc) do
  615. begin
  616. { Every paraloc must have a matching tmpparaloc }
  617. if not assigned(tmpparaloc) then
  618. internalerror(200408224);
  619. if callerparaloc^.size<>tmpparaloc^.size then
  620. internalerror(200408225);
  621. case callerparaloc^.loc of
  622. LOC_REGISTER:
  623. begin
  624. if tmpparaloc^.loc<>LOC_REGISTER then
  625. internalerror(200408221);
  626. if getsupreg(callerparaloc^.register)<first_int_imreg then
  627. cg.getcpuregister(exprasmlist,callerparaloc^.register);
  628. cg.a_load_reg_reg(exprasmlist,tmpparaloc^.size,tmpparaloc^.size,
  629. tmpparaloc^.register,callerparaloc^.register);
  630. end;
  631. LOC_FPUREGISTER:
  632. begin
  633. if tmpparaloc^.loc<>LOC_FPUREGISTER then
  634. internalerror(200408222);
  635. if getsupreg(callerparaloc^.register)<first_fpu_imreg then
  636. cg.getcpuregister(exprasmlist,callerparaloc^.register);
  637. cg.a_loadfpu_reg_reg(exprasmlist,ppn.tempcgpara.size,tmpparaloc^.register,callerparaloc^.register);
  638. end;
  639. LOC_MMREGISTER:
  640. begin
  641. if tmpparaloc^.loc<>LOC_MMREGISTER then
  642. internalerror(200408223);
  643. if getsupreg(callerparaloc^.register)<first_mm_imreg then
  644. cg.getcpuregister(exprasmlist,callerparaloc^.register);
  645. cg.a_loadmm_reg_reg(exprasmlist,tmpparaloc^.size,tmpparaloc^.size,
  646. tmpparaloc^.register,callerparaloc^.register,mms_movescalar);
  647. end;
  648. LOC_REFERENCE:
  649. begin
  650. {$ifdef cputargethasfixedstack}
  651. { Can't have a data copied to the stack, every location
  652. must contain a valid size field }
  653. if (ppn.tempcgpara.size=OS_NO) and
  654. ((tmpparaloc^.loc<>LOC_REFERENCE) or
  655. assigned(tmpparaloc^.next)) then
  656. internalerror(200501281);
  657. reference_reset_base(href,callerparaloc^.reference.index,callerparaloc^.reference.offset);
  658. { copy parameters in case they were moved to a temp. location because we've a fixed stack }
  659. case tmpparaloc^.loc of
  660. LOC_REFERENCE:
  661. begin
  662. reference_reset_base(htempref,tmpparaloc^.reference.index,tmpparaloc^.reference.offset);
  663. { use concatcopy, because it can also be a float which fails when
  664. load_ref_ref is used }
  665. if (ppn.tempcgpara.size <> OS_NO) then
  666. cg.g_concatcopy(exprasmlist,htempref,href,tcgsize2size[tmpparaloc^.size])
  667. else
  668. cg.g_concatcopy(exprasmlist,htempref,href,sizeleft)
  669. end;
  670. LOC_REGISTER:
  671. cg.a_load_reg_ref(exprasmlist,tmpparaloc^.size,tmpparaloc^.size,tmpparaloc^.register,href);
  672. LOC_FPUREGISTER:
  673. cg.a_loadfpu_reg_ref(exprasmlist,tmpparaloc^.size,tmpparaloc^.register,href);
  674. LOC_MMREGISTER:
  675. cg.a_loadmm_reg_ref(exprasmlist,tmpparaloc^.size,tmpparaloc^.size,tmpparaloc^.register,href,mms_movescalar);
  676. else
  677. internalerror(200402081);
  678. end;
  679. {$endif cputargethasfixedstack}
  680. end;
  681. end;
  682. dec(sizeleft,tcgsize2size[tmpparaloc^.size]);
  683. callerparaloc:=callerparaloc^.next;
  684. tmpparaloc:=tmpparaloc^.next;
  685. end;
  686. end;
  687. ppn:=tcgcallparanode(ppn.right);
  688. end;
  689. end;
  690. procedure tcgcallnode.freeparas;
  691. var
  692. ppn : tcgcallparanode;
  693. begin
  694. { free the resources allocated for the parameters }
  695. ppn:=tcgcallparanode(left);
  696. while assigned(ppn) do
  697. begin
  698. if (ppn.left.nodetype<>nothingn) then
  699. begin
  700. if (ppn.parasym.paraloc[callerside].location^.loc <> LOC_REFERENCE) then
  701. paramanager.freeparaloc(exprasmlist,ppn.parasym.paraloc[callerside]);
  702. end;
  703. ppn:=tcgcallparanode(ppn.right);
  704. end;
  705. end;
  706. procedure tcgcallnode.pass_2;
  707. var
  708. regs_to_save_int,
  709. regs_to_save_fpu,
  710. regs_to_save_mm : Tcpuregisterset;
  711. href : treference;
  712. pop_size : longint;
  713. pvreg,
  714. vmtreg : tregister;
  715. oldaktcallnode : tcallnode;
  716. begin
  717. if not assigned(procdefinition) or
  718. not procdefinition.has_paraloc_info then
  719. internalerror(200305264);
  720. if assigned(methodpointerinit) then
  721. secondpass(methodpointerinit);
  722. if resulttype.def.needs_inittable and
  723. not paramanager.ret_in_param(resulttype.def,procdefinition.proccalloption) and
  724. not assigned(funcretnode) then
  725. begin
  726. tg.gettemptyped(exprasmlist,resulttype.def,tt_normal,refcountedtemp);
  727. cg.g_decrrefcount(exprasmlist,resulttype.def,refcountedtemp);
  728. end;
  729. regs_to_save_int:=paramanager.get_volatile_registers_int(procdefinition.proccalloption);
  730. regs_to_save_fpu:=paramanager.get_volatile_registers_fpu(procdefinition.proccalloption);
  731. regs_to_save_mm:=paramanager.get_volatile_registers_mm(procdefinition.proccalloption);
  732. { Include Function result registers }
  733. if (not is_void(resulttype.def)) then
  734. begin
  735. case procdefinition.funcretloc[callerside].loc of
  736. LOC_REGISTER,
  737. LOC_CREGISTER:
  738. include(regs_to_save_int,getsupreg(procdefinition.funcretloc[callerside].register));
  739. LOC_FPUREGISTER,
  740. LOC_CFPUREGISTER:
  741. include(regs_to_save_fpu,getsupreg(procdefinition.funcretloc[callerside].register));
  742. LOC_MMREGISTER,
  743. LOC_CMMREGISTER:
  744. include(regs_to_save_mm,getsupreg(procdefinition.funcretloc[callerside].register));
  745. LOC_REFERENCE,
  746. LOC_VOID:
  747. ;
  748. else
  749. internalerror(2004110213);
  750. end;
  751. end;
  752. { Process parameters, register parameters will be loaded
  753. in imaginary registers. The actual load to the correct
  754. register is done just before the call }
  755. oldaktcallnode:=aktcallnode;
  756. aktcallnode:=self;
  757. if assigned(left) then
  758. tcallparanode(left).secondcallparan;
  759. aktcallnode:=oldaktcallnode;
  760. { procedure variable or normal function call ? }
  761. if (right=nil) then
  762. begin
  763. { When methodpointer is typen we don't need (and can't) load
  764. a pointer. We can directly call the correct procdef (PFV) }
  765. if (po_virtualmethod in procdefinition.procoptions) and
  766. assigned(methodpointer) and
  767. (methodpointer.nodetype<>typen) then
  768. begin
  769. { virtual methods require an index }
  770. if tprocdef(procdefinition).extnumber=$ffff then
  771. internalerror(200304021);
  772. secondpass(methodpointer);
  773. { Load VMT from self }
  774. if methodpointer.resulttype.def.deftype=objectdef then
  775. gen_load_vmt_register(exprasmlist,tobjectdef(methodpointer.resulttype.def),methodpointer.location,vmtreg)
  776. else
  777. begin
  778. { Load VMT value in register }
  779. location_force_reg(exprasmlist,methodpointer.location,OS_ADDR,false);
  780. vmtreg:=methodpointer.location.register;
  781. end;
  782. { test validity of VMT }
  783. if not(is_interface(tprocdef(procdefinition)._class)) and
  784. not(is_cppclass(tprocdef(procdefinition)._class)) then
  785. cg.g_maybe_testvmt(exprasmlist,vmtreg,tprocdef(procdefinition)._class);
  786. pvreg:=cg.getintregister(exprasmlist,OS_ADDR);
  787. reference_reset_base(href,vmtreg,
  788. tprocdef(procdefinition)._class.vmtmethodoffset(tprocdef(procdefinition).extnumber));
  789. cg.a_load_ref_reg(exprasmlist,OS_ADDR,OS_ADDR,href,pvreg);
  790. { Load parameters that are in temporary registers in the
  791. correct parameter register }
  792. if assigned(left) then
  793. begin
  794. pushparas;
  795. { free the resources allocated for the parameters }
  796. freeparas;
  797. end;
  798. cg.alloccpuregisters(exprasmlist,R_INTREGISTER,regs_to_save_int);
  799. if cg.uses_registers(R_FPUREGISTER) then
  800. cg.alloccpuregisters(exprasmlist,R_FPUREGISTER,regs_to_save_fpu);
  801. if cg.uses_registers(R_MMREGISTER) then
  802. cg.alloccpuregisters(exprasmlist,R_MMREGISTER,regs_to_save_mm);
  803. { call method }
  804. extra_call_code;
  805. cg.a_call_reg(exprasmlist,pvreg);
  806. extra_post_call_code;
  807. end
  808. else
  809. begin
  810. { Load parameters that are in temporary registers in the
  811. correct parameter register }
  812. if assigned(left) then
  813. begin
  814. pushparas;
  815. { free the resources allocated for the parameters }
  816. freeparas;
  817. end;
  818. cg.alloccpuregisters(exprasmlist,R_INTREGISTER,regs_to_save_int);
  819. if cg.uses_registers(R_FPUREGISTER) then
  820. cg.alloccpuregisters(exprasmlist,R_FPUREGISTER,regs_to_save_fpu);
  821. if cg.uses_registers(R_MMREGISTER) then
  822. cg.alloccpuregisters(exprasmlist,R_MMREGISTER,regs_to_save_mm);
  823. if procdefinition.proccalloption=pocall_syscall then
  824. do_syscall
  825. else
  826. begin
  827. { Calling interrupt from the same code requires some
  828. extra code }
  829. if (po_interrupt in procdefinition.procoptions) then
  830. extra_interrupt_code;
  831. extra_call_code;
  832. cg.a_call_name(exprasmlist,tprocdef(procdefinition).mangledname);
  833. extra_post_call_code;
  834. end;
  835. end;
  836. end
  837. else
  838. { now procedure variable case }
  839. begin
  840. secondpass(right);
  841. pvreg:=cg.getintregister(exprasmlist,OS_ADDR);
  842. { Only load OS_ADDR from the reference }
  843. if right.location.loc in [LOC_REFERENCE,LOC_CREFERENCE] then
  844. cg.a_load_ref_reg(exprasmlist,OS_ADDR,OS_ADDR,right.location.reference,pvreg)
  845. else
  846. cg.a_load_loc_reg(exprasmlist,OS_ADDR,right.location,pvreg);
  847. location_freetemp(exprasmlist,right.location);
  848. { Load parameters that are in temporary registers in the
  849. correct parameter register }
  850. if assigned(left) then
  851. begin
  852. pushparas;
  853. { free the resources allocated for the parameters }
  854. freeparas;
  855. end;
  856. cg.alloccpuregisters(exprasmlist,R_INTREGISTER,regs_to_save_int);
  857. if cg.uses_registers(R_FPUREGISTER) then
  858. cg.alloccpuregisters(exprasmlist,R_FPUREGISTER,regs_to_save_fpu);
  859. if cg.uses_registers(R_MMREGISTER) then
  860. cg.alloccpuregisters(exprasmlist,R_MMREGISTER,regs_to_save_mm);
  861. { Calling interrupt from the same code requires some
  862. extra code }
  863. if (po_interrupt in procdefinition.procoptions) then
  864. extra_interrupt_code;
  865. extra_call_code;
  866. cg.a_call_reg(exprasmlist,pvreg);
  867. extra_post_call_code;
  868. end;
  869. { Need to remove the parameters from the stack? }
  870. if (procdefinition.proccalloption in clearstack_pocalls) then
  871. begin
  872. pop_size:=pushedparasize;
  873. { for Cdecl functions we don't need to pop the funcret when it
  874. was pushed by para }
  875. if paramanager.ret_in_param(procdefinition.rettype.def,procdefinition.proccalloption) then
  876. dec(pop_size,sizeof(aint));
  877. { Remove parameters/alignment from the stack }
  878. pop_parasize(pop_size);
  879. end;
  880. { Release registers, but not the registers that contain the
  881. function result }
  882. if (not is_void(resulttype.def)) then
  883. begin
  884. case procdefinition.funcretloc[callerside].loc of
  885. LOC_REGISTER,
  886. LOC_CREGISTER:
  887. begin
  888. {$ifndef cpu64bit}
  889. if procdefinition.funcretloc[callerside].size in [OS_64,OS_S64] then
  890. begin
  891. exclude(regs_to_save_int,getsupreg(procdefinition.funcretloc[callerside].register64.reghi));
  892. exclude(regs_to_save_int,getsupreg(procdefinition.funcretloc[callerside].register64.reglo));
  893. end
  894. else
  895. {$endif cpu64bit}
  896. exclude(regs_to_save_int,getsupreg(procdefinition.funcretloc[callerside].register));
  897. end;
  898. LOC_FPUREGISTER,
  899. LOC_CFPUREGISTER:
  900. exclude(regs_to_save_fpu,getsupreg(procdefinition.funcretloc[callerside].register));
  901. LOC_MMREGISTER,
  902. LOC_CMMREGISTER:
  903. exclude(regs_to_save_mm,getsupreg(procdefinition.funcretloc[callerside].register));
  904. LOC_REFERENCE,
  905. LOC_VOID:
  906. ;
  907. else
  908. internalerror(2004110214);
  909. end;
  910. end;
  911. if cg.uses_registers(R_MMREGISTER) then
  912. cg.dealloccpuregisters(exprasmlist,R_MMREGISTER,regs_to_save_mm);
  913. if cg.uses_registers(R_FPUREGISTER) then
  914. cg.dealloccpuregisters(exprasmlist,R_FPUREGISTER,regs_to_save_fpu);
  915. cg.dealloccpuregisters(exprasmlist,R_INTREGISTER,regs_to_save_int);
  916. { handle function results }
  917. if (not is_void(resulttype.def)) then
  918. handle_return_value
  919. else
  920. location_reset(location,LOC_VOID,OS_NO);
  921. { perhaps i/o check ? }
  922. if (cs_check_io in aktlocalswitches) and
  923. (po_iocheck in procdefinition.procoptions) and
  924. not(po_iocheck in current_procinfo.procdef.procoptions) and
  925. { no IO check for methods and procedure variables }
  926. (right=nil) and
  927. not(po_virtualmethod in procdefinition.procoptions) then
  928. begin
  929. cg.allocallcpuregisters(exprasmlist);
  930. cg.a_call_name(exprasmlist,'FPC_IOCHECK');
  931. cg.deallocallcpuregisters(exprasmlist);
  932. end;
  933. { release temps of paras }
  934. release_para_temps;
  935. if assigned(methodpointerdone) then
  936. secondpass(methodpointerdone);
  937. end;
  938. begin
  939. ccallparanode:=tcgcallparanode;
  940. ccallnode:=tcgcallnode;
  941. end.