ncgcal.pas 55 KB

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