ncgcal.pas 52 KB

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