ncgcal.pas 55 KB

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