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. hp : tnode;
  328. begin
  329. if not(assigned(parasym)) then
  330. internalerror(200304242);
  331. { Skip nothingn nodes which are used after disabling
  332. a parameter }
  333. if (left.nodetype<>nothingn) then
  334. begin
  335. otlabel:=truelabel;
  336. oflabel:=falselabel;
  337. objectlibrary.getlabel(truelabel);
  338. objectlibrary.getlabel(falselabel);
  339. secondpass(left);
  340. {$ifdef PASS2INLINE}
  341. if assigned(aktcallnode.inlinecode) then
  342. paramanager.duplicateparaloc(exprasmlist,aktcallnode.procdefinition.proccalloption,parasym,tempcgpara)
  343. else
  344. {$endif PASS2INLINE}
  345. paramanager.createtempparaloc(exprasmlist,aktcallnode.procdefinition.proccalloption,parasym,tempcgpara);
  346. { handle varargs first, because parasym is not valid }
  347. if (cpf_varargs_para in callparaflags) then
  348. begin
  349. if paramanager.push_addr_param(vs_value,left.resulttype.def,
  350. aktcallnode.procdefinition.proccalloption) then
  351. push_addr_para
  352. else
  353. push_value_para;
  354. end
  355. { hidden parameters }
  356. else if (vo_is_hidden_para in parasym.varoptions) then
  357. begin
  358. { don't push a node that already generated a pointer type
  359. by address for implicit hidden parameters }
  360. if (vo_is_funcret in parasym.varoptions) or
  361. (not(left.resulttype.def.deftype in [pointerdef,classrefdef]) and
  362. paramanager.push_addr_param(parasym.varspez,parasym.vartype.def,
  363. aktcallnode.procdefinition.proccalloption)) then
  364. push_addr_para
  365. else
  366. push_value_para;
  367. end
  368. { formal def }
  369. else if (parasym.vartype.def.deftype=formaldef) then
  370. begin
  371. { allow passing of a constant to a const formaldef }
  372. if (parasym.varspez=vs_const) and
  373. (left.location.loc=LOC_CONSTANT) then
  374. location_force_mem(exprasmlist,left.location);
  375. push_addr_para;
  376. end
  377. { Normal parameter }
  378. else
  379. begin
  380. { don't push a node that already generated a pointer type
  381. by address for implicit hidden parameters }
  382. if (not(
  383. (vo_is_hidden_para in parasym.varoptions) and
  384. (left.resulttype.def.deftype in [pointerdef,classrefdef])
  385. ) and
  386. paramanager.push_addr_param(parasym.varspez,parasym.vartype.def,
  387. aktcallnode.procdefinition.proccalloption)) then
  388. begin
  389. { Passing a var parameter to a var parameter, we can
  390. just push the address transparently }
  391. if (left.nodetype=loadn) and
  392. (tloadnode(left).is_addr_param_load) then
  393. begin
  394. if (left.location.reference.index<>NR_NO) or
  395. (left.location.reference.offset<>0) then
  396. internalerror(200410107);
  397. cg.a_param_reg(exprasmlist,OS_ADDR,left.location.reference.base,tempcgpara)
  398. end
  399. else
  400. begin
  401. { Check for passing a constant to var,out parameter }
  402. if (parasym.varspez in [vs_var,vs_out]) and
  403. (left.location.loc<>LOC_REFERENCE) then
  404. begin
  405. { passing self to a var parameter is allowed in
  406. TP and delphi }
  407. if not((left.location.loc=LOC_CREFERENCE) and
  408. is_self_node(left)) then
  409. internalerror(200106041);
  410. end;
  411. { Force to be in memory }
  412. if not(left.location.loc in [LOC_CREFERENCE,LOC_REFERENCE]) then
  413. location_force_mem(exprasmlist,left.location);
  414. push_addr_para;
  415. end;
  416. end
  417. else
  418. push_value_para;
  419. end;
  420. truelabel:=otlabel;
  421. falselabel:=oflabel;
  422. { update return location in callnode when this is the function
  423. result }
  424. if assigned(parasym) and
  425. (vo_is_funcret in parasym.varoptions) then
  426. location_copy(aktcallnode.location,left.location);
  427. end;
  428. { next parameter }
  429. if assigned(right) then
  430. tcallparanode(right).secondcallparan;
  431. end;
  432. {*****************************************************************************
  433. TCGCALLNODE
  434. *****************************************************************************}
  435. procedure tcgcallnode.extra_interrupt_code;
  436. begin
  437. end;
  438. procedure tcgcallnode.extra_call_code;
  439. begin
  440. end;
  441. procedure tcgcallnode.pop_parasize(pop_size:longint);
  442. begin
  443. end;
  444. procedure tcgcallnode.handle_return_value;
  445. var
  446. cgsize : tcgsize;
  447. retloc : tlocation;
  448. hregister : tregister;
  449. tempnode : tnode;
  450. begin
  451. cgsize:=procdefinition.funcretloc[callerside].size;
  452. { structured results are easy to handle....
  453. needed also when result_no_used !! }
  454. if (procdefinition.proctypeoption<>potype_constructor) and
  455. paramanager.ret_in_param(resulttype.def,procdefinition.proccalloption) then
  456. begin
  457. { Location should be setup by the funcret para }
  458. if location.loc<>LOC_REFERENCE then
  459. internalerror(200304241);
  460. end
  461. else
  462. { ansi/widestrings must be registered, so we can dispose them }
  463. if resulttype.def.needs_inittable then
  464. begin
  465. if procdefinition.funcretloc[callerside].loc<>LOC_REGISTER then
  466. internalerror(200409261);
  467. { the FUNCTION_RESULT_REG is already allocated }
  468. if getsupreg(procdefinition.funcretloc[callerside].register)<first_int_imreg then
  469. cg.ungetcpuregister(exprasmlist,procdefinition.funcretloc[callerside].register);
  470. if not assigned(funcretnode) then
  471. begin
  472. { reg_ref could generate two instrcutions and allocate a register so we've to
  473. save the result first before releasing it }
  474. hregister:=cg.getaddressregister(exprasmlist);
  475. cg.a_load_reg_reg(exprasmlist,OS_ADDR,OS_ADDR,procdefinition.funcretloc[callerside].register,hregister);
  476. location_reset(location,LOC_REFERENCE,OS_ADDR);
  477. location.reference:=refcountedtemp;
  478. cg.a_load_reg_ref(exprasmlist,OS_ADDR,OS_ADDR,hregister,location.reference);
  479. end
  480. else
  481. begin
  482. hregister := cg.getaddressregister(exprasmlist);
  483. cg.a_load_reg_reg(exprasmlist,OS_ADDR,OS_ADDR,procdefinition.funcretloc[callerside].register,hregister);
  484. { in case of a regular funcretnode with ret_in_param, the }
  485. { original funcretnode isn't touched -> make sure it's }
  486. { the same here (not sure if it's necessary) }
  487. tempnode := funcretnode.getcopy;
  488. tempnode.pass_2;
  489. location := tempnode.location;
  490. tempnode.free;
  491. cg.g_decrrefcount(exprasmlist,resulttype.def,location.reference);
  492. cg.a_load_reg_ref(exprasmlist,OS_ADDR,OS_ADDR,hregister,location.reference);
  493. end;
  494. end
  495. else
  496. { normal (ordinal,float,pointer) result value }
  497. begin
  498. { we have only to handle the result if it is used }
  499. if (cnf_return_value_used in callnodeflags) then
  500. begin
  501. location.loc:=procdefinition.funcretloc[callerside].loc;
  502. case procdefinition.funcretloc[callerside].loc of
  503. LOC_FPUREGISTER:
  504. begin
  505. location_reset(location,LOC_FPUREGISTER,cgsize);
  506. location.register:=procdefinition.funcretloc[callerside].register;
  507. {$ifdef x86}
  508. tcgx86(cg).inc_fpu_stack;
  509. {$else x86}
  510. if getsupreg(procdefinition.funcretloc[callerside].register)<first_fpu_imreg then
  511. cg.ungetcpuregister(exprasmlist,procdefinition.funcretloc[callerside].register);
  512. hregister:=cg.getfpuregister(exprasmlist,location.size);
  513. cg.a_loadfpu_reg_reg(exprasmlist,location.size,location.register,hregister);
  514. location.register:=hregister;
  515. {$endif x86}
  516. end;
  517. LOC_REGISTER:
  518. begin
  519. if cgsize<>OS_NO then
  520. begin
  521. location_reset(location,LOC_REGISTER,cgsize);
  522. {$ifndef cpu64bit}
  523. if cgsize in [OS_64,OS_S64] then
  524. begin
  525. retloc:=procdefinition.funcretloc[callerside];
  526. if retloc.loc<>LOC_REGISTER then
  527. internalerror(200409141);
  528. { the function result registers are already allocated }
  529. if getsupreg(retloc.register64.reglo)<first_int_imreg then
  530. cg.ungetcpuregister(exprasmlist,retloc.register64.reglo);
  531. location.register64.reglo:=cg.getintregister(exprasmlist,OS_32);
  532. cg.a_load_reg_reg(exprasmlist,OS_32,OS_32,retloc.register64.reglo,location.register64.reglo);
  533. if getsupreg(retloc.register64.reghi)<first_int_imreg then
  534. cg.ungetcpuregister(exprasmlist,retloc.register64.reghi);
  535. location.register64.reghi:=cg.getintregister(exprasmlist,OS_32);
  536. cg.a_load_reg_reg(exprasmlist,OS_32,OS_32,retloc.register64.reghi,location.register64.reghi);
  537. end
  538. else
  539. {$endif cpu64bit}
  540. begin
  541. { change register size after the unget because the
  542. getregister was done for the full register
  543. def_cgsize(resulttype.def) is used here because
  544. it could be a constructor call }
  545. if getsupreg(procdefinition.funcretloc[callerside].register)<first_int_imreg then
  546. cg.ungetcpuregister(exprasmlist,procdefinition.funcretloc[callerside].register);
  547. location.register:=cg.getintregister(exprasmlist,def_cgsize(resulttype.def));
  548. cg.a_load_reg_reg(exprasmlist,cgsize,def_cgsize(resulttype.def),procdefinition.funcretloc[callerside].register,location.register);
  549. end;
  550. end
  551. else
  552. begin
  553. if resulttype.def.size>0 then
  554. internalerror(200305131);
  555. end;
  556. end;
  557. LOC_MMREGISTER:
  558. begin
  559. location_reset(location,LOC_MMREGISTER,cgsize);
  560. if getsupreg(procdefinition.funcretloc[callerside].register)<first_mm_imreg then
  561. cg.ungetcpuregister(exprasmlist,procdefinition.funcretloc[callerside].register);
  562. location.register:=cg.getmmregister(exprasmlist,cgsize);
  563. cg.a_loadmm_reg_reg(exprasmlist,cgsize,cgsize,procdefinition.funcretloc[callerside].register,location.register,mms_movescalar);
  564. end;
  565. else
  566. internalerror(200405023);
  567. end;
  568. end
  569. else
  570. begin
  571. {$ifdef x86}
  572. { release FPU stack }
  573. if procdefinition.funcretloc[callerside].loc=LOC_FPUREGISTER then
  574. emit_reg(A_FSTP,S_NO,NR_FPU_RESULT_REG);
  575. {$endif x86}
  576. if cgsize<>OS_NO then
  577. location_free(exprasmlist,procdefinition.funcretloc[callerside]);
  578. location_reset(location,LOC_VOID,OS_NO);
  579. end;
  580. end;
  581. { When the result is not used we need to finalize the result and
  582. can release the temp }
  583. if not(cnf_return_value_used in callnodeflags) then
  584. begin
  585. if location.loc=LOC_REFERENCE then
  586. begin
  587. if resulttype.def.needs_inittable then
  588. cg.g_finalize(exprasmlist,resulttype.def,location.reference);
  589. tg.ungetiftemp(exprasmlist,location.reference)
  590. end;
  591. end;
  592. end;
  593. procedure tcgcallnode.release_para_temps;
  594. var
  595. hp : tnode;
  596. ppn : tcallparanode;
  597. begin
  598. { Release temps from parameters }
  599. ppn:=tcallparanode(left);
  600. while assigned(ppn) do
  601. begin
  602. if assigned(ppn.left) then
  603. begin
  604. { don't release the funcret temp }
  605. if not(assigned(ppn.parasym)) or
  606. not(vo_is_funcret in ppn.parasym.varoptions) then
  607. location_freetemp(exprasmlist,ppn.left.location);
  608. { process also all nodes of an array of const }
  609. if ppn.left.nodetype=arrayconstructorn then
  610. begin
  611. if assigned(tarrayconstructornode(ppn.left).left) then
  612. begin
  613. hp:=ppn.left;
  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. end;
  622. ppn:=tcallparanode(ppn.right);
  623. end;
  624. end;
  625. procedure tcgcallnode.pushparas;
  626. var
  627. ppn : tcgcallparanode;
  628. callerparaloc,
  629. tmpparaloc : pcgparalocation;
  630. {$ifdef cputargethasfixedstack}
  631. htempref,
  632. href : treference;
  633. {$endif cputargethasfixedstack}
  634. begin
  635. { copy all resources to the allocated registers }
  636. ppn:=tcgcallparanode(left);
  637. while assigned(ppn) do
  638. begin
  639. if (ppn.left.nodetype<>nothingn) then
  640. begin
  641. { better check for the real location of the parameter here, when stack passed parameters
  642. are saved temporary in registers, checking for the tmpparaloc.loc is wrong
  643. }
  644. {$ifdef PASS2INLINE}
  645. if not assigned(inlinecode) then
  646. {$endif PASS2INLINE}
  647. paramanager.freeparaloc(exprasmlist,ppn.tempcgpara);
  648. tmpparaloc:=ppn.tempcgpara.location;
  649. callerparaloc:=ppn.parasym.paraloc[callerside].location;
  650. while assigned(callerparaloc) do
  651. begin
  652. { Every paraloc must have a matching tmpparaloc }
  653. if not assigned(tmpparaloc) then
  654. internalerror(200408224);
  655. if callerparaloc^.size<>tmpparaloc^.size then
  656. internalerror(200408225);
  657. case callerparaloc^.loc of
  658. LOC_REGISTER:
  659. begin
  660. if tmpparaloc^.loc<>LOC_REGISTER then
  661. internalerror(200408221);
  662. if getsupreg(callerparaloc^.register)<first_int_imreg then
  663. cg.getcpuregister(exprasmlist,callerparaloc^.register);
  664. cg.a_load_reg_reg(exprasmlist,tmpparaloc^.size,tmpparaloc^.size,
  665. tmpparaloc^.register,callerparaloc^.register);
  666. end;
  667. LOC_FPUREGISTER:
  668. begin
  669. if tmpparaloc^.loc<>LOC_FPUREGISTER then
  670. internalerror(200408222);
  671. if getsupreg(callerparaloc^.register)<first_fpu_imreg then
  672. cg.getcpuregister(exprasmlist,callerparaloc^.register);
  673. cg.a_loadfpu_reg_reg(exprasmlist,ppn.tempcgpara.size,tmpparaloc^.register,callerparaloc^.register);
  674. end;
  675. LOC_MMREGISTER:
  676. begin
  677. if tmpparaloc^.loc<>LOC_MMREGISTER then
  678. internalerror(200408223);
  679. if getsupreg(callerparaloc^.register)<first_mm_imreg then
  680. cg.getcpuregister(exprasmlist,callerparaloc^.register);
  681. cg.a_loadmm_reg_reg(exprasmlist,tmpparaloc^.size,tmpparaloc^.size,
  682. tmpparaloc^.register,callerparaloc^.register,mms_movescalar);
  683. end;
  684. LOC_REFERENCE:
  685. begin
  686. {$ifdef PASS2INLINE}
  687. if not assigned(inlinecode) then
  688. {$endif PASS2INLINE}
  689. begin
  690. {$ifdef cputargethasfixedstack}
  691. reference_reset_base(href,callerparaloc^.reference.index,callerparaloc^.reference.offset);
  692. { copy parameters in case they were moved to a temp. location because we've a fixed stack }
  693. case tmpparaloc^.loc of
  694. LOC_REFERENCE:
  695. begin
  696. reference_reset_base(htempref,tmpparaloc^.reference.index,tmpparaloc^.reference.offset);
  697. { use concatcopy, because it can also be a float which fails when
  698. load_ref_ref is used }
  699. cg.g_concatcopy(exprasmlist,htempref,href,tcgsize2size[tmpparaloc^.size]);
  700. end;
  701. LOC_REGISTER:
  702. cg.a_load_reg_ref(exprasmlist,tmpparaloc^.size,tmpparaloc^.size,tmpparaloc^.register,href);
  703. LOC_FPUREGISTER:
  704. cg.a_loadfpu_reg_ref(exprasmlist,tmpparaloc^.size,tmpparaloc^.register,href);
  705. LOC_MMREGISTER:
  706. cg.a_loadmm_reg_ref(exprasmlist,tmpparaloc^.size,tmpparaloc^.size,tmpparaloc^.register,href,mms_movescalar);
  707. else
  708. internalerror(200402081);
  709. end;
  710. {$endif cputargethasfixedstack}
  711. end;
  712. end;
  713. end;
  714. callerparaloc:=callerparaloc^.next;
  715. tmpparaloc:=tmpparaloc^.next;
  716. end;
  717. end;
  718. ppn:=tcgcallparanode(ppn.right);
  719. end;
  720. end;
  721. procedure tcgcallnode.freeparas;
  722. var
  723. ppn : tcgcallparanode;
  724. begin
  725. { free the resources allocated for the parameters }
  726. ppn:=tcgcallparanode(left);
  727. while assigned(ppn) do
  728. begin
  729. if
  730. {$ifdef PASS2INLINE}
  731. not assigned(inlinecode) or
  732. {$endif PASS2INLINE}
  733. (ppn.parasym.paraloc[callerside].location^.loc <> LOC_REFERENCE) then
  734. paramanager.freeparaloc(exprasmlist,ppn.parasym.paraloc[callerside]);
  735. ppn:=tcgcallparanode(ppn.right);
  736. end;
  737. end;
  738. procedure tcgcallnode.normal_pass_2;
  739. var
  740. regs_to_save_int,
  741. regs_to_save_fpu,
  742. regs_to_save_mm : Tcpuregisterset;
  743. href : treference;
  744. pop_size : longint;
  745. pvreg,
  746. vmtreg : tregister;
  747. oldaktcallnode : tcallnode;
  748. begin
  749. if not assigned(procdefinition) or
  750. not procdefinition.has_paraloc_info then
  751. internalerror(200305264);
  752. if resulttype.def.needs_inittable and
  753. not paramanager.ret_in_param(resulttype.def,procdefinition.proccalloption) and
  754. not assigned(funcretnode) then
  755. begin
  756. tg.gettemptyped(exprasmlist,resulttype.def,tt_normal,refcountedtemp);
  757. cg.g_decrrefcount(exprasmlist,resulttype.def,refcountedtemp);
  758. end;
  759. regs_to_save_int:=paramanager.get_volatile_registers_int(procdefinition.proccalloption);
  760. regs_to_save_fpu:=paramanager.get_volatile_registers_fpu(procdefinition.proccalloption);
  761. regs_to_save_mm:=paramanager.get_volatile_registers_mm(procdefinition.proccalloption);
  762. { Include Function result registers }
  763. if (not is_void(resulttype.def)) then
  764. begin
  765. case procdefinition.funcretloc[callerside].loc of
  766. LOC_REGISTER,
  767. LOC_CREGISTER:
  768. include(regs_to_save_int,getsupreg(procdefinition.funcretloc[callerside].register));
  769. LOC_FPUREGISTER,
  770. LOC_CFPUREGISTER:
  771. include(regs_to_save_fpu,getsupreg(procdefinition.funcretloc[callerside].register));
  772. LOC_MMREGISTER,
  773. LOC_CMMREGISTER:
  774. include(regs_to_save_mm,getsupreg(procdefinition.funcretloc[callerside].register));
  775. LOC_REFERENCE,
  776. LOC_VOID:
  777. ;
  778. else
  779. internalerror(2004110213);
  780. end;
  781. end;
  782. { Process parameters, register parameters will be loaded
  783. in imaginary registers. The actual load to the correct
  784. register is done just before the call }
  785. oldaktcallnode:=aktcallnode;
  786. aktcallnode:=self;
  787. if assigned(left) then
  788. tcallparanode(left).secondcallparan;
  789. aktcallnode:=oldaktcallnode;
  790. { procedure variable or normal function call ? }
  791. if (right=nil) then
  792. begin
  793. { When methodpointer is typen we don't need (and can't) load
  794. a pointer. We can directly call the correct procdef (PFV) }
  795. if (po_virtualmethod in procdefinition.procoptions) and
  796. assigned(methodpointer) and
  797. (methodpointer.nodetype<>typen) then
  798. begin
  799. secondpass(methodpointer);
  800. location_force_reg(exprasmlist,methodpointer.location,OS_ADDR,false);
  801. { virtual methods require an index }
  802. if tprocdef(procdefinition).extnumber=$ffff then
  803. internalerror(200304021);
  804. { VMT should already be loaded in a register }
  805. if methodpointer.location.register=NR_NO then
  806. internalerror(200304022);
  807. { test validity of VMT }
  808. if not(is_interface(tprocdef(procdefinition)._class)) and
  809. not(is_cppclass(tprocdef(procdefinition)._class)) then
  810. cg.g_maybe_testvmt(exprasmlist,methodpointer.location.register,tprocdef(procdefinition)._class);
  811. vmtreg:=methodpointer.location.register;
  812. pvreg:=cg.getintregister(exprasmlist,OS_ADDR);
  813. reference_reset_base(href,vmtreg,
  814. tprocdef(procdefinition)._class.vmtmethodoffset(tprocdef(procdefinition).extnumber));
  815. cg.a_load_ref_reg(exprasmlist,OS_ADDR,OS_ADDR,href,pvreg);
  816. { Load parameters that are in temporary registers in the
  817. correct parameter register }
  818. if assigned(left) then
  819. begin
  820. pushparas;
  821. { free the resources allocated for the parameters }
  822. freeparas;
  823. end;
  824. cg.alloccpuregisters(exprasmlist,R_INTREGISTER,regs_to_save_int);
  825. if cg.uses_registers(R_FPUREGISTER) then
  826. cg.alloccpuregisters(exprasmlist,R_FPUREGISTER,regs_to_save_fpu);
  827. if cg.uses_registers(R_MMREGISTER) then
  828. cg.alloccpuregisters(exprasmlist,R_MMREGISTER,regs_to_save_mm);
  829. { call method }
  830. extra_call_code;
  831. cg.a_call_reg(exprasmlist,pvreg);
  832. end
  833. else
  834. begin
  835. { Load parameters that are in temporary registers in the
  836. correct parameter register }
  837. if assigned(left) then
  838. begin
  839. pushparas;
  840. { free the resources allocated for the parameters }
  841. freeparas;
  842. end;
  843. cg.alloccpuregisters(exprasmlist,R_INTREGISTER,regs_to_save_int);
  844. if cg.uses_registers(R_FPUREGISTER) then
  845. cg.alloccpuregisters(exprasmlist,R_FPUREGISTER,regs_to_save_fpu);
  846. if cg.uses_registers(R_MMREGISTER) then
  847. cg.alloccpuregisters(exprasmlist,R_MMREGISTER,regs_to_save_mm);
  848. if procdefinition.proccalloption=pocall_syscall then
  849. do_syscall
  850. else
  851. begin
  852. { Calling interrupt from the same code requires some
  853. extra code }
  854. if (po_interrupt in procdefinition.procoptions) then
  855. extra_interrupt_code;
  856. extra_call_code;
  857. cg.a_call_name(exprasmlist,tprocdef(procdefinition).mangledname);
  858. end;
  859. end;
  860. end
  861. else
  862. { now procedure variable case }
  863. begin
  864. secondpass(right);
  865. pvreg:=cg.getintregister(exprasmlist,OS_ADDR);
  866. { Only load OS_ADDR from the reference }
  867. if right.location.loc in [LOC_REFERENCE,LOC_CREFERENCE] then
  868. cg.a_load_ref_reg(exprasmlist,OS_ADDR,OS_ADDR,right.location.reference,pvreg)
  869. else
  870. cg.a_load_loc_reg(exprasmlist,OS_ADDR,right.location,pvreg);
  871. location_freetemp(exprasmlist,right.location);
  872. { Load parameters that are in temporary registers in the
  873. correct parameter register }
  874. if assigned(left) then
  875. begin
  876. pushparas;
  877. { free the resources allocated for the parameters }
  878. freeparas;
  879. end;
  880. cg.alloccpuregisters(exprasmlist,R_INTREGISTER,regs_to_save_int);
  881. if cg.uses_registers(R_FPUREGISTER) then
  882. cg.alloccpuregisters(exprasmlist,R_FPUREGISTER,regs_to_save_fpu);
  883. if cg.uses_registers(R_MMREGISTER) then
  884. cg.alloccpuregisters(exprasmlist,R_MMREGISTER,regs_to_save_mm);
  885. { Calling interrupt from the same code requires some
  886. extra code }
  887. if (po_interrupt in procdefinition.procoptions) then
  888. extra_interrupt_code;
  889. {$warning fixme regvars.}
  890. { rg.saveotherregvars(exprasmlist,ALL_OTHERREGISTERS);}
  891. extra_call_code;
  892. cg.a_call_reg(exprasmlist,pvreg);
  893. end;
  894. { Need to remove the parameters from the stack? }
  895. if (procdefinition.proccalloption in clearstack_pocalls) then
  896. begin
  897. pop_size:=pushedparasize;
  898. { for Cdecl functions we don't need to pop the funcret when it
  899. was pushed by para }
  900. if paramanager.ret_in_param(procdefinition.rettype.def,procdefinition.proccalloption) then
  901. dec(pop_size,sizeof(aint));
  902. { Remove parameters/alignment from the stack }
  903. pop_parasize(pop_size);
  904. end;
  905. { Release registers, but not the registers that contain the
  906. function result }
  907. if (not is_void(resulttype.def)) then
  908. begin
  909. case procdefinition.funcretloc[callerside].loc of
  910. LOC_REGISTER,
  911. LOC_CREGISTER:
  912. exclude(regs_to_save_int,getsupreg(procdefinition.funcretloc[callerside].register));
  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.191 2005-01-02 16:58:48 peter
  1144. * Don't release methodpointer. It is maybe still needed when we need to
  1145. convert the calln to loadn
  1146. Revision 1.190 2004/12/05 12:28:11 peter
  1147. * procvar handling for tp procvar mode fixed
  1148. * proc to procvar moved from addrnode to typeconvnode
  1149. * inlininginfo is now allocated only for inline routines that
  1150. can be inlined, introduced a new flag po_has_inlining_info
  1151. Revision 1.189 2004/12/02 19:26:15 peter
  1152. * disable pass2inline
  1153. Revision 1.188 2004/11/21 18:13:31 peter
  1154. * fixed funcretloc for sparc
  1155. Revision 1.187 2004/11/21 17:54:59 peter
  1156. * ttempcreatenode.create_reg merged into .create with parameter
  1157. whether a register is allowed
  1158. * funcret_paraloc renamed to funcretloc
  1159. Revision 1.186 2004/11/21 17:17:03 florian
  1160. * changed funcret location back to tlocation
  1161. Revision 1.185 2004/11/15 23:35:31 peter
  1162. * tparaitem removed, use tparavarsym instead
  1163. * parameter order is now calculated from paranr value in tparavarsym
  1164. Revision 1.184 2004/11/08 22:09:59 peter
  1165. * tvarsym splitted
  1166. Revision 1.183 2004/11/01 17:41:28 florian
  1167. * fixed arm compilation with cgutils
  1168. * ...
  1169. Revision 1.182 2004/10/31 21:45:03 peter
  1170. * generic tlocation
  1171. * move tlocation to cgutils
  1172. Revision 1.181 2004/10/24 20:01:08 peter
  1173. * remove saveregister calling convention
  1174. Revision 1.180 2004/10/24 11:53:45 peter
  1175. * fixed compilation with removed loadref
  1176. Revision 1.179 2004/10/24 11:44:28 peter
  1177. * small regvar fixes
  1178. * loadref parameter removed from concatcopy,incrrefcount,etc
  1179. Revision 1.178 2004/10/15 09:14:16 mazen
  1180. - remove $IFDEF DELPHI and related code
  1181. - remove $IFDEF FPCPROCVAR and related code
  1182. Revision 1.177 2004/10/10 20:21:18 peter
  1183. * passing a var parameter to var parameter is now also allowed
  1184. for register locations (=regvars)
  1185. Revision 1.176 2004/09/27 15:15:20 peter
  1186. * dealloc function result registers, register allocation is now
  1187. back at pre-paraloc level
  1188. Revision 1.175 2004/09/25 14:23:54 peter
  1189. * ungetregister is now only used for cpuregisters, renamed to
  1190. ungetcpuregister
  1191. * renamed (get|unget)explicitregister(s) to ..cpuregister
  1192. * removed location-release/reference_release
  1193. Revision 1.174 2004/09/21 17:25:12 peter
  1194. * paraloc branch merged
  1195. Revision 1.173.4.3 2004/09/20 20:46:34 peter
  1196. * register allocation optimized for 64bit loading of parameters
  1197. and return values
  1198. Revision 1.173.4.2 2004/09/17 17:19:26 peter
  1199. * fixed 64 bit unaryminus for sparc
  1200. * fixed 64 bit inlining
  1201. * signness of not operation
  1202. Revision 1.173.4.1 2004/08/31 20:43:06 peter
  1203. * paraloc patch
  1204. Revision 1.173 2004/07/12 10:47:42 michael
  1205. + Fix for bug 3207 from Peter
  1206. Revision 1.172 2004/07/11 19:01:13 peter
  1207. * comps are passed in int registers
  1208. Revision 1.171 2004/07/09 23:41:04 jonas
  1209. * support register parameters for inlined procedures + some inline
  1210. cleanups
  1211. Revision 1.170 2004/06/29 20:56:46 peter
  1212. * constructors don't return in parameter
  1213. Revision 1.169 2004/06/20 08:55:29 florian
  1214. * logs truncated
  1215. Revision 1.168 2004/06/16 20:07:08 florian
  1216. * dwarf branch merged
  1217. Revision 1.167 2004/05/23 18:28:41 peter
  1218. * methodpointer is loaded into a temp when it was a calln
  1219. Revision 1.166 2004/05/22 23:34:27 peter
  1220. tai_regalloc.allocation changed to ratype to notify rgobj of register size changes
  1221. Revision 1.165 2004/04/28 15:19:03 florian
  1222. + syscall directive support for MorphOS added
  1223. Revision 1.164.2.13 2004/06/12 17:01:01 florian
  1224. * fixed compilation of arm compiler
  1225. }