ncgcal.pas 71 KB

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