ncgcal.pas 72 KB

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