ncgcal.pas 69 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698
  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. cpubase,
  24. globtype,
  25. symdef,node,ncal;
  26. type
  27. tcgcallparanode = class(tcallparanode)
  28. procedure secondcallparan(push_from_left_to_right:boolean;calloption:tproccalloption;
  29. para_alignment,para_offset : longint);override;
  30. end;
  31. tcgcallnode = class(tcallnode)
  32. private
  33. function push_self_and_vmt(needvmtreg:boolean):tregister;
  34. protected
  35. // funcretref : treference;
  36. refcountedtemp : treference;
  37. procedure handle_return_value(inlined:boolean);
  38. {# This routine is used to push the current frame pointer
  39. on the stack. This is used in nested routines where the
  40. value of the frame pointer is always pushed as an extra
  41. parameter.
  42. The default handling is the standard handling used on
  43. most stack based machines, where the frame pointer is
  44. the first invisible parameter.
  45. }
  46. function align_parasize(parasize,para_alignment:longint):longint;virtual;
  47. procedure pop_parasize(pop_size:longint);virtual;
  48. procedure push_framepointer;virtual;
  49. procedure extra_interrupt_code;virtual;
  50. public
  51. procedure pass_2;override;
  52. end;
  53. tcgprocinlinenode = class(tprocinlinenode)
  54. procedure pass_2;override;
  55. end;
  56. implementation
  57. uses
  58. systems,
  59. cutils,verbose,globals,
  60. symconst,symbase,symsym,symtable,defutil,paramgr,
  61. {$ifdef GDB}
  62. {$ifdef delphi}
  63. sysutils,
  64. {$else}
  65. strings,
  66. {$endif}
  67. gdb,
  68. {$endif GDB}
  69. cginfo,cgbase,pass_2,
  70. cpuinfo,cpupi,aasmbase,aasmtai,aasmcpu,
  71. nbas,nmem,nld,ncnv,
  72. {$ifdef x86}
  73. cga,
  74. {$endif x86}
  75. {$ifdef cpu64bit}
  76. cg64f64,
  77. {$else cpu64bit}
  78. cg64f32,
  79. {$endif cpu64bit}
  80. ncgutil,cgobj,tgobj,regvars,rgobj,rgcpu,cgcpu;
  81. var
  82. { Current callnode, this is needed for having a link
  83. between the callparanodes and the callnode they belong to }
  84. aktcallnode : tcallnode;
  85. {*****************************************************************************
  86. TCGCALLPARANODE
  87. *****************************************************************************}
  88. procedure tcgcallparanode.secondcallparan(push_from_left_to_right:boolean;calloption:tproccalloption;para_alignment,para_offset : longint);
  89. var
  90. otlabel,
  91. oflabel : tasmlabel;
  92. tmpreg : tregister;
  93. href : treference;
  94. varspez : tvarspez;
  95. begin
  96. if not(assigned(paraitem.paratype.def) or
  97. assigned(paraitem.parasym)) then
  98. internalerror(200304242);
  99. { set default para_alignment to target_info.stackalignment }
  100. if para_alignment=0 then
  101. para_alignment:=aktalignment.paraalign;
  102. { push from left to right if specified }
  103. if push_from_left_to_right and assigned(right) then
  104. begin
  105. if (nf_varargs_para in flags) then
  106. tcallparanode(right).secondcallparan(push_from_left_to_right,
  107. calloption,para_alignment,para_offset)
  108. else
  109. tcallparanode(right).secondcallparan(push_from_left_to_right,
  110. calloption,para_alignment,para_offset);
  111. end;
  112. otlabel:=truelabel;
  113. oflabel:=falselabel;
  114. objectlibrary.getlabel(truelabel);
  115. objectlibrary.getlabel(falselabel);
  116. secondpass(left);
  117. { retrieve the type of parameter, for hidden parameters
  118. the value is stored in the parasym }
  119. varspez:=paraitem.paratyp;
  120. if varspez=vs_hidden then
  121. varspez:=tvarsym(paraitem.parasym).varspez;
  122. { handle varargs first, because defcoll is not valid }
  123. if (nf_varargs_para in flags) then
  124. begin
  125. if paramanager.push_addr_param(left.resulttype.def,calloption) then
  126. begin
  127. inc(pushedparasize,POINTER_SIZE);
  128. cg.a_paramaddr_ref(exprasmlist,left.location.reference,paraitem.paraloc);
  129. location_release(exprasmlist,left.location);
  130. end
  131. else
  132. push_value_para(exprasmlist,left,calloption,para_offset,para_alignment,paraitem.paraloc);
  133. end
  134. { filter array of const c styled args }
  135. else if is_array_of_const(left.resulttype.def) and (nf_cargs in left.flags) then
  136. begin
  137. { nothing, everything is already pushed }
  138. end
  139. { in codegen.handleread.. paraitem.data is set to nil }
  140. else if assigned(paraitem.paratype.def) and
  141. (paraitem.paratype.def.deftype=formaldef) then
  142. begin
  143. { allow passing of a constant to a const formaldef }
  144. if (varspez=vs_const) and
  145. (left.location.loc=LOC_CONSTANT) then
  146. location_force_mem(exprasmlist,left.location);
  147. { allow @var }
  148. inc(pushedparasize,POINTER_SIZE);
  149. if (left.nodetype=addrn) and
  150. (not(nf_procvarload in left.flags)) then
  151. begin
  152. if calloption=pocall_inline then
  153. begin
  154. reference_reset_base(href,current_procinfo.framepointer,para_offset-pushedparasize);
  155. cg.a_load_loc_ref(exprasmlist,left.location,href);
  156. end
  157. else
  158. cg.a_param_loc(exprasmlist,left.location,paraitem.paraloc);
  159. location_release(exprasmlist,left.location);
  160. end
  161. else
  162. begin
  163. if not(left.location.loc in [LOC_CREFERENCE,LOC_REFERENCE]) then
  164. internalerror(200304235);
  165. if calloption=pocall_inline then
  166. begin
  167. {$ifdef newra}
  168. tmpreg:=rg.getaddressregister(exprasmlist);
  169. {$else}
  170. tmpreg:=cg.get_scratch_reg_address(exprasmlist);
  171. {$endif newra}
  172. cg.a_loadaddr_ref_reg(exprasmlist,left.location.reference,tmpreg);
  173. reference_reset_base(href,current_procinfo.framepointer,para_offset-pushedparasize);
  174. cg.a_load_reg_ref(exprasmlist,OS_ADDR,tmpreg,href);
  175. {$ifdef newra}
  176. rg.ungetregisterint(exprasmlist,tmpreg);
  177. {$else}
  178. cg.free_scratch_reg(exprasmlist,tmpreg);
  179. {$endif}
  180. end
  181. else
  182. cg.a_paramaddr_ref(exprasmlist,left.location.reference,paraitem.paraloc);
  183. location_release(exprasmlist,left.location);
  184. end;
  185. end
  186. { handle call by reference parameter }
  187. else if (varspez in [vs_var,vs_out]) then
  188. begin
  189. if (left.location.loc<>LOC_REFERENCE) then
  190. begin
  191. { passing self to a var parameter is allowed in
  192. TP and delphi }
  193. if not((left.location.loc=LOC_CREFERENCE) and
  194. (left.nodetype=selfn)) then
  195. internalerror(200106041);
  196. end;
  197. if (varspez=vs_out) and
  198. assigned(paraitem.paratype.def) and
  199. not is_class(paraitem.paratype.def) and
  200. paraitem.paratype.def.needs_inittable then
  201. cg.g_finalize(exprasmlist,paraitem.paratype.def,left.location.reference,false);
  202. inc(pushedparasize,POINTER_SIZE);
  203. if calloption=pocall_inline then
  204. begin
  205. {$ifdef newra}
  206. tmpreg:=rg.getaddressregister(exprasmlist);
  207. {$else}
  208. tmpreg:=cg.get_scratch_reg_address(exprasmlist);
  209. {$endif}
  210. cg.a_loadaddr_ref_reg(exprasmlist,left.location.reference,tmpreg);
  211. reference_reset_base(href,current_procinfo.framepointer,para_offset-pushedparasize);
  212. cg.a_load_reg_ref(exprasmlist,OS_ADDR,tmpreg,href);
  213. {$ifdef newra}
  214. rg.ungetregisterint(exprasmlist,tmpreg);
  215. {$else}
  216. cg.free_scratch_reg(exprasmlist,tmpreg);
  217. {$endif}
  218. end
  219. else
  220. cg.a_paramaddr_ref(exprasmlist,left.location.reference,paraitem.paraloc);
  221. location_release(exprasmlist,left.location);
  222. end
  223. else
  224. begin
  225. { open array must always push the address, this is needed to
  226. also push addr of small open arrays and with cdecl functions (PFV) }
  227. if (
  228. assigned(paraitem.paratype.def) and
  229. (is_open_array(paraitem.paratype.def) or
  230. is_array_of_const(paraitem.paratype.def))
  231. ) or
  232. (
  233. paramanager.push_addr_param(resulttype.def,calloption)
  234. ) then
  235. begin
  236. if not(left.location.loc in [LOC_CREFERENCE,LOC_REFERENCE]) then
  237. begin
  238. { allow passing nil to a procvardef (methodpointer) }
  239. if (left.nodetype=typeconvn) and
  240. (left.resulttype.def.deftype=procvardef) and
  241. (ttypeconvnode(left).left.nodetype=niln) then
  242. begin
  243. tg.GetTemp(exprasmlist,tcgsize2size[left.location.size],tt_normal,href);
  244. if not (left.location.size in [OS_64,OS_S64]) then
  245. cg.a_load_loc_ref(exprasmlist,left.location,href)
  246. else
  247. cg64.a_load64_loc_ref(exprasmlist,left.location,href);
  248. location_reset(left.location,LOC_REFERENCE,left.location.size);
  249. left.location.reference:=href;
  250. end
  251. else
  252. internalerror(200204011);
  253. end;
  254. inc(pushedparasize,POINTER_SIZE);
  255. if calloption=pocall_inline then
  256. begin
  257. {$ifdef newra}
  258. tmpreg:=rg.getaddressregister(exprasmlist);
  259. {$else}
  260. tmpreg:=cg.get_scratch_reg_address(exprasmlist);
  261. {$endif}
  262. cg.a_loadaddr_ref_reg(exprasmlist,left.location.reference,tmpreg);
  263. reference_reset_base(href,current_procinfo.framepointer,para_offset-pushedparasize);
  264. cg.a_load_reg_ref(exprasmlist,OS_ADDR,tmpreg,href);
  265. {$ifdef newra}
  266. rg.ungetregisterint(exprasmlist,tmpreg);
  267. {$else}
  268. cg.free_scratch_reg(exprasmlist,tmpreg);
  269. {$endif}
  270. end
  271. else
  272. cg.a_paramaddr_ref(exprasmlist,left.location.reference,paraitem.paraloc);
  273. location_release(exprasmlist,left.location);
  274. end
  275. else
  276. begin
  277. push_value_para(exprasmlist,left,calloption,
  278. para_offset,para_alignment,paraitem.paraloc);
  279. end;
  280. end;
  281. truelabel:=otlabel;
  282. falselabel:=oflabel;
  283. { update return location in callnode when this is the function
  284. result }
  285. if (vo_is_funcret in tvarsym(paraitem.parasym).varoptions) then
  286. begin
  287. location_copy(aktcallnode.location,left.location);
  288. end;
  289. { push from right to left }
  290. if not push_from_left_to_right and assigned(right) then
  291. begin
  292. if (nf_varargs_para in flags) then
  293. tcallparanode(right).secondcallparan(push_from_left_to_right,
  294. calloption,para_alignment,para_offset)
  295. else
  296. tcallparanode(right).secondcallparan(push_from_left_to_right,
  297. calloption,para_alignment,para_offset);
  298. end;
  299. end;
  300. {*****************************************************************************
  301. TCGCALLNODE
  302. *****************************************************************************}
  303. procedure tcgcallnode.extra_interrupt_code;
  304. begin
  305. end;
  306. function tcgcallnode.align_parasize(parasize,para_alignment:longint):longint;
  307. begin
  308. result:=0;
  309. end;
  310. procedure tcgcallnode.pop_parasize(pop_size:longint);
  311. begin
  312. end;
  313. function tcgcallnode.push_self_and_vmt(needvmtreg:boolean):tregister;
  314. var
  315. href : treference;
  316. vmtloc,selfloc : tlocation;
  317. self_is_vmt,
  318. vmtrefaddr,
  319. selfrefaddr : boolean;
  320. procedure selfloc_to_register;
  321. var
  322. hregister : tregister;
  323. begin
  324. case selfloc.loc of
  325. LOC_REGISTER :
  326. hregister:=selfloc.register;
  327. LOC_CREFERENCE,
  328. LOC_REFERENCE :
  329. begin
  330. hregister:=rg.getaddressregister(exprasmlist);
  331. if selfrefaddr then
  332. begin
  333. cg.a_loadaddr_ref_reg(exprasmlist,selfloc.reference,hregister);
  334. selfrefaddr:=false;
  335. end
  336. else
  337. cg.a_load_ref_reg(exprasmlist,OS_ADDR,selfloc.reference,hregister);
  338. reference_release(exprasmlist,selfloc.reference);
  339. end;
  340. else
  341. internalerror(200303269);
  342. end;
  343. location_reset(selfloc,LOC_REGISTER,OS_ADDR);
  344. selfloc.register:=hregister;
  345. end;
  346. begin
  347. result.enum:=R_INTREGISTER;
  348. result.number:=NR_NO;
  349. location_reset(vmtloc,LOC_CONSTANT,OS_ADDR);
  350. location_reset(selfloc,LOC_CONSTANT,OS_ADDR);
  351. vmtrefaddr:=false;
  352. selfrefaddr:=false;
  353. self_is_vmt:=false;
  354. { generate fake methodpointer node for withsymtable }
  355. if (symtableproc.symtabletype=withsymtable) then
  356. begin
  357. methodpointer:=cnothingnode.create;
  358. methodpointer.resulttype:=twithnode(twithsymtable(symtableproc).withnode).left.resulttype;
  359. end;
  360. if assigned(methodpointer) then
  361. begin
  362. case methodpointer.nodetype of
  363. typen:
  364. begin
  365. if (sp_static in symtableprocentry.symoptions) then
  366. begin
  367. self_is_vmt:=true;
  368. if (oo_has_vmt in tobjectdef(methodpointer.resulttype.def).objectoptions) then
  369. begin
  370. location_reset(vmtloc,LOC_REFERENCE,OS_NO);
  371. reference_reset_symbol(vmtloc.reference,objectlibrary.newasmsymboldata(tobjectdef(methodpointer.resulttype.def).vmt_mangledname),0);
  372. vmtrefaddr:=true;
  373. end;
  374. end
  375. else
  376. begin
  377. { normal member call, load self. Not for classes
  378. when we call the constructor }
  379. if not(
  380. is_class(methodpointer.resulttype.def) and
  381. (procdefinition.proctypeoption=potype_constructor) and
  382. (current_procdef.proctypeoption<>potype_constructor)
  383. ) then
  384. begin
  385. location_reset(selfloc,LOC_REGISTER,OS_ADDR);
  386. selfloc.register:=cg.g_load_self(exprasmlist);
  387. end;
  388. end;
  389. if (procdefinition.proctypeoption in [potype_constructor,potype_destructor]) then
  390. begin
  391. if is_object(methodpointer.resulttype.def) then
  392. begin
  393. { reset self when calling constructor from destructor }
  394. if (procdefinition.proctypeoption=potype_constructor) and
  395. assigned(current_procdef) and
  396. (current_procdef.proctypeoption=potype_destructor) then
  397. begin
  398. location_release(exprasmlist,selfloc);
  399. location_reset(selfloc,LOC_CONSTANT,OS_ADDR);
  400. end;
  401. end;
  402. end;
  403. end;
  404. hnewn:
  405. begin
  406. { constructor with extended syntax called from new }
  407. { vmt }
  408. location_reset(vmtloc,LOC_REFERENCE,OS_ADDR);
  409. reference_reset_symbol(vmtloc.reference,objectlibrary.newasmsymboldata(tobjectdef(methodpointer.resulttype.def).vmt_mangledname),0);
  410. vmtrefaddr:=true;
  411. end;
  412. hdisposen:
  413. begin
  414. { destructor with extended syntax called from dispose }
  415. { hdisposen always deliver LOC_REFERENCE }
  416. secondpass(methodpointer);
  417. { vmt }
  418. location_reset(vmtloc,LOC_REFERENCE,OS_ADDR);
  419. reference_reset_symbol(vmtloc.reference,objectlibrary.newasmsymboldata(tobjectdef(methodpointer.resulttype.def).vmt_mangledname),0);
  420. vmtrefaddr:=true;
  421. { self, load in register first when it requires a virtual call }
  422. location_reset(selfloc,LOC_REFERENCE,OS_ADDR);
  423. selfloc.reference:=methodpointer.location.reference;
  424. selfrefaddr:=true;
  425. end;
  426. else
  427. begin
  428. { call to an instance member }
  429. if (symtableproc.symtabletype<>withsymtable) then
  430. begin
  431. secondpass(methodpointer);
  432. case methodpointer.location.loc of
  433. LOC_CREGISTER,
  434. LOC_REGISTER:
  435. begin
  436. location_reset(selfloc,LOC_REGISTER,OS_ADDR);
  437. selfloc.register:=methodpointer.location.register;
  438. end;
  439. LOC_CREFERENCE,
  440. LOC_REFERENCE :
  441. begin
  442. location_reset(selfloc,LOC_REFERENCE,OS_ADDR);
  443. selfloc.reference:=methodpointer.location.reference;
  444. if (methodpointer.resulttype.def.deftype<>classrefdef) and
  445. not(is_class_or_interface(methodpointer.resulttype.def)) then
  446. selfrefaddr:=true;
  447. end;
  448. else
  449. internalerror(200303212);
  450. end;
  451. end
  452. else
  453. begin
  454. location_reset(selfloc,LOC_REFERENCE,OS_ADDR);
  455. selfloc.reference:=twithnode(twithsymtable(symtableproc).withnode).withreference;
  456. if (nf_islocal in twithnode(twithsymtable(symtableproc).withnode).flags) and
  457. (twithsymtable(symtableproc).direct_with) and
  458. not(is_class_or_interface(twithnode(twithsymtable(symtableproc).withnode).left.resulttype.def)) then
  459. selfrefaddr:=true;
  460. end;
  461. if (po_staticmethod in procdefinition.procoptions) or
  462. (po_classmethod in procdefinition.procoptions) then
  463. begin
  464. self_is_vmt:=true;
  465. { classref are already loaded with VMT }
  466. if (methodpointer.resulttype.def.deftype=classrefdef) then
  467. location_copy(vmtloc,selfloc)
  468. else
  469. begin
  470. if (oo_has_vmt in tprocdef(procdefinition)._class.objectoptions) then
  471. begin
  472. { load VMT from passed self }
  473. selfloc_to_register;
  474. cg.g_maybe_testself(exprasmlist,selfloc.register);
  475. location_copy(vmtloc,selfloc);
  476. reference_reset_base(href,vmtloc.register,tprocdef(procdefinition)._class.vmt_offset);
  477. cg.a_load_ref_reg(exprasmlist,OS_ADDR,href,vmtloc.register);
  478. end;
  479. end;
  480. { reset self }
  481. location_reset(selfloc,LOC_CONSTANT,OS_ADDR);
  482. end;
  483. if (procdefinition.proctypeoption in [potype_constructor,potype_destructor]) then
  484. begin
  485. { constructor call via classreference => allocate memory }
  486. if (methodpointer.resulttype.def.deftype=classrefdef) then
  487. begin
  488. if (procdefinition.proctypeoption=potype_constructor) and
  489. is_class(tclassrefdef(methodpointer.resulttype.def).pointertype.def) then
  490. begin
  491. self_is_vmt:=true;
  492. { vmt load from provided methodpointer that
  493. was already loaded in selfloc }
  494. location_copy(vmtloc,selfloc);
  495. { reset self }
  496. location_reset(selfloc,LOC_CONSTANT,OS_ADDR);
  497. end;
  498. end
  499. else
  500. { class }
  501. if is_class(methodpointer.resulttype.def) then
  502. begin
  503. { destructor: release instance, flag(vmt)=1
  504. constructor: direct call, do nothing, leave vmt=0 }
  505. if (procdefinition.proctypeoption=potype_destructor) then
  506. begin
  507. { flag 1 for destructor: remove data }
  508. location_reset(vmtloc,LOC_CONSTANT,OS_ADDR);
  509. vmtloc.value:=1;
  510. end;
  511. end
  512. else
  513. { object }
  514. begin
  515. { destructor: direct call, no dispose, vmt=0
  516. constructor: initialize object, load vmt }
  517. if (procdefinition.proctypeoption=potype_constructor) then
  518. begin
  519. { vmt }
  520. location_reset(vmtloc,LOC_REFERENCE,OS_ADDR);
  521. reference_reset_symbol(vmtloc.reference,objectlibrary.newasmsymboldata(
  522. tobjectdef(methodpointer.resulttype.def).vmt_mangledname),0);
  523. vmtrefaddr:=true;
  524. end;
  525. end;
  526. end;
  527. end;
  528. end;
  529. end
  530. else
  531. { No methodpointer }
  532. begin
  533. if (po_staticmethod in procdefinition.procoptions) or
  534. (po_classmethod in procdefinition.procoptions) then
  535. begin
  536. self_is_vmt:=true;
  537. { Load VMT from self? }
  538. if (
  539. (po_classmethod in procdefinition.procoptions) and
  540. not(assigned(current_procdef) and
  541. (po_classmethod in current_procdef.procoptions))
  542. ) or
  543. (
  544. (po_staticmethod in procdefinition.procoptions) and
  545. not(assigned(current_procdef) and
  546. (po_staticmethod in current_procdef.procoptions))
  547. ) then
  548. begin
  549. if (oo_has_vmt in tprocdef(procdefinition)._class.objectoptions) then
  550. begin
  551. { load vmt from self passed to the current method }
  552. location_reset(vmtloc,LOC_REGISTER,OS_ADDR);
  553. vmtloc.register:=cg.g_load_self(exprasmlist);
  554. cg.g_maybe_testself(exprasmlist,vmtloc.register);
  555. reference_reset_base(href,vmtloc.register,tprocdef(procdefinition)._class.vmt_offset);
  556. cg.a_load_ref_reg(exprasmlist,OS_ADDR,href,vmtloc.register);
  557. end;
  558. end
  559. else
  560. begin
  561. { self is already VMT }
  562. location_reset(vmtloc,LOC_REGISTER,OS_ADDR);
  563. vmtloc.register:=cg.g_load_self(exprasmlist);
  564. end;
  565. end
  566. else
  567. begin
  568. { member call, load self }
  569. location_reset(selfloc,LOC_REGISTER,OS_ADDR);
  570. selfloc.register:=cg.g_load_self(exprasmlist);
  571. end;
  572. end;
  573. { Do we need to push the VMT as self for
  574. class methods and static methods? }
  575. if self_is_vmt then
  576. begin
  577. location_release(exprasmlist,selfloc);
  578. location_copy(selfloc,vmtloc);
  579. selfrefaddr:=vmtrefaddr;
  580. end;
  581. { when we need the vmt in a register then we already
  582. load self in a register so it can generate optimized code }
  583. if needvmtreg then
  584. selfloc_to_register;
  585. { constructor/destructor need vmt }
  586. if (procdefinition.proctypeoption in [potype_constructor,potype_destructor]) then
  587. begin
  588. if vmtrefaddr then
  589. cg.a_paramaddr_ref(exprasmlist,vmtloc.reference,paramanager.getintparaloc(2))
  590. else
  591. cg.a_param_loc(exprasmlist,vmtloc,paramanager.getintparaloc(2));
  592. end;
  593. if not self_is_vmt then
  594. location_release(exprasmlist,vmtloc);
  595. { push self }
  596. if selfrefaddr then
  597. cg.a_paramaddr_ref(exprasmlist,selfloc.reference,paramanager.getintparaloc(1))
  598. else
  599. cg.a_param_loc(exprasmlist,selfloc,paramanager.getintparaloc(1));
  600. if needvmtreg then
  601. begin
  602. { self should already be loaded in a register }
  603. if selfloc.register.number=NR_NO then
  604. internalerror(2003032611);
  605. { load vmt from self, this is already done
  606. for static/class methods }
  607. if not self_is_vmt then
  608. begin
  609. cg.g_maybe_testself(exprasmlist,selfloc.register);
  610. { this is one point where we need vmt_offset (PM) }
  611. reference_reset_base(href,selfloc.register,tprocdef(procdefinition)._class.vmt_offset);
  612. cg.a_load_ref_reg(exprasmlist,OS_ADDR,href,selfloc.register);
  613. end;
  614. result:=selfloc.register;
  615. end
  616. else
  617. location_release(exprasmlist,selfloc);
  618. end;
  619. procedure tcgcallnode.push_framepointer;
  620. var
  621. href : treference;
  622. hregister : tregister;
  623. i : integer;
  624. begin
  625. { this routine is itself not nested }
  626. if current_procdef.parast.symtablelevel=(tprocdef(procdefinition).parast.symtablelevel) then
  627. begin
  628. reference_reset_base(href,current_procinfo.framepointer,current_procinfo.framepointer_offset);
  629. cg.a_param_ref(exprasmlist,OS_ADDR,href,paramanager.getintparaloc(1));
  630. end
  631. { one nesting level }
  632. else if (current_procdef.parast.symtablelevel=(tprocdef(procdefinition).parast.symtablelevel)-1) then
  633. begin
  634. cg.a_param_reg(exprasmlist,OS_ADDR,current_procinfo.framepointer,paramanager.getintparaloc(1));
  635. end
  636. { very complex nesting level ... }
  637. else if (current_procdef.parast.symtablelevel>(tprocdef(procdefinition).parast.symtablelevel)) then
  638. begin
  639. hregister:=rg.getaddressregister(exprasmlist);
  640. reference_reset_base(href,current_procinfo.framepointer,current_procinfo.framepointer_offset);
  641. cg.a_load_ref_reg(exprasmlist,OS_ADDR,href,hregister);
  642. i:=current_procdef.parast.symtablelevel;
  643. while (i>tprocdef(procdefinition).parast.symtablelevel) do
  644. begin
  645. reference_reset_base(href,hregister,current_procinfo.framepointer_offset);
  646. cg.a_load_ref_reg(exprasmlist,OS_ADDR,href,hregister);
  647. dec(i);
  648. end;
  649. cg.a_param_reg(exprasmlist,OS_ADDR,hregister,paramanager.getintparaloc(1));
  650. rg.ungetaddressregister(exprasmlist,hregister);
  651. end;
  652. end;
  653. procedure tcgcallnode.handle_return_value(inlined:boolean);
  654. var
  655. cgsize : tcgsize;
  656. r,hregister : tregister;
  657. nr:Tnewregister;
  658. begin
  659. { structured results are easy to handle.... }
  660. { needed also when result_no_used !! }
  661. if paramanager.ret_in_param(resulttype.def,procdefinition.proccalloption) then
  662. begin
  663. { Location should be setup by the funcret para }
  664. if location.loc<>LOC_REFERENCE then
  665. internalerror(200304241);
  666. end
  667. else
  668. { ansi/widestrings must be registered, so we can dispose them }
  669. if is_ansistring(resulttype.def) or
  670. is_widestring(resulttype.def) then
  671. begin
  672. location_reset(location,LOC_CREFERENCE,OS_ADDR);
  673. location.reference:=refcountedtemp;
  674. r.enum:=accumulator;
  675. cg.a_reg_alloc(exprasmlist,r);
  676. cg.a_load_reg_ref(exprasmlist,OS_ADDR,r,location.reference);
  677. cg.a_reg_dealloc(exprasmlist,r);
  678. end
  679. else
  680. { we have only to handle the result if it is used }
  681. if (nf_return_value_used in flags) then
  682. begin
  683. case resulttype.def.deftype of
  684. enumdef,
  685. orddef :
  686. begin
  687. cgsize:=def_cgsize(resulttype.def);
  688. { an object constructor is a function with pointer result }
  689. if (inlined or (right=nil)) and
  690. (procdefinition.proctypeoption=potype_constructor) then
  691. cgsize:=OS_ADDR;
  692. if cgsize<>OS_NO then
  693. begin
  694. location_reset(location,LOC_REGISTER,cgsize);
  695. {$ifndef cpu64bit}
  696. if cgsize in [OS_64,OS_S64] then
  697. begin
  698. {Move the function result to free registers, preferably the
  699. accumulator/accumulatorhigh, so no move is necessary.}
  700. r.enum:=R_INTREGISTER;
  701. r.number:=NR_ACCUMULATOR;
  702. hregister.enum:=R_INTREGISTER;
  703. hregister.number:=NR_ACCUMULATORHIGH;
  704. {$ifdef newra}
  705. rg.getexplicitregisterint(exprasmlist,NR_ACCUMULATOR);
  706. rg.getexplicitregisterint(exprasmlist,NR_ACCUMULATORHIGH);
  707. rg.ungetregisterint(exprasmlist,r);
  708. rg.ungetregisterint(exprasmlist,hregister);
  709. location.registerlow:=rg.getregisterint(exprasmlist,OS_INT);
  710. location.registerhigh:=rg.getregisterint(exprasmlist,OS_INT);
  711. {$else newra}
  712. cg.a_reg_alloc(exprasmlist,r);
  713. cg.a_reg_alloc(exprasmlist,hregister);
  714. if RS_ACCUMULATOR in rg.unusedregsint then
  715. location.registerlow:=rg.getexplicitregisterint(exprasmlist,NR_ACCUMULATOR)
  716. else
  717. location.registerlow:=rg.getregisterint(exprasmlist,OS_INT);
  718. if RS_ACCUMULATORHIGH in rg.unusedregsint then
  719. location.registerhigh:=rg.getexplicitregisterint(exprasmlist,NR_ACCUMULATORHIGH)
  720. else
  721. location.registerhigh:=rg.getregisterint(exprasmlist,OS_INT);
  722. {$endif newra}
  723. cg64.a_load64_reg_reg(exprasmlist,joinreg64(r,hregister),
  724. location.register64);
  725. end
  726. else
  727. {$endif cpu64bit}
  728. begin
  729. {Move the function result to a free register, preferably the
  730. accumulator, so no move is necessary.}
  731. nr:=RS_ACCUMULATOR shl 8 or cgsize2subreg(cgsize);
  732. r.enum:=R_INTREGISTER;
  733. r.number:=nr;
  734. {$ifdef newra}
  735. rg.getexplicitregisterint(exprasmlist,nr);
  736. rg.ungetregisterint(exprasmlist,r);
  737. location.register:=rg.getregisterint(exprasmlist,cgsize);
  738. {$else newra}
  739. cg.a_reg_alloc(exprasmlist,r);
  740. if RS_ACCUMULATOR in rg.unusedregsint then
  741. location.register:=rg.getexplicitregisterint(exprasmlist,nr)
  742. else
  743. location.register:=rg.getregisterint(exprasmlist,cgsize);
  744. {$endif newra}
  745. cg.a_load_reg_reg(exprasmlist,cgsize,cgsize,r,location.register);
  746. end;
  747. end;
  748. end;
  749. floatdef :
  750. begin
  751. location_reset(location,LOC_FPUREGISTER,def_cgsize(resulttype.def));
  752. {$ifdef cpufpemu}
  753. if cs_fp_emulation in aktmoduleswitches then
  754. location.register.enum := accumulator
  755. else
  756. {$endif cpufpemu}
  757. location.register.enum:=FPU_RESULT_REG;
  758. {$ifdef x86}
  759. inc(trgcpu(rg).fpuvaroffset);
  760. {$endif x86}
  761. end;
  762. {$ifdef TEST_WIN32_RECORDS}
  763. recorddef :
  764. begin
  765. if (target_info.system=system_i386_win32) then
  766. begin
  767. location_reset(location,LOC_REFERENCE,def_cgsize(resulttype.def));
  768. tg.GetTemp(exprasmlist,resulttype.size,tt_normal,location);
  769. {$ifndef cpu64bit}
  770. if cgsize in [OS_64,OS_S64] then
  771. cg64.a_load64_reg_loc(exprasmlist,joinreg64(accumulator,accumulatorhigh),location)
  772. else
  773. {$endif cpu64bit}
  774. cg.a_load_reg_loc(exprasmlist,accumulator,location);
  775. end
  776. else
  777. internalerror(200211141);
  778. end;
  779. {$endif TEST_WIN32_RECORDS}
  780. else
  781. begin
  782. location_reset(location,LOC_REGISTER,OS_INT);
  783. r.enum:=R_INTREGISTER;
  784. r.number:=NR_ACCUMULATOR;
  785. {$ifdef newra}
  786. rg.getexplicitregisterint(exprasmlist,NR_ACCUMULATOR);
  787. rg.ungetregisterint(exprasmlist,r);
  788. location.register:=rg.getregisterint(exprasmlist,OS_INT);
  789. {$else newra}
  790. if RS_ACCUMULATOR in rg.unusedregsint then
  791. location.register:=rg.getexplicitregisterint(exprasmlist,NR_ACCUMULATOR)
  792. else
  793. location.register:=rg.getregisterint(exprasmlist,OS_INT);
  794. {$endif newra}
  795. cg.a_load_reg_reg(exprasmlist,OS_INT,OS_INT,r,location.register);
  796. end;
  797. end;
  798. end
  799. else
  800. location_reset(location,LOC_VOID,OS_NO);
  801. end;
  802. procedure tcgcallnode.pass_2;
  803. var
  804. regs_to_push_int : Tsupregset;
  805. regs_to_push_other : tregisterset;
  806. unusedstate: pointer;
  807. pushed : tpushedsaved;
  808. pushedint : tpushedsavedint;
  809. oldpushedparasize : longint;
  810. { adress returned from an I/O-error }
  811. iolabel : tasmlabel;
  812. { help reference pointer }
  813. href : treference;
  814. hp : tnode;
  815. pp : tcallparanode;
  816. virtual_vmt_call,
  817. inlined : boolean;
  818. inlinecode : tprocinlinenode;
  819. store_parast_fixup,
  820. para_alignment,
  821. para_offset : longint;
  822. pop_size : longint;
  823. returnref,
  824. pararef : treference;
  825. accreg,
  826. vmtreg : tregister;
  827. oldaktcallnode : tcallnode;
  828. begin
  829. iolabel:=nil;
  830. inlinecode:=nil;
  831. inlined:=false;
  832. rg.saveunusedstate(unusedstate);
  833. { if we allocate the temp. location for ansi- or widestrings }
  834. { already here, we avoid later a push/pop }
  835. if is_widestring(resulttype.def) then
  836. begin
  837. tg.GetTemp(exprasmlist,pointer_size,tt_widestring,refcountedtemp);
  838. cg.g_decrrefcount(exprasmlist,resulttype.def,refcountedtemp,false);
  839. end
  840. else if is_ansistring(resulttype.def) then
  841. begin
  842. tg.GetTemp(exprasmlist,pointer_size,tt_ansistring,refcountedtemp);
  843. cg.g_decrrefcount(exprasmlist,resulttype.def,refcountedtemp,false);
  844. end;
  845. if (procdefinition.proccalloption in [pocall_cdecl,pocall_cppdecl,pocall_stdcall]) then
  846. para_alignment:=4
  847. else
  848. para_alignment:=aktalignment.paraalign;
  849. if not assigned(procdefinition) then
  850. exit;
  851. if (procdefinition.proccalloption=pocall_inline) then
  852. begin
  853. inlined:=true;
  854. inlinecode:=tprocinlinenode(right);
  855. right:=nil;
  856. { set it to the same lexical level as the local symtable, becuase
  857. the para's are stored there }
  858. tprocdef(procdefinition).parast.symtablelevel:=current_procdef.localst.symtablelevel;
  859. if assigned(left) then
  860. begin
  861. inlinecode.para_size:=tprocdef(procdefinition).para_size(para_alignment);
  862. tg.GetTemp(exprasmlist,inlinecode.para_size,tt_persistant,pararef);
  863. inlinecode.para_offset:=pararef.offset;
  864. end;
  865. store_parast_fixup:=tprocdef(procdefinition).parast.address_fixup;
  866. tprocdef(procdefinition).parast.address_fixup:=inlinecode.para_offset;
  867. {$ifdef extdebug}
  868. Comment(V_debug,
  869. 'inlined parasymtable is at offset '
  870. +tostr(tprocdef(procdefinition).parast.address_fixup));
  871. exprasmList.concat(tai_comment.Create(
  872. strpnew('inlined parasymtable is at offset '
  873. +tostr(tprocdef(procdefinition).parast.address_fixup))));
  874. {$endif extdebug}
  875. end;
  876. { proc variables destroy all registers }
  877. if (inlined or
  878. (right=nil)) and
  879. { virtual methods too }
  880. not(po_virtualmethod in procdefinition.procoptions) then
  881. begin
  882. if (cs_check_io in aktlocalswitches) and
  883. (po_iocheck in procdefinition.procoptions) and
  884. not(po_iocheck in current_procdef.procoptions) then
  885. begin
  886. objectlibrary.getaddrlabel(iolabel);
  887. cg.a_label(exprasmlist,iolabel);
  888. end
  889. else
  890. iolabel:=nil;
  891. { save all used registers and possible registers
  892. used for the return value }
  893. regs_to_push_int := tprocdef(procdefinition).usedintregisters;
  894. regs_to_push_other := tprocdef(procdefinition).usedotherregisters;
  895. if (not is_void(resulttype.def)) and
  896. (not paramanager.ret_in_param(resulttype.def,procdefinition.proccalloption)) then
  897. begin
  898. include(regs_to_push_int,RS_ACCUMULATOR);
  899. {$ifndef cpu64bit}
  900. if resulttype.def.size>sizeof(aword) then
  901. include(regs_to_push_int,RS_ACCUMULATORHIGH);
  902. {$endif cpu64bit}
  903. end;
  904. rg.saveusedintregisters(exprasmlist,pushedint,regs_to_push_int);
  905. rg.saveusedotherregisters(exprasmlist,pushed,regs_to_push_other);
  906. { give used registers through }
  907. rg.usedintinproc:=rg.usedintinproc + tprocdef(procdefinition).usedintregisters;
  908. rg.usedinproc:=rg.usedinproc + tprocdef(procdefinition).usedotherregisters;
  909. end
  910. else
  911. begin
  912. regs_to_push_int := all_intregisters;
  913. regs_to_push_other := all_registers;
  914. rg.saveusedintregisters(exprasmlist,pushedint,regs_to_push_int);
  915. rg.saveusedotherregisters(exprasmlist,pushed,regs_to_push_other);
  916. rg.usedinproc:=all_registers;
  917. { no IO check for methods and procedure variables }
  918. iolabel:=nil;
  919. end;
  920. { Initialize for pushing the parameters }
  921. oldpushedparasize:=pushedparasize;
  922. pushedparasize:=0;
  923. pop_size:=0;
  924. { Align stack if required }
  925. if not inlined then
  926. pop_size:=align_parasize(oldpushedparasize,para_alignment);
  927. { Push parameters }
  928. oldaktcallnode:=aktcallnode;
  929. aktcallnode:=self;
  930. if assigned(left) then
  931. begin
  932. { be found elsewhere }
  933. if inlined then
  934. para_offset:=tprocdef(procdefinition).parast.address_fixup+
  935. tprocdef(procdefinition).parast.datasize
  936. else
  937. para_offset:=0;
  938. if not(inlined) and
  939. assigned(right) then
  940. tcallparanode(left).secondcallparan(
  941. (po_leftright in procdefinition.procoptions),procdefinition.proccalloption,
  942. para_alignment,para_offset)
  943. else
  944. tcallparanode(left).secondcallparan(
  945. (po_leftright in procdefinition.procoptions),procdefinition.proccalloption,
  946. para_alignment,para_offset);
  947. end;
  948. aktcallnode:=oldaktcallnode;
  949. { Allocate return value for inlined routines }
  950. if inlined and
  951. (resulttype.def.size>0) then
  952. begin
  953. tg.GetTemp(exprasmlist,Align(resulttype.def.size,aktalignment.paraalign),tt_persistant,returnref);
  954. inlinecode.retoffset:=returnref.offset;
  955. end;
  956. { procedure variable or normal function call ? }
  957. if inlined or
  958. (right=nil) then
  959. begin
  960. { Virtual function call through VMT? }
  961. vmtreg.enum:=R_INTREGISTER;
  962. vmtreg.number:=NR_NO;
  963. virtual_vmt_call:=(po_virtualmethod in procdefinition.procoptions) and
  964. not(assigned(methodpointer) and
  965. (methodpointer.nodetype=typen));
  966. { push self/vmt for methods }
  967. if assigned(symtableproc) and
  968. (symtableproc.symtabletype in [withsymtable,objectsymtable]) then
  969. vmtreg:=push_self_and_vmt(virtual_vmt_call);
  970. { push base pointer ?}
  971. { never when inlining, since if necessary, the base pointer }
  972. { can/will be gottten from the current procedure's symtable }
  973. { (JM) }
  974. if not inlined then
  975. if (current_procdef.parast.symtablelevel>=normal_function_level) and
  976. assigned(tprocdef(procdefinition).parast) and
  977. ((tprocdef(procdefinition).parast.symtablelevel)>normal_function_level) then
  978. push_framepointer;
  979. rg.saveintregvars(exprasmlist,regs_to_push_int);
  980. rg.saveotherregvars(exprasmlist,regs_to_push_other);
  981. if virtual_vmt_call then
  982. begin
  983. { virtual methods require an index }
  984. if tprocdef(procdefinition).extnumber=-1 then
  985. internalerror(200304021);
  986. { VMT should already be loaded in a register }
  987. if vmtreg.number=NR_NO then
  988. internalerror(200304022);
  989. { test validity of VMT }
  990. if not(is_interface(tprocdef(procdefinition)._class)) and
  991. not(is_cppclass(tprocdef(procdefinition)._class)) then
  992. cg.g_maybe_testvmt(exprasmlist,vmtreg,tprocdef(procdefinition)._class);
  993. { call method }
  994. reference_reset_base(href,vmtreg,
  995. tprocdef(procdefinition)._class.vmtmethodoffset(tprocdef(procdefinition).extnumber));
  996. cg.a_call_ref(exprasmlist,href);
  997. { release self }
  998. rg.ungetregisterint(exprasmlist,vmtreg);
  999. end
  1000. else
  1001. begin
  1002. if not inlined then
  1003. begin
  1004. { Calling interrupt from the same code requires some
  1005. extra code }
  1006. if (po_interrupt in procdefinition.procoptions) then
  1007. extra_interrupt_code;
  1008. cg.a_call_name(exprasmlist,tprocdef(procdefinition).mangledname);
  1009. end
  1010. else { inlined proc }
  1011. begin
  1012. { process the inlinecode }
  1013. secondpass(tnode(inlinecode));
  1014. { free the args }
  1015. if tprocdef(procdefinition).parast.datasize>0 then
  1016. tg.UnGetTemp(exprasmlist,pararef);
  1017. end;
  1018. end;
  1019. end
  1020. else
  1021. { now procedure variable case }
  1022. begin
  1023. secondpass(right);
  1024. { Calling interrupt from the same code requires some
  1025. extra code }
  1026. if (po_interrupt in procdefinition.procoptions) then
  1027. extra_interrupt_code;
  1028. if (po_methodpointer in procdefinition.procoptions) then
  1029. begin
  1030. { push self, but not if it's already explicitly pushed }
  1031. if not(po_containsself in procdefinition.procoptions) then
  1032. begin
  1033. { push self }
  1034. href:=right.location.reference;
  1035. inc(href.offset,POINTER_SIZE);
  1036. cg.a_param_ref(exprasmlist,OS_ADDR,href,paramanager.getintparaloc(1));
  1037. end;
  1038. rg.saveintregvars(exprasmlist,ALL_INTREGISTERS);
  1039. rg.saveotherregvars(exprasmlist,ALL_REGISTERS);
  1040. cg.a_call_ref(exprasmlist,right.location.reference);
  1041. reference_release(exprasmlist,right.location.reference);
  1042. tg.Ungetiftemp(exprasmlist,right.location.reference);
  1043. end
  1044. else
  1045. begin
  1046. rg.saveintregvars(exprasmlist,ALL_INTREGISTERS);
  1047. rg.saveotherregvars(exprasmlist,ALL_REGISTERS);
  1048. cg.a_call_loc(exprasmlist,right.location);
  1049. location_release(exprasmlist,right.location);
  1050. location_freetemp(exprasmlist,right.location);
  1051. end;
  1052. end;
  1053. { Need to remove the parameters from the stack? }
  1054. if (not inlined) and (po_clearstack in procdefinition.procoptions) then
  1055. begin
  1056. { the old pop_size was already included in pushedparasize }
  1057. pop_size:=pushedparasize;
  1058. end;
  1059. { Remove parameters/alignment from the stack }
  1060. if pop_size>0 then
  1061. pop_parasize(pop_size);
  1062. {$ifdef powerpc}
  1063. { this calculation must be done in pass_1 anyway, so don't worry }
  1064. if tppcprocinfo(current_procinfo).maxpushedparasize<pushedparasize then
  1065. tppcprocinfo(current_procinfo).maxpushedparasize:=pushedparasize;
  1066. {$endif powerpc}
  1067. { Restore }
  1068. pushedparasize:=oldpushedparasize;
  1069. rg.restoreunusedstate(unusedstate);
  1070. {$ifdef TEMPREGDEBUG}
  1071. testregisters32;
  1072. {$endif TEMPREGDEBUG}
  1073. { Called an inherited constructor? Then
  1074. we need to check the result }
  1075. if (inlined or (right=nil)) and
  1076. (procdefinition.proctypeoption=potype_constructor) and
  1077. assigned(methodpointer) and
  1078. (methodpointer.nodetype=typen) and
  1079. (current_procdef.proctypeoption=potype_constructor) then
  1080. begin
  1081. accreg.enum:=R_INTREGISTER;
  1082. accreg.number:=NR_ACCUMULATOR;
  1083. cg.a_reg_alloc(exprasmlist,accreg);
  1084. cg.a_cmp_const_reg_label(exprasmlist,OS_ADDR,OC_EQ,0,accreg,faillabel);
  1085. cg.a_reg_dealloc(exprasmlist,accreg);
  1086. end;
  1087. { handle function results }
  1088. if (not is_void(resulttype.def)) then
  1089. handle_return_value(inlined)
  1090. else
  1091. location_reset(location,LOC_VOID,OS_NO);
  1092. { perhaps i/o check ? }
  1093. if iolabel<>nil then
  1094. begin
  1095. reference_reset_symbol(href,iolabel,0);
  1096. cg.a_paramaddr_ref(exprasmlist,href,paramanager.getintparaloc(1));
  1097. cg.a_call_name(exprasmlist,'FPC_IOCHECK');
  1098. end;
  1099. { restore registers }
  1100. rg.restoreusedotherregisters(exprasmlist,pushed);
  1101. rg.restoreusedintregisters(exprasmlist,pushedint);
  1102. { Release temps from parameters }
  1103. pp:=tcallparanode(left);
  1104. while assigned(pp) do
  1105. begin
  1106. if assigned(pp.left) then
  1107. begin
  1108. { don't release the funcret temp }
  1109. if not(vo_is_funcret in tvarsym(pp.paraitem.parasym).varoptions) then
  1110. location_freetemp(exprasmlist,pp.left.location);
  1111. { process also all nodes of an array of const }
  1112. if pp.left.nodetype=arrayconstructorn then
  1113. begin
  1114. if assigned(tarrayconstructornode(pp.left).left) then
  1115. begin
  1116. hp:=pp.left;
  1117. while assigned(hp) do
  1118. begin
  1119. location_freetemp(exprasmlist,tarrayconstructornode(hp).left.location);
  1120. hp:=tarrayconstructornode(hp).right;
  1121. end;
  1122. end;
  1123. end;
  1124. end;
  1125. pp:=tcallparanode(pp.right);
  1126. end;
  1127. if inlined then
  1128. begin
  1129. if (resulttype.def.size>0) then
  1130. tg.UnGetTemp(exprasmlist,returnref);
  1131. tprocdef(procdefinition).parast.address_fixup:=store_parast_fixup;
  1132. right:=inlinecode;
  1133. { from now on the result can be freed normally }
  1134. if paramanager.ret_in_param(resulttype.def,procdefinition.proccalloption) then
  1135. tg.ChangeTempType(exprasmlist,funcretnode.location.reference,tt_normal);
  1136. end;
  1137. { if return value is not used }
  1138. if (not(nf_return_value_used in flags)) and (not is_void(resulttype.def)) then
  1139. begin
  1140. if location.loc in [LOC_CREFERENCE,LOC_REFERENCE] then
  1141. begin
  1142. { data which must be finalized ? }
  1143. if (resulttype.def.needs_inittable) then
  1144. cg.g_finalize(exprasmlist,resulttype.def,location.reference,false);
  1145. { release unused temp }
  1146. tg.ungetiftemp(exprasmlist,location.reference)
  1147. end
  1148. else if location.loc=LOC_FPUREGISTER then
  1149. begin
  1150. {$ifdef x86}
  1151. { release FPU stack }
  1152. accreg.enum:=FPU_RESULT_REG;
  1153. emit_reg(A_FSTP,S_NO,accreg);
  1154. {
  1155. dec(trgcpu(rg).fpuvaroffset);
  1156. do NOT decrement as the increment before
  1157. is not called for unused results PM }
  1158. {$endif x86}
  1159. end;
  1160. end;
  1161. end;
  1162. {*****************************************************************************
  1163. TCGPROCINLINENODE
  1164. *****************************************************************************}
  1165. procedure tcgprocinlinenode.pass_2;
  1166. var st : tsymtable;
  1167. oldprocdef : tprocdef;
  1168. ps, i : longint;
  1169. oldprocinfo : tprocinfo;
  1170. oldinlining_procedure,
  1171. nostackframe,make_global : boolean;
  1172. inlineentrycode,inlineexitcode : TAAsmoutput;
  1173. oldexitlabel,oldexit2label,oldquickexitlabel:tasmlabel;
  1174. oldregstate: pointer;
  1175. localsref : treference;
  1176. {$ifdef GDB}
  1177. startlabel,endlabel : tasmlabel;
  1178. pp : pchar;
  1179. mangled_length : longint;
  1180. {$endif GDB}
  1181. begin
  1182. { deallocate the registers used for the current procedure's regvars }
  1183. if assigned(current_procdef.regvarinfo) then
  1184. begin
  1185. with pregvarinfo(current_procdef.regvarinfo)^ do
  1186. for i := 1 to maxvarregs do
  1187. if assigned(regvars[i]) then
  1188. store_regvar(exprasmlist,regvars[i].reg);
  1189. rg.saveStateForInline(oldregstate);
  1190. { make sure the register allocator knows what the regvars in the }
  1191. { inlined code block are (JM) }
  1192. rg.resetusableregisters;
  1193. rg.clearregistercount;
  1194. {$ifndef newra}
  1195. rg.cleartempgen;
  1196. {$endif}
  1197. if assigned(inlineprocdef.regvarinfo) then
  1198. with pregvarinfo(inlineprocdef.regvarinfo)^ do
  1199. for i := 1 to maxvarregs do
  1200. if assigned(regvars[i]) then
  1201. begin
  1202. {Fix me!!}
  1203. {tmpreg:=rg.makeregsize(regvars[i].reg,OS_INT);
  1204. rg.makeregvar(tmpreg);}
  1205. internalerror(200301232);
  1206. end;
  1207. end;
  1208. oldinlining_procedure:=inlining_procedure;
  1209. oldexitlabel:=aktexitlabel;
  1210. oldexit2label:=aktexit2label;
  1211. oldquickexitlabel:=quickexitlabel;
  1212. oldprocdef:=current_procdef;
  1213. oldprocinfo:=current_procinfo;
  1214. objectlibrary.getlabel(aktexitlabel);
  1215. objectlibrary.getlabel(aktexit2label);
  1216. { we're inlining a procedure }
  1217. inlining_procedure:=true;
  1218. current_procdef:=inlineprocdef;
  1219. { clone procinfo, but not the asmlists }
  1220. current_procinfo:=tprocinfo(cprocinfo.newinstance);
  1221. move(pointer(oldprocinfo)^,pointer(current_procinfo)^,cprocinfo.InstanceSize);
  1222. current_procinfo.aktentrycode:=nil;
  1223. current_procinfo.aktexitcode:=nil;
  1224. current_procinfo.aktproccode:=nil;
  1225. current_procinfo.aktlocaldata:=nil;
  1226. { set new procinfo }
  1227. current_procinfo.return_offset:=retoffset;
  1228. { arg space has been filled by the parent secondcall }
  1229. st:=current_procdef.localst;
  1230. { set it to the same lexical level }
  1231. st.symtablelevel:=oldprocdef.localst.symtablelevel;
  1232. if st.datasize>0 then
  1233. begin
  1234. tg.GetTemp(exprasmlist,st.datasize,tt_persistant,localsref);
  1235. st.address_fixup:=localsref.offset+st.datasize;
  1236. {$ifdef extdebug}
  1237. Comment(V_debug,'local symtable is at offset '+tostr(st.address_fixup));
  1238. exprasmList.concat(tai_comment.Create(strpnew(
  1239. 'local symtable is at offset '+tostr(st.address_fixup))));
  1240. {$endif extdebug}
  1241. end;
  1242. exprasmList.concat(Tai_Marker.Create(InlineStart));
  1243. {$ifdef extdebug}
  1244. exprasmList.concat(tai_comment.Create(strpnew('Start of inlined proc')));
  1245. {$endif extdebug}
  1246. {$ifdef GDB}
  1247. if (cs_debuginfo in aktmoduleswitches) then
  1248. begin
  1249. objectlibrary.getaddrlabel(startlabel);
  1250. objectlibrary.getaddrlabel(endlabel);
  1251. cg.a_label(exprasmlist,startlabel);
  1252. inlineprocdef.localst.symtabletype:=inlinelocalsymtable;
  1253. inlineprocdef.parast.symtabletype:=inlineparasymtable;
  1254. { Here we must include the para and local symtable info }
  1255. inlineprocdef.concatstabto(withdebuglist);
  1256. { set it back for safety }
  1257. inlineprocdef.localst.symtabletype:=localsymtable;
  1258. inlineprocdef.parast.symtabletype:=parasymtable;
  1259. mangled_length:=length(oldprocdef.mangledname);
  1260. getmem(pp,mangled_length+50);
  1261. strpcopy(pp,'192,0,0,'+startlabel.name);
  1262. if (target_info.use_function_relative_addresses) then
  1263. begin
  1264. strpcopy(strend(pp),'-');
  1265. strpcopy(strend(pp),oldprocdef.mangledname);
  1266. end;
  1267. withdebugList.concat(Tai_stabn.Create(strnew(pp)));
  1268. end;
  1269. {$endif GDB}
  1270. { takes care of local data initialization }
  1271. inlineentrycode:=TAAsmoutput.Create;
  1272. inlineexitcode:=TAAsmoutput.Create;
  1273. ps:=para_size;
  1274. make_global:=false; { to avoid warning }
  1275. genentrycode(inlineentrycode,make_global,0,ps,nostackframe,true);
  1276. if po_assembler in current_procdef.procoptions then
  1277. inlineentrycode.insert(Tai_marker.Create(asmblockstart));
  1278. exprasmList.concatlist(inlineentrycode);
  1279. secondpass(inlinetree);
  1280. genexitcode(inlineexitcode,0,false,true);
  1281. if po_assembler in current_procdef.procoptions then
  1282. inlineexitcode.concat(Tai_marker.Create(asmblockend));
  1283. exprasmList.concatlist(inlineexitcode);
  1284. inlineentrycode.free;
  1285. inlineexitcode.free;
  1286. {$ifdef extdebug}
  1287. exprasmList.concat(tai_comment.Create(strpnew('End of inlined proc')));
  1288. {$endif extdebug}
  1289. exprasmList.concat(Tai_Marker.Create(InlineEnd));
  1290. {we can free the local data now, reset also the fixup address }
  1291. if st.datasize>0 then
  1292. begin
  1293. tg.UnGetTemp(exprasmlist,localsref);
  1294. st.address_fixup:=0;
  1295. end;
  1296. { restore procinfo }
  1297. current_procinfo.free;
  1298. current_procinfo:=oldprocinfo;
  1299. {$ifdef GDB}
  1300. if (cs_debuginfo in aktmoduleswitches) then
  1301. begin
  1302. cg.a_label(exprasmlist,endlabel);
  1303. strpcopy(pp,'224,0,0,'+endlabel.name);
  1304. if (target_info.use_function_relative_addresses) then
  1305. begin
  1306. strpcopy(strend(pp),'-');
  1307. strpcopy(strend(pp),oldprocdef.mangledname);
  1308. end;
  1309. withdebugList.concat(Tai_stabn.Create(strnew(pp)));
  1310. freemem(pp,mangled_length+50);
  1311. end;
  1312. {$endif GDB}
  1313. { restore }
  1314. current_procdef:=oldprocdef;
  1315. aktexitlabel:=oldexitlabel;
  1316. aktexit2label:=oldexit2label;
  1317. quickexitlabel:=oldquickexitlabel;
  1318. inlining_procedure:=oldinlining_procedure;
  1319. { reallocate the registers used for the current procedure's regvars, }
  1320. { since they may have been used and then deallocated in the inlined }
  1321. { procedure (JM) }
  1322. if assigned(current_procdef.regvarinfo) then
  1323. begin
  1324. rg.restoreStateAfterInline(oldregstate);
  1325. end;
  1326. end;
  1327. begin
  1328. ccallparanode:=tcgcallparanode;
  1329. ccallnode:=tcgcallnode;
  1330. cprocinlinenode:=tcgprocinlinenode;
  1331. end.
  1332. {
  1333. $Log$
  1334. Revision 1.57 2003-04-30 20:53:32 florian
  1335. * error when address of an abstract method is taken
  1336. * fixed some x86-64 problems
  1337. * merged some more x86-64 and i386 code
  1338. Revision 1.56 2003/04/29 07:28:52 michael
  1339. + Patch from peter to fix wrong pushing of ansistring function results in open array
  1340. Revision 1.55 2003/04/27 11:21:33 peter
  1341. * aktprocdef renamed to current_procdef
  1342. * procinfo renamed to current_procinfo
  1343. * procinfo will now be stored in current_module so it can be
  1344. cleaned up properly
  1345. * gen_main_procsym changed to create_main_proc and release_main_proc
  1346. to also generate a tprocinfo structure
  1347. * fixed unit implicit initfinal
  1348. Revision 1.54 2003/04/27 07:29:50 peter
  1349. * current_procdef cleanup, current_procdef is now always nil when parsing
  1350. a new procdef declaration
  1351. * aktprocsym removed
  1352. * lexlevel removed, use symtable.symtablelevel instead
  1353. * implicit init/final code uses the normal genentry/genexit
  1354. * funcret state checking updated for new funcret handling
  1355. Revision 1.53 2003/04/25 20:59:33 peter
  1356. * removed funcretn,funcretsym, function result is now in varsym
  1357. and aliases for result and function name are added using absolutesym
  1358. * vs_hidden parameter for funcret passed in parameter
  1359. * vs_hidden fixes
  1360. * writenode changed to printnode and released from extdebug
  1361. * -vp option added to generate a tree.log with the nodetree
  1362. * nicer printnode for statements, callnode
  1363. Revision 1.52 2003/04/25 08:25:26 daniel
  1364. * Ifdefs around a lot of calls to cleartempgen
  1365. * Fixed registers that are allocated but not freed in several nodes
  1366. * Tweak to register allocator to cause less spills
  1367. * 8-bit registers now interfere with esi,edi and ebp
  1368. Compiler can now compile rtl successfully when using new register
  1369. allocator
  1370. Revision 1.51 2003/04/22 23:50:22 peter
  1371. * firstpass uses expectloc
  1372. * checks if there are differences between the expectloc and
  1373. location.loc from secondpass in EXTDEBUG
  1374. Revision 1.50 2003/04/22 14:33:38 peter
  1375. * removed some notes/hints
  1376. Revision 1.49 2003/04/22 13:47:08 peter
  1377. * fixed C style array of const
  1378. * fixed C array passing
  1379. * fixed left to right with high parameters
  1380. Revision 1.48 2003/04/22 10:09:34 daniel
  1381. + Implemented the actual register allocator
  1382. + Scratch registers unavailable when new register allocator used
  1383. + maybe_save/maybe_restore unavailable when new register allocator used
  1384. Revision 1.47 2003/04/22 09:49:44 peter
  1385. * do not load self when calling a non-inherited class constructor
  1386. Revision 1.46 2003/04/21 20:03:32 peter
  1387. * forgot to copy vmtrefaddr to selfrefaddr when self=vmt
  1388. Revision 1.45 2003/04/21 13:53:16 jonas
  1389. - removed copying of all paras when secondpassing a callnode (this used
  1390. to be necessary for inlinign support, but currently the whole inlined
  1391. procedure is already copied in advance). Note that the compiler crashes
  1392. when compiling ucomplex with -dTEST_INLINE (also after fixing the
  1393. syntax errors), but that was also the case before this change.
  1394. Revision 1.44 2003/04/10 17:57:52 peter
  1395. * vs_hidden released
  1396. Revision 1.43 2003/04/06 21:11:23 olle
  1397. * changed newasmsymbol to newasmsymboldata for data symbols
  1398. Revision 1.42 2003/04/04 15:38:56 peter
  1399. * moved generic code from n386cal to ncgcal, i386 now also
  1400. uses the generic ncgcal
  1401. Revision 1.41 2003/03/28 19:16:56 peter
  1402. * generic constructor working for i386
  1403. * remove fixed self register
  1404. * esi added as address register for i386
  1405. Revision 1.40 2003/03/06 11:35:50 daniel
  1406. * Fixed internalerror 7843 issue
  1407. Revision 1.39 2003/02/19 22:00:14 daniel
  1408. * Code generator converted to new register notation
  1409. - Horribily outdated todo.txt removed
  1410. Revision 1.38 2003/02/15 22:17:38 carl
  1411. * bugfix of FPU emulation code
  1412. Revision 1.37 2003/02/12 22:10:07 carl
  1413. * load_frame_pointer is now generic
  1414. * change fpu emulation routine names
  1415. Revision 1.36 2003/01/30 21:46:57 peter
  1416. * self fixes for static methods (merged)
  1417. Revision 1.35 2003/01/22 20:45:15 mazen
  1418. * making math code in RTL compiling.
  1419. *NB : This does NOT mean necessary that it will generate correct code!
  1420. Revision 1.34 2003/01/17 12:03:45 daniel
  1421. * Optalign conditional code adapted to record Tregister
  1422. Revision 1.33 2003/01/08 18:43:56 daniel
  1423. * Tregister changed into a record
  1424. Revision 1.32 2002/12/15 22:50:00 florian
  1425. + some stuff for the new hidden parameter handling added
  1426. Revision 1.31 2002/12/15 21:30:12 florian
  1427. * tcallnode.paraitem introduced, all references to defcoll removed
  1428. Revision 1.30 2002/11/27 20:04:39 peter
  1429. * cdecl array of const fixes
  1430. Revision 1.29 2002/11/25 17:43:17 peter
  1431. * splitted defbase in defutil,symutil,defcmp
  1432. * merged isconvertable and is_equal into compare_defs(_ext)
  1433. * made operator search faster by walking the list only once
  1434. Revision 1.28 2002/11/18 17:31:54 peter
  1435. * pass proccalloption to ret_in_xxx and push_xxx functions
  1436. Revision 1.27 2002/11/16 15:34:30 florian
  1437. * generic location for float results
  1438. Revision 1.26 2002/11/15 01:58:51 peter
  1439. * merged changes from 1.0.7 up to 04-11
  1440. - -V option for generating bug report tracing
  1441. - more tracing for option parsing
  1442. - errors for cdecl and high()
  1443. - win32 import stabs
  1444. - win32 records<=8 are returned in eax:edx (turned off by default)
  1445. - heaptrc update
  1446. - more info for temp management in .s file with EXTDEBUG
  1447. Revision 1.25 2002/10/05 12:43:25 carl
  1448. * fixes for Delphi 6 compilation
  1449. (warning : Some features do not work under Delphi)
  1450. Revision 1.24 2002/09/30 07:00:45 florian
  1451. * fixes to common code to get the alpha compiler compiled applied
  1452. Revision 1.23 2002/09/17 18:54:02 jonas
  1453. * a_load_reg_reg() now has two size parameters: source and dest. This
  1454. allows some optimizations on architectures that don't encode the
  1455. register size in the register name.
  1456. Revision 1.22 2002/09/07 15:25:02 peter
  1457. * old logs removed and tabs fixed
  1458. Revision 1.21 2002/09/07 11:50:02 jonas
  1459. * fixed small regalloction info bug
  1460. Revision 1.20 2002/09/02 11:25:20 florian
  1461. * fixed generic procedure variable calling
  1462. Revision 1.19 2002/09/01 21:04:48 florian
  1463. * several powerpc related stuff fixed
  1464. Revision 1.18 2002/09/01 18:43:27 peter
  1465. * include accumulator in regs_to_push list
  1466. Revision 1.17 2002/09/01 12:13:00 peter
  1467. * use a_call_reg
  1468. * ungetiftemp for procvar of object temp
  1469. Revision 1.16 2002/08/25 19:25:18 peter
  1470. * sym.insert_in_data removed
  1471. * symtable.insertvardata/insertconstdata added
  1472. * removed insert_in_data call from symtable.insert, it needs to be
  1473. called separatly. This allows to deref the address calculation
  1474. * procedures now calculate the parast addresses after the procedure
  1475. directives are parsed. This fixes the cdecl parast problem
  1476. * push_addr_param has an extra argument that specifies if cdecl is used
  1477. or not
  1478. Revision 1.15 2002/08/23 16:14:48 peter
  1479. * tempgen cleanup
  1480. * tt_noreuse temp type added that will be used in genentrycode
  1481. Revision 1.14 2002/08/20 16:55:38 peter
  1482. * don't write (stabs)line info when inlining a procedure
  1483. Revision 1.13 2002/08/19 19:36:42 peter
  1484. * More fixes for cross unit inlining, all tnodes are now implemented
  1485. * Moved pocall_internconst to po_internconst because it is not a
  1486. calling type at all and it conflicted when inlining of these small
  1487. functions was requested
  1488. Revision 1.12 2002/08/18 20:06:23 peter
  1489. * inlining is now also allowed in interface
  1490. * renamed write/load to ppuwrite/ppuload
  1491. * tnode storing in ppu
  1492. * nld,ncon,nbas are already updated for storing in ppu
  1493. Revision 1.11 2002/08/17 22:09:44 florian
  1494. * result type handling in tcgcal.pass_2 overhauled
  1495. * better tnode.dowrite
  1496. * some ppc stuff fixed
  1497. Revision 1.10 2002/08/17 09:23:35 florian
  1498. * first part of procinfo rewrite
  1499. Revision 1.9 2002/08/13 21:40:55 florian
  1500. * more fixes for ppc calling conventions
  1501. Revision 1.8 2002/08/13 18:01:51 carl
  1502. * rename swatoperands to swapoperands
  1503. + m68k first compilable version (still needs a lot of testing):
  1504. assembler generator, system information , inline
  1505. assembler reader.
  1506. Revision 1.7 2002/08/12 15:08:39 carl
  1507. + stab register indexes for powerpc (moved from gdb to cpubase)
  1508. + tprocessor enumeration moved to cpuinfo
  1509. + linker in target_info is now a class
  1510. * many many updates for m68k (will soon start to compile)
  1511. - removed some ifdef or correct them for correct cpu
  1512. Revision 1.6 2002/08/11 14:32:26 peter
  1513. * renamed current_library to objectlibrary
  1514. Revision 1.5 2002/08/11 13:24:11 peter
  1515. * saving of asmsymbols in ppu supported
  1516. * asmsymbollist global is removed and moved into a new class
  1517. tasmlibrarydata that will hold the info of a .a file which
  1518. corresponds with a single module. Added librarydata to tmodule
  1519. to keep the library info stored for the module. In the future the
  1520. objectfiles will also be stored to the tasmlibrarydata class
  1521. * all getlabel/newasmsymbol and friends are moved to the new class
  1522. Revision 1.4 2002/08/06 20:55:20 florian
  1523. * first part of ppc calling conventions fix
  1524. Revision 1.3 2002/07/20 11:57:53 florian
  1525. * types.pas renamed to defbase.pas because D6 contains a types
  1526. unit so this would conflicts if D6 programms are compiled
  1527. + Willamette/SSE2 instructions to assembler added
  1528. Revision 1.2 2002/07/13 19:38:43 florian
  1529. * some more generic calling stuff fixed
  1530. }