ncgcal.pas 74 KB

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