ncgcal.pas 69 KB

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