ncgcal.pas 51 KB

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