ncgcal.pas 72 KB

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