ncgcal.pas 71 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543
  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,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. objectlibrary.getlabel(truelabel);
  91. objectlibrary.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. objectlibrary.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,objectlibrary.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,objectlibrary.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,objectlibrary.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,objectlibrary.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,objectlibrary.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,objectlibrary.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. {$ifdef i386}
  1029. (aktoptprocessor=ClassP5) and
  1030. {$endif}
  1031. (procinfo^._class=nil) then
  1032. begin
  1033. rg.getexplicitregisterint(exprasmlist,R_EDI);
  1034. emit_reg(A_POP,S_L,R_EDI);
  1035. rg.ungetregisterint(exprasmlist,R_EDI);
  1036. exprasmList.concat(tai_regalloc.Alloc(R_ESI));
  1037. emit_reg(A_POP,S_L,R_ESI);
  1038. exprasmList.concat(tai_regalloc.DeAlloc(R_ESI));
  1039. end
  1040. else if pushedparasize<>0 then
  1041. emit_const_reg(A_ADD,S_L,pushedparasize,R_ESP);
  1042. end;
  1043. {$endif dummy}
  1044. if procinfo^.maxpushedparasize<pushedparasize then
  1045. procinfo^.maxpushedparasize:=pushedparasize;
  1046. {$ifdef OPTALIGN}
  1047. if pop_esp then
  1048. emit_reg(A_POP,S_L,R_ESP);
  1049. {$endif OPTALIGN}
  1050. dont_call:
  1051. pushedparasize:=oldpushedparasize;
  1052. rg.restoreunusedstate(unusedstate);
  1053. {$ifdef TEMPREGDEBUG}
  1054. testregisters32;
  1055. {$endif TEMPREGDEBUG}
  1056. { a constructor could be a function with boolean result }
  1057. { if calling constructor called fail we
  1058. must jump directly to quickexitlabel PM
  1059. but only if it is a call of an inherited constructor }
  1060. if (inlined or
  1061. (right=nil)) and
  1062. (procdefinition.proctypeoption=potype_constructor) and
  1063. assigned(methodpointer) and
  1064. (methodpointer.nodetype=typen) and
  1065. (aktprocdef.proctypeoption=potype_constructor) then
  1066. begin
  1067. cg.a_cmp_const_reg_label(exprasmlist,OS_ADDR,OC_EQ,0,accumulator,faillabel);
  1068. end;
  1069. { call to AfterConstruction? }
  1070. if is_class(resulttype.def) and
  1071. (inlined or
  1072. (right=nil)) and
  1073. (procdefinition.proctypeoption=potype_constructor) and
  1074. assigned(methodpointer) and
  1075. (methodpointer.nodetype<>typen) then
  1076. begin
  1077. objectlibrary.getlabel(constructorfailed);
  1078. cg.a_cmp_const_reg_label(exprasmlist,OS_ADDR,OC_EQ,0,self_pointer_reg,constructorfailed);
  1079. cg.a_param_reg(exprasmlist,OS_ADDR,accumulator,paramanager.getintparaloc(1));
  1080. reference_reset_base(href,self_pointer_reg,0);
  1081. tmpreg:=cg.get_scratch_reg_address(exprasmlist);
  1082. cg.a_load_ref_reg(exprasmlist,OS_ADDR,href,tmpreg);
  1083. reference_reset_base(href,tmpreg,17*pointer_size);
  1084. cg.a_call_ref(exprasmlist,href);
  1085. cg.free_scratch_reg(exprasmlist,tmpreg);
  1086. exprasmList.concat(tai_regalloc.Alloc(accumulator));
  1087. cg.a_label(exprasmlist,constructorfailed);
  1088. cg.a_load_reg_reg(exprasmlist,OS_ADDR,self_pointer_reg,accumulator);
  1089. end;
  1090. { handle function results }
  1091. if (not is_void(resulttype.def)) then
  1092. begin
  1093. { structured results are easy to handle.... }
  1094. { needed also when result_no_used !! }
  1095. if paramanager.ret_in_param(resulttype.def) then
  1096. begin
  1097. location_reset(location,LOC_CREFERENCE,def_cgsize(resulttype.def));
  1098. location.reference.symbol:=nil;
  1099. location.reference:=funcretref;
  1100. end
  1101. else
  1102. { ansi/widestrings must be registered, so we can dispose them }
  1103. if is_ansistring(resulttype.def) or
  1104. is_widestring(resulttype.def) then
  1105. begin
  1106. location_reset(location,LOC_CREFERENCE,OS_ADDR);
  1107. location.reference:=refcountedtemp;
  1108. cg.a_reg_alloc(exprasmlist,accumulator);
  1109. cg.a_load_reg_ref(exprasmlist,OS_ADDR,accumulator,location.reference);
  1110. cg.a_reg_dealloc(exprasmlist,accumulator);
  1111. end
  1112. else
  1113. { we have only to handle the result if it is used }
  1114. if (nf_return_value_used in flags) then
  1115. begin
  1116. case resulttype.def.deftype of
  1117. enumdef,
  1118. orddef :
  1119. begin
  1120. cgsize:=def_cgsize(resulttype.def);
  1121. { an object constructor is a function with boolean result }
  1122. if (inlined or (right=nil)) and
  1123. (procdefinition.proctypeoption=potype_constructor) then
  1124. begin
  1125. if extended_new then
  1126. cgsize:=OS_INT
  1127. else
  1128. begin
  1129. {$ifdef dummy}
  1130. cgsize:=OS_NO;
  1131. { this fails if popsize > 0 PM }
  1132. location_reset(location,LOC_FLAGS,OS_NO);
  1133. location.resflags:=F_NE;
  1134. {$endif dummy}
  1135. end;
  1136. end;
  1137. if cgsize<>OS_NO then
  1138. begin
  1139. location_reset(location,LOC_REGISTER,cgsize);
  1140. cg.a_reg_alloc(exprasmlist,accumulator);
  1141. if cgsize in [OS_64,OS_S64] then
  1142. begin
  1143. cg.a_reg_alloc(exprasmlist,accumulatorhigh);
  1144. if accumulatorhigh in rg.unusedregsint then
  1145. begin
  1146. location.registerhigh:=rg.getexplicitregisterint(exprasmlist,accumulatorhigh);
  1147. location.registerlow:=rg.getexplicitregisterint(exprasmlist,accumulator);
  1148. end
  1149. else
  1150. begin
  1151. location.registerhigh:=rg.getexplicitregisterint(exprasmlist,accumulatorhigh);
  1152. location.registerlow:=rg.getexplicitregisterint(exprasmlist,accumulator);
  1153. end;
  1154. cg64.a_load64_reg_reg(exprasmlist,joinreg64(accumulator,accumulatorhigh),
  1155. location.register64);
  1156. end
  1157. else
  1158. begin
  1159. location.register:=rg.getexplicitregisterint(exprasmlist,accumulator);
  1160. hregister:=rg.makeregsize(accumulator,cgsize);
  1161. location.register:=rg.makeregsize(location.register,cgsize);
  1162. cg.a_load_reg_reg(exprasmlist,cgsize,hregister,location.register);
  1163. end;
  1164. end;
  1165. end;
  1166. floatdef :
  1167. begin
  1168. {$ifdef dummy}
  1169. location_reset(location,LOC_FPUREGISTER,def_cgsize(resulttype.def));
  1170. location.register:=R_ST;
  1171. inc(trgcpu(rg).fpuvaroffset);
  1172. {$endif dummy}
  1173. end;
  1174. else
  1175. begin
  1176. location_reset(location,LOC_REGISTER,OS_INT);
  1177. location.register:=rg.getexplicitregisterint(exprasmlist,accumulator);
  1178. cg.a_load_reg_reg(exprasmlist,OS_INT,accumulator,location.register);
  1179. end;
  1180. end;
  1181. end;
  1182. end;
  1183. { perhaps i/o check ? }
  1184. if iolabel<>nil then
  1185. begin
  1186. reference_reset_symbol(href,iolabel,0);
  1187. cg.a_paramaddr_ref(exprasmlist,href,paramanager.getintparaloc(1));
  1188. cg.a_call_name(exprasmlist,'FPC_IOCHECK');
  1189. end;
  1190. {$ifdef i386}
  1191. if pop_size>0 then
  1192. emit_const_reg(A_ADD,S_L,pop_size,R_ESP);
  1193. {$endif i386}
  1194. { restore registers }
  1195. rg.restoreusedregisters(exprasmlist,pushed);
  1196. { at last, restore instance pointer (SELF) }
  1197. if loadesi then
  1198. cg.g_maybe_loadself(exprasmlist);
  1199. pp:=tbinarynode(params);
  1200. while assigned(pp) do
  1201. begin
  1202. if assigned(pp.left) then
  1203. begin
  1204. location_freetemp(exprasmlist,pp.left.location);
  1205. { process also all nodes of an array of const }
  1206. if pp.left.nodetype=arrayconstructorn then
  1207. begin
  1208. if assigned(tarrayconstructornode(pp.left).left) then
  1209. begin
  1210. hp:=pp.left;
  1211. while assigned(hp) do
  1212. begin
  1213. location_freetemp(exprasmlist,tarrayconstructornode(hp).left.location);
  1214. hp:=tarrayconstructornode(hp).right;
  1215. end;
  1216. end;
  1217. end;
  1218. end;
  1219. pp:=tbinarynode(pp.right);
  1220. end;
  1221. if inlined then
  1222. begin
  1223. tg.ungetpersistanttemp(exprasmlist,inlinecode.retoffset);
  1224. tprocdef(procdefinition).parast.address_fixup:=store_parast_fixup;
  1225. right:=inlinecode;
  1226. end;
  1227. if assigned(params) then
  1228. params.free;
  1229. { from now on the result can be freed normally }
  1230. if inlined and paramanager.ret_in_param(resulttype.def) then
  1231. tg.persistanttemptonormal(funcretref.offset);
  1232. { if return value is not used }
  1233. if (not(nf_return_value_used in flags)) and (not is_void(resulttype.def)) then
  1234. begin
  1235. if location.loc in [LOC_CREFERENCE,LOC_REFERENCE] then
  1236. begin
  1237. { data which must be finalized ? }
  1238. if (resulttype.def.needs_inittable) then
  1239. cg.g_finalize(exprasmlist,resulttype.def,location.reference,false);
  1240. { release unused temp }
  1241. tg.ungetiftemp(exprasmlist,location.reference)
  1242. end
  1243. else if location.loc=LOC_FPUREGISTER then
  1244. begin
  1245. {$ifdef i386}
  1246. { release FPU stack }
  1247. emit_reg(A_FSTP,S_NO,R_ST);
  1248. {
  1249. dec(trgcpu(rg).fpuvaroffset);
  1250. do NOT decrement as the increment before
  1251. is not called for unused results PM }
  1252. {$endif i386}
  1253. end;
  1254. end;
  1255. end;
  1256. {*****************************************************************************
  1257. TCGPROCINLINENODE
  1258. *****************************************************************************}
  1259. procedure tcgprocinlinenode.pass_2;
  1260. var st : tsymtable;
  1261. oldprocdef : tprocdef;
  1262. ps, i : longint;
  1263. tmpreg: tregister;
  1264. oldprocinfo : pprocinfo;
  1265. oldinlining_procedure,
  1266. nostackframe,make_global : boolean;
  1267. inlineentrycode,inlineexitcode : TAAsmoutput;
  1268. oldexitlabel,oldexit2label,oldquickexitlabel:tasmlabel;
  1269. oldregstate: pointer;
  1270. {$ifdef GDB}
  1271. startlabel,endlabel : tasmlabel;
  1272. pp : pchar;
  1273. mangled_length : longint;
  1274. {$endif GDB}
  1275. begin
  1276. { deallocate the registers used for the current procedure's regvars }
  1277. if assigned(aktprocdef.regvarinfo) then
  1278. begin
  1279. with pregvarinfo(aktprocdef.regvarinfo)^ do
  1280. for i := 1 to maxvarregs do
  1281. if assigned(regvars[i]) then
  1282. store_regvar(exprasmlist,regvars[i].reg);
  1283. rg.saveStateForInline(oldregstate);
  1284. { make sure the register allocator knows what the regvars in the }
  1285. { inlined code block are (JM) }
  1286. rg.resetusableregisters;
  1287. rg.clearregistercount;
  1288. rg.cleartempgen;
  1289. if assigned(inlineprocdef.regvarinfo) then
  1290. with pregvarinfo(inlineprocdef.regvarinfo)^ do
  1291. for i := 1 to maxvarregs do
  1292. if assigned(regvars[i]) then
  1293. begin
  1294. tmpreg:=rg.makeregsize(regvars[i].reg,OS_INT);
  1295. rg.makeregvar(tmpreg);
  1296. end;
  1297. end;
  1298. oldinlining_procedure:=inlining_procedure;
  1299. oldexitlabel:=aktexitlabel;
  1300. oldexit2label:=aktexit2label;
  1301. oldquickexitlabel:=quickexitlabel;
  1302. objectlibrary.getlabel(aktexitlabel);
  1303. objectlibrary.getlabel(aktexit2label);
  1304. { we're inlining a procedure }
  1305. inlining_procedure:=true;
  1306. { save old procinfo }
  1307. oldprocdef:=aktprocdef;
  1308. getmem(oldprocinfo,sizeof(tprocinfo));
  1309. move(procinfo^,oldprocinfo^,sizeof(tprocinfo));
  1310. { set new procinfo }
  1311. aktprocdef:=inlineprocdef;
  1312. procinfo^.return_offset:=retoffset;
  1313. procinfo^.para_offset:=para_offset;
  1314. procinfo^.no_fast_exit:=false;
  1315. { arg space has been filled by the parent secondcall }
  1316. st:=aktprocdef.localst;
  1317. { set it to the same lexical level }
  1318. st.symtablelevel:=oldprocdef.localst.symtablelevel;
  1319. if st.datasize>0 then
  1320. begin
  1321. st.address_fixup:=tg.gettempofsizepersistant(exprasmlist,st.datasize)+st.datasize;
  1322. {$ifdef extdebug}
  1323. Comment(V_debug,'local symtable is at offset '+tostr(st.address_fixup));
  1324. exprasmList.concat(Tai_asm_comment.Create(strpnew(
  1325. 'local symtable is at offset '+tostr(st.address_fixup))));
  1326. {$endif extdebug}
  1327. end;
  1328. exprasmList.concat(Tai_Marker.Create(InlineStart));
  1329. {$ifdef extdebug}
  1330. exprasmList.concat(Tai_asm_comment.Create(strpnew('Start of inlined proc')));
  1331. {$endif extdebug}
  1332. {$ifdef GDB}
  1333. if (cs_debuginfo in aktmoduleswitches) then
  1334. begin
  1335. objectlibrary.getaddrlabel(startlabel);
  1336. objectlibrary.getaddrlabel(endlabel);
  1337. cg.a_label(exprasmlist,startlabel);
  1338. inlineprocdef.localst.symtabletype:=inlinelocalsymtable;
  1339. inlineprocdef.parast.symtabletype:=inlineparasymtable;
  1340. { Here we must include the para and local symtable info }
  1341. inlineprocdef.concatstabto(withdebuglist);
  1342. { set it back for safety }
  1343. inlineprocdef.localst.symtabletype:=localsymtable;
  1344. inlineprocdef.parast.symtabletype:=parasymtable;
  1345. mangled_length:=length(oldprocdef.mangledname);
  1346. getmem(pp,mangled_length+50);
  1347. strpcopy(pp,'192,0,0,'+startlabel.name);
  1348. if (target_info.use_function_relative_addresses) then
  1349. begin
  1350. strpcopy(strend(pp),'-');
  1351. strpcopy(strend(pp),oldprocdef.mangledname);
  1352. end;
  1353. withdebugList.concat(Tai_stabn.Create(strnew(pp)));
  1354. end;
  1355. {$endif GDB}
  1356. { takes care of local data initialization }
  1357. inlineentrycode:=TAAsmoutput.Create;
  1358. inlineexitcode:=TAAsmoutput.Create;
  1359. ps:=para_size;
  1360. make_global:=false; { to avoid warning }
  1361. genentrycode(inlineentrycode,make_global,0,ps,nostackframe,true);
  1362. if po_assembler in aktprocdef.procoptions then
  1363. inlineentrycode.insert(Tai_marker.Create(asmblockstart));
  1364. exprasmList.concatlist(inlineentrycode);
  1365. secondpass(inlinetree);
  1366. genexitcode(inlineexitcode,0,false,true);
  1367. if po_assembler in aktprocdef.procoptions then
  1368. inlineexitcode.concat(Tai_marker.Create(asmblockend));
  1369. exprasmList.concatlist(inlineexitcode);
  1370. inlineentrycode.free;
  1371. inlineexitcode.free;
  1372. {$ifdef extdebug}
  1373. exprasmList.concat(Tai_asm_comment.Create(strpnew('End of inlined proc')));
  1374. {$endif extdebug}
  1375. exprasmList.concat(Tai_Marker.Create(InlineEnd));
  1376. {we can free the local data now, reset also the fixup address }
  1377. if st.datasize>0 then
  1378. begin
  1379. tg.ungetpersistanttemp(exprasmlist,st.address_fixup-st.datasize);
  1380. st.address_fixup:=0;
  1381. end;
  1382. { restore procinfo }
  1383. move(oldprocinfo^,procinfo^,sizeof(tprocinfo));
  1384. freemem(oldprocinfo,sizeof(tprocinfo));
  1385. {$ifdef GDB}
  1386. if (cs_debuginfo in aktmoduleswitches) then
  1387. begin
  1388. cg.a_label(exprasmlist,endlabel);
  1389. strpcopy(pp,'224,0,0,'+endlabel.name);
  1390. if (target_info.use_function_relative_addresses) then
  1391. begin
  1392. strpcopy(strend(pp),'-');
  1393. strpcopy(strend(pp),oldprocdef.mangledname);
  1394. end;
  1395. withdebugList.concat(Tai_stabn.Create(strnew(pp)));
  1396. freemem(pp,mangled_length+50);
  1397. end;
  1398. {$endif GDB}
  1399. { restore }
  1400. aktprocdef:=oldprocdef;
  1401. aktexitlabel:=oldexitlabel;
  1402. aktexit2label:=oldexit2label;
  1403. quickexitlabel:=oldquickexitlabel;
  1404. inlining_procedure:=oldinlining_procedure;
  1405. { reallocate the registers used for the current procedure's regvars, }
  1406. { since they may have been used and then deallocated in the inlined }
  1407. { procedure (JM) }
  1408. if assigned(aktprocdef.regvarinfo) then
  1409. begin
  1410. rg.restoreStateAfterInline(oldregstate);
  1411. end;
  1412. end;
  1413. begin
  1414. ccallparanode:=tcgcallparanode;
  1415. ccallnode:=tcgcallnode;
  1416. cprocinlinenode:=tcgprocinlinenode;
  1417. end.
  1418. {
  1419. $Log$
  1420. Revision 1.8 2002-08-13 18:01:51 carl
  1421. * rename swatoperands to swapoperands
  1422. + m68k first compilable version (still needs a lot of testing):
  1423. assembler generator, system information , inline
  1424. assembler reader.
  1425. Revision 1.7 2002/08/12 15:08:39 carl
  1426. + stab register indexes for powerpc (moved from gdb to cpubase)
  1427. + tprocessor enumeration moved to cpuinfo
  1428. + linker in target_info is now a class
  1429. * many many updates for m68k (will soon start to compile)
  1430. - removed some ifdef or correct them for correct cpu
  1431. Revision 1.6 2002/08/11 14:32:26 peter
  1432. * renamed current_library to objectlibrary
  1433. Revision 1.5 2002/08/11 13:24:11 peter
  1434. * saving of asmsymbols in ppu supported
  1435. * asmsymbollist global is removed and moved into a new class
  1436. tasmlibrarydata that will hold the info of a .a file which
  1437. corresponds with a single module. Added librarydata to tmodule
  1438. to keep the library info stored for the module. In the future the
  1439. objectfiles will also be stored to the tasmlibrarydata class
  1440. * all getlabel/newasmsymbol and friends are moved to the new class
  1441. Revision 1.4 2002/08/06 20:55:20 florian
  1442. * first part of ppc calling conventions fix
  1443. Revision 1.3 2002/07/20 11:57:53 florian
  1444. * types.pas renamed to defbase.pas because D6 contains a types
  1445. unit so this would conflicts if D6 programms are compiled
  1446. + Willamette/SSE2 instructions to assembler added
  1447. Revision 1.2 2002/07/13 19:38:43 florian
  1448. * some more generic calling stuff fixed
  1449. Revision 1.1 2002/07/11 14:41:28 florian
  1450. * start of the new generic parameter handling
  1451. }