ncgcal.pas 53 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306
  1. {
  2. $Id$
  3. Copyright (c) 1998-2002 by Florian Klaempfl
  4. Generate assembler for call nodes
  5. This program is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 2 of the License, or
  8. (at your option) any later version.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with this program; if not, write to the Free Software
  15. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  16. ****************************************************************************
  17. }
  18. unit ncgcal;
  19. {$i fpcdefs.inc}
  20. interface
  21. uses
  22. cpubase,
  23. globtype,
  24. parabase,cgutils,
  25. symdef,node,ncal;
  26. type
  27. tcgcallparanode = class(tcallparanode)
  28. private
  29. tempcgpara : tcgpara;
  30. procedure push_addr_para;
  31. procedure push_value_para;
  32. public
  33. constructor create(expr,next : tnode);override;
  34. destructor destroy;override;
  35. procedure secondcallparan;override;
  36. end;
  37. tcgcallnode = class(tcallnode)
  38. private
  39. procedure release_para_temps;
  40. procedure normal_pass_2;
  41. {$ifdef PASS2INLINE}
  42. procedure inlined_pass_2;
  43. {$endif PASS2INLINE}
  44. procedure pushparas;
  45. procedure freeparas;
  46. protected
  47. framepointer_paraloc : tcgpara;
  48. refcountedtemp : treference;
  49. procedure handle_return_value;
  50. {# This routine is used to push the current frame pointer
  51. on the stack. This is used in nested routines where the
  52. value of the frame pointer is always pushed as an extra
  53. parameter.
  54. The default handling is the standard handling used on
  55. most stack based machines, where the frame pointer is
  56. the first invisible parameter.
  57. }
  58. procedure pop_parasize(pop_size:longint);virtual;
  59. procedure extra_interrupt_code;virtual;
  60. procedure extra_call_code;virtual;
  61. procedure extra_post_call_code;virtual;
  62. procedure do_syscall;virtual;abstract;
  63. public
  64. procedure pass_2;override;
  65. end;
  66. implementation
  67. uses
  68. systems,
  69. cutils,verbose,globals,
  70. symconst,symtable,defutil,paramgr,
  71. {$ifdef GDB}
  72. strings,
  73. gdb,
  74. {$endif GDB}
  75. cgbase,pass_2,
  76. aasmbase,aasmtai,
  77. nbas,nmem,nld,ncnv,nutils,
  78. {$ifdef x86}
  79. cga,cgx86,
  80. {$endif x86}
  81. ncgutil,
  82. cgobj,tgobj,
  83. procinfo;
  84. {*****************************************************************************
  85. TCGCALLPARANODE
  86. *****************************************************************************}
  87. constructor tcgcallparanode.create(expr,next : tnode);
  88. begin
  89. inherited create(expr,next);
  90. tempcgpara.init;
  91. end;
  92. destructor tcgcallparanode.destroy;
  93. begin
  94. tempcgpara.done;
  95. inherited destroy;
  96. end;
  97. procedure tcgcallparanode.push_addr_para;
  98. begin
  99. if not(left.location.loc in [LOC_CREFERENCE,LOC_REFERENCE]) then
  100. internalerror(200304235);
  101. cg.a_paramaddr_ref(exprasmlist,left.location.reference,tempcgpara);
  102. end;
  103. procedure tcgcallparanode.push_value_para;
  104. {$ifdef i386}
  105. var
  106. href : treference;
  107. size : longint;
  108. {$endif i386}
  109. begin
  110. { we've nothing to push when the size of the parameter is 0 }
  111. if left.resulttype.def.size=0 then
  112. exit;
  113. { Move flags and jump in register to make it less complex }
  114. if left.location.loc in [LOC_FLAGS,LOC_JUMP] then
  115. location_force_reg(exprasmlist,left.location,def_cgsize(left.resulttype.def),false);
  116. { Handle Floating point types differently }
  117. if left.resulttype.def.deftype=floatdef then
  118. begin
  119. {$ifdef i386}
  120. if tempcgpara.location^.loc<>LOC_REFERENCE then
  121. internalerror(200309291);
  122. case left.location.loc of
  123. LOC_FPUREGISTER,
  124. LOC_CFPUREGISTER:
  125. begin
  126. size:=align(TCGSize2Size[left.location.size],tempcgpara.alignment);
  127. if tempcgpara.location^.reference.index=NR_STACK_POINTER_REG then
  128. begin
  129. cg.g_stackpointer_alloc(exprasmlist,size);
  130. reference_reset_base(href,NR_STACK_POINTER_REG,0);
  131. end
  132. else
  133. reference_reset_base(href,tempcgpara.location^.reference.index,tempcgpara.location^.reference.offset);
  134. cg.a_loadfpu_reg_ref(exprasmlist,left.location.size,left.location.register,href);
  135. end;
  136. LOC_MMREGISTER,
  137. LOC_CMMREGISTER:
  138. begin
  139. size:=align(tfloatdef(left.resulttype.def).size,tempcgpara.alignment);
  140. if tempcgpara.location^.reference.index=NR_STACK_POINTER_REG then
  141. begin
  142. cg.g_stackpointer_alloc(exprasmlist,size);
  143. reference_reset_base(href,NR_STACK_POINTER_REG,0);
  144. end
  145. else
  146. reference_reset_base(href,tempcgpara.location^.reference.index,tempcgpara.location^.reference.offset);
  147. cg.a_loadmm_reg_ref(exprasmlist,left.location.size,left.location.size,left.location.register,href,mms_movescalar);
  148. end;
  149. LOC_REFERENCE,
  150. LOC_CREFERENCE :
  151. begin
  152. size:=align(left.resulttype.def.size,tempcgpara.alignment);
  153. if tempcgpara.location^.reference.index=NR_STACK_POINTER_REG then
  154. cg.a_param_ref(exprasmlist,left.location.size,left.location.reference,tempcgpara)
  155. else
  156. begin
  157. reference_reset_base(href,tempcgpara.location^.reference.index,tempcgpara.location^.reference.offset);
  158. cg.g_concatcopy(exprasmlist,left.location.reference,href,size);
  159. end;
  160. end;
  161. else
  162. internalerror(2002042430);
  163. end;
  164. {$else i386}
  165. case left.location.loc of
  166. LOC_MMREGISTER,
  167. LOC_CMMREGISTER:
  168. case tempcgpara.location^.loc of
  169. LOC_REFERENCE,
  170. LOC_CREFERENCE,
  171. LOC_MMREGISTER,
  172. LOC_CMMREGISTER:
  173. cg.a_parammm_reg(exprasmlist,left.location.size,left.location.register,tempcgpara,mms_movescalar);
  174. LOC_FPUREGISTER,
  175. LOC_CFPUREGISTER:
  176. begin
  177. location_force_fpureg(exprasmlist,left.location,false);
  178. cg.a_paramfpu_reg(exprasmlist,left.location.size,left.location.register,tempcgpara);
  179. end;
  180. else
  181. internalerror(2002042433);
  182. end;
  183. LOC_FPUREGISTER,
  184. LOC_CFPUREGISTER:
  185. case tempcgpara.location^.loc of
  186. LOC_MMREGISTER,
  187. LOC_CMMREGISTER:
  188. begin
  189. location_force_mmregscalar(exprasmlist,left.location,false);
  190. cg.a_parammm_reg(exprasmlist,left.location.size,left.location.register,tempcgpara,mms_movescalar);
  191. end;
  192. {$ifdef x86_64}
  193. { x86_64 pushes s64comp in normal register }
  194. LOC_REGISTER,
  195. LOC_CREGISTER :
  196. begin
  197. location_force_mem(exprasmlist,left.location);
  198. { force integer size }
  199. left.location.size:=int_cgsize(tcgsize2size[left.location.size]);
  200. cg.a_param_ref(exprasmlist,left.location.size,left.location.reference,tempcgpara);
  201. end;
  202. {$endif x86_64}
  203. {$ifdef sparc}
  204. { sparc pushes floats in normal registers }
  205. LOC_REGISTER,
  206. LOC_CREGISTER,
  207. {$endif sparc}
  208. LOC_REFERENCE,
  209. LOC_CREFERENCE,
  210. LOC_FPUREGISTER,
  211. LOC_CFPUREGISTER:
  212. cg.a_paramfpu_reg(exprasmlist,left.location.size,left.location.register,tempcgpara);
  213. else
  214. internalerror(2002042433);
  215. end;
  216. LOC_REFERENCE,
  217. LOC_CREFERENCE:
  218. case tempcgpara.location^.loc of
  219. LOC_MMREGISTER,
  220. LOC_CMMREGISTER:
  221. cg.a_parammm_ref(exprasmlist,left.location.size,left.location.reference,tempcgpara,mms_movescalar);
  222. {$ifdef x86_64}
  223. { x86_64 pushes s64comp in normal register }
  224. LOC_REGISTER,
  225. LOC_CREGISTER :
  226. begin
  227. { force integer size }
  228. left.location.size:=int_cgsize(tcgsize2size[left.location.size]);
  229. cg.a_param_ref(exprasmlist,left.location.size,left.location.reference,tempcgpara);
  230. end;
  231. {$endif x86_64}
  232. {$ifdef sparc}
  233. { sparc pushes floats in normal registers }
  234. LOC_REGISTER,
  235. LOC_CREGISTER,
  236. {$endif sparc}
  237. LOC_REFERENCE,
  238. LOC_CREFERENCE,
  239. LOC_FPUREGISTER,
  240. LOC_CFPUREGISTER:
  241. cg.a_paramfpu_ref(exprasmlist,left.location.size,left.location.reference,tempcgpara);
  242. else
  243. internalerror(2002042431);
  244. end;
  245. else
  246. internalerror(2002042432);
  247. end;
  248. {$endif i386}
  249. end
  250. else
  251. begin
  252. case left.location.loc of
  253. LOC_CONSTANT,
  254. LOC_REGISTER,
  255. LOC_CREGISTER,
  256. LOC_REFERENCE,
  257. LOC_CREFERENCE :
  258. begin
  259. {$ifndef cpu64bit}
  260. { use cg64 only for int64, not for 8 byte records }
  261. if is_64bit(left.resulttype.def) then
  262. cg64.a_param64_loc(exprasmlist,left.location,tempcgpara)
  263. else
  264. {$endif cpu64bit}
  265. begin
  266. {$ifndef cpu64bit}
  267. { Only a_param_ref supports multiple locations, when the
  268. value is still a const or in a register then write it
  269. to a reference first. This situation can be triggered
  270. by typecasting an int64 constant to a record of 8 bytes }
  271. if left.location.size in [OS_64,OS_S64] then
  272. location_force_mem(exprasmlist,left.location);
  273. {$endif cpu64bit}
  274. cg.a_param_loc(exprasmlist,left.location,tempcgpara);
  275. end;
  276. end;
  277. {$ifdef SUPPORT_MMX}
  278. LOC_MMXREGISTER,
  279. LOC_CMMXREGISTER:
  280. cg.a_parammm_reg(exprasmlist,left.location.register);
  281. {$endif SUPPORT_MMX}
  282. else
  283. internalerror(200204241);
  284. end;
  285. end;
  286. end;
  287. procedure tcgcallparanode.secondcallparan;
  288. var
  289. href : treference;
  290. otlabel,
  291. oflabel : tasmlabel;
  292. begin
  293. if not(assigned(parasym)) then
  294. internalerror(200304242);
  295. { Skip nothingn nodes which are used after disabling
  296. a parameter }
  297. if (left.nodetype<>nothingn) then
  298. begin
  299. otlabel:=truelabel;
  300. oflabel:=falselabel;
  301. objectlibrary.getlabel(truelabel);
  302. objectlibrary.getlabel(falselabel);
  303. secondpass(left);
  304. { release memory for refcnt out parameters }
  305. if (parasym.varspez=vs_out) and
  306. (left.resulttype.def.needs_inittable) then
  307. begin
  308. location_get_data_ref(exprasmlist,left.location,href,false);
  309. cg.g_decrrefcount(exprasmlist,left.resulttype.def,href);
  310. end;
  311. {$ifdef PASS2INLINE}
  312. if assigned(aktcallnode.inlinecode) then
  313. paramanager.duplicateparaloc(exprasmlist,aktcallnode.procdefinition.proccalloption,parasym,tempcgpara)
  314. else
  315. {$endif PASS2INLINE}
  316. paramanager.createtempparaloc(exprasmlist,aktcallnode.procdefinition.proccalloption,parasym,tempcgpara);
  317. { handle varargs first, because parasym is not valid }
  318. if (cpf_varargs_para in callparaflags) then
  319. begin
  320. if paramanager.push_addr_param(vs_value,left.resulttype.def,
  321. aktcallnode.procdefinition.proccalloption) then
  322. push_addr_para
  323. else
  324. push_value_para;
  325. end
  326. { hidden parameters }
  327. else if (vo_is_hidden_para in parasym.varoptions) then
  328. begin
  329. { don't push a node that already generated a pointer type
  330. by address for implicit hidden parameters }
  331. if (vo_is_funcret in parasym.varoptions) or
  332. (not(left.resulttype.def.deftype in [pointerdef,classrefdef]) and
  333. paramanager.push_addr_param(parasym.varspez,parasym.vartype.def,
  334. aktcallnode.procdefinition.proccalloption)) then
  335. push_addr_para
  336. else
  337. push_value_para;
  338. end
  339. { formal def }
  340. else if (parasym.vartype.def.deftype=formaldef) then
  341. begin
  342. { allow passing of a constant to a const formaldef }
  343. if (parasym.varspez=vs_const) and
  344. (left.location.loc=LOC_CONSTANT) then
  345. location_force_mem(exprasmlist,left.location);
  346. push_addr_para;
  347. end
  348. { Normal parameter }
  349. else
  350. begin
  351. { don't push a node that already generated a pointer type
  352. by address for implicit hidden parameters }
  353. if (not(
  354. (vo_is_hidden_para in parasym.varoptions) and
  355. (left.resulttype.def.deftype in [pointerdef,classrefdef])
  356. ) and
  357. paramanager.push_addr_param(parasym.varspez,parasym.vartype.def,
  358. aktcallnode.procdefinition.proccalloption)) then
  359. begin
  360. { Passing a var parameter to a var parameter, we can
  361. just push the address transparently }
  362. if (left.nodetype=loadn) and
  363. (tloadnode(left).is_addr_param_load) then
  364. begin
  365. if (left.location.reference.index<>NR_NO) or
  366. (left.location.reference.offset<>0) then
  367. internalerror(200410107);
  368. cg.a_param_reg(exprasmlist,OS_ADDR,left.location.reference.base,tempcgpara)
  369. end
  370. else
  371. begin
  372. { Check for passing a constant to var,out parameter }
  373. if (parasym.varspez in [vs_var,vs_out]) and
  374. (left.location.loc<>LOC_REFERENCE) then
  375. begin
  376. { passing self to a var parameter is allowed in
  377. TP and delphi }
  378. if not((left.location.loc=LOC_CREFERENCE) and
  379. is_self_node(left)) then
  380. internalerror(200106041);
  381. end;
  382. { Force to be in memory }
  383. if not(left.location.loc in [LOC_CREFERENCE,LOC_REFERENCE]) then
  384. location_force_mem(exprasmlist,left.location);
  385. push_addr_para;
  386. end;
  387. end
  388. else
  389. push_value_para;
  390. end;
  391. truelabel:=otlabel;
  392. falselabel:=oflabel;
  393. { update return location in callnode when this is the function
  394. result }
  395. if assigned(parasym) and
  396. (vo_is_funcret in parasym.varoptions) then
  397. location_copy(aktcallnode.location,left.location);
  398. end;
  399. { next parameter }
  400. if assigned(right) then
  401. tcallparanode(right).secondcallparan;
  402. end;
  403. {*****************************************************************************
  404. TCGCALLNODE
  405. *****************************************************************************}
  406. procedure tcgcallnode.extra_interrupt_code;
  407. begin
  408. end;
  409. procedure tcgcallnode.extra_call_code;
  410. begin
  411. end;
  412. procedure tcgcallnode.extra_post_call_code;
  413. begin
  414. end;
  415. procedure tcgcallnode.pop_parasize(pop_size:longint);
  416. begin
  417. end;
  418. procedure tcgcallnode.handle_return_value;
  419. var
  420. cgsize : tcgsize;
  421. retloc : tlocation;
  422. hregister : tregister;
  423. tempnode : tnode;
  424. begin
  425. cgsize:=procdefinition.funcretloc[callerside].size;
  426. { structured results are easy to handle....
  427. needed also when result_no_used !! }
  428. if (procdefinition.proctypeoption<>potype_constructor) and
  429. paramanager.ret_in_param(resulttype.def,procdefinition.proccalloption) then
  430. begin
  431. { Location should be setup by the funcret para }
  432. if location.loc<>LOC_REFERENCE then
  433. internalerror(200304241);
  434. end
  435. else
  436. { ansi/widestrings must be registered, so we can dispose them }
  437. if resulttype.def.needs_inittable then
  438. begin
  439. if procdefinition.funcretloc[callerside].loc<>LOC_REGISTER then
  440. internalerror(200409261);
  441. { the FUNCTION_RESULT_REG is already allocated }
  442. if getsupreg(procdefinition.funcretloc[callerside].register)<first_int_imreg then
  443. cg.ungetcpuregister(exprasmlist,procdefinition.funcretloc[callerside].register);
  444. if not assigned(funcretnode) then
  445. begin
  446. { reg_ref could generate two instrcutions and allocate a register so we've to
  447. save the result first before releasing it }
  448. hregister:=cg.getaddressregister(exprasmlist);
  449. cg.a_load_reg_reg(exprasmlist,OS_ADDR,OS_ADDR,procdefinition.funcretloc[callerside].register,hregister);
  450. location_reset(location,LOC_REFERENCE,OS_ADDR);
  451. location.reference:=refcountedtemp;
  452. cg.a_load_reg_ref(exprasmlist,OS_ADDR,OS_ADDR,hregister,location.reference);
  453. end
  454. else
  455. begin
  456. hregister := cg.getaddressregister(exprasmlist);
  457. cg.a_load_reg_reg(exprasmlist,OS_ADDR,OS_ADDR,procdefinition.funcretloc[callerside].register,hregister);
  458. { in case of a regular funcretnode with ret_in_param, the }
  459. { original funcretnode isn't touched -> make sure it's }
  460. { the same here (not sure if it's necessary) }
  461. tempnode := funcretnode.getcopy;
  462. tempnode.pass_2;
  463. location := tempnode.location;
  464. tempnode.free;
  465. cg.g_decrrefcount(exprasmlist,resulttype.def,location.reference);
  466. cg.a_load_reg_ref(exprasmlist,OS_ADDR,OS_ADDR,hregister,location.reference);
  467. end;
  468. end
  469. else
  470. { normal (ordinal,float,pointer) result value }
  471. begin
  472. { we have only to handle the result if it is used }
  473. if (cnf_return_value_used in callnodeflags) then
  474. begin
  475. location.loc:=procdefinition.funcretloc[callerside].loc;
  476. case procdefinition.funcretloc[callerside].loc of
  477. LOC_FPUREGISTER:
  478. begin
  479. location_reset(location,LOC_FPUREGISTER,cgsize);
  480. location.register:=procdefinition.funcretloc[callerside].register;
  481. {$ifdef x86}
  482. tcgx86(cg).inc_fpu_stack;
  483. {$else x86}
  484. if getsupreg(procdefinition.funcretloc[callerside].register)<first_fpu_imreg then
  485. cg.ungetcpuregister(exprasmlist,procdefinition.funcretloc[callerside].register);
  486. hregister:=cg.getfpuregister(exprasmlist,location.size);
  487. cg.a_loadfpu_reg_reg(exprasmlist,location.size,location.register,hregister);
  488. location.register:=hregister;
  489. {$endif x86}
  490. end;
  491. LOC_REGISTER:
  492. begin
  493. if cgsize<>OS_NO then
  494. begin
  495. location_reset(location,LOC_REGISTER,cgsize);
  496. {$ifndef cpu64bit}
  497. if cgsize in [OS_64,OS_S64] then
  498. begin
  499. retloc:=procdefinition.funcretloc[callerside];
  500. if retloc.loc<>LOC_REGISTER then
  501. internalerror(200409141);
  502. { the function result registers are already allocated }
  503. if getsupreg(retloc.register64.reglo)<first_int_imreg then
  504. cg.ungetcpuregister(exprasmlist,retloc.register64.reglo);
  505. location.register64.reglo:=cg.getintregister(exprasmlist,OS_32);
  506. cg.a_load_reg_reg(exprasmlist,OS_32,OS_32,retloc.register64.reglo,location.register64.reglo);
  507. if getsupreg(retloc.register64.reghi)<first_int_imreg then
  508. cg.ungetcpuregister(exprasmlist,retloc.register64.reghi);
  509. location.register64.reghi:=cg.getintregister(exprasmlist,OS_32);
  510. cg.a_load_reg_reg(exprasmlist,OS_32,OS_32,retloc.register64.reghi,location.register64.reghi);
  511. end
  512. else
  513. {$endif cpu64bit}
  514. begin
  515. { change register size after the unget because the
  516. getregister was done for the full register
  517. def_cgsize(resulttype.def) is used here because
  518. it could be a constructor call }
  519. if getsupreg(procdefinition.funcretloc[callerside].register)<first_int_imreg then
  520. cg.ungetcpuregister(exprasmlist,procdefinition.funcretloc[callerside].register);
  521. location.register:=cg.getintregister(exprasmlist,def_cgsize(resulttype.def));
  522. cg.a_load_reg_reg(exprasmlist,cgsize,def_cgsize(resulttype.def),procdefinition.funcretloc[callerside].register,location.register);
  523. end;
  524. end
  525. else
  526. begin
  527. if resulttype.def.size>0 then
  528. internalerror(200305131);
  529. end;
  530. end;
  531. LOC_MMREGISTER:
  532. begin
  533. location_reset(location,LOC_MMREGISTER,cgsize);
  534. if getsupreg(procdefinition.funcretloc[callerside].register)<first_mm_imreg then
  535. cg.ungetcpuregister(exprasmlist,procdefinition.funcretloc[callerside].register);
  536. location.register:=cg.getmmregister(exprasmlist,cgsize);
  537. cg.a_loadmm_reg_reg(exprasmlist,cgsize,cgsize,procdefinition.funcretloc[callerside].register,location.register,mms_movescalar);
  538. end;
  539. else
  540. internalerror(200405023);
  541. end;
  542. end
  543. else
  544. begin
  545. {$ifdef x86}
  546. { release FPU stack }
  547. if procdefinition.funcretloc[callerside].loc=LOC_FPUREGISTER then
  548. emit_reg(A_FSTP,S_NO,NR_FPU_RESULT_REG);
  549. {$endif x86}
  550. if cgsize<>OS_NO then
  551. location_free(exprasmlist,procdefinition.funcretloc[callerside]);
  552. location_reset(location,LOC_VOID,OS_NO);
  553. end;
  554. end;
  555. { When the result is not used we need to finalize the result and
  556. can release the temp }
  557. if not(cnf_return_value_used in callnodeflags) then
  558. begin
  559. if location.loc=LOC_REFERENCE then
  560. begin
  561. if resulttype.def.needs_inittable then
  562. cg.g_finalize(exprasmlist,resulttype.def,location.reference);
  563. tg.ungetiftemp(exprasmlist,location.reference)
  564. end;
  565. end;
  566. end;
  567. procedure tcgcallnode.release_para_temps;
  568. var
  569. hp : tnode;
  570. ppn : tcallparanode;
  571. begin
  572. { Release temps from parameters }
  573. ppn:=tcallparanode(left);
  574. while assigned(ppn) do
  575. begin
  576. if assigned(ppn.left) then
  577. begin
  578. { don't release the funcret temp }
  579. if not(assigned(ppn.parasym)) or
  580. not(vo_is_funcret in ppn.parasym.varoptions) then
  581. location_freetemp(exprasmlist,ppn.left.location);
  582. { process also all nodes of an array of const }
  583. hp:=ppn.left;
  584. while (hp.nodetype=typeconvn) do
  585. hp:=ttypeconvnode(hp).left;
  586. if (hp.nodetype=arrayconstructorn) and
  587. assigned(tarrayconstructornode(hp).left) then
  588. begin
  589. while assigned(hp) do
  590. begin
  591. location_freetemp(exprasmlist,tarrayconstructornode(hp).left.location);
  592. hp:=tarrayconstructornode(hp).right;
  593. end;
  594. end;
  595. end;
  596. ppn:=tcallparanode(ppn.right);
  597. end;
  598. end;
  599. procedure tcgcallnode.pushparas;
  600. var
  601. ppn : tcgcallparanode;
  602. callerparaloc,
  603. tmpparaloc : pcgparalocation;
  604. sizeleft: aint;
  605. {$ifdef cputargethasfixedstack}
  606. htempref,
  607. href : treference;
  608. {$endif cputargethasfixedstack}
  609. begin
  610. { copy all resources to the allocated registers }
  611. ppn:=tcgcallparanode(left);
  612. while assigned(ppn) do
  613. begin
  614. if (ppn.left.nodetype<>nothingn) then
  615. begin
  616. { better check for the real location of the parameter here, when stack passed parameters
  617. are saved temporary in registers, checking for the tmpparaloc.loc is wrong
  618. }
  619. {$ifdef PASS2INLINE}
  620. if not assigned(inlinecode) then
  621. {$endif PASS2INLINE}
  622. paramanager.freeparaloc(exprasmlist,ppn.tempcgpara);
  623. tmpparaloc:=ppn.tempcgpara.location;
  624. sizeleft:=ppn.tempcgpara.intsize;
  625. callerparaloc:=ppn.parasym.paraloc[callerside].location;
  626. while assigned(callerparaloc) do
  627. begin
  628. { Every paraloc must have a matching tmpparaloc }
  629. if not assigned(tmpparaloc) then
  630. internalerror(200408224);
  631. if callerparaloc^.size<>tmpparaloc^.size then
  632. internalerror(200408225);
  633. case callerparaloc^.loc of
  634. LOC_REGISTER:
  635. begin
  636. if tmpparaloc^.loc<>LOC_REGISTER then
  637. internalerror(200408221);
  638. if getsupreg(callerparaloc^.register)<first_int_imreg then
  639. cg.getcpuregister(exprasmlist,callerparaloc^.register);
  640. cg.a_load_reg_reg(exprasmlist,tmpparaloc^.size,tmpparaloc^.size,
  641. tmpparaloc^.register,callerparaloc^.register);
  642. end;
  643. LOC_FPUREGISTER:
  644. begin
  645. if tmpparaloc^.loc<>LOC_FPUREGISTER then
  646. internalerror(200408222);
  647. if getsupreg(callerparaloc^.register)<first_fpu_imreg then
  648. cg.getcpuregister(exprasmlist,callerparaloc^.register);
  649. cg.a_loadfpu_reg_reg(exprasmlist,ppn.tempcgpara.size,tmpparaloc^.register,callerparaloc^.register);
  650. end;
  651. LOC_MMREGISTER:
  652. begin
  653. if tmpparaloc^.loc<>LOC_MMREGISTER then
  654. internalerror(200408223);
  655. if getsupreg(callerparaloc^.register)<first_mm_imreg then
  656. cg.getcpuregister(exprasmlist,callerparaloc^.register);
  657. cg.a_loadmm_reg_reg(exprasmlist,tmpparaloc^.size,tmpparaloc^.size,
  658. tmpparaloc^.register,callerparaloc^.register,mms_movescalar);
  659. end;
  660. LOC_REFERENCE:
  661. begin
  662. {$ifdef PASS2INLINE}
  663. if not assigned(inlinecode) then
  664. {$endif PASS2INLINE}
  665. begin
  666. {$ifdef cputargethasfixedstack}
  667. { Can't have a data copied to the stack, every location
  668. must contain a valid size field }
  669. if (ppn.tempcgpara.size=OS_NO) and
  670. ((tmpparaloc^.loc<>LOC_REFERENCE) or
  671. assigned(tmpparaloc^.next)) then
  672. internalerror(200501281);
  673. reference_reset_base(href,callerparaloc^.reference.index,callerparaloc^.reference.offset);
  674. { copy parameters in case they were moved to a temp. location because we've a fixed stack }
  675. case tmpparaloc^.loc of
  676. LOC_REFERENCE:
  677. begin
  678. reference_reset_base(htempref,tmpparaloc^.reference.index,tmpparaloc^.reference.offset);
  679. { use concatcopy, because it can also be a float which fails when
  680. load_ref_ref is used }
  681. if (ppn.tempcgpara.size <> OS_NO) then
  682. cg.g_concatcopy(exprasmlist,htempref,href,tcgsize2size[tmpparaloc^.size])
  683. else
  684. cg.g_concatcopy(exprasmlist,htempref,href,sizeleft)
  685. end;
  686. LOC_REGISTER:
  687. cg.a_load_reg_ref(exprasmlist,tmpparaloc^.size,tmpparaloc^.size,tmpparaloc^.register,href);
  688. LOC_FPUREGISTER:
  689. cg.a_loadfpu_reg_ref(exprasmlist,tmpparaloc^.size,tmpparaloc^.register,href);
  690. LOC_MMREGISTER:
  691. cg.a_loadmm_reg_ref(exprasmlist,tmpparaloc^.size,tmpparaloc^.size,tmpparaloc^.register,href,mms_movescalar);
  692. else
  693. internalerror(200402081);
  694. end;
  695. {$endif cputargethasfixedstack}
  696. end;
  697. end;
  698. end;
  699. dec(sizeleft,tcgsize2size[tmpparaloc^.size]);
  700. callerparaloc:=callerparaloc^.next;
  701. tmpparaloc:=tmpparaloc^.next;
  702. end;
  703. end;
  704. ppn:=tcgcallparanode(ppn.right);
  705. end;
  706. end;
  707. procedure tcgcallnode.freeparas;
  708. var
  709. ppn : tcgcallparanode;
  710. begin
  711. { free the resources allocated for the parameters }
  712. ppn:=tcgcallparanode(left);
  713. while assigned(ppn) do
  714. begin
  715. if (ppn.left.nodetype<>nothingn) then
  716. begin
  717. if
  718. {$ifdef PASS2INLINE}
  719. not assigned(inlinecode) or
  720. {$endif PASS2INLINE}
  721. (ppn.parasym.paraloc[callerside].location^.loc <> LOC_REFERENCE) then
  722. paramanager.freeparaloc(exprasmlist,ppn.parasym.paraloc[callerside]);
  723. end;
  724. ppn:=tcgcallparanode(ppn.right);
  725. end;
  726. end;
  727. procedure tcgcallnode.normal_pass_2;
  728. var
  729. regs_to_save_int,
  730. regs_to_save_fpu,
  731. regs_to_save_mm : Tcpuregisterset;
  732. href : treference;
  733. pop_size : longint;
  734. pvreg,
  735. vmtreg : tregister;
  736. oldaktcallnode : tcallnode;
  737. begin
  738. if not assigned(procdefinition) or
  739. not procdefinition.has_paraloc_info then
  740. internalerror(200305264);
  741. if resulttype.def.needs_inittable and
  742. not paramanager.ret_in_param(resulttype.def,procdefinition.proccalloption) and
  743. not assigned(funcretnode) then
  744. begin
  745. tg.gettemptyped(exprasmlist,resulttype.def,tt_normal,refcountedtemp);
  746. cg.g_decrrefcount(exprasmlist,resulttype.def,refcountedtemp);
  747. end;
  748. regs_to_save_int:=paramanager.get_volatile_registers_int(procdefinition.proccalloption);
  749. regs_to_save_fpu:=paramanager.get_volatile_registers_fpu(procdefinition.proccalloption);
  750. regs_to_save_mm:=paramanager.get_volatile_registers_mm(procdefinition.proccalloption);
  751. { Include Function result registers }
  752. if (not is_void(resulttype.def)) then
  753. begin
  754. case procdefinition.funcretloc[callerside].loc of
  755. LOC_REGISTER,
  756. LOC_CREGISTER:
  757. include(regs_to_save_int,getsupreg(procdefinition.funcretloc[callerside].register));
  758. LOC_FPUREGISTER,
  759. LOC_CFPUREGISTER:
  760. include(regs_to_save_fpu,getsupreg(procdefinition.funcretloc[callerside].register));
  761. LOC_MMREGISTER,
  762. LOC_CMMREGISTER:
  763. include(regs_to_save_mm,getsupreg(procdefinition.funcretloc[callerside].register));
  764. LOC_REFERENCE,
  765. LOC_VOID:
  766. ;
  767. else
  768. internalerror(2004110213);
  769. end;
  770. end;
  771. { Process parameters, register parameters will be loaded
  772. in imaginary registers. The actual load to the correct
  773. register is done just before the call }
  774. oldaktcallnode:=aktcallnode;
  775. aktcallnode:=self;
  776. if assigned(left) then
  777. tcallparanode(left).secondcallparan;
  778. aktcallnode:=oldaktcallnode;
  779. { procedure variable or normal function call ? }
  780. if (right=nil) then
  781. begin
  782. { When methodpointer is typen we don't need (and can't) load
  783. a pointer. We can directly call the correct procdef (PFV) }
  784. if (po_virtualmethod in procdefinition.procoptions) and
  785. assigned(methodpointer) and
  786. (methodpointer.nodetype<>typen) then
  787. begin
  788. secondpass(methodpointer);
  789. location_force_reg(exprasmlist,methodpointer.location,OS_ADDR,false);
  790. { virtual methods require an index }
  791. if tprocdef(procdefinition).extnumber=$ffff then
  792. internalerror(200304021);
  793. { VMT should already be loaded in a register }
  794. if methodpointer.location.register=NR_NO then
  795. internalerror(200304022);
  796. { test validity of VMT }
  797. if not(is_interface(tprocdef(procdefinition)._class)) and
  798. not(is_cppclass(tprocdef(procdefinition)._class)) then
  799. cg.g_maybe_testvmt(exprasmlist,methodpointer.location.register,tprocdef(procdefinition)._class);
  800. vmtreg:=methodpointer.location.register;
  801. pvreg:=cg.getintregister(exprasmlist,OS_ADDR);
  802. reference_reset_base(href,vmtreg,
  803. tprocdef(procdefinition)._class.vmtmethodoffset(tprocdef(procdefinition).extnumber));
  804. cg.a_load_ref_reg(exprasmlist,OS_ADDR,OS_ADDR,href,pvreg);
  805. { Load parameters that are in temporary registers in the
  806. correct parameter register }
  807. if assigned(left) then
  808. begin
  809. pushparas;
  810. { free the resources allocated for the parameters }
  811. freeparas;
  812. end;
  813. cg.alloccpuregisters(exprasmlist,R_INTREGISTER,regs_to_save_int);
  814. if cg.uses_registers(R_FPUREGISTER) then
  815. cg.alloccpuregisters(exprasmlist,R_FPUREGISTER,regs_to_save_fpu);
  816. if cg.uses_registers(R_MMREGISTER) then
  817. cg.alloccpuregisters(exprasmlist,R_MMREGISTER,regs_to_save_mm);
  818. { call method }
  819. extra_call_code;
  820. cg.a_call_reg(exprasmlist,pvreg);
  821. extra_post_call_code;
  822. end
  823. else
  824. begin
  825. { Load parameters that are in temporary registers in the
  826. correct parameter register }
  827. if assigned(left) then
  828. begin
  829. pushparas;
  830. { free the resources allocated for the parameters }
  831. freeparas;
  832. end;
  833. cg.alloccpuregisters(exprasmlist,R_INTREGISTER,regs_to_save_int);
  834. if cg.uses_registers(R_FPUREGISTER) then
  835. cg.alloccpuregisters(exprasmlist,R_FPUREGISTER,regs_to_save_fpu);
  836. if cg.uses_registers(R_MMREGISTER) then
  837. cg.alloccpuregisters(exprasmlist,R_MMREGISTER,regs_to_save_mm);
  838. if procdefinition.proccalloption=pocall_syscall then
  839. do_syscall
  840. else
  841. begin
  842. { Calling interrupt from the same code requires some
  843. extra code }
  844. if (po_interrupt in procdefinition.procoptions) then
  845. extra_interrupt_code;
  846. extra_call_code;
  847. cg.a_call_name(exprasmlist,tprocdef(procdefinition).mangledname);
  848. extra_post_call_code;
  849. end;
  850. end;
  851. end
  852. else
  853. { now procedure variable case }
  854. begin
  855. secondpass(right);
  856. pvreg:=cg.getintregister(exprasmlist,OS_ADDR);
  857. { Only load OS_ADDR from the reference }
  858. if right.location.loc in [LOC_REFERENCE,LOC_CREFERENCE] then
  859. cg.a_load_ref_reg(exprasmlist,OS_ADDR,OS_ADDR,right.location.reference,pvreg)
  860. else
  861. cg.a_load_loc_reg(exprasmlist,OS_ADDR,right.location,pvreg);
  862. location_freetemp(exprasmlist,right.location);
  863. { Load parameters that are in temporary registers in the
  864. correct parameter register }
  865. if assigned(left) then
  866. begin
  867. pushparas;
  868. { free the resources allocated for the parameters }
  869. freeparas;
  870. end;
  871. cg.alloccpuregisters(exprasmlist,R_INTREGISTER,regs_to_save_int);
  872. if cg.uses_registers(R_FPUREGISTER) then
  873. cg.alloccpuregisters(exprasmlist,R_FPUREGISTER,regs_to_save_fpu);
  874. if cg.uses_registers(R_MMREGISTER) then
  875. cg.alloccpuregisters(exprasmlist,R_MMREGISTER,regs_to_save_mm);
  876. { Calling interrupt from the same code requires some
  877. extra code }
  878. if (po_interrupt in procdefinition.procoptions) then
  879. extra_interrupt_code;
  880. extra_call_code;
  881. cg.a_call_reg(exprasmlist,pvreg);
  882. extra_post_call_code;
  883. end;
  884. { Need to remove the parameters from the stack? }
  885. if (procdefinition.proccalloption in clearstack_pocalls) then
  886. begin
  887. pop_size:=pushedparasize;
  888. { for Cdecl functions we don't need to pop the funcret when it
  889. was pushed by para }
  890. if paramanager.ret_in_param(procdefinition.rettype.def,procdefinition.proccalloption) then
  891. dec(pop_size,sizeof(aint));
  892. { Remove parameters/alignment from the stack }
  893. pop_parasize(pop_size);
  894. end;
  895. { Release registers, but not the registers that contain the
  896. function result }
  897. if (not is_void(resulttype.def)) then
  898. begin
  899. case procdefinition.funcretloc[callerside].loc of
  900. LOC_REGISTER,
  901. LOC_CREGISTER:
  902. begin
  903. {$ifndef cpu64bit}
  904. if procdefinition.funcretloc[callerside].size in [OS_64,OS_S64] then
  905. begin
  906. exclude(regs_to_save_int,getsupreg(procdefinition.funcretloc[callerside].register64.reghi));
  907. exclude(regs_to_save_int,getsupreg(procdefinition.funcretloc[callerside].register64.reglo));
  908. end
  909. else
  910. {$endif cpu64bit}
  911. exclude(regs_to_save_int,getsupreg(procdefinition.funcretloc[callerside].register));
  912. end;
  913. LOC_FPUREGISTER,
  914. LOC_CFPUREGISTER:
  915. exclude(regs_to_save_fpu,getsupreg(procdefinition.funcretloc[callerside].register));
  916. LOC_MMREGISTER,
  917. LOC_CMMREGISTER:
  918. exclude(regs_to_save_mm,getsupreg(procdefinition.funcretloc[callerside].register));
  919. LOC_REFERENCE,
  920. LOC_VOID:
  921. ;
  922. else
  923. internalerror(2004110214);
  924. end;
  925. end;
  926. if cg.uses_registers(R_MMREGISTER) then
  927. cg.dealloccpuregisters(exprasmlist,R_MMREGISTER,regs_to_save_mm);
  928. if cg.uses_registers(R_FPUREGISTER) then
  929. cg.dealloccpuregisters(exprasmlist,R_FPUREGISTER,regs_to_save_fpu);
  930. cg.dealloccpuregisters(exprasmlist,R_INTREGISTER,regs_to_save_int);
  931. { handle function results }
  932. if (not is_void(resulttype.def)) then
  933. handle_return_value
  934. else
  935. location_reset(location,LOC_VOID,OS_NO);
  936. { perhaps i/o check ? }
  937. if (cs_check_io in aktlocalswitches) and
  938. (po_iocheck in procdefinition.procoptions) and
  939. not(po_iocheck in current_procinfo.procdef.procoptions) and
  940. { no IO check for methods and procedure variables }
  941. (right=nil) and
  942. not(po_virtualmethod in procdefinition.procoptions) then
  943. begin
  944. cg.alloccpuregisters(exprasmlist,R_INTREGISTER,paramanager.get_volatile_registers_int(pocall_default));
  945. cg.a_call_name(exprasmlist,'FPC_IOCHECK');
  946. cg.dealloccpuregisters(exprasmlist,R_INTREGISTER,paramanager.get_volatile_registers_int(pocall_default));
  947. end;
  948. { release temps of paras }
  949. release_para_temps;
  950. end;
  951. {$ifdef PASS2INLINE}
  952. procedure tcgcallnode.inlined_pass_2;
  953. var
  954. oldaktcallnode : tcallnode;
  955. oldprocinfo : tprocinfo;
  956. oldinlining_procedure : boolean;
  957. inlineentrycode,inlineexitcode : TAAsmoutput;
  958. {$ifdef GDB}
  959. startlabel,endlabel : tasmlabel;
  960. pp : pchar;
  961. mangled_length : longint;
  962. {$endif GDB}
  963. begin
  964. if not(assigned(procdefinition) and (procdefinition.deftype=procdef)) then
  965. internalerror(200305262);
  966. oldinlining_procedure:=inlining_procedure;
  967. oldprocinfo:=current_procinfo;
  968. { we're inlining a procedure }
  969. inlining_procedure:=true;
  970. { Add inling start }
  971. {$ifdef GDB}
  972. exprasmlist.concat(Tai_force_line.Create);
  973. {$endif GDB}
  974. exprasmList.concat(Tai_Marker.Create(InlineStart));
  975. {$ifdef extdebug}
  976. exprasmList.concat(tai_comment.Create(strpnew('Start of inlined proc '+tprocdef(procdefinition).procsym.name)));
  977. {$endif extdebug}
  978. { calculate registers to pass the parameters }
  979. paramanager.create_inline_paraloc_info(procdefinition);
  980. { Allocate parameters and locals }
  981. gen_alloc_inline_parast(exprasmlist,tprocdef(procdefinition));
  982. gen_alloc_inline_funcret(exprasmlist,tprocdef(procdefinition));
  983. gen_alloc_symtable(exprasmlist,tprocdef(procdefinition).localst);
  984. { if we allocate the temp. location for ansi- or widestrings }
  985. { already here, we avoid later a push/pop }
  986. if resulttype.def.needs_inittable and
  987. not paramanager.ret_in_param(resulttype.def,procdefinition.proccalloption) then
  988. begin
  989. tg.gettemptyped(exprasmlist,resulttype.def,tt_normal,refcountedtemp);
  990. cg.g_decrrefcount(exprasmlist,resulttype.def,refcountedtemp);
  991. end;
  992. { Push parameters, still use the old current_procinfo. This
  993. is required that have the correct information available like
  994. _class and nested procedure }
  995. oldaktcallnode:=aktcallnode;
  996. aktcallnode:=self;
  997. if assigned(left) then
  998. begin
  999. tcallparanode(left).secondcallparan;
  1000. pushparas;
  1001. end;
  1002. aktcallnode:=oldaktcallnode;
  1003. { create temp procinfo that will be used for the inlinecode tree }
  1004. current_procinfo:=cprocinfo.create(nil);
  1005. current_procinfo.procdef:=tprocdef(procdefinition);
  1006. current_procinfo.flags:=oldprocinfo.flags;
  1007. current_procinfo.aktlocaldata.destroy;
  1008. current_procinfo.aktlocaldata:=oldprocinfo.aktlocaldata;
  1009. { when the oldprocinfo is also being inlined reuse the
  1010. inlining_procinfo }
  1011. if assigned(oldprocinfo.inlining_procinfo) then
  1012. current_procinfo.inlining_procinfo:=oldprocinfo.inlining_procinfo
  1013. else
  1014. current_procinfo.inlining_procinfo:=oldprocinfo;
  1015. { takes care of local data initialization }
  1016. inlineentrycode:=TAAsmoutput.Create;
  1017. inlineexitcode:=TAAsmoutput.Create;
  1018. {$ifdef GDB}
  1019. if (cs_debuginfo in aktmoduleswitches) and
  1020. not(cs_gdb_valgrind in aktglobalswitches) then
  1021. begin
  1022. objectlibrary.getaddrlabel(startlabel);
  1023. objectlibrary.getaddrlabel(endlabel);
  1024. cg.a_label(exprasmlist,startlabel);
  1025. { Here we must include the para and local symtable info }
  1026. procdefinition.concatstabto(withdebuglist);
  1027. mangled_length:=length(current_procinfo.inlining_procinfo.procdef.mangledname);
  1028. getmem(pp,mangled_length+50);
  1029. strpcopy(pp,'192,0,0,'+startlabel.name);
  1030. if (target_info.use_function_relative_addresses) then
  1031. begin
  1032. strpcopy(strend(pp),'-');
  1033. strpcopy(strend(pp),current_procinfo.inlining_procinfo.procdef.mangledname);
  1034. end;
  1035. withdebugList.concat(Tai_stabn.Create(strnew(pp)));
  1036. end;
  1037. {$endif GDB}
  1038. gen_load_para_value(inlineentrycode);
  1039. { now that we've loaded the para's, free them }
  1040. if assigned(left) then
  1041. freeparas;
  1042. gen_initialize_code(inlineentrycode);
  1043. if po_assembler in current_procinfo.procdef.procoptions then
  1044. inlineentrycode.insert(Tai_marker.Create(asmblockstart));
  1045. exprasmList.concatlist(inlineentrycode);
  1046. { process the inline code }
  1047. secondpass(inlinecode);
  1048. cg.a_label(exprasmlist,current_procinfo.aktexitlabel);
  1049. gen_finalize_code(inlineexitcode);
  1050. gen_load_return_value(inlineexitcode);
  1051. if po_assembler in current_procinfo.procdef.procoptions then
  1052. inlineexitcode.concat(Tai_marker.Create(asmblockend));
  1053. exprasmlist.concatlist(inlineexitcode);
  1054. inlineentrycode.free;
  1055. inlineexitcode.free;
  1056. {$ifdef extdebug}
  1057. exprasmList.concat(tai_comment.Create(strpnew('End of inlined proc')));
  1058. {$endif extdebug}
  1059. exprasmList.concat(Tai_Marker.Create(InlineEnd));
  1060. { handle function results }
  1061. if (not is_void(resulttype.def)) then
  1062. handle_return_value
  1063. else
  1064. location_reset(location,LOC_VOID,OS_NO);
  1065. { perhaps i/o check ? }
  1066. if (cs_check_io in aktlocalswitches) and
  1067. (po_iocheck in procdefinition.procoptions) and
  1068. not(po_iocheck in current_procinfo.procdef.procoptions) and
  1069. { no IO check for methods and procedure variables }
  1070. (right=nil) and
  1071. not(po_virtualmethod in procdefinition.procoptions) then
  1072. begin
  1073. cg.alloccpuregisters(exprasmlist,R_INTREGISTER,paramanager.get_volatile_registers_int(pocall_default));
  1074. cg.a_call_name(exprasmlist,'FPC_IOCHECK');
  1075. cg.dealloccpuregisters(exprasmlist,R_INTREGISTER,paramanager.get_volatile_registers_int(pocall_default));
  1076. end;
  1077. { release temps of paras }
  1078. release_para_temps;
  1079. { if return value is not used }
  1080. if (not is_void(resulttype.def)) and
  1081. (not(cnf_return_value_used in callnodeflags)) then
  1082. begin
  1083. if location.loc in [LOC_CREFERENCE,LOC_REFERENCE] then
  1084. begin
  1085. { data which must be finalized ? }
  1086. if (resulttype.def.needs_inittable) then
  1087. cg.g_finalize(exprasmlist,resulttype.def,location.reference);
  1088. { release unused temp }
  1089. tg.ungetiftemp(exprasmlist,location.reference)
  1090. end
  1091. else if location.loc=LOC_FPUREGISTER then
  1092. begin
  1093. {$ifdef x86}
  1094. { release FPU stack }
  1095. emit_reg(A_FSTP,S_NO,NR_FPU_RESULT_REG);
  1096. {$endif x86}
  1097. end;
  1098. end;
  1099. { Release parameters and locals }
  1100. gen_free_symtable(exprasmlist,tparasymtable(current_procinfo.procdef.parast));
  1101. gen_free_symtable(exprasmlist,tlocalsymtable(current_procinfo.procdef.localst));
  1102. {$ifdef GDB}
  1103. if (cs_debuginfo in aktmoduleswitches) and
  1104. not(cs_gdb_valgrind in aktglobalswitches) then
  1105. begin
  1106. cg.a_label(exprasmlist,endlabel);
  1107. strpcopy(pp,'224,0,0,'+endlabel.name);
  1108. if (target_info.use_function_relative_addresses) then
  1109. begin
  1110. strpcopy(strend(pp),'-');
  1111. strpcopy(strend(pp),current_procinfo.inlining_procinfo.procdef.mangledname);
  1112. end;
  1113. withdebugList.concat(Tai_stabn.Create(strnew(pp)));
  1114. freemem(pp,mangled_length+50);
  1115. end;
  1116. {$endif GDB}
  1117. { restore }
  1118. current_procinfo.aktlocaldata:=nil;
  1119. current_procinfo.destroy;
  1120. current_procinfo:=oldprocinfo;
  1121. inlining_procedure:=oldinlining_procedure;
  1122. end;
  1123. {$endif PASS2INLINE}
  1124. procedure tcgcallnode.pass_2;
  1125. begin
  1126. if assigned(methodpointerinit) then
  1127. secondpass(methodpointerinit);
  1128. {$ifdef PASS2INLINE}
  1129. if assigned(inlinecode) then
  1130. inlined_pass_2
  1131. else
  1132. {$endif PASS2INLINE}
  1133. normal_pass_2;
  1134. if assigned(methodpointerdone) then
  1135. secondpass(methodpointerdone);
  1136. end;
  1137. begin
  1138. ccallparanode:=tcgcallparanode;
  1139. ccallnode:=tcgcallnode;
  1140. end.
  1141. {
  1142. $Log$
  1143. Revision 1.204 2005-04-25 09:41:28 peter
  1144. decr refcnt for out paras
  1145. Revision 1.203 2005/04/05 21:06:44 peter
  1146. * support typecasting a ordinal const to 8 byte record. a_param_loc
  1147. can't be used. Instead force the location to memory so it uses
  1148. a_param_ref
  1149. Revision 1.202 2005/02/27 16:40:13 peter
  1150. fix register deallocation for 64bit results
  1151. Revision 1.201 2005/02/15 21:39:48 peter
  1152. * remove is_single_reference
  1153. * revert loading of ref-to-ref para valu
  1154. Revision 1.200 2005/02/14 17:13:06 peter
  1155. * truncate log
  1156. Revision 1.199 2005/01/30 21:51:57 jonas
  1157. * fixed darwin cycle
  1158. Revision 1.198 2005/01/29 11:36:52 peter
  1159. * update x86_64 with new cpupara
  1160. Revision 1.197 2005/01/20 17:47:01 peter
  1161. * remove copy_value_on_stack and a_param_copy_ref
  1162. Revision 1.196 2005/01/18 22:19:20 peter
  1163. * multiple location support for i386 a_param_ref
  1164. * remove a_param_copy_ref for i386
  1165. Revision 1.195 2005/01/12 10:02:22 florian
  1166. * removed ie20050111
  1167. Revision 1.194 2005/01/10 21:50:05 jonas
  1168. + support for passing records in registers under darwin
  1169. * tcgpara now also has an intsize field, which contains the size in
  1170. bytes of the whole parameter
  1171. Revision 1.193 2005/01/07 16:22:54 florian
  1172. + implemented abi compliant handling of strucutured functions results on sparc platform
  1173. Revision 1.192 2005/01/04 16:36:51 peter
  1174. * release temps in array constructor
  1175. Revision 1.191 2005/01/02 16:58:48 peter
  1176. * Don't release methodpointer. It is maybe still needed when we need to
  1177. convert the calln to loadn
  1178. }