ncgcal.pas 70 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516
  1. {
  2. $Id$
  3. Copyright (c) 1998-2002 by Florian Klaempfl
  4. Generate i386 assembler for in 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 bymethodpointer
  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. { $define AnsiStrRef}
  22. uses
  23. symdef,node,ncal;
  24. type
  25. tcgcallparanode = class(tcallparanode)
  26. procedure secondcallparan(defcoll : TParaItem;
  27. push_from_left_to_right,inlined,is_cdecl : boolean;
  28. para_alignment,para_offset : longint);override;
  29. end;
  30. tcgcallnode = class(tcallnode)
  31. procedure pass_2;override;
  32. end;
  33. tcgprocinlinenode = class(tprocinlinenode)
  34. procedure pass_2;override;
  35. end;
  36. implementation
  37. uses
  38. globtype,systems,
  39. cutils,verbose,globals,
  40. symconst,symbase,symsym,symtable,defbase,paramgr,
  41. {$ifdef GDB}
  42. {$ifdef delphi}
  43. sysutils,
  44. {$else}
  45. strings,
  46. {$endif}
  47. gdb,
  48. {$endif GDB}
  49. cginfo,cgbase,pass_2,
  50. cpuinfo,cpubase,aasmbase,aasmtai,aasmcpu,
  51. nmem,nld,ncnv,
  52. ncgutil,cga,cgobj,tgobj,regvars,rgobj,rgcpu,cg64f32,cgcpu;
  53. {*****************************************************************************
  54. TCGCALLPARANODE
  55. *****************************************************************************}
  56. procedure tcgcallparanode.secondcallparan(defcoll : TParaItem;
  57. push_from_left_to_right,inlined,is_cdecl : boolean;para_alignment,para_offset : longint);
  58. { goes to pass 1 }
  59. procedure maybe_push_high;
  60. begin
  61. { open array ? }
  62. { defcoll.data can be nil for read/write }
  63. if assigned(defcoll.paratype.def) and
  64. assigned(hightree) then
  65. begin
  66. secondpass(hightree);
  67. { this is a longint anyway ! }
  68. push_value_para(hightree,inlined,false,para_offset,4,defcoll.paraloc);
  69. end;
  70. end;
  71. var
  72. otlabel,oflabel : tasmlabel;
  73. { temporary variables: }
  74. tempdeftype : tdeftype;
  75. tmpreg : tregister;
  76. href : treference;
  77. begin
  78. { push from left to right if specified }
  79. if push_from_left_to_right and assigned(right) then
  80. begin
  81. if (nf_varargs_para in flags) then
  82. tcallparanode(right).secondcallparan(defcoll,push_from_left_to_right,
  83. inlined,is_cdecl,para_alignment,para_offset)
  84. else
  85. tcallparanode(right).secondcallparan(TParaItem(defcoll.next),push_from_left_to_right,
  86. inlined,is_cdecl,para_alignment,para_offset);
  87. end;
  88. otlabel:=truelabel;
  89. oflabel:=falselabel;
  90. getlabel(truelabel);
  91. getlabel(falselabel);
  92. secondpass(left);
  93. { handle varargs first, because defcoll is not valid }
  94. if (nf_varargs_para in flags) then
  95. begin
  96. if paramanager.push_addr_param(left.resulttype.def) then
  97. begin
  98. inc(pushedparasize,4);
  99. cg.a_paramaddr_ref(exprasmlist,left.location.reference,defcoll.paraloc);
  100. location_release(exprasmlist,left.location);
  101. end
  102. else
  103. push_value_para(left,inlined,is_cdecl,para_offset,para_alignment,defcoll.paraloc);
  104. end
  105. { filter array constructor with c styled args }
  106. else if is_array_constructor(left.resulttype.def) and (nf_cargs in left.flags) then
  107. begin
  108. { nothing, everything is already pushed }
  109. end
  110. { in codegen.handleread.. defcoll.data is set to nil }
  111. else if assigned(defcoll.paratype.def) and
  112. (defcoll.paratype.def.deftype=formaldef) then
  113. begin
  114. { allow passing of a constant to a const formaldef }
  115. if (defcoll.paratyp=vs_const) and
  116. (left.location.loc=LOC_CONSTANT) then
  117. location_force_mem(exprasmlist,left.location);
  118. { allow @var }
  119. inc(pushedparasize,4);
  120. if (left.nodetype=addrn) and
  121. (not(nf_procvarload in left.flags)) then
  122. begin
  123. if inlined then
  124. begin
  125. reference_reset_base(href,procinfo^.framepointer,para_offset-pushedparasize);
  126. cg.a_load_loc_ref(exprasmlist,left.location,href);
  127. end
  128. else
  129. cg.a_param_loc(exprasmlist,left.location,defcoll.paraloc);
  130. location_release(exprasmlist,left.location);
  131. end
  132. else
  133. begin
  134. if not(left.location.loc in [LOC_CREFERENCE,LOC_REFERENCE]) then
  135. CGMessage(type_e_mismatch)
  136. else
  137. begin
  138. if inlined then
  139. begin
  140. tmpreg:=cg.get_scratch_reg_address(exprasmlist);
  141. cg.a_loadaddr_ref_reg(exprasmlist,left.location.reference,tmpreg);
  142. reference_reset_base(href,procinfo^.framepointer,para_offset-pushedparasize);
  143. cg.a_load_reg_ref(exprasmlist,OS_ADDR,tmpreg,href);
  144. cg.free_scratch_reg(exprasmlist,tmpreg);
  145. end
  146. else
  147. cg.a_paramaddr_ref(exprasmlist,left.location.reference,defcoll.paraloc);
  148. location_release(exprasmlist,left.location);
  149. end;
  150. end;
  151. end
  152. { handle call by reference parameter }
  153. else if (defcoll.paratyp in [vs_var,vs_out]) then
  154. begin
  155. if (left.location.loc<>LOC_REFERENCE) then
  156. begin
  157. { passing self to a var parameter is allowed in
  158. TP and delphi }
  159. if not((left.location.loc=LOC_CREFERENCE) and
  160. (left.nodetype=selfn)) then
  161. internalerror(200106041);
  162. end;
  163. maybe_push_high;
  164. if (defcoll.paratyp=vs_out) and
  165. assigned(defcoll.paratype.def) and
  166. not is_class(defcoll.paratype.def) and
  167. defcoll.paratype.def.needs_inittable then
  168. cg.g_finalize(exprasmlist,defcoll.paratype.def,left.location.reference,false);
  169. inc(pushedparasize,4);
  170. if inlined then
  171. begin
  172. tmpreg:=cg.get_scratch_reg_address(exprasmlist);
  173. cg.a_loadaddr_ref_reg(exprasmlist,left.location.reference,tmpreg);
  174. reference_reset_base(href,procinfo^.framepointer,para_offset-pushedparasize);
  175. cg.a_load_reg_ref(exprasmlist,OS_ADDR,tmpreg,href);
  176. cg.free_scratch_reg(exprasmlist,tmpreg);
  177. end
  178. else
  179. cg.a_paramaddr_ref(exprasmlist,left.location.reference,defcoll.paraloc);
  180. location_release(exprasmlist,left.location);
  181. end
  182. else
  183. begin
  184. tempdeftype:=resulttype.def.deftype;
  185. if tempdeftype=filedef then
  186. CGMessage(cg_e_file_must_call_by_reference);
  187. { open array must always push the address, this is needed to
  188. also push addr of small open arrays and with cdecl functions (PFV) }
  189. if (
  190. assigned(defcoll.paratype.def) and
  191. (is_open_array(defcoll.paratype.def) or
  192. is_array_of_const(defcoll.paratype.def))
  193. ) or
  194. (
  195. paramanager.push_addr_param(resulttype.def) and
  196. not is_cdecl
  197. ) then
  198. begin
  199. if not(left.location.loc in [LOC_CREFERENCE,LOC_REFERENCE]) then
  200. begin
  201. { allow passing nil to a procvardef (methodpointer) }
  202. if (left.nodetype=typeconvn) and
  203. (left.resulttype.def.deftype=procvardef) and
  204. (ttypeconvnode(left).left.nodetype=niln) then
  205. begin
  206. tg.gettempofsizereference(exprasmlist,tcgsize2size[left.location.size],href);
  207. cg.a_load_loc_ref(exprasmlist,left.location,href);
  208. location_reset(left.location,LOC_REFERENCE,left.location.size);
  209. left.location.reference:=href;
  210. end
  211. else
  212. internalerror(200204011);
  213. end;
  214. maybe_push_high;
  215. inc(pushedparasize,4);
  216. if inlined then
  217. begin
  218. tmpreg:=cg.get_scratch_reg_address(exprasmlist);
  219. cg.a_loadaddr_ref_reg(exprasmlist,left.location.reference,tmpreg);
  220. reference_reset_base(href,procinfo^.framepointer,para_offset-pushedparasize);
  221. cg.a_load_reg_ref(exprasmlist,OS_ADDR,tmpreg,href);
  222. cg.free_scratch_reg(exprasmlist,tmpreg);
  223. end
  224. else
  225. cg.a_paramaddr_ref(exprasmlist,left.location.reference,defcoll.paraloc);
  226. location_release(exprasmlist,left.location);
  227. end
  228. else
  229. begin
  230. push_value_para(left,inlined,is_cdecl,
  231. para_offset,para_alignment,defcoll.paraloc);
  232. end;
  233. end;
  234. truelabel:=otlabel;
  235. falselabel:=oflabel;
  236. { push from right to left }
  237. if not push_from_left_to_right and assigned(right) then
  238. begin
  239. if (nf_varargs_para in flags) then
  240. tcallparanode(right).secondcallparan(defcoll,push_from_left_to_right,
  241. inlined,is_cdecl,para_alignment,para_offset)
  242. else
  243. tcallparanode(right).secondcallparan(TParaItem(defcoll.next),push_from_left_to_right,
  244. inlined,is_cdecl,para_alignment,para_offset);
  245. end;
  246. end;
  247. {*****************************************************************************
  248. TCGCALLNODE
  249. *****************************************************************************}
  250. procedure tcgcallnode.pass_2;
  251. var
  252. regs_to_push : tregisterset;
  253. unusedstate: pointer;
  254. pushed : tpushedsaved;
  255. funcretref,refcountedtemp : treference;
  256. tmpreg : tregister;
  257. hregister : tregister;
  258. oldpushedparasize : longint;
  259. { true if ESI must be loaded again after the subroutine }
  260. loadesi : boolean;
  261. { true if a virtual method must be called directly }
  262. no_virtual_call : boolean;
  263. { true if we produce a con- or destrutor in a call }
  264. is_con_or_destructor : boolean;
  265. { true if a constructor is called again }
  266. extended_new : boolean;
  267. { adress returned from an I/O-error }
  268. iolabel : tasmlabel;
  269. { lexlevel count }
  270. i : longint;
  271. { help reference pointer }
  272. href : treference;
  273. hrefvmt : treference;
  274. hp : tnode;
  275. pp : tbinarynode;
  276. params : tnode;
  277. inlined : boolean;
  278. inlinecode : tprocinlinenode;
  279. store_parast_fixup,
  280. para_alignment,
  281. para_offset : longint;
  282. cgsize : tcgsize;
  283. { instruction for alignement correction }
  284. { corr : paicpu;}
  285. { we must pop this size also after !! }
  286. { must_pop : boolean; }
  287. pop_size : longint;
  288. {$ifdef OPTALIGN}
  289. pop_esp : boolean;
  290. push_size : longint;
  291. {$endif OPTALIGN}
  292. pop_allowed : boolean;
  293. release_tmpreg : boolean;
  294. constructorfailed : tasmlabel;
  295. label
  296. dont_call;
  297. begin
  298. extended_new:=false;
  299. iolabel:=nil;
  300. inlinecode:=nil;
  301. inlined:=false;
  302. loadesi:=true;
  303. no_virtual_call:=false;
  304. rg.saveunusedstate(unusedstate);
  305. { if we allocate the temp. location for ansi- or widestrings }
  306. { already here, we avoid later a push/pop }
  307. if is_widestring(resulttype.def) then
  308. begin
  309. tg.gettempwidestringreference(exprasmlist,refcountedtemp);
  310. cg.g_decrrefcount(exprasmlist,resulttype.def,refcountedtemp);
  311. end
  312. else if is_ansistring(resulttype.def) then
  313. begin
  314. tg.gettempansistringreference(exprasmlist,refcountedtemp);
  315. cg.g_decrrefcount(exprasmlist,resulttype.def,refcountedtemp);
  316. end;
  317. if (procdefinition.proccalloption in [pocall_cdecl,pocall_cppdecl,pocall_stdcall]) then
  318. para_alignment:=4
  319. else
  320. para_alignment:=aktalignment.paraalign;
  321. if not assigned(procdefinition) then
  322. exit;
  323. { Deciding whether we may still need the parameters happens next (JM) }
  324. if assigned(left) then
  325. params:=left.getcopy
  326. else params := nil;
  327. if (procdefinition.proccalloption=pocall_inline) then
  328. begin
  329. inlined:=true;
  330. inlinecode:=tprocinlinenode(right);
  331. right:=nil;
  332. { set it to the same lexical level as the local symtable, becuase
  333. the para's are stored there }
  334. tprocdef(procdefinition).parast.symtablelevel:=aktprocdef.localst.symtablelevel;
  335. if assigned(params) then
  336. inlinecode.para_offset:=tg.gettempofsizepersistant(exprasmlist,inlinecode.para_size);
  337. store_parast_fixup:=tprocdef(procdefinition).parast.address_fixup;
  338. tprocdef(procdefinition).parast.address_fixup:=inlinecode.para_offset;
  339. {$ifdef extdebug}
  340. Comment(V_debug,
  341. 'inlined parasymtable is at offset '
  342. +tostr(tprocdef(procdefinition).parast.address_fixup));
  343. exprasmList.concat(Tai_asm_comment.Create(
  344. strpnew('inlined parasymtable is at offset '
  345. +tostr(tprocdef(procdefinition).parast.address_fixup))));
  346. {$endif extdebug}
  347. end;
  348. { only if no proc var }
  349. if inlined or
  350. not(assigned(right)) then
  351. is_con_or_destructor:=(procdefinition.proctypeoption in [potype_constructor,potype_destructor]);
  352. { proc variables destroy all registers }
  353. if (inlined or
  354. (right=nil)) and
  355. { virtual methods too }
  356. not(po_virtualmethod in procdefinition.procoptions) then
  357. begin
  358. if (cs_check_io in aktlocalswitches) and
  359. (po_iocheck in procdefinition.procoptions) and
  360. not(po_iocheck in aktprocdef.procoptions) then
  361. begin
  362. getaddrlabel(iolabel);
  363. cg.a_label(exprasmlist,iolabel);
  364. end
  365. else
  366. iolabel:=nil;
  367. { save all used registers }
  368. regs_to_push := tprocdef(procdefinition).usedregisters;
  369. rg.saveusedregisters(exprasmlist,pushed,regs_to_push);
  370. { give used registers through }
  371. rg.usedinproc:=rg.usedinproc + tprocdef(procdefinition).usedregisters;
  372. end
  373. else
  374. begin
  375. regs_to_push := all_registers;
  376. rg.saveusedregisters(exprasmlist,pushed,regs_to_push);
  377. rg.usedinproc:=all_registers;
  378. { no IO check for methods and procedure variables }
  379. iolabel:=nil;
  380. end;
  381. { generate the code for the parameter and push them }
  382. oldpushedparasize:=pushedparasize;
  383. pushedparasize:=0;
  384. pop_size:=0;
  385. {$ifdef dummy}
  386. { no inc esp for inlined procedure
  387. and for objects constructors PM }
  388. if inlined or
  389. ((procdefinition.proctypeoption=potype_constructor) and
  390. { quick'n'dirty check if it is a class or an object }
  391. (resulttype.def.deftype=orddef)) then
  392. pop_allowed:=false
  393. else
  394. pop_allowed:=true;
  395. if pop_allowed then
  396. begin
  397. { Old pushedsize aligned on 4 ? }
  398. i:=oldpushedparasize and 3;
  399. if i>0 then
  400. inc(pop_size,4-i);
  401. { This parasize aligned on 4 ? }
  402. i:=procdefinition.para_size(para_alignment) and 3;
  403. if i>0 then
  404. inc(pop_size,4-i);
  405. { insert the opcode and update pushedparasize }
  406. { never push 4 or more !! }
  407. pop_size:=pop_size mod 4;
  408. if pop_size>0 then
  409. begin
  410. inc(pushedparasize,pop_size);
  411. cg.a_const_reg(A_SUB,S_L,pop_size,R_ESP);
  412. {$ifdef GDB}
  413. if (cs_debuginfo in aktmoduleswitches) and
  414. (exprasmList.first=exprasmList.last) then
  415. exprasmList.concat(Tai_force_line.Create);
  416. {$endif GDB}
  417. end;
  418. end;
  419. {$endif dummy}
  420. {$ifdef OPTALIGN}
  421. if pop_allowed and (cs_align in aktglobalswitches) then
  422. begin
  423. pop_esp:=true;
  424. push_size:=procdefinition.para_size(para_alignment);
  425. { !!!! here we have to take care of return type, self
  426. and nested procedures
  427. }
  428. inc(push_size,12);
  429. emit_reg_reg(A_MOV,S_L,R_ESP,R_EDI);
  430. if (push_size mod 8)=0 then
  431. emit_const_reg(A_AND,S_L,$fffffff8,R_ESP)
  432. else
  433. begin
  434. emit_const_reg(A_SUB,S_L,push_size,R_ESP);
  435. emit_const_reg(A_AND,S_L,$fffffff8,R_ESP);
  436. emit_const_reg(A_SUB,S_L,push_size,R_ESP);
  437. end;
  438. emit_reg(A_PUSH,S_L,R_EDI);
  439. end
  440. else
  441. pop_esp:=false;
  442. {$endif OPTALIGN}
  443. { Push parameters }
  444. if assigned(params) then
  445. begin
  446. { be found elsewhere }
  447. if inlined then
  448. para_offset:=tprocdef(procdefinition).parast.address_fixup+
  449. tprocdef(procdefinition).parast.datasize
  450. else
  451. para_offset:=0;
  452. if not(inlined) and
  453. assigned(right) then
  454. tcallparanode(params).secondcallparan(TParaItem(tabstractprocdef(right.resulttype.def).Para.first),
  455. (po_leftright in procdefinition.procoptions),inlined,
  456. (procdefinition.proccalloption in [pocall_cdecl,pocall_cppdecl]),
  457. para_alignment,para_offset)
  458. else
  459. tcallparanode(params).secondcallparan(TParaItem(procdefinition.Para.first),
  460. (po_leftright in procdefinition.procoptions),inlined,
  461. (procdefinition.proccalloption in [pocall_cdecl,pocall_cppdecl]),
  462. para_alignment,para_offset);
  463. end;
  464. { Allocate return value for inlined routines }
  465. if inlined then
  466. inlinecode.retoffset:=tg.gettempofsizepersistant(exprasmlist,Align(resulttype.def.size,aktalignment.paraalign));
  467. { Allocate return value when returned in argument }
  468. if paramanager.ret_in_param(resulttype.def) then
  469. begin
  470. if assigned(funcretrefnode) then
  471. begin
  472. secondpass(funcretrefnode);
  473. if codegenerror then
  474. exit;
  475. if (funcretrefnode.location.loc<>LOC_REFERENCE) then
  476. internalerror(200204246);
  477. funcretref:=funcretrefnode.location.reference;
  478. end
  479. else
  480. begin
  481. if inlined then
  482. begin
  483. reference_reset(funcretref);
  484. funcretref.offset:=tg.gettempofsizepersistant(exprasmlist,resulttype.def.size);
  485. funcretref.base:=procinfo^.framepointer;
  486. {$ifdef extdebug}
  487. Comment(V_debug,'function return value is at offset '
  488. +tostr(funcretref.offset));
  489. exprasmlist.concat(tai_asm_comment.create(
  490. strpnew('function return value is at offset '
  491. +tostr(funcretref.offset))));
  492. {$endif extdebug}
  493. end
  494. else
  495. tg.gettempofsizereference(exprasmlist,resulttype.def.size,funcretref);
  496. end;
  497. { This must not be counted for C code
  498. complex return address is removed from stack
  499. by function itself ! }
  500. {$ifdef OLD_C_STACK}
  501. inc(pushedparasize,4); { lets try without it PM }
  502. {$endif not OLD_C_STACK}
  503. if inlined then
  504. begin
  505. hregister:=cg.get_scratch_reg_address(exprasmlist);
  506. cg.a_loadaddr_ref_reg(exprasmlist,funcretref,hregister);
  507. reference_reset_base(href,procinfo^.framepointer,inlinecode.retoffset);
  508. cg.a_load_reg_ref(exprasmlist,OS_ADDR,hregister,href);
  509. cg.free_scratch_reg(exprasmlist,hregister);
  510. end
  511. else
  512. cg.a_paramaddr_ref(exprasmlist,funcretref,
  513. paramanager.getfuncretloc(procdefinition));
  514. end;
  515. { procedure variable or normal function call ? }
  516. if inlined or
  517. (right=nil) then
  518. begin
  519. { Normal function call }
  520. {$ifdef dummy}
  521. { overloaded operator has no symtable }
  522. { push self }
  523. if assigned(symtableproc) and
  524. (symtableproc.symtabletype=withsymtable) then
  525. begin
  526. { dirty trick to avoid the secondcall below }
  527. methodpointer:=ccallparanode.create(nil,nil);
  528. location_reset(methodpointer.location,LOC_REGISTER,OS_ADDR);
  529. rg.getexplicitregisterint(exprasmlist,R_ESI);
  530. methodpointer.location.register:=R_ESI;
  531. { ARGHHH this is wrong !!!
  532. if we can init from base class for a child
  533. class that the wrong VMT will be
  534. transfered to constructor !! }
  535. methodpointer.resulttype:=
  536. twithnode(twithsymtable(symtableproc).withnode).left.resulttype;
  537. { make a reference }
  538. href:=twithnode(twithsymtable(symtableproc).withnode).withreference;
  539. if ((not(nf_islocal in twithnode(twithsymtable(symtableproc).withnode).flags)) and
  540. (not twithsymtable(symtableproc).direct_with)) or
  541. is_class_or_interface(methodpointer.resulttype.def) then
  542. cg.a_load_ref_reg(exprasmlist,OS_ADDR,href,self_pointer_reg)
  543. else
  544. cg.a_loadaddr_ref_reg(exprasmlist,href,self_pointer_reg);
  545. end;
  546. { push self }
  547. if assigned(symtableproc) and
  548. ((symtableproc.symtabletype=objectsymtable) or
  549. (symtableproc.symtabletype=withsymtable)) then
  550. begin
  551. if assigned(methodpointer) then
  552. begin
  553. {
  554. if methodpointer^.resulttype.def=classrefdef then
  555. begin
  556. two possibilities:
  557. 1. constructor
  558. 2. class method
  559. end
  560. else }
  561. begin
  562. case methodpointer.nodetype of
  563. typen:
  564. begin
  565. { direct call to inherited method }
  566. if (po_abstractmethod in procdefinition.procoptions) then
  567. begin
  568. CGMessage(cg_e_cant_call_abstract_method);
  569. goto dont_call;
  570. end;
  571. { generate no virtual call }
  572. no_virtual_call:=true;
  573. if (sp_static in symtableprocentry.symoptions) then
  574. begin
  575. { well lets put the VMT address directly into ESI }
  576. { it is kind of dirty but that is the simplest }
  577. { way to accept virtual static functions (PM) }
  578. loadesi:=true;
  579. { if no VMT just use $0 bug0214 PM }
  580. rg.getexplicitregisterint(exprasmlist,R_ESI);
  581. if not(oo_has_vmt in tobjectdef(methodpointer.resulttype.def).objectoptions) then
  582. cg.a_load_const_reg(exprasmlist,OS_ADDR,0,self_pointer_reg)
  583. else
  584. begin
  585. reference_reset_symbol(href,newasmsymbol(tobjectdef(methodpointer.resulttype.def).vmt_mangledname),0);
  586. cg.a_loadaddr_ref_reg(exprasmlist,href,self_pointer_reg);
  587. end;
  588. { emit_reg(A_PUSH,S_L,R_ESI);
  589. this is done below !! }
  590. end
  591. else
  592. { this is a member call, so ESI isn't modfied }
  593. loadesi:=false;
  594. { a class destructor needs a flag }
  595. if is_class(tobjectdef(methodpointer.resulttype.def)) and
  596. (procdefinition.proctypeoption=potype_destructor) then
  597. begin
  598. cg.a_param_const(exprasmlist,OS_ADDR,0,2);
  599. cg.a_param_reg(exprasmlist,OS_ADDR,self_pointer_reg,1);
  600. end;
  601. if not(is_con_or_destructor and
  602. is_class(methodpointer.resulttype.def) and
  603. (procdefinition.proctypeoption in [potype_constructor,potype_destructor])
  604. ) then
  605. cg.a_param_reg(exprasmlist,OS_ADDR,self_pointer_reg,1);
  606. { if an inherited con- or destructor should be }
  607. { called in a con- or destructor then a warning }
  608. { will be made }
  609. { con- and destructors need a pointer to the vmt }
  610. if is_con_or_destructor and
  611. is_object(methodpointer.resulttype.def) and
  612. assigned(aktprocdef) then
  613. begin
  614. if not(aktprocdef.proctypeoption in
  615. [potype_constructor,potype_destructor]) then
  616. CGMessage(cg_w_member_cd_call_from_method);
  617. end;
  618. { class destructors get there flag above }
  619. { constructor flags ? }
  620. if is_con_or_destructor and
  621. not(
  622. is_class(methodpointer.resulttype.def) and
  623. assigned(aktprocdef) and
  624. (aktprocdef.proctypeoption=potype_destructor)) then
  625. begin
  626. { a constructor needs also a flag }
  627. if is_class(methodpointer.resulttype.def) then
  628. cg.a_param_const(exprasmlist,OS_ADDR,0,2);
  629. cg.a_param_const(exprasmlist,OS_ADDR,0,1);
  630. end;
  631. end;
  632. hnewn:
  633. begin
  634. { extended syntax of new }
  635. { ESI must be zero }
  636. rg.getexplicitregisterint(exprasmlist,R_ESI);
  637. cg.a_load_const_reg(exprasmlist,OS_ADDR,0,self_pointer_reg);
  638. cg.a_param_reg(exprasmlist,OS_ADDR,self_pointer_reg,2);
  639. { insert the vmt }
  640. reference_reset_symbol(href,newasmsymbol(tobjectdef(methodpointer.resulttype.def).vmt_mangledname),0);
  641. cg.a_paramaddr_ref(exprasmlist,href,1);
  642. extended_new:=true;
  643. end;
  644. hdisposen:
  645. begin
  646. secondpass(methodpointer);
  647. { destructor with extended syntax called from dispose }
  648. { hdisposen always deliver LOC_REFERENCE }
  649. rg.getexplicitregisterint(exprasmlist,R_ESI);
  650. emit_ref_reg(A_LEA,S_L,methodpointer.location.reference,R_ESI);
  651. reference_release(exprasmlist,methodpointer.location.reference);
  652. cg.a_param_reg(exprasmlist,OS_ADDR,self_pointer_reg,2);
  653. reference_reset_symbol(href,newasmsymbol(tobjectdef(methodpointer.resulttype.def).vmt_mangledname),0);
  654. cg.a_paramaddr_ref(exprasmlist,href,1);
  655. end;
  656. else
  657. begin
  658. { call to an instance member }
  659. if (symtableproc.symtabletype<>withsymtable) then
  660. begin
  661. secondpass(methodpointer);
  662. rg.getexplicitregisterint(exprasmlist,R_ESI);
  663. case methodpointer.location.loc of
  664. LOC_CREGISTER,
  665. LOC_REGISTER:
  666. begin
  667. cg.a_load_reg_reg(exprasmlist,OS_ADDR,methodpointer.location.register,R_ESI);
  668. rg.ungetregisterint(exprasmlist,methodpointer.location.register);
  669. end;
  670. else
  671. begin
  672. if (methodpointer.resulttype.def.deftype=classrefdef) or
  673. is_class_or_interface(methodpointer.resulttype.def) then
  674. cg.a_load_ref_reg(exprasmlist,OS_ADDR,methodpointer.location.reference,R_ESI)
  675. else
  676. cg.a_loadaddr_ref_reg(exprasmlist,methodpointer.location.reference,R_ESI);
  677. reference_release(exprasmlist,methodpointer.location.reference);
  678. end;
  679. end;
  680. end;
  681. { when calling a class method, we have to load ESI with the VMT !
  682. But, not for a class method via self }
  683. if not(po_containsself in procdefinition.procoptions) then
  684. begin
  685. if (po_classmethod in procdefinition.procoptions) and
  686. not(methodpointer.resulttype.def.deftype=classrefdef) then
  687. begin
  688. { class method needs current VMT }
  689. rg.getexplicitregisterint(exprasmlist,R_ESI);
  690. reference_reset_base(href,R_ESI,tprocdef(procdefinition)._class.vmt_offset);
  691. cg.a_load_ref_reg(exprasmlist,OS_ADDR,href,self_pointer_reg);
  692. end;
  693. { direct call to destructor: remove data }
  694. if (procdefinition.proctypeoption=potype_destructor) and
  695. is_class(methodpointer.resulttype.def) then
  696. cg.a_param_const(exprasmlist,OS_INT,1,1);
  697. { direct call to class constructor, don't allocate memory }
  698. if (procdefinition.proctypeoption=potype_constructor) and
  699. is_class(methodpointer.resulttype.def) then
  700. begin
  701. cg.a_param_const(exprasmlist,OS_INT,0,2);
  702. cg.a_param_const(exprasmlist,OS_INT,0,1);
  703. end
  704. else
  705. begin
  706. { constructor call via classreference => allocate memory }
  707. if (procdefinition.proctypeoption=potype_constructor) and
  708. (methodpointer.resulttype.def.deftype=classrefdef) and
  709. is_class(tclassrefdef(methodpointer.resulttype.def).pointertype.def) then
  710. cg.a_param_const(exprasmlist,OS_INT,1,1);
  711. cg.a_param_reg(exprasmlist,OS_ADDR,self_pointer_reg,1);
  712. end;
  713. end;
  714. if is_con_or_destructor then
  715. begin
  716. { classes don't get a VMT pointer pushed }
  717. if is_object(methodpointer.resulttype.def) then
  718. begin
  719. if (procdefinition.proctypeoption=potype_constructor) then
  720. begin
  721. { it's no bad idea, to insert the VMT }
  722. reference_reset_symbol(href,newasmsymbol(
  723. tobjectdef(methodpointer.resulttype.def).vmt_mangledname),0);
  724. cg.a_paramaddr_ref(exprasmlist,href,1);
  725. end
  726. { destructors haven't to dispose the instance, if this is }
  727. { a direct call }
  728. else
  729. cg.a_param_const(exprasmlist,OS_INT,0,1);
  730. end;
  731. end;
  732. end;
  733. end;
  734. end;
  735. end
  736. else
  737. begin
  738. if (po_classmethod in procdefinition.procoptions) and
  739. not(
  740. assigned(aktprocdef) and
  741. (po_classmethod in aktprocdef.procoptions)
  742. ) then
  743. begin
  744. { class method needs current VMT }
  745. rg.getexplicitregisterint(exprasmlist,R_ESI);
  746. reference_reset_base(href,R_ESI,tprocdef(procdefinition)._class.vmt_offset);
  747. cg.a_load_ref_reg(exprasmlist,OS_ADDR,href,R_ESI);
  748. end
  749. else
  750. begin
  751. { member call, ESI isn't modified }
  752. loadesi:=false;
  753. end;
  754. { direct call to destructor: don't remove data! }
  755. if is_class(procinfo^._class) then
  756. begin
  757. if (procdefinition.proctypeoption=potype_destructor) then
  758. begin
  759. cg.a_param_const(exprasmlist,OS_INT,0,2);
  760. cg.a_param_reg(exprasmlist,OS_ADDR,R_ESI,1);
  761. end
  762. else if (procdefinition.proctypeoption=potype_constructor) then
  763. begin
  764. cg.a_param_const(exprasmlist,OS_INT,0,2);
  765. cg.a_param_const(exprasmlist,OS_INT,0,1);
  766. end
  767. else
  768. cg.a_param_reg(exprasmlist,OS_ADDR,R_ESI,1);
  769. end
  770. else if is_object(procinfo^._class) then
  771. begin
  772. cg.a_param_reg(exprasmlist,OS_ADDR,R_ESI,1);
  773. if is_con_or_destructor then
  774. begin
  775. if (procdefinition.proctypeoption=potype_constructor) then
  776. begin
  777. { it's no bad idea, to insert the VMT }
  778. reference_reset_symbol(href,newasmsymbol(procinfo^._class.vmt_mangledname),0);
  779. cg.a_paramaddr_ref(exprasmlist,href,1);
  780. end
  781. { destructors haven't to dispose the instance, if this is }
  782. { a direct call }
  783. else
  784. cg.a_param_const(exprasmlist,OS_INT,0,1);
  785. end;
  786. end
  787. else
  788. Internalerror(200006165);
  789. end;
  790. end;
  791. { call to BeforeDestruction? }
  792. if (procdefinition.proctypeoption=potype_destructor) and
  793. assigned(methodpointer) and
  794. (methodpointer.nodetype<>typen) and
  795. is_class(tobjectdef(methodpointer.resulttype.def)) and
  796. (inlined or
  797. (right=nil)) then
  798. begin
  799. cg.a_param_reg(exprasmlist,OS_ADDR,self_pointer_reg,1);
  800. reference_reset_base(href,self_pointer_reg,0);
  801. tmpreg:=cg.get_scratch_reg_address(exprasmlist);
  802. cg.a_load_ref_reg(exprasmlist,OS_ADDR,href,tmpreg);
  803. reference_reset_base(href,tmpreg,72);
  804. cg.a_call_ref(exprasmlist,href);
  805. cg.free_scratch_reg(exprasmlist,tmpreg);
  806. end;
  807. { push base pointer ?}
  808. { never when inlining, since if necessary, the base pointer }
  809. { can/will be gottten from the current procedure's symtable }
  810. { (JM) }
  811. if not inlined then
  812. if (lexlevel>=normal_function_level) and assigned(tprocdef(procdefinition).parast) and
  813. ((tprocdef(procdefinition).parast.symtablelevel)>normal_function_level) then
  814. begin
  815. { if we call a nested function in a method, we must }
  816. { push also SELF! }
  817. { THAT'S NOT TRUE, we have to load ESI via frame pointer }
  818. { access }
  819. {
  820. begin
  821. loadesi:=false;
  822. emit_reg(A_PUSH,S_L,R_ESI);
  823. end;
  824. }
  825. if lexlevel=(tprocdef(procdefinition).parast.symtablelevel) then
  826. begin
  827. reference_reset_base(href,procinfo^.framepointer,procinfo^.framepointer_offset);
  828. cg.a_param_ref(exprasmlist,OS_ADDR,href,-1);
  829. end
  830. { this is only true if the difference is one !!
  831. but it cannot be more !! }
  832. else if (lexlevel=(tprocdef(procdefinition).parast.symtablelevel)-1) then
  833. begin
  834. cg.a_param_reg(exprasmlist,OS_ADDR,procinfo^.framepointer,-1);
  835. end
  836. else if (lexlevel>(tprocdef(procdefinition).parast.symtablelevel)) then
  837. begin
  838. hregister:=rg.getregisterint(exprasmlist);
  839. reference_reset_base(href,procinfo^.framepointer,procinfo^.framepointer_offset);
  840. cg.a_load_ref_reg(exprasmlist,OS_ADDR,href,hregister);
  841. for i:=(tprocdef(procdefinition).parast.symtablelevel) to lexlevel-1 do
  842. begin
  843. {we should get the correct frame_pointer_offset at each level
  844. how can we do this !!! }
  845. reference_reset_base(href,hregister,procinfo^.framepointer_offset);
  846. cg.a_load_ref_reg(exprasmlist,OS_ADDR,href,hregister);
  847. end;
  848. cg.a_param_reg(exprasmlist,OS_ADDR,hregister,-1);
  849. rg.ungetregisterint(exprasmlist,hregister);
  850. end
  851. else
  852. internalerror(25000);
  853. end;
  854. {$endif dummy}
  855. rg.saveregvars(exprasmlist,regs_to_push);
  856. {$ifdef dummy}
  857. if (po_virtualmethod in procdefinition.procoptions) and
  858. not(no_virtual_call) then
  859. begin
  860. { static functions contain the vmt_address in ESI }
  861. { also class methods }
  862. { Here it is quite tricky because it also depends }
  863. { on the methodpointer PM }
  864. release_tmpreg:=false;
  865. rg.getexplicitregisterint(exprasmlist,R_ESI);
  866. if assigned(aktprocdef) then
  867. begin
  868. if (((sp_static in aktprocdef.procsym.symoptions) or
  869. (po_classmethod in aktprocdef.procoptions)) and
  870. ((methodpointer=nil) or (methodpointer.nodetype=typen)))
  871. or
  872. (po_staticmethod in procdefinition.procoptions) or
  873. ((procdefinition.proctypeoption=potype_constructor) and
  874. { esi contains the vmt if we call a constructor via a class ref }
  875. assigned(methodpointer) and
  876. (methodpointer.resulttype.def.deftype=classrefdef)
  877. ) or
  878. { is_interface(tprocdef(procdefinition)._class) or }
  879. { ESI is loaded earlier }
  880. (po_classmethod in procdefinition.procoptions) then
  881. begin
  882. reference_reset_base(href,R_ESI,0);
  883. end
  884. else
  885. begin
  886. { this is one point where we need vmt_offset (PM) }
  887. reference_reset_base(href,R_ESI,tprocdef(procdefinition)._class.vmt_offset);
  888. tmpreg:=cg.get_scratch_reg_address(exprasmlist);
  889. cg.a_load_ref_reg(exprasmlist,OS_ADDR,href,tmpreg);
  890. reference_reset_base(href,tmpreg,0);
  891. release_tmpreg:=true;
  892. end;
  893. end
  894. else
  895. { aktprocdef should be assigned, also in main program }
  896. internalerror(12345);
  897. if tprocdef(procdefinition).extnumber=-1 then
  898. internalerror(44584);
  899. href.offset:=tprocdef(procdefinition)._class.vmtmethodoffset(tprocdef(procdefinition).extnumber);
  900. if not(is_interface(tprocdef(procdefinition)._class)) and
  901. not(is_cppclass(tprocdef(procdefinition)._class)) then
  902. begin
  903. if (cs_check_object in aktlocalswitches) then
  904. begin
  905. reference_reset_symbol(hrefvmt,newasmsymbol(tprocdef(procdefinition)._class.vmt_mangledname),0);
  906. cg.a_paramaddr_ref(exprasmlist,hrefvmt,2);
  907. cg.a_param_reg(exprasmlist,OS_ADDR,href.base,1);
  908. cg.a_call_name(exprasmlist,'FPC_CHECK_OBJECT_EXT');
  909. end
  910. else if (cs_check_range in aktlocalswitches) then
  911. begin
  912. cg.a_param_reg(exprasmlist,OS_ADDR,href.base,1);
  913. cg.a_call_name(exprasmlist,'FPC_CHECK_OBJECT');
  914. end;
  915. end;
  916. cg.a_call_ref(exprasmlist,href);
  917. if release_tmpreg then
  918. cg.free_scratch_reg(exprasmlist,tmpreg);
  919. end
  920. else
  921. {$endif dummy}
  922. if not inlined then
  923. begin
  924. {$ifdef i386}
  925. { We can call interrupts from within the smae code
  926. by just pushing the flags and CS PM }
  927. if (po_interrupt in procdefinition.procoptions) then
  928. begin
  929. emit_none(A_PUSHF,S_L);
  930. emit_reg(A_PUSH,S_L,R_CS);
  931. end;
  932. {$endif i386}
  933. cg.a_call_name(exprasmlist,tprocdef(procdefinition).mangledname);
  934. end
  935. else { inlined proc }
  936. { inlined code is in inlinecode }
  937. begin
  938. { process the inlinecode }
  939. secondpass(inlinecode);
  940. { free the args }
  941. if tprocdef(procdefinition).parast.datasize>0 then
  942. tg.ungetpersistanttemp(exprasmlist,tprocdef(procdefinition).parast.address_fixup);
  943. end;
  944. end;
  945. {$ifdef dummy}
  946. else
  947. { now procedure variable case }
  948. begin
  949. secondpass(right);
  950. {$ifdef i386}
  951. if (po_interrupt in procdefinition.procoptions) then
  952. begin
  953. emit_none(A_PUSHF,S_L);
  954. emit_reg(A_PUSH,S_L,R_CS);
  955. end;
  956. {$endif i386}
  957. { procedure of object? }
  958. if (po_methodpointer in procdefinition.procoptions) then
  959. begin
  960. { method pointer can't be in a register }
  961. hregister:=R_NO;
  962. { do some hacking if we call a method pointer }
  963. { which is a class member }
  964. { else ESI is overwritten ! }
  965. if (right.location.reference.base=R_ESI) or
  966. (right.location.reference.index=R_ESI) then
  967. begin
  968. reference_release(exprasmlist,right.location.reference);
  969. hregister:=cg.get_scratch_reg_address(exprasmlist);
  970. cg.a_load_ref_reg(exprasmlist,OS_ADDR,right.location.reference,hregister);
  971. end;
  972. { load self, but not if it's already explicitly pushed }
  973. if not(po_containsself in procdefinition.procoptions) then
  974. begin
  975. { load ESI }
  976. href:=right.location.reference;
  977. inc(href.offset,4);
  978. rg.getexplicitregisterint(exprasmlist,R_ESI);
  979. cg.a_load_ref_reg(exprasmlist,OS_ADDR,href,self_pointer_reg);
  980. { push self pointer }
  981. cg.a_param_reg(exprasmlist,OS_ADDR,self_pointer_reg,-1);
  982. end;
  983. rg.saveregvars(exprasmlist,ALL_REGISTERS);
  984. if hregister<>R_NO then
  985. reference_reset_base(href,hregister,0)
  986. else
  987. href:=right.location.reference;
  988. cg.a_call_ref(exprasmlist,href);
  989. if hregister<>R_NO then
  990. cg.free_scratch_reg(exprasmlist,hregister);
  991. reference_release(exprasmlist,right.location.reference);
  992. end
  993. else
  994. begin
  995. rg.saveregvars(exprasmlist,ALL_REGISTERS);
  996. case right.location.loc of
  997. LOC_REGISTER,LOC_CREGISTER:
  998. reference_reset_base(href,right.location.register,0);
  999. LOC_REFERENCE,LOC_CREFERENCE :
  1000. href:=right.location.reference;
  1001. else
  1002. internalerror(200203311);
  1003. end;
  1004. cg.a_call_ref(exprasmlist,href);
  1005. location_release(exprasmlist,right.location);
  1006. end;
  1007. end;
  1008. {$endif dummy}
  1009. {$ifdef dummy}
  1010. { this was only for normal functions
  1011. displaced here so we also get
  1012. it to work for procvars PM }
  1013. if (not inlined) and (po_clearstack in procdefinition.procoptions) then
  1014. begin
  1015. { we also add the pop_size which is included in pushedparasize }
  1016. pop_size:=0;
  1017. { better than an add on all processors }
  1018. if pushedparasize=4 then
  1019. begin
  1020. rg.getexplicitregisterint(exprasmlist,R_EDI);
  1021. emit_reg(A_POP,S_L,R_EDI);
  1022. rg.ungetregisterint(exprasmlist,R_EDI);
  1023. end
  1024. { the pentium has two pipes and pop reg is pairable }
  1025. { but the registers must be different! }
  1026. else if (pushedparasize=8) and
  1027. not(cs_littlesize in aktglobalswitches) and
  1028. (aktoptprocessor=ClassP5) and
  1029. (procinfo^._class=nil) then
  1030. begin
  1031. rg.getexplicitregisterint(exprasmlist,R_EDI);
  1032. emit_reg(A_POP,S_L,R_EDI);
  1033. rg.ungetregisterint(exprasmlist,R_EDI);
  1034. exprasmList.concat(tai_regalloc.Alloc(R_ESI));
  1035. emit_reg(A_POP,S_L,R_ESI);
  1036. exprasmList.concat(tai_regalloc.DeAlloc(R_ESI));
  1037. end
  1038. else if pushedparasize<>0 then
  1039. emit_const_reg(A_ADD,S_L,pushedparasize,R_ESP);
  1040. end;
  1041. {$endif dummy}
  1042. if procinfo^.maxpushedparasize<pushedparasize then
  1043. procinfo^.maxpushedparasize:=pushedparasize;
  1044. {$ifdef OPTALIGN}
  1045. if pop_esp then
  1046. emit_reg(A_POP,S_L,R_ESP);
  1047. {$endif OPTALIGN}
  1048. dont_call:
  1049. pushedparasize:=oldpushedparasize;
  1050. rg.restoreunusedstate(unusedstate);
  1051. {$ifdef TEMPREGDEBUG}
  1052. testregisters32;
  1053. {$endif TEMPREGDEBUG}
  1054. { a constructor could be a function with boolean result }
  1055. { if calling constructor called fail we
  1056. must jump directly to quickexitlabel PM
  1057. but only if it is a call of an inherited constructor }
  1058. if (inlined or
  1059. (right=nil)) and
  1060. (procdefinition.proctypeoption=potype_constructor) and
  1061. assigned(methodpointer) and
  1062. (methodpointer.nodetype=typen) and
  1063. (aktprocdef.proctypeoption=potype_constructor) then
  1064. begin
  1065. cg.a_cmp_const_reg_label(exprasmlist,OS_ADDR,OC_EQ,0,accumulator,faillabel);
  1066. end;
  1067. { call to AfterConstruction? }
  1068. if is_class(resulttype.def) and
  1069. (inlined or
  1070. (right=nil)) and
  1071. (procdefinition.proctypeoption=potype_constructor) and
  1072. assigned(methodpointer) and
  1073. (methodpointer.nodetype<>typen) then
  1074. begin
  1075. getlabel(constructorfailed);
  1076. cg.a_cmp_const_reg_label(exprasmlist,OS_ADDR,OC_EQ,0,self_pointer_reg,constructorfailed);
  1077. cg.a_param_reg(exprasmlist,OS_ADDR,accumulator,paramanager.getintparaloc(1));
  1078. reference_reset_base(href,self_pointer_reg,0);
  1079. tmpreg:=cg.get_scratch_reg_address(exprasmlist);
  1080. cg.a_load_ref_reg(exprasmlist,OS_ADDR,href,tmpreg);
  1081. reference_reset_base(href,tmpreg,17*pointer_size);
  1082. cg.a_call_ref(exprasmlist,href);
  1083. cg.free_scratch_reg(exprasmlist,tmpreg);
  1084. exprasmList.concat(tai_regalloc.Alloc(accumulator));
  1085. cg.a_label(exprasmlist,constructorfailed);
  1086. cg.a_load_reg_reg(exprasmlist,OS_ADDR,self_pointer_reg,accumulator);
  1087. end;
  1088. { handle function results }
  1089. if (not is_void(resulttype.def)) then
  1090. begin
  1091. { structured results are easy to handle.... }
  1092. { needed also when result_no_used !! }
  1093. if paramanager.ret_in_param(resulttype.def) then
  1094. begin
  1095. location_reset(location,LOC_CREFERENCE,def_cgsize(resulttype.def));
  1096. location.reference.symbol:=nil;
  1097. location.reference:=funcretref;
  1098. end
  1099. else
  1100. { ansi/widestrings must be registered, so we can dispose them }
  1101. if is_ansistring(resulttype.def) or
  1102. is_widestring(resulttype.def) then
  1103. begin
  1104. location_reset(location,LOC_CREFERENCE,OS_ADDR);
  1105. location.reference:=refcountedtemp;
  1106. cg.a_reg_alloc(exprasmlist,accumulator);
  1107. cg.a_load_reg_ref(exprasmlist,OS_ADDR,accumulator,location.reference);
  1108. cg.a_reg_dealloc(exprasmlist,accumulator);
  1109. end
  1110. else
  1111. { we have only to handle the result if it is used }
  1112. if (nf_return_value_used in flags) then
  1113. begin
  1114. case resulttype.def.deftype of
  1115. enumdef,
  1116. orddef :
  1117. begin
  1118. cgsize:=def_cgsize(resulttype.def);
  1119. { an object constructor is a function with boolean result }
  1120. if (inlined or (right=nil)) and
  1121. (procdefinition.proctypeoption=potype_constructor) then
  1122. begin
  1123. if extended_new then
  1124. cgsize:=OS_INT
  1125. else
  1126. begin
  1127. {$ifdef dummy}
  1128. cgsize:=OS_NO;
  1129. { this fails if popsize > 0 PM }
  1130. location_reset(location,LOC_FLAGS,OS_NO);
  1131. location.resflags:=F_NE;
  1132. {$endif dummy}
  1133. end;
  1134. end;
  1135. if cgsize<>OS_NO then
  1136. begin
  1137. location_reset(location,LOC_REGISTER,cgsize);
  1138. cg.a_reg_alloc(exprasmlist,accumulator);
  1139. if cgsize in [OS_64,OS_S64] then
  1140. begin
  1141. cg.a_reg_alloc(exprasmlist,accumulatorhigh);
  1142. if accumulatorhigh in rg.unusedregsint then
  1143. begin
  1144. location.registerhigh:=rg.getexplicitregisterint(exprasmlist,accumulatorhigh);
  1145. location.registerlow:=rg.getexplicitregisterint(exprasmlist,accumulator);
  1146. end
  1147. else
  1148. begin
  1149. location.registerhigh:=rg.getexplicitregisterint(exprasmlist,accumulatorhigh);
  1150. location.registerlow:=rg.getexplicitregisterint(exprasmlist,accumulator);
  1151. end;
  1152. cg64.a_load64_reg_reg(exprasmlist,joinreg64(accumulator,accumulatorhigh),
  1153. location.register64);
  1154. end
  1155. else
  1156. begin
  1157. location.register:=rg.getexplicitregisterint(exprasmlist,accumulator);
  1158. hregister:=rg.makeregsize(accumulator,cgsize);
  1159. location.register:=rg.makeregsize(location.register,cgsize);
  1160. cg.a_load_reg_reg(exprasmlist,cgsize,hregister,location.register);
  1161. end;
  1162. end;
  1163. end;
  1164. floatdef :
  1165. begin
  1166. {$ifdef dummy}
  1167. location_reset(location,LOC_FPUREGISTER,def_cgsize(resulttype.def));
  1168. location.register:=R_ST;
  1169. inc(trgcpu(rg).fpuvaroffset);
  1170. {$endif dummy}
  1171. end;
  1172. else
  1173. begin
  1174. location_reset(location,LOC_REGISTER,OS_INT);
  1175. location.register:=rg.getexplicitregisterint(exprasmlist,accumulator);
  1176. cg.a_load_reg_reg(exprasmlist,OS_INT,accumulator,location.register);
  1177. end;
  1178. end;
  1179. end;
  1180. end;
  1181. { perhaps i/o check ? }
  1182. if iolabel<>nil then
  1183. begin
  1184. reference_reset_symbol(href,iolabel,0);
  1185. cg.a_paramaddr_ref(exprasmlist,href,paramanager.getintparaloc(1));
  1186. cg.a_call_name(exprasmlist,'FPC_IOCHECK');
  1187. end;
  1188. {$ifdef i386}
  1189. if pop_size>0 then
  1190. emit_const_reg(A_ADD,S_L,pop_size,R_ESP);
  1191. {$endif i386}
  1192. { restore registers }
  1193. rg.restoreusedregisters(exprasmlist,pushed);
  1194. { at last, restore instance pointer (SELF) }
  1195. if loadesi then
  1196. cg.g_maybe_loadself(exprasmlist);
  1197. pp:=tbinarynode(params);
  1198. while assigned(pp) do
  1199. begin
  1200. if assigned(pp.left) then
  1201. begin
  1202. location_freetemp(exprasmlist,pp.left.location);
  1203. { process also all nodes of an array of const }
  1204. if pp.left.nodetype=arrayconstructorn then
  1205. begin
  1206. if assigned(tarrayconstructornode(pp.left).left) then
  1207. begin
  1208. hp:=pp.left;
  1209. while assigned(hp) do
  1210. begin
  1211. location_freetemp(exprasmlist,tarrayconstructornode(hp).left.location);
  1212. hp:=tarrayconstructornode(hp).right;
  1213. end;
  1214. end;
  1215. end;
  1216. end;
  1217. pp:=tbinarynode(pp.right);
  1218. end;
  1219. if inlined then
  1220. begin
  1221. tg.ungetpersistanttemp(exprasmlist,inlinecode.retoffset);
  1222. tprocdef(procdefinition).parast.address_fixup:=store_parast_fixup;
  1223. right:=inlinecode;
  1224. end;
  1225. if assigned(params) then
  1226. params.free;
  1227. { from now on the result can be freed normally }
  1228. if inlined and paramanager.ret_in_param(resulttype.def) then
  1229. tg.persistanttemptonormal(funcretref.offset);
  1230. { if return value is not used }
  1231. if (not(nf_return_value_used in flags)) and (not is_void(resulttype.def)) then
  1232. begin
  1233. if location.loc in [LOC_CREFERENCE,LOC_REFERENCE] then
  1234. begin
  1235. { data which must be finalized ? }
  1236. if (resulttype.def.needs_inittable) then
  1237. cg.g_finalize(exprasmlist,resulttype.def,location.reference,false);
  1238. { release unused temp }
  1239. tg.ungetiftemp(exprasmlist,location.reference)
  1240. end
  1241. else if location.loc=LOC_FPUREGISTER then
  1242. begin
  1243. {$ifdef i386}
  1244. { release FPU stack }
  1245. emit_reg(A_FSTP,S_NO,R_ST);
  1246. {
  1247. dec(trgcpu(rg).fpuvaroffset);
  1248. do NOT decrement as the increment before
  1249. is not called for unused results PM }
  1250. {$endif i386}
  1251. end;
  1252. end;
  1253. end;
  1254. {*****************************************************************************
  1255. TCGPROCINLINENODE
  1256. *****************************************************************************}
  1257. procedure tcgprocinlinenode.pass_2;
  1258. var st : tsymtable;
  1259. oldprocdef : tprocdef;
  1260. ps, i : longint;
  1261. tmpreg: tregister;
  1262. oldprocinfo : pprocinfo;
  1263. oldinlining_procedure,
  1264. nostackframe,make_global : boolean;
  1265. inlineentrycode,inlineexitcode : TAAsmoutput;
  1266. oldexitlabel,oldexit2label,oldquickexitlabel:tasmlabel;
  1267. oldregstate: pointer;
  1268. {$ifdef GDB}
  1269. startlabel,endlabel : tasmlabel;
  1270. pp : pchar;
  1271. mangled_length : longint;
  1272. {$endif GDB}
  1273. begin
  1274. { deallocate the registers used for the current procedure's regvars }
  1275. if assigned(aktprocdef.regvarinfo) then
  1276. begin
  1277. with pregvarinfo(aktprocdef.regvarinfo)^ do
  1278. for i := 1 to maxvarregs do
  1279. if assigned(regvars[i]) then
  1280. store_regvar(exprasmlist,regvars[i].reg);
  1281. rg.saveStateForInline(oldregstate);
  1282. { make sure the register allocator knows what the regvars in the }
  1283. { inlined code block are (JM) }
  1284. rg.resetusableregisters;
  1285. rg.clearregistercount;
  1286. rg.cleartempgen;
  1287. if assigned(inlineprocdef.regvarinfo) then
  1288. with pregvarinfo(inlineprocdef.regvarinfo)^ do
  1289. for i := 1 to maxvarregs do
  1290. if assigned(regvars[i]) then
  1291. begin
  1292. tmpreg:=rg.makeregsize(regvars[i].reg,OS_INT);
  1293. rg.makeregvar(tmpreg);
  1294. end;
  1295. end;
  1296. oldinlining_procedure:=inlining_procedure;
  1297. oldexitlabel:=aktexitlabel;
  1298. oldexit2label:=aktexit2label;
  1299. oldquickexitlabel:=quickexitlabel;
  1300. getlabel(aktexitlabel);
  1301. getlabel(aktexit2label);
  1302. { we're inlining a procedure }
  1303. inlining_procedure:=true;
  1304. { save old procinfo }
  1305. oldprocdef:=aktprocdef;
  1306. getmem(oldprocinfo,sizeof(tprocinfo));
  1307. move(procinfo^,oldprocinfo^,sizeof(tprocinfo));
  1308. { set new procinfo }
  1309. aktprocdef:=inlineprocdef;
  1310. procinfo^.return_offset:=retoffset;
  1311. procinfo^.para_offset:=para_offset;
  1312. procinfo^.no_fast_exit:=false;
  1313. { arg space has been filled by the parent secondcall }
  1314. st:=aktprocdef.localst;
  1315. { set it to the same lexical level }
  1316. st.symtablelevel:=oldprocdef.localst.symtablelevel;
  1317. if st.datasize>0 then
  1318. begin
  1319. st.address_fixup:=tg.gettempofsizepersistant(exprasmlist,st.datasize)+st.datasize;
  1320. {$ifdef extdebug}
  1321. Comment(V_debug,'local symtable is at offset '+tostr(st.address_fixup));
  1322. exprasmList.concat(Tai_asm_comment.Create(strpnew(
  1323. 'local symtable is at offset '+tostr(st.address_fixup))));
  1324. {$endif extdebug}
  1325. end;
  1326. exprasmList.concat(Tai_Marker.Create(InlineStart));
  1327. {$ifdef extdebug}
  1328. exprasmList.concat(Tai_asm_comment.Create(strpnew('Start of inlined proc')));
  1329. {$endif extdebug}
  1330. {$ifdef GDB}
  1331. if (cs_debuginfo in aktmoduleswitches) then
  1332. begin
  1333. getaddrlabel(startlabel);
  1334. getaddrlabel(endlabel);
  1335. cg.a_label(exprasmlist,startlabel);
  1336. inlineprocdef.localst.symtabletype:=inlinelocalsymtable;
  1337. inlineprocdef.parast.symtabletype:=inlineparasymtable;
  1338. { Here we must include the para and local symtable info }
  1339. inlineprocdef.concatstabto(withdebuglist);
  1340. { set it back for safety }
  1341. inlineprocdef.localst.symtabletype:=localsymtable;
  1342. inlineprocdef.parast.symtabletype:=parasymtable;
  1343. mangled_length:=length(oldprocdef.mangledname);
  1344. getmem(pp,mangled_length+50);
  1345. strpcopy(pp,'192,0,0,'+startlabel.name);
  1346. if (target_info.use_function_relative_addresses) then
  1347. begin
  1348. strpcopy(strend(pp),'-');
  1349. strpcopy(strend(pp),oldprocdef.mangledname);
  1350. end;
  1351. withdebugList.concat(Tai_stabn.Create(strnew(pp)));
  1352. end;
  1353. {$endif GDB}
  1354. { takes care of local data initialization }
  1355. inlineentrycode:=TAAsmoutput.Create;
  1356. inlineexitcode:=TAAsmoutput.Create;
  1357. ps:=para_size;
  1358. make_global:=false; { to avoid warning }
  1359. genentrycode(inlineentrycode,make_global,0,ps,nostackframe,true);
  1360. if po_assembler in aktprocdef.procoptions then
  1361. inlineentrycode.insert(Tai_marker.Create(asmblockstart));
  1362. exprasmList.concatlist(inlineentrycode);
  1363. secondpass(inlinetree);
  1364. genexitcode(inlineexitcode,0,false,true);
  1365. if po_assembler in aktprocdef.procoptions then
  1366. inlineexitcode.concat(Tai_marker.Create(asmblockend));
  1367. exprasmList.concatlist(inlineexitcode);
  1368. inlineentrycode.free;
  1369. inlineexitcode.free;
  1370. {$ifdef extdebug}
  1371. exprasmList.concat(Tai_asm_comment.Create(strpnew('End of inlined proc')));
  1372. {$endif extdebug}
  1373. exprasmList.concat(Tai_Marker.Create(InlineEnd));
  1374. {we can free the local data now, reset also the fixup address }
  1375. if st.datasize>0 then
  1376. begin
  1377. tg.ungetpersistanttemp(exprasmlist,st.address_fixup-st.datasize);
  1378. st.address_fixup:=0;
  1379. end;
  1380. { restore procinfo }
  1381. move(oldprocinfo^,procinfo^,sizeof(tprocinfo));
  1382. freemem(oldprocinfo,sizeof(tprocinfo));
  1383. {$ifdef GDB}
  1384. if (cs_debuginfo in aktmoduleswitches) then
  1385. begin
  1386. cg.a_label(exprasmlist,endlabel);
  1387. strpcopy(pp,'224,0,0,'+endlabel.name);
  1388. if (target_info.use_function_relative_addresses) then
  1389. begin
  1390. strpcopy(strend(pp),'-');
  1391. strpcopy(strend(pp),oldprocdef.mangledname);
  1392. end;
  1393. withdebugList.concat(Tai_stabn.Create(strnew(pp)));
  1394. freemem(pp,mangled_length+50);
  1395. end;
  1396. {$endif GDB}
  1397. { restore }
  1398. aktprocdef:=oldprocdef;
  1399. aktexitlabel:=oldexitlabel;
  1400. aktexit2label:=oldexit2label;
  1401. quickexitlabel:=oldquickexitlabel;
  1402. inlining_procedure:=oldinlining_procedure;
  1403. { reallocate the registers used for the current procedure's regvars, }
  1404. { since they may have been used and then deallocated in the inlined }
  1405. { procedure (JM) }
  1406. if assigned(aktprocdef.regvarinfo) then
  1407. begin
  1408. rg.restoreStateAfterInline(oldregstate);
  1409. end;
  1410. end;
  1411. begin
  1412. ccallparanode:=tcgcallparanode;
  1413. ccallnode:=tcgcallnode;
  1414. cprocinlinenode:=tcgprocinlinenode;
  1415. end.
  1416. {
  1417. $Log$
  1418. Revision 1.4 2002-08-06 20:55:20 florian
  1419. * first part of ppc calling conventions fix
  1420. Revision 1.3 2002/07/20 11:57:53 florian
  1421. * types.pas renamed to defbase.pas because D6 contains a types
  1422. unit so this would conflicts if D6 programms are compiled
  1423. + Willamette/SSE2 instructions to assembler added
  1424. Revision 1.2 2002/07/13 19:38:43 florian
  1425. * some more generic calling stuff fixed
  1426. Revision 1.1 2002/07/11 14:41:28 florian
  1427. * start of the new generic parameter handling
  1428. }