ncgcal.pas 74 KB

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