n386cal.pas 69 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487
  1. {
  2. $Id$
  3. Copyright (c) 1998-2002 by Florian Klaempfl
  4. Generate i386 assembler for in call nodes
  5. This program is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  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 n386cal;
  19. {$i fpcdefs.inc}
  20. interface
  21. { $define AnsiStrRef}
  22. uses
  23. globtype,
  24. symdef,
  25. node,ncal,ncgcal;
  26. type
  27. ti386callparanode = class(tcallparanode)
  28. procedure secondcallparan(push_from_left_to_right:boolean;calloption:tproccalloption;
  29. para_alignment,para_offset : longint);override;
  30. end;
  31. ti386callnode = class(tcgcallnode)
  32. procedure pass_2;override;
  33. end;
  34. implementation
  35. uses
  36. systems,
  37. cutils,verbose,globals,
  38. symconst,symbase,symsym,symtable,defutil,
  39. {$ifdef GDB}
  40. {$ifdef delphi}
  41. sysutils,
  42. {$else}
  43. strings,
  44. {$endif}
  45. gdb,
  46. {$endif GDB}
  47. cginfo,cgbase,pass_2,
  48. cpubase,paramgr,
  49. aasmbase,aasmtai,aasmcpu,
  50. nmem,nld,ncnv,
  51. ncgutil,cga,cgobj,tgobj,regvars,rgobj,rgcpu,cg64f32,cgcpu,cpuinfo;
  52. {*****************************************************************************
  53. TI386CALLPARANODE
  54. *****************************************************************************}
  55. procedure ti386callparanode.secondcallparan(push_from_left_to_right:boolean;calloption:tproccalloption;para_alignment,para_offset : longint);
  56. procedure maybe_push_high;
  57. begin
  58. { open array ? }
  59. { paraitem.data can be nil for read/write }
  60. if assigned(paraitem.paratype.def) and
  61. assigned(hightree) then
  62. begin
  63. secondpass(hightree);
  64. { this is a longint anyway ! }
  65. push_value_para(hightree,calloption,para_offset,4,paralocdummy);
  66. end;
  67. end;
  68. var
  69. otlabel,oflabel : tasmlabel;
  70. { temporary variables: }
  71. tempdeftype : tdeftype;
  72. tmpreg : tregister;
  73. href : treference;
  74. begin
  75. { set default para_alignment to target_info.stackalignment }
  76. if para_alignment=0 then
  77. para_alignment:=aktalignment.paraalign;
  78. { push from left to right if specified }
  79. if push_from_left_to_right and assigned(right) then
  80. begin
  81. if (nf_varargs_para in flags) then
  82. tcallparanode(right).secondcallparan(push_from_left_to_right,
  83. calloption,para_alignment,para_offset)
  84. else
  85. tcallparanode(right).secondcallparan(push_from_left_to_right,
  86. calloption,para_alignment,para_offset);
  87. end;
  88. otlabel:=truelabel;
  89. oflabel:=falselabel;
  90. objectlibrary.getlabel(truelabel);
  91. objectlibrary.getlabel(falselabel);
  92. secondpass(left);
  93. { handle varargs first, because paraitem is not valid }
  94. if (nf_varargs_para in flags) then
  95. begin
  96. if paramanager.push_addr_param(left.resulttype.def,calloption) then
  97. begin
  98. inc(pushedparasize,4);
  99. cg.a_paramaddr_ref(exprasmlist,left.location.reference,paralocdummy);
  100. location_release(exprasmlist,left.location);
  101. end
  102. else
  103. push_value_para(left,calloption,para_offset,para_alignment,paralocdummy);
  104. end
  105. { filter array constructor with c styled args }
  106. else if is_array_of_const(left.resulttype.def) and (nf_cargs in left.flags) then
  107. begin
  108. { nothing, everything is already pushed }
  109. end
  110. { in codegen.handleread.. paraitem.data is set to nil }
  111. else if assigned(paraitem.paratype.def) and
  112. (paraitem.paratype.def.deftype=formaldef) then
  113. begin
  114. { allow passing of a constant to a const formaldef }
  115. if (paraitem.paratyp=vs_const) and
  116. (left.location.loc=LOC_CONSTANT) then
  117. location_force_mem(exprasmlist,left.location);
  118. { allow @var }
  119. inc(pushedparasize,4);
  120. if (left.nodetype=addrn) and
  121. (not(nf_procvarload in left.flags)) then
  122. begin
  123. if calloption=pocall_inline then
  124. begin
  125. reference_reset_base(href,procinfo.framepointer,para_offset-pushedparasize);
  126. cg.a_load_loc_ref(exprasmlist,left.location,href);
  127. end
  128. else
  129. cg.a_param_loc(exprasmlist,left.location,paralocdummy);
  130. location_release(exprasmlist,left.location);
  131. end
  132. else
  133. begin
  134. if not(left.location.loc in [LOC_CREFERENCE,LOC_REFERENCE]) then
  135. CGMessage(type_e_mismatch)
  136. else
  137. begin
  138. if calloption=pocall_inline then
  139. begin
  140. tmpreg:=cg.get_scratch_reg_address(exprasmlist);
  141. cg.a_loadaddr_ref_reg(exprasmlist,left.location.reference,tmpreg);
  142. reference_reset_base(href,procinfo.framepointer,para_offset-pushedparasize);
  143. cg.a_load_reg_ref(exprasmlist,OS_ADDR,tmpreg,href);
  144. cg.free_scratch_reg(exprasmlist,tmpreg);
  145. end
  146. else
  147. cg.a_paramaddr_ref(exprasmlist,left.location.reference,paralocdummy);
  148. location_release(exprasmlist,left.location);
  149. end;
  150. end;
  151. end
  152. { handle call by reference parameter }
  153. else if (paraitem.paratyp in [vs_var,vs_out]) then
  154. begin
  155. if (left.location.loc<>LOC_REFERENCE) then
  156. begin
  157. { passing self to a var parameter is allowed in
  158. TP and delphi }
  159. if not((left.location.loc=LOC_CREFERENCE) and
  160. (left.nodetype=selfn)) then
  161. internalerror(200106041);
  162. end;
  163. {$ifdef unused}
  164. if not push_from_left_to_right then
  165. {$endif unused}
  166. maybe_push_high;
  167. if (paraitem.paratyp=vs_out) and
  168. assigned(paraitem.paratype.def) and
  169. not is_class(paraitem.paratype.def) and
  170. paraitem.paratype.def.needs_inittable then
  171. cg.g_finalize(exprasmlist,paraitem.paratype.def,left.location.reference,false);
  172. inc(pushedparasize,4);
  173. if calloption=pocall_inline then
  174. begin
  175. tmpreg:=cg.get_scratch_reg_address(exprasmlist);
  176. cg.a_loadaddr_ref_reg(exprasmlist,left.location.reference,tmpreg);
  177. reference_reset_base(href,procinfo.framepointer,para_offset-pushedparasize);
  178. cg.a_load_reg_ref(exprasmlist,OS_ADDR,tmpreg,href);
  179. cg.free_scratch_reg(exprasmlist,tmpreg);
  180. end
  181. else
  182. cg.a_paramaddr_ref(exprasmlist,left.location.reference,paralocdummy);
  183. location_release(exprasmlist,left.location);
  184. {$ifdef unused}
  185. if push_from_left_to_right then
  186. maybe_push_high;
  187. {$endif unused}
  188. end
  189. else
  190. begin
  191. tempdeftype:=resulttype.def.deftype;
  192. if tempdeftype=filedef then
  193. CGMessage(cg_e_file_must_call_by_reference);
  194. { open array must always push the address, this is needed to
  195. also push addr of small open arrays and with cdecl functions (PFV) }
  196. if (
  197. assigned(paraitem.paratype.def) and
  198. (is_open_array(paraitem.paratype.def) or
  199. is_array_of_const(paraitem.paratype.def))
  200. ) or
  201. (
  202. paramanager.push_addr_param(resulttype.def,calloption)
  203. ) then
  204. begin
  205. if not(left.location.loc in [LOC_CREFERENCE,LOC_REFERENCE]) then
  206. begin
  207. { allow passing nil to a procvardef (methodpointer) }
  208. if (left.nodetype=typeconvn) and
  209. (left.resulttype.def.deftype=procvardef) and
  210. (ttypeconvnode(left).left.nodetype=niln) then
  211. begin
  212. tg.GetTemp(exprasmlist,tcgsize2size[left.location.size],tt_normal,href);
  213. cg.a_load_loc_ref(exprasmlist,left.location,href);
  214. location_reset(left.location,LOC_REFERENCE,left.location.size);
  215. left.location.reference:=href;
  216. end
  217. else
  218. internalerror(200204011);
  219. end;
  220. {$ifdef unused}
  221. if not push_from_left_to_right then
  222. {$endif unused}
  223. maybe_push_high;
  224. inc(pushedparasize,4);
  225. if calloption=pocall_inline then
  226. begin
  227. tmpreg:=cg.get_scratch_reg_address(exprasmlist);
  228. cg.a_loadaddr_ref_reg(exprasmlist,left.location.reference,tmpreg);
  229. reference_reset_base(href,procinfo.framepointer,para_offset-pushedparasize);
  230. cg.a_load_reg_ref(exprasmlist,OS_ADDR,tmpreg,href);
  231. cg.free_scratch_reg(exprasmlist,tmpreg);
  232. end
  233. else
  234. cg.a_paramaddr_ref(exprasmlist,left.location.reference,paralocdummy);
  235. location_release(exprasmlist,left.location);
  236. {$ifdef unused}
  237. if push_from_left_to_right then
  238. maybe_push_high;
  239. {$endif unused}
  240. end
  241. else
  242. begin
  243. push_value_para(left,calloption,
  244. para_offset,para_alignment,paralocdummy);
  245. end;
  246. end;
  247. truelabel:=otlabel;
  248. falselabel:=oflabel;
  249. { push from right to left }
  250. if not push_from_left_to_right and assigned(right) then
  251. begin
  252. if (nf_varargs_para in flags) then
  253. tcallparanode(right).secondcallparan(push_from_left_to_right,
  254. calloption,para_alignment,para_offset)
  255. else
  256. tcallparanode(right).secondcallparan(push_from_left_to_right,
  257. calloption,para_alignment,para_offset);
  258. end;
  259. end;
  260. {*****************************************************************************
  261. TI386CALLNODE
  262. *****************************************************************************}
  263. procedure ti386callnode.pass_2;
  264. var
  265. regs_to_push_int : Tsupregset;
  266. regs_to_push_other : tregisterset;
  267. unusedstate: pointer;
  268. pushed : tpushedsaved;
  269. pushed_int : tpushedsavedint;
  270. tmpreg : tregister;
  271. hregister : tregister;
  272. oldpushedparasize : longint;
  273. { true if ESI must be loaded again after the subroutine }
  274. loadesi : boolean;
  275. { true if a virtual method must be called directly }
  276. no_virtual_call : boolean;
  277. { true if we produce a con- or destrutor in a call }
  278. is_con_or_destructor : boolean;
  279. { true if a constructor is called again }
  280. extended_new : boolean;
  281. { adress returned from an I/O-error }
  282. iolabel : tasmlabel;
  283. { lexlevel count }
  284. i : longint;
  285. { help reference pointer }
  286. href : treference;
  287. hrefvmt : treference;
  288. hp : tnode;
  289. pp : tbinarynode;
  290. params : tnode;
  291. inlined : boolean;
  292. inlinecode : tprocinlinenode;
  293. store_parast_fixup,
  294. para_alignment,
  295. para_offset : longint;
  296. cgsize : tcgsize;
  297. { instruction for alignement correction }
  298. { corr : paicpu;}
  299. { we must pop this size also after !! }
  300. { must_pop : boolean; }
  301. pop_size : longint;
  302. {$ifdef OPTALIGN}
  303. pop_esp : boolean;
  304. push_size : longint;
  305. {$endif OPTALIGN}
  306. pop_allowed : boolean;
  307. release_tmpreg : boolean;
  308. constructorfailed : tasmlabel;
  309. returnref,
  310. pararef : treference;
  311. r,r2,rsp:Tregister;
  312. label
  313. dont_call;
  314. begin
  315. rsp.enum:=R_INTREGISTER;
  316. rsp.number:=NR_ESP;
  317. extended_new:=false;
  318. iolabel:=nil;
  319. inlinecode:=nil;
  320. inlined:=false;
  321. loadesi:=true;
  322. no_virtual_call:=false;
  323. rg.saveunusedstate(unusedstate);
  324. { if we allocate the temp. location for ansi- or widestrings }
  325. { already here, we avoid later a push/pop }
  326. if is_widestring(resulttype.def) then
  327. begin
  328. tg.GetTemp(exprasmlist,pointer_size,tt_widestring,refcountedtemp);
  329. cg.g_decrrefcount(exprasmlist,resulttype.def,refcountedtemp);
  330. end
  331. else if is_ansistring(resulttype.def) then
  332. begin
  333. tg.GetTemp(exprasmlist,pointer_size,tt_ansistring,refcountedtemp);
  334. cg.g_decrrefcount(exprasmlist,resulttype.def,refcountedtemp);
  335. end;
  336. if (procdefinition.proccalloption in [pocall_cdecl,pocall_cppdecl,pocall_stdcall]) then
  337. para_alignment:=4
  338. else
  339. para_alignment:=aktalignment.paraalign;
  340. if not assigned(procdefinition) then
  341. exit;
  342. { Deciding whether we may still need the parameters happens next (JM) }
  343. if assigned(left) then
  344. params:=left.getcopy
  345. else params := nil;
  346. if (procdefinition.proccalloption=pocall_inline) then
  347. begin
  348. inlined:=true;
  349. inlinecode:=tprocinlinenode(right);
  350. right:=nil;
  351. { set it to the same lexical level as the local symtable, becuase
  352. the para's are stored there }
  353. tprocdef(procdefinition).parast.symtablelevel:=aktprocdef.localst.symtablelevel;
  354. if assigned(params) then
  355. begin
  356. inlinecode.para_size:=tprocdef(procdefinition).para_size(para_alignment);
  357. tg.GetTemp(exprasmlist,inlinecode.para_size,tt_persistant,pararef);
  358. inlinecode.para_offset:=pararef.offset;
  359. end;
  360. store_parast_fixup:=tprocdef(procdefinition).parast.address_fixup;
  361. tprocdef(procdefinition).parast.address_fixup:=inlinecode.para_offset;
  362. {$ifdef extdebug}
  363. Comment(V_debug,
  364. 'inlined parasymtable is at offset '
  365. +tostr(tprocdef(procdefinition).parast.address_fixup));
  366. exprasmList.concat(tai_comment.Create(
  367. strpnew('inlined parasymtable is at offset '
  368. +tostr(tprocdef(procdefinition).parast.address_fixup))));
  369. {$endif extdebug}
  370. end;
  371. { only if no proc var }
  372. if inlined or
  373. not(assigned(right)) then
  374. is_con_or_destructor:=(procdefinition.proctypeoption in [potype_constructor,potype_destructor]);
  375. { proc variables destroy all registers }
  376. if (inlined or
  377. (right=nil)) and
  378. { virtual methods too }
  379. not(po_virtualmethod in procdefinition.procoptions) then
  380. begin
  381. if (cs_check_io in aktlocalswitches) and
  382. (po_iocheck in procdefinition.procoptions) and
  383. not(po_iocheck in aktprocdef.procoptions) then
  384. begin
  385. objectlibrary.getaddrlabel(iolabel);
  386. cg.a_label(exprasmlist,iolabel);
  387. end
  388. else
  389. iolabel:=nil;
  390. { save all used registers and possible registers
  391. used for the return value }
  392. regs_to_push_int := tprocdef(procdefinition).usedintregisters;
  393. regs_to_push_other := tprocdef(procdefinition).usedotherregisters;
  394. if (not is_void(resulttype.def)) and
  395. (not paramanager.ret_in_param(resulttype.def,procdefinition.proccalloption)) then
  396. begin
  397. include(regs_to_push_int,RS_ACCUMULATOR);
  398. if resulttype.def.size>sizeof(aword) then
  399. include(regs_to_push_int,RS_ACCUMULATORHIGH);
  400. end;
  401. rg.saveusedintregisters(exprasmlist,pushed_int,regs_to_push_int);
  402. rg.saveusedotherregisters(exprasmlist,pushed,regs_to_push_other);
  403. { give used registers through }
  404. rg.usedintinproc:=rg.usedintinproc + tprocdef(procdefinition).usedintregisters;
  405. rg.usedinproc:=rg.usedinproc + tprocdef(procdefinition).usedotherregisters;
  406. end
  407. else
  408. begin
  409. regs_to_push_int := all_intregisters;
  410. regs_to_push_other:=all_registers;
  411. rg.saveusedintregisters(exprasmlist,pushed_int,regs_to_push_int);
  412. rg.saveusedotherregisters(exprasmlist,pushed,regs_to_push_other);
  413. rg.usedintinproc:=all_intregisters;
  414. rg.usedinproc:=all_registers;
  415. { no IO check for methods and procedure variables }
  416. iolabel:=nil;
  417. end;
  418. { generate the code for the parameter and push them }
  419. oldpushedparasize:=pushedparasize;
  420. pushedparasize:=0;
  421. pop_size:=0;
  422. { no inc esp for inlined procedure
  423. and for objects constructors PM }
  424. if inlined or
  425. ((procdefinition.proctypeoption=potype_constructor) and
  426. { quick'n'dirty check if it is a class or an object }
  427. (resulttype.def.deftype=orddef)) then
  428. pop_allowed:=false
  429. else
  430. pop_allowed:=true;
  431. if pop_allowed then
  432. begin
  433. { Old pushedsize aligned on 4 ? }
  434. i:=oldpushedparasize and 3;
  435. if i>0 then
  436. inc(pop_size,4-i);
  437. { This parasize aligned on 4 ? }
  438. i:=procdefinition.para_size(para_alignment) and 3;
  439. if i>0 then
  440. inc(pop_size,4-i);
  441. { insert the opcode and update pushedparasize }
  442. { never push 4 or more !! }
  443. pop_size:=pop_size mod 4;
  444. if pop_size>0 then
  445. begin
  446. inc(pushedparasize,pop_size);
  447. emit_const_reg(A_SUB,S_L,pop_size,rsp);
  448. {$ifdef GDB}
  449. if (cs_debuginfo in aktmoduleswitches) and
  450. (exprasmList.first=exprasmList.last) then
  451. exprasmList.concat(Tai_force_line.Create);
  452. {$endif GDB}
  453. end;
  454. end;
  455. {$ifdef OPTALIGN}
  456. if pop_allowed and (cs_align in aktglobalswitches) then
  457. begin
  458. pop_esp:=true;
  459. push_size:=procdefinition.para_size(para_alignment);
  460. { !!!! here we have to take care of return type, self
  461. and nested procedures
  462. }
  463. inc(push_size,12);
  464. emit_reg_reg(A_MOV,S_L,rsp,R_EDI);
  465. if (push_size mod 8)=0 then
  466. emit_const_reg(A_AND,S_L,$fffffff8,rsp)
  467. else
  468. begin
  469. emit_const_reg(A_SUB,S_L,push_size,rsp);
  470. emit_const_reg(A_AND,S_L,$fffffff8,rsp);
  471. emit_const_reg(A_SUB,S_L,push_size,rsp);
  472. end;
  473. r.enum:=R_INTREGISTER;
  474. r.number:=R_EDI;
  475. emit_reg(A_PUSH,S_L,r);
  476. end
  477. else
  478. pop_esp:=false;
  479. {$endif OPTALIGN}
  480. { Push parameters }
  481. if assigned(params) then
  482. begin
  483. { be found elsewhere }
  484. if inlined then
  485. para_offset:=tprocdef(procdefinition).parast.address_fixup+
  486. tprocdef(procdefinition).parast.datasize
  487. else
  488. para_offset:=0;
  489. if not(inlined) and
  490. assigned(right) then
  491. tcallparanode(params).secondcallparan(
  492. { TParaItem(tabstractprocdef(right.resulttype.def).Para.first), }
  493. (po_leftright in procdefinition.procoptions),procdefinition.proccalloption,
  494. para_alignment,para_offset)
  495. else
  496. tcallparanode(params).secondcallparan(
  497. { TParaItem(procdefinition.Para.first), }
  498. (po_leftright in procdefinition.procoptions),procdefinition.proccalloption,
  499. para_alignment,para_offset);
  500. end;
  501. { Allocate return value for inlined routines }
  502. if inlined and
  503. (resulttype.def.size>0) then
  504. begin
  505. tg.GetTemp(exprasmlist,Align(resulttype.def.size,aktalignment.paraalign),tt_persistant,returnref);
  506. inlinecode.retoffset:=returnref.offset;
  507. end;
  508. { Allocate return value when returned in argument }
  509. if paramanager.ret_in_param(resulttype.def,procdefinition.proccalloption) then
  510. begin
  511. if assigned(funcretrefnode) then
  512. begin
  513. secondpass(funcretrefnode);
  514. if codegenerror then
  515. exit;
  516. if (funcretrefnode.location.loc<>LOC_REFERENCE) then
  517. internalerror(200204246);
  518. funcretref:=funcretrefnode.location.reference;
  519. end
  520. else
  521. begin
  522. if inlined then
  523. begin
  524. tg.GetTemp(exprasmlist,resulttype.def.size,tt_persistant,funcretref);
  525. {$ifdef extdebug}
  526. Comment(V_debug,'function return value is at offset '
  527. +tostr(funcretref.offset));
  528. exprasmlist.concat(tai_comment.create(
  529. strpnew('function return value is at offset '
  530. +tostr(funcretref.offset))));
  531. {$endif extdebug}
  532. end
  533. else
  534. tg.GetTemp(exprasmlist,resulttype.def.size,tt_normal,funcretref);
  535. end;
  536. { This must not be counted for C code
  537. complex return address is removed from stack
  538. by function itself ! }
  539. {$ifdef OLD_C_STACK}
  540. inc(pushedparasize,4); { lets try without it PM }
  541. {$endif not OLD_C_STACK}
  542. if inlined then
  543. begin
  544. hregister:=cg.get_scratch_reg_address(exprasmlist);
  545. cg.a_loadaddr_ref_reg(exprasmlist,funcretref,hregister);
  546. reference_reset_base(href,procinfo.framepointer,inlinecode.retoffset);
  547. cg.a_load_reg_ref(exprasmlist,OS_ADDR,hregister,href);
  548. cg.free_scratch_reg(exprasmlist,hregister);
  549. end
  550. else
  551. cg.a_paramaddr_ref(exprasmlist,funcretref,paralocdummy);
  552. end;
  553. { procedure variable or normal function call ? }
  554. if inlined or
  555. (right=nil) then
  556. begin
  557. { Normal function call }
  558. { overloaded operator has no symtable }
  559. { push self }
  560. if assigned(symtableproc) and
  561. (symtableproc.symtabletype=withsymtable) then
  562. begin
  563. { dirty trick to avoid the secondcall below }
  564. methodpointer:=ccallparanode.create(nil,nil);
  565. location_reset(methodpointer.location,LOC_REGISTER,OS_ADDR);
  566. rg.getexplicitregisterint(exprasmlist,NR_ESI);
  567. methodpointer.location.register.enum:=R_INTREGISTER;
  568. methodpointer.location.register.number:=NR_SELF_POINTER_REG;
  569. { ARGHHH this is wrong !!!
  570. if we can init from base class for a child
  571. class that the wrong VMT will be
  572. transfered to constructor !! }
  573. methodpointer.resulttype:=
  574. twithnode(twithsymtable(symtableproc).withnode).left.resulttype;
  575. { make a reference }
  576. href:=twithnode(twithsymtable(symtableproc).withnode).withreference;
  577. r.enum:=R_INTREGISTER;
  578. r.number:=NR_SELF_POINTER_REG;
  579. if ((not(nf_islocal in twithnode(twithsymtable(symtableproc).withnode).flags)) and
  580. (not twithsymtable(symtableproc).direct_with)) or
  581. is_class_or_interface(methodpointer.resulttype.def) then
  582. cg.a_load_ref_reg(exprasmlist,OS_ADDR,href,r)
  583. else
  584. cg.a_loadaddr_ref_reg(exprasmlist,href,r);
  585. end;
  586. { push self }
  587. if assigned(symtableproc) and
  588. ((symtableproc.symtabletype=objectsymtable) or
  589. (symtableproc.symtabletype=withsymtable)) then
  590. begin
  591. if assigned(methodpointer) then
  592. begin
  593. {
  594. if methodpointer^.resulttype.def=classrefdef then
  595. begin
  596. two possibilities:
  597. 1. constructor
  598. 2. class method
  599. end
  600. else }
  601. begin
  602. case methodpointer.nodetype of
  603. typen:
  604. begin
  605. { direct call to inherited method }
  606. if (po_abstractmethod in procdefinition.procoptions) then
  607. begin
  608. CGMessage(cg_e_cant_call_abstract_method);
  609. goto dont_call;
  610. end;
  611. { generate no virtual call }
  612. no_virtual_call:=true;
  613. if (sp_static in symtableprocentry.symoptions) then
  614. begin
  615. { well lets put the VMT address directly into ESI }
  616. { it is kind of dirty but that is the simplest }
  617. { way to accept virtual static functions (PM) }
  618. loadesi:=true;
  619. { if no VMT just use $0 bug0214 PM }
  620. rg.getexplicitregisterint(exprasmlist,NR_ESI);
  621. r.enum:=R_INTREGISTER;
  622. r.number:=NR_SELF_POINTER_REG;
  623. if not(oo_has_vmt in tobjectdef(methodpointer.resulttype.def).objectoptions) then
  624. cg.a_load_const_reg(exprasmlist,OS_ADDR,0,r)
  625. else
  626. begin
  627. reference_reset_symbol(href,objectlibrary.newasmsymbol(tobjectdef(methodpointer.resulttype.def).vmt_mangledname),0);
  628. cg.a_loadaddr_ref_reg(exprasmlist,href,r);
  629. end;
  630. { emit_reg(A_PUSH,S_L,R_ESI);
  631. this is done below !! }
  632. end
  633. else
  634. { this is a member call, so ESI isn't modfied }
  635. loadesi:=false;
  636. { a class destructor needs a flag }
  637. r.enum:=R_INTREGISTER;
  638. r.number:=NR_SELF_POINTER_REG;
  639. if is_class(tobjectdef(methodpointer.resulttype.def)) and
  640. (procdefinition.proctypeoption=potype_destructor) then
  641. begin
  642. cg.a_param_const(exprasmlist,OS_ADDR,0,paramanager.getintparaloc(2));
  643. cg.a_param_reg(exprasmlist,OS_ADDR,r,paramanager.getintparaloc(1));
  644. end;
  645. r.enum:=R_INTREGISTER;
  646. r.number:=NR_SELF_POINTER_REG;
  647. if not(is_con_or_destructor and
  648. is_class(methodpointer.resulttype.def) and
  649. (procdefinition.proctypeoption in [potype_constructor,potype_destructor])
  650. ) then
  651. cg.a_param_reg(exprasmlist,OS_ADDR,r,paramanager.getintparaloc(1));
  652. { if an inherited con- or destructor should be }
  653. { called in a con- or destructor then a warning }
  654. { will be made }
  655. { con- and destructors need a pointer to the vmt }
  656. if is_con_or_destructor and
  657. is_object(methodpointer.resulttype.def) and
  658. assigned(aktprocdef) then
  659. begin
  660. if not(aktprocdef.proctypeoption in
  661. [potype_constructor,potype_destructor]) then
  662. CGMessage(cg_w_member_cd_call_from_method);
  663. end;
  664. { class destructors get there flag above }
  665. { constructor flags ? }
  666. if is_con_or_destructor and
  667. not(
  668. is_class(methodpointer.resulttype.def) and
  669. assigned(aktprocdef) and
  670. (aktprocdef.proctypeoption=potype_destructor)) then
  671. begin
  672. { a constructor needs also a flag }
  673. if is_class(methodpointer.resulttype.def) then
  674. cg.a_param_const(exprasmlist,OS_ADDR,0,paramanager.getintparaloc(2));
  675. cg.a_param_const(exprasmlist,OS_ADDR,0,paramanager.getintparaloc(1));
  676. end;
  677. end;
  678. hnewn:
  679. begin
  680. { extended syntax of new }
  681. { ESI must be zero }
  682. r.enum:=R_INTREGISTER;
  683. r.number:=NR_SELF_POINTER_REG;
  684. rg.getexplicitregisterint(exprasmlist,NR_ESI);
  685. cg.a_load_const_reg(exprasmlist,OS_ADDR,0,r);
  686. cg.a_param_reg(exprasmlist,OS_ADDR,r,paramanager.getintparaloc(2));
  687. { insert the vmt }
  688. reference_reset_symbol(href,objectlibrary.newasmsymbol(tobjectdef(methodpointer.resulttype.def).vmt_mangledname),0);
  689. cg.a_paramaddr_ref(exprasmlist,href,paramanager.getintparaloc(1));
  690. extended_new:=true;
  691. end;
  692. hdisposen:
  693. begin
  694. secondpass(methodpointer);
  695. { destructor with extended syntax called from dispose }
  696. { hdisposen always deliver LOC_REFERENCE }
  697. r.enum:=R_INTREGISTER;
  698. r.number:=NR_SELF_POINTER_REG;
  699. rg.getexplicitregisterint(exprasmlist,NR_ESI);
  700. emit_ref_reg(A_LEA,S_L,methodpointer.location.reference,r);
  701. reference_release(exprasmlist,methodpointer.location.reference);
  702. cg.a_param_reg(exprasmlist,OS_ADDR,r,paramanager.getintparaloc(2));
  703. reference_reset_symbol(href,objectlibrary.newasmsymbol(tobjectdef(methodpointer.resulttype.def).vmt_mangledname),0);
  704. cg.a_paramaddr_ref(exprasmlist,href,paramanager.getintparaloc(1));
  705. end;
  706. else
  707. begin
  708. { call to an instance member }
  709. if (symtableproc.symtabletype<>withsymtable) then
  710. begin
  711. r.enum:=R_INTREGISTER;
  712. r.number:=NR_SELF_POINTER_REG;
  713. secondpass(methodpointer);
  714. rg.getexplicitregisterint(exprasmlist,NR_ESI);
  715. case methodpointer.location.loc of
  716. LOC_CREGISTER,
  717. LOC_REGISTER:
  718. begin
  719. cg.a_load_reg_reg(exprasmlist,OS_ADDR,OS_ADDR,methodpointer.location.register,r);
  720. rg.ungetregisterint(exprasmlist,methodpointer.location.register);
  721. end;
  722. else
  723. begin
  724. if (methodpointer.resulttype.def.deftype=classrefdef) or
  725. is_class_or_interface(methodpointer.resulttype.def) then
  726. cg.a_load_ref_reg(exprasmlist,OS_ADDR,methodpointer.location.reference,r)
  727. else
  728. cg.a_loadaddr_ref_reg(exprasmlist,methodpointer.location.reference,r);
  729. reference_release(exprasmlist,methodpointer.location.reference);
  730. end;
  731. end;
  732. end;
  733. { when calling a class method, we have to load ESI with the VMT !
  734. But, not for a class method via self }
  735. if not(po_containsself in procdefinition.procoptions) then
  736. begin
  737. if (po_staticmethod in procdefinition.procoptions) or
  738. ((po_classmethod in procdefinition.procoptions) and
  739. not(methodpointer.resulttype.def.deftype=classrefdef)) then
  740. begin
  741. r.enum:=R_INTREGISTER;
  742. r.number:=NR_SELF_POINTER_REG;
  743. rg.getexplicitregisterint(exprasmlist,NR_ESI);
  744. if not(oo_has_vmt in tprocdef(procdefinition)._class.objectoptions) then
  745. cg.a_load_const_reg(exprasmlist,OS_ADDR,0,r)
  746. else
  747. begin
  748. { class method and static methods needs current VMT }
  749. cg.g_maybe_testself(exprasmlist,r);
  750. reference_reset_base(href,r,tprocdef(procdefinition)._class.vmt_offset);
  751. cg.a_load_ref_reg(exprasmlist,OS_ADDR,href,r);
  752. cg.g_maybe_testvmt(exprasmlist,r,tprocdef(procdefinition)._class);
  753. end;
  754. end;
  755. { direct call to destructor: remove data }
  756. if (procdefinition.proctypeoption=potype_destructor) and
  757. is_class(methodpointer.resulttype.def) then
  758. cg.a_param_const(exprasmlist,OS_INT,1,paramanager.getintparaloc(1));
  759. { direct call to class constructor, don't allocate memory }
  760. if (procdefinition.proctypeoption=potype_constructor) and
  761. is_class(methodpointer.resulttype.def) then
  762. begin
  763. cg.a_param_const(exprasmlist,OS_INT,0,paramanager.getintparaloc(2));
  764. cg.a_param_const(exprasmlist,OS_INT,0,paramanager.getintparaloc(1));
  765. end
  766. else
  767. begin
  768. { constructor call via classreference => allocate memory }
  769. if (procdefinition.proctypeoption=potype_constructor) and
  770. (methodpointer.resulttype.def.deftype=classrefdef) and
  771. is_class(tclassrefdef(methodpointer.resulttype.def).pointertype.def) then
  772. cg.a_param_const(exprasmlist,OS_INT,1,paramanager.getintparaloc(1));
  773. r.enum:=R_INTREGISTER;
  774. r.number:=NR_SELF_POINTER_REG;
  775. cg.a_param_reg(exprasmlist,OS_ADDR,r,paramanager.getintparaloc(1));
  776. end;
  777. end;
  778. if is_con_or_destructor then
  779. begin
  780. { classes don't get a VMT pointer pushed }
  781. if is_object(methodpointer.resulttype.def) then
  782. begin
  783. if (procdefinition.proctypeoption=potype_constructor) then
  784. begin
  785. { it's no bad idea, to insert the VMT }
  786. reference_reset_symbol(href,objectlibrary.newasmsymbol(
  787. tobjectdef(methodpointer.resulttype.def).vmt_mangledname),0);
  788. cg.a_paramaddr_ref(exprasmlist,href,paramanager.getintparaloc(1));
  789. end
  790. { destructors haven't to dispose the instance, if this is }
  791. { a direct call }
  792. else
  793. cg.a_param_const(exprasmlist,OS_INT,0,paramanager.getintparaloc(1));
  794. end;
  795. end;
  796. end;
  797. end;
  798. end;
  799. end
  800. else
  801. begin
  802. if (
  803. (po_classmethod in procdefinition.procoptions) and
  804. not(assigned(aktprocdef) and
  805. (po_classmethod in aktprocdef.procoptions))
  806. ) or
  807. (
  808. (po_staticmethod in procdefinition.procoptions) and
  809. not(assigned(aktprocdef) and
  810. (po_staticmethod in aktprocdef.procoptions))
  811. ) then
  812. begin
  813. r.enum:=R_INTREGISTER;
  814. r.number:=NR_SELF_POINTER_REG;
  815. rg.getexplicitregisterint(exprasmlist,NR_ESI);
  816. if not(oo_has_vmt in tprocdef(procdefinition)._class.objectoptions) then
  817. cg.a_load_const_reg(exprasmlist,OS_ADDR,0,r)
  818. else
  819. begin
  820. { class method and static methods needs current VMT }
  821. cg.g_maybe_testself(exprasmlist,r);
  822. reference_reset_base(href,r,tprocdef(procdefinition)._class.vmt_offset);
  823. cg.a_load_ref_reg(exprasmlist,OS_ADDR,href,r);
  824. cg.g_maybe_testvmt(exprasmlist,r,tprocdef(procdefinition)._class);
  825. end;
  826. end
  827. else
  828. begin
  829. { member call, ESI isn't modified }
  830. loadesi:=false;
  831. end;
  832. { direct call to destructor: don't remove data! }
  833. if is_class(procinfo._class) then
  834. begin
  835. r.enum:=R_INTREGISTER;
  836. r.number:=NR_SELF_POINTER_REG;
  837. if (procdefinition.proctypeoption=potype_destructor) then
  838. begin
  839. cg.a_param_const(exprasmlist,OS_INT,0,paramanager.getintparaloc(2));
  840. cg.a_param_reg(exprasmlist,OS_ADDR,r,paramanager.getintparaloc(1));
  841. end
  842. else if (procdefinition.proctypeoption=potype_constructor) then
  843. begin
  844. cg.a_param_const(exprasmlist,OS_INT,0,paramanager.getintparaloc(2));
  845. cg.a_param_const(exprasmlist,OS_INT,0,paramanager.getintparaloc(1));
  846. end
  847. else
  848. cg.a_param_reg(exprasmlist,OS_ADDR,r,paramanager.getintparaloc(1));
  849. end
  850. else if is_object(procinfo._class) then
  851. begin
  852. r.enum:=R_INTREGISTER;
  853. r.number:=NR_SELF_POINTER_REG;
  854. cg.a_param_reg(exprasmlist,OS_ADDR,r,paramanager.getintparaloc(1));
  855. if is_con_or_destructor then
  856. begin
  857. (*
  858. The constructor/destructor is called from the class
  859. itself, no need to push the VMT to create a new object
  860. if (procdefinition.proctypeoption=potype_constructor) then
  861. begin
  862. { it's no bad idea, to insert the VMT }
  863. reference_reset_symbol(href,objectlibrary.newasmsymbol(procinfo._class.vmt_mangledname),0);
  864. cg.a_paramaddr_ref(exprasmlist,href,paramanager.getintparaloc(1));
  865. end
  866. { destructors haven't to dispose the instance, if this is }
  867. { a direct call }
  868. else
  869. *)
  870. cg.a_param_const(exprasmlist,OS_INT,0,paramanager.getintparaloc(1));
  871. end;
  872. end
  873. else
  874. Internalerror(200006165);
  875. end;
  876. end;
  877. { call to BeforeDestruction? }
  878. if (procdefinition.proctypeoption=potype_destructor) and
  879. assigned(methodpointer) and
  880. (methodpointer.nodetype<>typen) and
  881. is_class(tobjectdef(methodpointer.resulttype.def)) and
  882. (inlined or
  883. (right=nil)) then
  884. begin
  885. r.enum:=R_INTREGISTER;
  886. r.number:=NR_SELF_POINTER_REG;
  887. cg.a_param_reg(exprasmlist,OS_ADDR,r,paramanager.getintparaloc(1));
  888. reference_reset_base(href,r,0);
  889. tmpreg:=cg.get_scratch_reg_address(exprasmlist);
  890. cg.a_load_ref_reg(exprasmlist,OS_ADDR,href,tmpreg);
  891. reference_reset_base(href,tmpreg,72);
  892. cg.a_call_ref(exprasmlist,href);
  893. cg.free_scratch_reg(exprasmlist,tmpreg);
  894. end;
  895. { push base pointer ?}
  896. { never when inlining, since if necessary, the base pointer }
  897. { can/will be gottten from the current procedure's symtable }
  898. { (JM) }
  899. if not inlined then
  900. if (lexlevel>=normal_function_level) and assigned(tprocdef(procdefinition).parast) and
  901. ((tprocdef(procdefinition).parast.symtablelevel)>normal_function_level) then
  902. begin
  903. { if we call a nested function in a method, we must }
  904. { push also SELF! }
  905. { THAT'S NOT TRUE, we have to load ESI via frame pointer }
  906. { access }
  907. {
  908. begin
  909. loadesi:=false;
  910. emit_reg(A_PUSH,S_L,R_ESI);
  911. end;
  912. }
  913. if lexlevel=(tprocdef(procdefinition).parast.symtablelevel) then
  914. begin
  915. reference_reset_base(href,procinfo.framepointer,procinfo.framepointer_offset);
  916. cg.a_param_ref(exprasmlist,OS_ADDR,href,paralocdummy);
  917. end
  918. { this is only true if the difference is one !!
  919. but it cannot be more !! }
  920. else if (lexlevel=(tprocdef(procdefinition).parast.symtablelevel)-1) then
  921. begin
  922. cg.a_param_reg(exprasmlist,OS_ADDR,procinfo.framepointer,paralocdummy);
  923. end
  924. else if (lexlevel>(tprocdef(procdefinition).parast.symtablelevel)) then
  925. begin
  926. hregister:=rg.getregisterint(exprasmlist,OS_ADDR);
  927. reference_reset_base(href,procinfo.framepointer,procinfo.framepointer_offset);
  928. cg.a_load_ref_reg(exprasmlist,OS_ADDR,href,hregister);
  929. for i:=(tprocdef(procdefinition).parast.symtablelevel) to lexlevel-1 do
  930. begin
  931. {we should get the correct frame_pointer_offset at each level
  932. how can we do this !!! }
  933. reference_reset_base(href,hregister,procinfo.framepointer_offset);
  934. cg.a_load_ref_reg(exprasmlist,OS_ADDR,href,hregister);
  935. end;
  936. cg.a_param_reg(exprasmlist,OS_ADDR,hregister,paralocdummy);
  937. rg.ungetregisterint(exprasmlist,hregister);
  938. end
  939. else
  940. internalerror(25000);
  941. end;
  942. rg.saveintregvars(exprasmlist,regs_to_push_int);
  943. if (po_virtualmethod in procdefinition.procoptions) and
  944. not(no_virtual_call) then
  945. begin
  946. { static functions contain the vmt_address in ESI }
  947. { also class methods }
  948. { Here it is quite tricky because it also depends }
  949. { on the methodpointer PM }
  950. release_tmpreg:=false;
  951. rg.getexplicitregisterint(exprasmlist,NR_ESI);
  952. r.enum:=R_INTREGISTER;
  953. r.number:=NR_SELF_POINTER_REG;
  954. if assigned(aktprocdef) then
  955. begin
  956. if (((sp_static in aktprocdef.procsym.symoptions) or
  957. (po_classmethod in aktprocdef.procoptions)) and
  958. ((methodpointer=nil) or (methodpointer.nodetype=typen)))
  959. or
  960. (po_staticmethod in procdefinition.procoptions) or
  961. ((procdefinition.proctypeoption=potype_constructor) and
  962. { esi contains the vmt if we call a constructor via a class ref }
  963. assigned(methodpointer) and
  964. (methodpointer.resulttype.def.deftype=classrefdef)
  965. ) or
  966. { is_interface(tprocdef(procdefinition)._class) or }
  967. { ESI is loaded earlier }
  968. (po_classmethod in procdefinition.procoptions) then
  969. begin
  970. reference_reset_base(href,r,0);
  971. end
  972. else
  973. begin
  974. cg.g_maybe_testself(exprasmlist,r);
  975. { this is one point where we need vmt_offset (PM) }
  976. reference_reset_base(href,r,tprocdef(procdefinition)._class.vmt_offset);
  977. tmpreg:=cg.get_scratch_reg_address(exprasmlist);
  978. cg.a_load_ref_reg(exprasmlist,OS_ADDR,href,tmpreg);
  979. reference_reset_base(href,tmpreg,0);
  980. release_tmpreg:=true;
  981. end;
  982. end
  983. else
  984. { aktprocdef should be assigned, also in main program }
  985. internalerror(12345);
  986. if tprocdef(procdefinition).extnumber=-1 then
  987. internalerror(44584);
  988. href.offset:=tprocdef(procdefinition)._class.vmtmethodoffset(tprocdef(procdefinition).extnumber);
  989. if not(is_interface(tprocdef(procdefinition)._class)) and
  990. not(is_cppclass(tprocdef(procdefinition)._class)) then
  991. cg.g_maybe_testvmt(exprasmlist,href.base,tprocdef(procdefinition)._class);
  992. cg.a_call_ref(exprasmlist,href);
  993. if release_tmpreg then
  994. cg.free_scratch_reg(exprasmlist,tmpreg);
  995. end
  996. else if not inlined then
  997. begin
  998. { We can call interrupts from within the smae code
  999. by just pushing the flags and CS PM }
  1000. if (po_interrupt in procdefinition.procoptions) then
  1001. begin
  1002. emit_none(A_PUSHF,S_L);
  1003. r.enum:=R_INTREGISTER;
  1004. r.number:=NR_CS;
  1005. emit_reg(A_PUSH,S_L,r);
  1006. end;
  1007. cg.a_call_name(exprasmlist,tprocdef(procdefinition).mangledname);
  1008. end
  1009. else { inlined proc }
  1010. { inlined code is in inlinecode }
  1011. begin
  1012. { process the inlinecode }
  1013. secondpass(tnode(inlinecode));
  1014. { free the args }
  1015. if tprocdef(procdefinition).parast.datasize>0 then
  1016. tg.UnGetTemp(exprasmlist,pararef);
  1017. end;
  1018. end
  1019. else
  1020. { now procedure variable case }
  1021. begin
  1022. secondpass(right);
  1023. if (po_interrupt in procdefinition.procoptions) then
  1024. begin
  1025. emit_none(A_PUSHF,S_L);
  1026. r.enum:=R_INTREGISTER;
  1027. r.number:=NR_CS;
  1028. emit_reg(A_PUSH,S_L,r);
  1029. end;
  1030. { procedure of object? }
  1031. if (po_methodpointer in procdefinition.procoptions) then
  1032. begin
  1033. { method pointer can't be in a register }
  1034. hregister.enum:=R_INTREGISTER;
  1035. hregister.number:=NR_NO;
  1036. { do some hacking if we call a method pointer }
  1037. { which is a class member }
  1038. { else ESI is overwritten ! }
  1039. if (right.location.reference.base.number=NR_ESI) or
  1040. (right.location.reference.index.number=NR_ESI) then
  1041. begin
  1042. reference_release(exprasmlist,right.location.reference);
  1043. hregister:=cg.get_scratch_reg_address(exprasmlist);
  1044. cg.a_load_ref_reg(exprasmlist,OS_ADDR,right.location.reference,hregister);
  1045. end;
  1046. { load self, but not if it's already explicitly pushed }
  1047. if not(po_containsself in procdefinition.procoptions) then
  1048. begin
  1049. { load ESI }
  1050. href:=right.location.reference;
  1051. inc(href.offset,4);
  1052. r.enum:=R_INTREGISTER;
  1053. r.number:=NR_SELF_POINTER_REG;
  1054. rg.getexplicitregisterint(exprasmlist,NR_ESI);
  1055. cg.a_load_ref_reg(exprasmlist,OS_ADDR,href,r);
  1056. { push self pointer }
  1057. cg.a_param_reg(exprasmlist,OS_ADDR,r,paralocdummy);
  1058. end;
  1059. rg.saveintregvars(exprasmlist,ALL_INTREGISTERS);
  1060. rg.saveotherregvars(exprasmlist,ALL_REGISTERS);
  1061. if hregister.number<>NR_NO then
  1062. cg.a_call_reg(exprasmlist,hregister)
  1063. else
  1064. cg.a_call_ref(exprasmlist,right.location.reference);
  1065. if hregister.number<>NR_NO then
  1066. cg.free_scratch_reg(exprasmlist,hregister);
  1067. reference_release(exprasmlist,right.location.reference);
  1068. tg.Ungetiftemp(exprasmlist,right.location.reference);
  1069. end
  1070. else
  1071. begin
  1072. rg.saveintregvars(exprasmlist,ALL_INTREGISTERS);
  1073. rg.saveotherregvars(exprasmlist,ALL_REGISTERS);
  1074. cg.a_call_loc(exprasmlist,right.location);
  1075. location_release(exprasmlist,right.location);
  1076. location_freetemp(exprasmlist,right.location);
  1077. end;
  1078. end;
  1079. { this was only for normal functions
  1080. displaced here so we also get
  1081. it to work for procvars PM }
  1082. if (not inlined) and (po_clearstack in procdefinition.procoptions) then
  1083. begin
  1084. { we also add the pop_size which is included in pushedparasize }
  1085. pop_size:=0;
  1086. { better than an add on all processors }
  1087. if pushedparasize=4 then
  1088. begin
  1089. r.enum:=R_INTREGISTER;
  1090. r.number:=NR_EDI;
  1091. rg.getexplicitregisterint(exprasmlist,NR_EDI);
  1092. emit_reg(A_POP,S_L,r);
  1093. rg.ungetregisterint(exprasmlist,r);
  1094. end
  1095. { the pentium has two pipes and pop reg is pairable }
  1096. { but the registers must be different! }
  1097. else if (pushedparasize=8) and
  1098. not(cs_littlesize in aktglobalswitches) and
  1099. (aktoptprocessor=ClassP5) and
  1100. (procinfo._class=nil) then
  1101. begin
  1102. rg.getexplicitregisterint(exprasmlist,NR_EDI);
  1103. r.enum:=R_INTREGISTER;
  1104. r.number:=NR_EDI;
  1105. emit_reg(A_POP,S_L,r);
  1106. rg.ungetregisterint(exprasmlist,r);
  1107. r.number:=NR_ESI;
  1108. exprasmList.concat(tai_regalloc.Alloc(r));
  1109. emit_reg(A_POP,S_L,r);
  1110. exprasmList.concat(tai_regalloc.DeAlloc(r));
  1111. end
  1112. else if pushedparasize<>0 then
  1113. emit_const_reg(A_ADD,S_L,pushedparasize,rsp);
  1114. end;
  1115. {$ifdef OPTALIGN}
  1116. if pop_esp then
  1117. emit_reg(A_POP,S_L,rsp);
  1118. {$endif OPTALIGN}
  1119. dont_call:
  1120. pushedparasize:=oldpushedparasize;
  1121. rg.restoreunusedstate(unusedstate);
  1122. {$ifdef TEMPREGDEBUG}
  1123. testregisters32;
  1124. {$endif TEMPREGDEBUG}
  1125. { a constructor could be a function with boolean result }
  1126. { if calling constructor called fail we
  1127. must jump directly to quickexitlabel PM
  1128. but only if it is a call of an inherited constructor }
  1129. if (inlined or
  1130. (right=nil)) and
  1131. (procdefinition.proctypeoption=potype_constructor) and
  1132. assigned(methodpointer) and
  1133. (methodpointer.nodetype=typen) and
  1134. (aktprocdef.proctypeoption=potype_constructor) then
  1135. begin
  1136. emitjmp(C_Z,faillabel);
  1137. {$ifdef TEST_GENERIC}
  1138. { should be moved to generic version! }
  1139. reference_reset_base(href, procinfo.framepointer,procinfo.selfpointer_offset);
  1140. cg.a_load_ref_reg(exprasmlist, OS_ADDR, href, SELF_POINTER_REG);
  1141. {$endif}
  1142. end;
  1143. { call to AfterConstruction? }
  1144. if is_class(resulttype.def) and
  1145. (inlined or
  1146. (right=nil)) and
  1147. (procdefinition.proctypeoption=potype_constructor) and
  1148. assigned(methodpointer) and
  1149. (methodpointer.nodetype<>typen) then
  1150. begin
  1151. r.enum:=R_INTREGISTER;
  1152. r.number:=NR_ACCUMULATOR;
  1153. r2.enum:=R_INTREGISTER;
  1154. r2.number:=NR_SELF_POINTER_REG;
  1155. objectlibrary.getlabel(constructorfailed);
  1156. emitjmp(C_Z,constructorfailed);
  1157. cg.a_param_reg(exprasmlist,OS_ADDR,r2,paramanager.getintparaloc(1));
  1158. reference_reset_base(href,r2,0);
  1159. tmpreg:=cg.get_scratch_reg_address(exprasmlist);
  1160. cg.a_load_ref_reg(exprasmlist,OS_ADDR,href,tmpreg);
  1161. reference_reset_base(href,tmpreg,68);
  1162. cg.a_call_ref(exprasmlist,href);
  1163. cg.free_scratch_reg(exprasmlist,tmpreg);
  1164. exprasmList.concat(tai_regalloc.Alloc(r));
  1165. cg.a_label(exprasmlist,constructorfailed);
  1166. cg.a_load_reg_reg(exprasmlist,OS_ADDR,OS_ADDR,r2,r);
  1167. end;
  1168. { handle function results }
  1169. if (not is_void(resulttype.def)) then
  1170. handle_return_value(inlined,extended_new);
  1171. { perhaps i/o check ? }
  1172. if iolabel<>nil then
  1173. begin
  1174. reference_reset_symbol(href,iolabel,0);
  1175. cg.a_paramaddr_ref(exprasmlist,href,paramanager.getintparaloc(1));
  1176. cg.a_call_name(exprasmlist,'FPC_IOCHECK');
  1177. end;
  1178. if pop_size>0 then
  1179. emit_const_reg(A_ADD,S_L,pop_size,rsp);
  1180. { restore registers }
  1181. rg.restoreusedotherregisters(exprasmlist,pushed);
  1182. rg.restoreusedintregisters(exprasmlist,pushed_int);
  1183. { at last, restore instance pointer (SELF) }
  1184. if loadesi then
  1185. cg.g_maybe_loadself(exprasmlist);
  1186. pp:=tbinarynode(params);
  1187. while assigned(pp) do
  1188. begin
  1189. if assigned(pp.left) then
  1190. begin
  1191. location_freetemp(exprasmlist,pp.left.location);
  1192. { process also all nodes of an array of const }
  1193. if pp.left.nodetype=arrayconstructorn then
  1194. begin
  1195. if assigned(tarrayconstructornode(pp.left).left) then
  1196. begin
  1197. hp:=pp.left;
  1198. while assigned(hp) do
  1199. begin
  1200. location_freetemp(exprasmlist,tarrayconstructornode(hp).left.location);
  1201. hp:=tarrayconstructornode(hp).right;
  1202. end;
  1203. end;
  1204. end;
  1205. end;
  1206. pp:=tbinarynode(pp.right);
  1207. end;
  1208. if inlined then
  1209. begin
  1210. if (resulttype.def.size>0) then
  1211. tg.UnGetTemp(exprasmlist,returnref);
  1212. tprocdef(procdefinition).parast.address_fixup:=store_parast_fixup;
  1213. right:=inlinecode;
  1214. end;
  1215. if assigned(params) then
  1216. params.free;
  1217. { from now on the result can be freed normally }
  1218. if inlined and paramanager.ret_in_param(resulttype.def,procdefinition.proccalloption) then
  1219. tg.ChangeTempType(exprasmlist,funcretref,tt_normal);
  1220. { if return value is not used }
  1221. if (not(nf_return_value_used in flags)) and (not is_void(resulttype.def)) then
  1222. begin
  1223. if location.loc in [LOC_CREFERENCE,LOC_REFERENCE] then
  1224. begin
  1225. { data which must be finalized ? }
  1226. if (resulttype.def.needs_inittable) then
  1227. cg.g_finalize(exprasmlist,resulttype.def,location.reference,false);
  1228. { release unused temp }
  1229. tg.ungetiftemp(exprasmlist,location.reference)
  1230. end
  1231. else if location.loc=LOC_FPUREGISTER then
  1232. begin
  1233. { release FPU stack }
  1234. r.enum:=R_ST;
  1235. emit_reg(A_FSTP,S_NO,r);
  1236. {
  1237. dec(trgcpu(rg).fpuvaroffset);
  1238. do NOT decrement as the increment before
  1239. is not called for unused results PM }
  1240. end;
  1241. end;
  1242. end;
  1243. begin
  1244. ccallparanode:=ti386callparanode;
  1245. ccallnode:=ti386callnode;
  1246. end.
  1247. {
  1248. $Log$
  1249. Revision 1.84 2003-03-13 19:52:23 jonas
  1250. * and more new register allocator fixes (in the i386 code generator this
  1251. time). At least now the ppc cross compiler can compile the linux
  1252. system unit again, but I haven't tested it.
  1253. Revision 1.83 2003/03/06 11:35:50 daniel
  1254. * Fixed internalerror 7843 issue
  1255. Revision 1.82 2003/02/19 22:00:15 daniel
  1256. * Code generator converted to new register notation
  1257. - Horribily outdated todo.txt removed
  1258. Revision 1.81 2003/01/30 21:46:57 peter
  1259. * self fixes for static methods (merged)
  1260. Revision 1.80 2003/01/13 18:37:44 daniel
  1261. * Work on register conversion
  1262. Revision 1.79 2003/01/08 18:43:57 daniel
  1263. * Tregister changed into a record
  1264. Revision 1.78 2002/12/15 21:30:12 florian
  1265. * tcallnode.paraitem introduced, all references to defcoll removed
  1266. Revision 1.77 2002/11/27 20:05:06 peter
  1267. * cdecl array of const fixes
  1268. Revision 1.76 2002/11/25 17:43:26 peter
  1269. * splitted defbase in defutil,symutil,defcmp
  1270. * merged isconvertable and is_equal into compare_defs(_ext)
  1271. * made operator search faster by walking the list only once
  1272. Revision 1.75 2002/11/18 17:32:00 peter
  1273. * pass proccalloption to ret_in_xxx and push_xxx functions
  1274. Revision 1.74 2002/11/15 01:58:57 peter
  1275. * merged changes from 1.0.7 up to 04-11
  1276. - -V option for generating bug report tracing
  1277. - more tracing for option parsing
  1278. - errors for cdecl and high()
  1279. - win32 import stabs
  1280. - win32 records<=8 are returned in eax:edx (turned off by default)
  1281. - heaptrc update
  1282. - more info for temp management in .s file with EXTDEBUG
  1283. Revision 1.73 2002/10/05 12:43:29 carl
  1284. * fixes for Delphi 6 compilation
  1285. (warning : Some features do not work under Delphi)
  1286. Revision 1.72 2002/09/17 18:54:03 jonas
  1287. * a_load_reg_reg() now has two size parameters: source and dest. This
  1288. allows some optimizations on architectures that don't encode the
  1289. register size in the register name.
  1290. Revision 1.71 2002/09/16 19:07:37 peter
  1291. * push 0 instead of VMT when calling a constructor from a member
  1292. Revision 1.70 2002/09/07 15:25:10 peter
  1293. * old logs removed and tabs fixed
  1294. Revision 1.69 2002/09/01 18:43:27 peter
  1295. * include accumulator in regs_to_push list
  1296. Revision 1.68 2002/09/01 12:13:00 peter
  1297. * use a_call_reg
  1298. * ungetiftemp for procvar of object temp
  1299. Revision 1.67 2002/08/25 19:25:21 peter
  1300. * sym.insert_in_data removed
  1301. * symtable.insertvardata/insertconstdata added
  1302. * removed insert_in_data call from symtable.insert, it needs to be
  1303. called separatly. This allows to deref the address calculation
  1304. * procedures now calculate the parast addresses after the procedure
  1305. directives are parsed. This fixes the cdecl parast problem
  1306. * push_addr_param has an extra argument that specifies if cdecl is used
  1307. or not
  1308. Revision 1.66 2002/08/23 16:14:49 peter
  1309. * tempgen cleanup
  1310. * tt_noreuse temp type added that will be used in genentrycode
  1311. Revision 1.65 2002/08/18 20:06:30 peter
  1312. * inlining is now also allowed in interface
  1313. * renamed write/load to ppuwrite/ppuload
  1314. * tnode storing in ppu
  1315. * nld,ncon,nbas are already updated for storing in ppu
  1316. Revision 1.64 2002/08/17 09:23:45 florian
  1317. * first part of procinfo rewrite
  1318. Revision 1.63 2002/08/12 15:08:42 carl
  1319. + stab register indexes for powerpc (moved from gdb to cpubase)
  1320. + tprocessor enumeration moved to cpuinfo
  1321. + linker in target_info is now a class
  1322. * many many updates for m68k (will soon start to compile)
  1323. - removed some ifdef or correct them for correct cpu
  1324. Revision 1.62 2002/08/11 14:32:30 peter
  1325. * renamed current_library to objectlibrary
  1326. Revision 1.61 2002/08/11 13:24:16 peter
  1327. * saving of asmsymbols in ppu supported
  1328. * asmsymbollist global is removed and moved into a new class
  1329. tasmlibrarydata that will hold the info of a .a file which
  1330. corresponds with a single module. Added librarydata to tmodule
  1331. to keep the library info stored for the module. In the future the
  1332. objectfiles will also be stored to the tasmlibrarydata class
  1333. * all getlabel/newasmsymbol and friends are moved to the new class
  1334. Revision 1.60 2002/07/20 11:58:01 florian
  1335. * types.pas renamed to defbase.pas because D6 contains a types
  1336. unit so this would conflicts if D6 programms are compiled
  1337. + Willamette/SSE2 instructions to assembler added
  1338. Revision 1.59 2002/07/11 14:41:33 florian
  1339. * start of the new generic parameter handling
  1340. Revision 1.58 2002/07/07 09:52:34 florian
  1341. * powerpc target fixed, very simple units can be compiled
  1342. * some basic stuff for better callparanode handling, far from being finished
  1343. Revision 1.57 2002/07/06 20:27:26 carl
  1344. + generic set handling
  1345. Revision 1.56 2002/07/01 18:46:31 peter
  1346. * internal linker
  1347. * reorganized aasm layer
  1348. Revision 1.55 2002/07/01 16:23:56 peter
  1349. * cg64 patch
  1350. * basics for currency
  1351. * asnode updates for class and interface (not finished)
  1352. Revision 1.54 2002/05/20 13:30:40 carl
  1353. * bugfix of hdisponen (base must be set, not index)
  1354. * more portability fixes
  1355. Revision 1.53 2002/05/18 13:34:23 peter
  1356. * readded missing revisions
  1357. Revision 1.52 2002/05/16 19:46:51 carl
  1358. + defines.inc -> fpcdefs.inc to avoid conflicts if compiling by hand
  1359. + try to fix temp allocation (still in ifdef)
  1360. + generic constructor calls
  1361. + start of tassembler / tmodulebase class cleanup
  1362. Revision 1.50 2002/05/13 19:54:38 peter
  1363. * removed n386ld and n386util units
  1364. * maybe_save/maybe_restore added instead of the old maybe_push
  1365. Revision 1.49 2002/05/12 16:53:17 peter
  1366. * moved entry and exitcode to ncgutil and cgobj
  1367. * foreach gets extra argument for passing local data to the
  1368. iterator function
  1369. * -CR checks also class typecasts at runtime by changing them
  1370. into as
  1371. * fixed compiler to cycle with the -CR option
  1372. * fixed stabs with elf writer, finally the global variables can
  1373. be watched
  1374. * removed a lot of routines from cga unit and replaced them by
  1375. calls to cgobj
  1376. * u32bit-s32bit updates for and,or,xor nodes. When one element is
  1377. u32bit then the other is typecasted also to u32bit without giving
  1378. a rangecheck warning/error.
  1379. * fixed pascal calling method with reversing also the high tree in
  1380. the parast, detected by tcalcst3 test
  1381. }