cg386cal.pas 70 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607
  1. {
  2. $Id$
  3. Copyright (c) 1993-98 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 cg386cal;
  19. interface
  20. uses
  21. symtable,tree;
  22. procedure secondcallparan(var p : ptree;defcoll : pdefcoll;
  23. push_from_left_to_right,inlined : boolean;para_offset : longint);
  24. procedure secondcalln(var p : ptree);
  25. procedure secondprocinline(var p : ptree);
  26. implementation
  27. uses
  28. globtype,systems,
  29. cobjects,verbose,globals,
  30. aasm,types,
  31. {$ifdef GDB}
  32. gdb,
  33. {$endif GDB}
  34. hcodegen,temp_gen,pass_2,
  35. {$ifdef ag386bin}
  36. i386base,i386asm,
  37. {$else}
  38. i386,
  39. {$endif}
  40. cgai386,tgeni386,cg386ld;
  41. {*****************************************************************************
  42. SecondCallParaN
  43. *****************************************************************************}
  44. procedure secondcallparan(var p : ptree;defcoll : pdefcoll;
  45. push_from_left_to_right,inlined : boolean;para_offset : longint);
  46. procedure maybe_push_high;
  47. {$ifdef OLDHIGH}
  48. var
  49. r : preference;
  50. hreg : tregister;
  51. href : treference;
  52. len : longint;
  53. {$endif}
  54. begin
  55. { open array ? }
  56. { defcoll^.data can be nil for read/write }
  57. if assigned(defcoll^.data) and
  58. push_high_param(defcoll^.data) then
  59. begin
  60. {$ifndef OLDHIGH}
  61. if assigned(p^.hightree) then
  62. begin
  63. secondpass(p^.hightree);
  64. push_value_para(p^.hightree,inlined,para_offset);
  65. end
  66. else
  67. internalerror(432645);
  68. {$else}
  69. { push high }
  70. case p^.left^.resulttype^.deftype of
  71. arraydef : begin
  72. if is_open_array(p^.left^.resulttype) then
  73. begin
  74. p^.location.reference.base:=procinfo.framepointer;
  75. p^.location.reference.offset:=pvarsym(p^.symtableentry)^.address;
  76. r:=new_reference(highframepointer,highoffset+4);
  77. len:=-1;
  78. end
  79. else
  80. len:=parraydef(p^.left^.resulttype)^.highrange-
  81. parraydef(p^.left^.resulttype)^.lowrange
  82. end;
  83. stringdef : begin
  84. if is_open_string(defcoll^.data) then
  85. begin
  86. if is_open_string(p^.left^.resulttype) then
  87. begin
  88. r:=new_reference(highframepointer,highoffset+4);
  89. exprasmlist^.concat(new(pai386,op_ref_reg(A_MOV,S_L,r,R_EDI)));
  90. hreg:=R_EDI;
  91. len:=-2;
  92. end
  93. else
  94. len:=pstringdef(p^.left^.resulttype)^.len
  95. end
  96. else
  97. { passing a string to an array of char }
  98. begin
  99. if (p^.left^.treetype=stringconstn) then
  100. len:=str_length(p^.left)
  101. else
  102. begin
  103. href:=p^.location.reference;
  104. exprasmlist^.concat(new(pai386,op_ref_reg(A_MOVZX,S_BL,newreference(href),R_EDI)));
  105. hreg:=R_EDI;
  106. len:=-2;
  107. end;
  108. end;
  109. end;
  110. else
  111. len:=0;
  112. end;
  113. { Push from the reference? }
  114. if len=-1 then
  115. begin
  116. if inlined then
  117. begin
  118. exprasmlist^.concat(new(pai386,op_ref_reg(A_MOV,S_L,r,R_EDI)));
  119. r:=new_reference(procinfo.framepointer,para_offset-pushedparasize);
  120. exprasmlist^.concat(new(pai386,op_reg_ref(A_MOV,S_L,R_EDI,r)));
  121. end
  122. else
  123. exprasmlist^.concat(new(pai386,op_ref(A_PUSH,S_L,r)));
  124. end
  125. else
  126. { Push from a register? }
  127. if len=-2 then
  128. begin
  129. if inlined then
  130. begin
  131. r:=new_reference(procinfo.framepointer,para_offset-pushedparasize);
  132. exprasmlist^.concat(new(pai386,op_reg_ref(A_MOV,S_L,hreg,r)));
  133. end
  134. else
  135. exprasmlist^.concat(new(pai386,op_reg(A_PUSH,S_L,hreg)));
  136. ungetregister32(hreg);
  137. end
  138. else
  139. { Push direct value }
  140. begin
  141. if inlined then
  142. begin
  143. r:=new_reference(procinfo.framepointer,para_offset-pushedparasize);
  144. exprasmlist^.concat(new(pai386,op_const_ref(A_MOV,S_L,len,r)));
  145. end
  146. else
  147. push_int(len);
  148. end;
  149. inc(pushedparasize,4);
  150. {$endif OLDHIGH}
  151. end;
  152. end;
  153. var
  154. otlabel,oflabel : plabel;
  155. { temporary variables: }
  156. tempdeftype : tdeftype;
  157. r : preference;
  158. begin
  159. { push from left to right if specified }
  160. if push_from_left_to_right and assigned(p^.right) then
  161. secondcallparan(p^.right,defcoll^.next,push_from_left_to_right,inlined,para_offset);
  162. otlabel:=truelabel;
  163. oflabel:=falselabel;
  164. getlabel(truelabel);
  165. getlabel(falselabel);
  166. secondpass(p^.left);
  167. { filter array constructor with c styled args }
  168. if is_array_constructor(p^.left^.resulttype) and p^.left^.cargs then
  169. begin
  170. { nothing, everything is already pushed }
  171. end
  172. { in codegen.handleread.. defcoll^.data is set to nil }
  173. else if assigned(defcoll^.data) and
  174. (defcoll^.data^.deftype=formaldef) then
  175. begin
  176. { allow @var }
  177. inc(pushedparasize,4);
  178. if p^.left^.treetype=addrn then
  179. begin
  180. { always a register }
  181. if inlined then
  182. begin
  183. r:=new_reference(procinfo.framepointer,para_offset-pushedparasize);
  184. exprasmlist^.concat(new(pai386,op_reg_ref(A_MOV,S_L,
  185. p^.left^.location.register,r)));
  186. end
  187. else
  188. exprasmlist^.concat(new(pai386,op_reg(A_PUSH,S_L,p^.left^.location.register)));
  189. ungetregister32(p^.left^.location.register);
  190. end
  191. else
  192. begin
  193. if not(p^.left^.location.loc in [LOC_MEM,LOC_REFERENCE]) then
  194. CGMessage(type_e_mismatch)
  195. else
  196. begin
  197. if inlined then
  198. begin
  199. exprasmlist^.concat(new(pai386,op_ref_reg(A_LEA,S_L,
  200. newreference(p^.left^.location.reference),R_EDI)));
  201. r:=new_reference(procinfo.framepointer,para_offset-pushedparasize);
  202. exprasmlist^.concat(new(pai386,op_reg_ref(A_MOV,S_L,R_EDI,r)));
  203. end
  204. else
  205. emitpushreferenceaddr(exprasmlist,p^.left^.location.reference);
  206. del_reference(p^.left^.location.reference);
  207. end;
  208. end;
  209. end
  210. { handle call by reference parameter }
  211. else if (defcoll^.paratyp=vs_var) then
  212. begin
  213. if (p^.left^.location.loc<>LOC_REFERENCE) then
  214. CGMessage(cg_e_var_must_be_reference);
  215. maybe_push_high;
  216. inc(pushedparasize,4);
  217. if inlined then
  218. begin
  219. exprasmlist^.concat(new(pai386,op_ref_reg(A_LEA,S_L,
  220. newreference(p^.left^.location.reference),R_EDI)));
  221. r:=new_reference(procinfo.framepointer,para_offset-pushedparasize);
  222. exprasmlist^.concat(new(pai386,op_reg_ref(A_MOV,S_L,R_EDI,r)));
  223. end
  224. else
  225. emitpushreferenceaddr(exprasmlist,p^.left^.location.reference);
  226. del_reference(p^.left^.location.reference);
  227. end
  228. else
  229. begin
  230. tempdeftype:=p^.resulttype^.deftype;
  231. if tempdeftype=filedef then
  232. CGMessage(cg_e_file_must_call_by_reference);
  233. if push_addr_param(p^.resulttype) then
  234. begin
  235. maybe_push_high;
  236. inc(pushedparasize,4);
  237. if inlined then
  238. begin
  239. exprasmlist^.concat(new(pai386,op_ref_reg(A_LEA,S_L,
  240. newreference(p^.left^.location.reference),R_EDI)));
  241. r:=new_reference(procinfo.framepointer,para_offset-pushedparasize);
  242. exprasmlist^.concat(new(pai386,op_reg_ref(A_MOV,S_L,
  243. R_EDI,r)));
  244. end
  245. else
  246. emitpushreferenceaddr(exprasmlist,p^.left^.location.reference);
  247. del_reference(p^.left^.location.reference);
  248. end
  249. else
  250. push_value_para(p^.left,inlined,para_offset);
  251. end;
  252. freelabel(truelabel);
  253. freelabel(falselabel);
  254. truelabel:=otlabel;
  255. falselabel:=oflabel;
  256. { push from right to left }
  257. if not push_from_left_to_right and assigned(p^.right) then
  258. secondcallparan(p^.right,defcoll^.next,push_from_left_to_right,inlined,para_offset);
  259. end;
  260. {*****************************************************************************
  261. SecondCallN
  262. *****************************************************************************}
  263. procedure secondcalln(var p : ptree);
  264. var
  265. unusedregisters : tregisterset;
  266. pushed,pushedregs : tpushed;
  267. hr,funcretref : treference;
  268. hregister,hregister2 : tregister;
  269. oldpushedparasize : longint;
  270. { true if ESI must be loaded again after the subroutine }
  271. loadesi : boolean;
  272. { true if a virtual method must be called directly }
  273. no_virtual_call : boolean;
  274. { true if we produce a con- or destrutor in a call }
  275. is_con_or_destructor : boolean;
  276. { true if a constructor is called again }
  277. extended_new : boolean;
  278. { adress returned from an I/O-error }
  279. iolabel : plabel;
  280. { lexlevel count }
  281. i : longint;
  282. { help reference pointer }
  283. r : preference;
  284. hp,
  285. pp,params : ptree;
  286. inlined : boolean;
  287. inlinecode : ptree;
  288. para_offset : longint;
  289. { instruction for alignement correction }
  290. { corr : pai386;}
  291. { we must pop this size also after !! }
  292. { must_pop : boolean; }
  293. pop_size : longint;
  294. oldrl : plinkedlist;
  295. label
  296. dont_call;
  297. begin
  298. reset_reference(p^.location.reference);
  299. extended_new:=false;
  300. iolabel:=nil;
  301. inlinecode:=nil;
  302. inlined:=false;
  303. loadesi:=true;
  304. no_virtual_call:=false;
  305. unusedregisters:=unused;
  306. { save old ansi string release list }
  307. oldrl:=temptoremove;
  308. temptoremove:=new(plinkedlist,init);
  309. if not assigned(p^.procdefinition) then
  310. exit;
  311. if (p^.procdefinition^.options and poinline)<>0 then
  312. begin
  313. inlined:=true;
  314. inlinecode:=p^.right;
  315. { set it to the same lexical level }
  316. p^.procdefinition^.parast^.symtablelevel:=
  317. aktprocsym^.definition^.parast^.symtablelevel;
  318. if assigned(p^.left) then
  319. inlinecode^.para_offset:=
  320. gettempofsizepersistant(inlinecode^.para_size);
  321. p^.procdefinition^.parast^.call_offset:=
  322. inlinecode^.para_offset;
  323. {$ifdef extdebug}
  324. Comment(V_debug,
  325. 'inlined parasymtable is at offset '
  326. +tostr(p^.procdefinition^.parast^.call_offset));
  327. exprasmlist^.concat(new(pai_asm_comment,init(
  328. strpnew('inlined parasymtable is at offset '
  329. +tostr(p^.procdefinition^.parast^.call_offset)))));
  330. {$endif extdebug}
  331. p^.right:=nil;
  332. { disable further inlining of the same proc
  333. in the args }
  334. p^.procdefinition^.options:=p^.procdefinition^.options and (not poinline);
  335. end;
  336. { only if no proc var }
  337. if not(assigned(p^.right)) then
  338. is_con_or_destructor:=((p^.procdefinition^.options and poconstructor)<>0)
  339. or ((p^.procdefinition^.options and podestructor)<>0);
  340. { proc variables destroy all registers }
  341. if (p^.right=nil) and
  342. { virtual methods too }
  343. ((p^.procdefinition^.options and povirtualmethod)=0) then
  344. begin
  345. if ((p^.procdefinition^.options and poiocheck)<>0) and
  346. ((aktprocsym^.definition^.options and poiocheck)=0) and
  347. (cs_check_io in aktlocalswitches) then
  348. begin
  349. getlabel(iolabel);
  350. emitlab(iolabel);
  351. end
  352. else
  353. iolabel:=nil;
  354. { save all used registers }
  355. pushusedregisters(pushed,p^.procdefinition^.usedregisters);
  356. { give used registers through }
  357. usedinproc:=usedinproc or p^.procdefinition^.usedregisters;
  358. end
  359. else
  360. begin
  361. pushusedregisters(pushed,$ff);
  362. usedinproc:=$ff;
  363. { no IO check for methods and procedure variables }
  364. iolabel:=nil;
  365. end;
  366. { generate the code for the parameter and push them }
  367. oldpushedparasize:=pushedparasize;
  368. pushedparasize:=0;
  369. pop_size:=0;
  370. if (not inlined) then
  371. begin
  372. { Old pushedsize aligned on 4 ? }
  373. i:=oldpushedparasize and 3;
  374. if i>0 then
  375. inc(pop_size,4-i);
  376. { This parasize aligned on 4 ? }
  377. i:=p^.procdefinition^.para_size and 3;
  378. if i>0 then
  379. inc(pop_size,4-i);
  380. { insert the opcode and update pushedparasize }
  381. if pop_size>0 then
  382. begin
  383. inc(pushedparasize,pop_size);
  384. exprasmlist^.concat(new(pai386,op_const_reg(A_SUB,S_L,pop_size,R_ESP)));
  385. {$ifdef GDB}
  386. if (cs_debuginfo in aktmoduleswitches) and
  387. (exprasmlist^.first=exprasmlist^.last) then
  388. exprasmlist^.concat(new(pai_force_line,init));
  389. {$endif GDB}
  390. end;
  391. end;
  392. if (p^.resulttype<>pdef(voiddef)) and
  393. ret_in_param(p^.resulttype) then
  394. begin
  395. funcretref.symbol:=nil;
  396. {$ifdef test_dest_loc}
  397. if dest_loc_known and (dest_loc_tree=p) and
  398. (dest_loc.loc in [LOC_REFERENCE,LOC_MEM]) then
  399. begin
  400. funcretref:=dest_loc.reference;
  401. if assigned(dest_loc.reference.symbol) then
  402. funcretref.symbol:=stringdup(dest_loc.reference.symbol^);
  403. in_dest_loc:=true;
  404. end
  405. else
  406. {$endif test_dest_loc}
  407. if inlined then
  408. begin
  409. reset_reference(funcretref);
  410. funcretref.offset:=gettempofsizepersistant(p^.procdefinition^.retdef^.size);
  411. funcretref.base:=procinfo.framepointer;
  412. end
  413. else
  414. gettempofsizereference(p^.procdefinition^.retdef^.size,funcretref);
  415. end;
  416. if assigned(p^.left) then
  417. begin
  418. { be found elsewhere }
  419. if inlined then
  420. para_offset:=p^.procdefinition^.parast^.call_offset+
  421. p^.procdefinition^.parast^.datasize
  422. else
  423. para_offset:=0;
  424. if assigned(p^.right) then
  425. secondcallparan(p^.left,pprocvardef(p^.right^.resulttype)^.para1,
  426. (p^.procdefinition^.options and poleftright)<>0,inlined,para_offset)
  427. else
  428. secondcallparan(p^.left,p^.procdefinition^.para1,
  429. (p^.procdefinition^.options and poleftright)<>0,inlined,para_offset);
  430. end;
  431. params:=p^.left;
  432. p^.left:=nil;
  433. if inlined then
  434. inlinecode^.retoffset:=gettempofsizepersistant(4);
  435. if ret_in_param(p^.resulttype) then
  436. begin
  437. inc(pushedparasize,4);
  438. if inlined then
  439. begin
  440. exprasmlist^.concat(new(pai386,op_ref_reg(A_LEA,S_L,
  441. newreference(funcretref),R_EDI)));
  442. r:=new_reference(procinfo.framepointer,inlinecode^.retoffset);
  443. exprasmlist^.concat(new(pai386,op_reg_ref(A_MOV,S_L,
  444. R_EDI,r)));
  445. end
  446. else
  447. emitpushreferenceaddr(exprasmlist,funcretref);
  448. end;
  449. { procedure variable ? }
  450. if (p^.right=nil) then
  451. begin
  452. { overloaded operator have no symtable }
  453. { push self }
  454. if assigned(p^.symtable) and
  455. (p^.symtable^.symtabletype=withsymtable) then
  456. begin
  457. { dirty trick to avoid the secondcall below }
  458. p^.methodpointer:=genzeronode(callparan);
  459. p^.methodpointer^.location.loc:=LOC_REGISTER;
  460. p^.methodpointer^.location.register:=R_ESI;
  461. { ARGHHH this is wrong !!!
  462. if we can init from base class for a child
  463. class that the wrong VMT will be
  464. transfered to constructor !! }
  465. {$ifdef NODIRECTWITH}
  466. p^.methodpointer^.resulttype:=p^.symtable^.defowner;
  467. {$else NODIRECTWITH}
  468. p^.methodpointer^.resulttype:=
  469. ptree(pwithsymtable(p^.symtable)^.withnode)^.left^.resulttype;
  470. {$endif def NODIRECTWITH}
  471. { change dispose type !! }
  472. p^.disposetyp:=dt_mbleft_and_method;
  473. { make a reference }
  474. new(r);
  475. reset_reference(r^);
  476. {$ifndef NODIRECTWITH}
  477. if assigned(ptree(pwithsymtable(p^.symtable)^.withnode)^.pref) then
  478. begin
  479. r^:=ptree(pwithsymtable(p^.symtable)^.withnode)^.pref^;
  480. {if assigned(r^.symbol) then
  481. r^.symbol:=stringdup(r^.symbol^);}
  482. end
  483. else
  484. {$endif def NODIRECTWITH}
  485. begin
  486. r^.offset:=p^.symtable^.datasize;
  487. r^.base:=procinfo.framepointer;
  488. end;
  489. {$ifndef NODIRECTWITH}
  490. if (not pwithsymtable(p^.symtable)^.direct_with) or
  491. pobjectdef(p^.methodpointer^.resulttype)^.isclass then
  492. {$endif def NODIRECTWITH}
  493. exprasmlist^.concat(new(pai386,op_ref_reg(A_MOV,S_L,r,R_ESI)))
  494. {$ifndef NODIRECTWITH}
  495. else
  496. exprasmlist^.concat(new(pai386,op_ref_reg(A_LEA,S_L,r,R_ESI)))
  497. {$endif def NODIRECTWITH}
  498. ;
  499. end;
  500. { push self }
  501. if assigned(p^.symtable) and
  502. ((p^.symtable^.symtabletype=objectsymtable) or
  503. (p^.symtable^.symtabletype=withsymtable)) then
  504. begin
  505. if assigned(p^.methodpointer) then
  506. begin
  507. {
  508. if p^.methodpointer^.resulttype=classrefdef then
  509. begin
  510. two possibilities:
  511. 1. constructor
  512. 2. class method
  513. end
  514. else }
  515. begin
  516. case p^.methodpointer^.treetype of
  517. typen:
  518. begin
  519. { direct call to inherited method }
  520. if (p^.procdefinition^.options and poabstractmethod)<>0 then
  521. begin
  522. CGMessage(cg_e_cant_call_abstract_method);
  523. goto dont_call;
  524. end;
  525. { generate no virtual call }
  526. no_virtual_call:=true;
  527. if (p^.symtableprocentry^.properties and sp_static)<>0 then
  528. begin
  529. { well lets put the VMT address directly into ESI }
  530. { it is kind of dirty but that is the simplest }
  531. { way to accept virtual static functions (PM) }
  532. loadesi:=true;
  533. { if no VMT just use $0 bug0214 PM }
  534. if (pobjectdef(p^.methodpointer^.resulttype)^.options and oo_hasvmt)=0 then
  535. exprasmlist^.concat(new(pai386,op_const_reg(A_MOV,S_L,0,R_ESI)))
  536. else
  537. begin
  538. exprasmlist^.concat(new(pai386,op_sym_ofs_reg(A_MOV,S_L,
  539. newasmsymbol(pobjectdef(
  540. p^.methodpointer^.resulttype)^.vmt_mangledname),0,R_ESI)));
  541. maybe_concat_external(pobjectdef(p^.methodpointer^.resulttype)^.owner,
  542. pobjectdef(p^.methodpointer^.resulttype)^.vmt_mangledname);
  543. end;
  544. { exprasmlist^.concat(new(pai386,op_reg(A_PUSH,S_L,R_ESI)));
  545. this is done below !! }
  546. end
  547. else
  548. { this is a member call, so ESI isn't modfied }
  549. loadesi:=false;
  550. { a class destructor needs a flag }
  551. if pobjectdef(p^.methodpointer^.resulttype)^.isclass and
  552. assigned(aktprocsym) and
  553. ((aktprocsym^.definition^.options and
  554. (podestructor))<>0) then
  555. begin
  556. push_int(0);
  557. exprasmlist^.concat(new(pai386,op_reg(A_PUSH,S_L,R_ESI)));
  558. end;
  559. if not(is_con_or_destructor and
  560. pobjectdef(p^.methodpointer^.resulttype)^.isclass and
  561. assigned(aktprocsym) and
  562. ((aktprocsym^.definition^.options and
  563. (poconstructor or podestructor))<>0)) then
  564. exprasmlist^.concat(new(pai386,op_reg(A_PUSH,S_L,R_ESI)));
  565. { if an inherited con- or destructor should be }
  566. { called in a con- or destructor then a warning }
  567. { will be made }
  568. { con- and destructors need a pointer to the vmt }
  569. if is_con_or_destructor and
  570. not(pobjectdef(p^.methodpointer^.resulttype)^.isclass) and
  571. assigned(aktprocsym) then
  572. begin
  573. if not ((aktprocsym^.definition^.options
  574. and (poconstructor or podestructor))<>0) then
  575. CGMessage(cg_w_member_cd_call_from_method);
  576. end;
  577. { class destructors get there flag below }
  578. if is_con_or_destructor and
  579. not(pobjectdef(p^.methodpointer^.resulttype)^.isclass and
  580. assigned(aktprocsym) and
  581. ((aktprocsym^.definition^.options and
  582. (podestructor))<>0)) then
  583. push_int(0);
  584. end;
  585. hnewn:
  586. begin
  587. { extended syntax of new }
  588. { ESI must be zero }
  589. exprasmlist^.concat(new(pai386,op_reg_reg(A_XOR,S_L,R_ESI,R_ESI)));
  590. exprasmlist^.concat(new(pai386,op_reg(A_PUSH,S_L,R_ESI)));
  591. { insert the vmt }
  592. exprasmlist^.concat(new(pai386,op_sym(A_PUSH,S_L,
  593. newasmsymbol(pobjectdef(p^.methodpointer^.resulttype)^.vmt_mangledname))));
  594. maybe_concat_external(pobjectdef(p^.methodpointer^.resulttype)^.owner,
  595. pobjectdef(p^.methodpointer^.resulttype)^.vmt_mangledname);
  596. extended_new:=true;
  597. end;
  598. hdisposen:
  599. begin
  600. secondpass(p^.methodpointer);
  601. { destructor with extended syntax called from dispose }
  602. { hdisposen always deliver LOC_REFERENCE }
  603. exprasmlist^.concat(new(pai386,op_ref_reg(A_LEA,S_L,
  604. newreference(p^.methodpointer^.location.reference),R_ESI)));
  605. del_reference(p^.methodpointer^.location.reference);
  606. exprasmlist^.concat(new(pai386,op_reg(A_PUSH,S_L,R_ESI)));
  607. exprasmlist^.concat(new(pai386,op_sym(A_PUSH,S_L,
  608. newasmsymbol(pobjectdef(p^.methodpointer^.resulttype)^.vmt_mangledname))));
  609. maybe_concat_external(pobjectdef(p^.methodpointer^.resulttype)^.owner,
  610. pobjectdef(p^.methodpointer^.resulttype)^.vmt_mangledname);
  611. end;
  612. else
  613. begin
  614. { call to an instance member }
  615. if (p^.symtable^.symtabletype<>withsymtable) then
  616. begin
  617. secondpass(p^.methodpointer);
  618. case p^.methodpointer^.location.loc of
  619. LOC_CREGISTER,
  620. LOC_REGISTER:
  621. begin
  622. ungetregister32(p^.methodpointer^.location.register);
  623. emit_reg_reg(A_MOV,S_L,p^.methodpointer^.location.register,R_ESI);
  624. end;
  625. else
  626. begin
  627. if (p^.methodpointer^.resulttype^.deftype=classrefdef) or
  628. ((p^.methodpointer^.resulttype^.deftype=objectdef) and
  629. pobjectdef(p^.methodpointer^.resulttype)^.isclass) then
  630. exprasmlist^.concat(new(pai386,op_ref_reg(A_MOV,S_L,
  631. newreference(p^.methodpointer^.location.reference),R_ESI)))
  632. else
  633. exprasmlist^.concat(new(pai386,op_ref_reg(A_LEA,S_L,
  634. newreference(p^.methodpointer^.location.reference),R_ESI)));
  635. del_reference(p^.methodpointer^.location.reference);
  636. end;
  637. end;
  638. end;
  639. { when calling a class method, we have
  640. to load ESI with the VMT !
  641. But that's wrong, if we call a class method via self
  642. }
  643. if ((p^.procdefinition^.options and poclassmethod)<>0)
  644. and not(p^.methodpointer^.resulttype^.deftype=classrefdef) then
  645. begin
  646. { class method needs current VMT }
  647. new(r);
  648. reset_reference(r^);
  649. r^.base:=R_ESI;
  650. r^.offset:= p^.procdefinition^._class^.vmt_offset;
  651. exprasmlist^.concat(new(pai386,op_ref_reg(A_MOV,S_L,r,R_ESI)));
  652. end;
  653. { direct call to destructor: don't remove data! }
  654. if ((p^.procdefinition^.options and podestructor)<>0) and
  655. (p^.methodpointer^.resulttype^.deftype=objectdef) and
  656. (pobjectdef(p^.methodpointer^.resulttype)^.isclass) then
  657. exprasmlist^.concat(new(pai386,op_const(A_PUSH,S_L,1)));
  658. { direct call to class constructor, don't allocate memory }
  659. if ((p^.procdefinition^.options and poconstructor)<>0) and
  660. (p^.methodpointer^.resulttype^.deftype=objectdef) and
  661. (pobjectdef(p^.methodpointer^.resulttype)^.isclass) then
  662. exprasmlist^.concat(new(pai386,op_const(A_PUSH,S_L,0)))
  663. else
  664. exprasmlist^.concat(new(pai386,op_reg(A_PUSH,S_L,R_ESI)));
  665. if is_con_or_destructor then
  666. begin
  667. { classes don't get a VMT pointer pushed }
  668. if (p^.methodpointer^.resulttype^.deftype=objectdef) and
  669. not(pobjectdef(p^.methodpointer^.resulttype)^.isclass) then
  670. begin
  671. if ((p^.procdefinition^.options and poconstructor)<>0) then
  672. begin
  673. { it's no bad idea, to insert the VMT }
  674. exprasmlist^.concat(new(pai386,op_sym(A_PUSH,S_L,newasmsymbol(
  675. pobjectdef(p^.methodpointer^.resulttype)^.vmt_mangledname))));
  676. maybe_concat_external(pobjectdef(p^.methodpointer^.resulttype)^.owner,
  677. pobjectdef(p^.methodpointer^.resulttype)^.vmt_mangledname);
  678. end
  679. { destructors haven't to dispose the instance, if this is }
  680. { a direct call }
  681. else
  682. push_int(0);
  683. end;
  684. end;
  685. end;
  686. end;
  687. end;
  688. end
  689. else
  690. begin
  691. if ((p^.procdefinition^.options and poclassmethod)<>0) and
  692. not(
  693. assigned(aktprocsym) and
  694. ((aktprocsym^.definition^.options and poclassmethod)<>0)
  695. ) then
  696. begin
  697. { class method needs current VMT }
  698. new(r);
  699. reset_reference(r^);
  700. r^.base:=R_ESI;
  701. r^.offset:= p^.procdefinition^._class^.vmt_offset;
  702. exprasmlist^.concat(new(pai386,op_ref_reg(A_MOV,S_L,r,R_ESI)));
  703. end
  704. else
  705. begin
  706. { member call, ESI isn't modified }
  707. loadesi:=false;
  708. end;
  709. exprasmlist^.concat(new(pai386,op_reg(A_PUSH,S_L,R_ESI)));
  710. { but a con- or destructor here would probably almost }
  711. { always be placed wrong }
  712. if is_con_or_destructor then
  713. begin
  714. CGMessage(cg_w_member_cd_call_from_method);
  715. push_int(0);
  716. end;
  717. end;
  718. end;
  719. { push base pointer ?}
  720. if (lexlevel>=normal_function_level) and assigned(pprocdef(p^.procdefinition)^.parast) and
  721. ((p^.procdefinition^.parast^.symtablelevel)>normal_function_level) then
  722. begin
  723. { if we call a nested function in a method, we must }
  724. { push also SELF! }
  725. { THAT'S NOT TRUE, we have to load ESI via frame pointer }
  726. { access }
  727. {
  728. begin
  729. loadesi:=false;
  730. exprasmlist^.concat(new(pai386,op_reg(A_PUSH,S_L,R_ESI)));
  731. end;
  732. }
  733. if lexlevel=(p^.procdefinition^.parast^.symtablelevel) then
  734. begin
  735. new(r);
  736. reset_reference(r^);
  737. r^.offset:=procinfo.framepointer_offset;
  738. r^.base:=procinfo.framepointer;
  739. exprasmlist^.concat(new(pai386,op_ref(A_PUSH,S_L,r)))
  740. end
  741. { this is only true if the difference is one !!
  742. but it cannot be more !! }
  743. else if (lexlevel=p^.procdefinition^.parast^.symtablelevel-1) then
  744. begin
  745. exprasmlist^.concat(new(pai386,op_reg(A_PUSH,S_L,procinfo.framepointer)))
  746. end
  747. else if (lexlevel>p^.procdefinition^.parast^.symtablelevel) then
  748. begin
  749. hregister:=getregister32;
  750. new(r);
  751. reset_reference(r^);
  752. r^.offset:=procinfo.framepointer_offset;
  753. r^.base:=procinfo.framepointer;
  754. exprasmlist^.concat(new(pai386,op_ref_reg(A_MOV,S_L,r,hregister)));
  755. for i:=(p^.procdefinition^.parast^.symtablelevel) to lexlevel-1 do
  756. begin
  757. new(r);
  758. reset_reference(r^);
  759. {we should get the correct frame_pointer_offset at each level
  760. how can we do this !!! }
  761. r^.offset:=procinfo.framepointer_offset;
  762. r^.base:=hregister;
  763. exprasmlist^.concat(new(pai386,op_ref_reg(A_MOV,S_L,r,hregister)));
  764. end;
  765. exprasmlist^.concat(new(pai386,op_reg(A_PUSH,S_L,hregister)));
  766. ungetregister32(hregister);
  767. end
  768. else
  769. internalerror(25000);
  770. end;
  771. if ((p^.procdefinition^.options and povirtualmethod)<>0) and
  772. not(no_virtual_call) then
  773. begin
  774. { static functions contain the vmt_address in ESI }
  775. { also class methods }
  776. { Here it is quite tricky because it also depends }
  777. { on the methodpointer PM }
  778. if assigned(aktprocsym) then
  779. begin
  780. if ((((aktprocsym^.properties and sp_static)<>0) or
  781. ((aktprocsym^.definition^.options and poclassmethod)<>0)) and
  782. ((p^.methodpointer=nil) or (p^.methodpointer^.treetype=typen)))
  783. or
  784. ((p^.procdefinition^.options and postaticmethod)<>0) or
  785. ((p^.procdefinition^.options and poconstructor)<>0) or
  786. { ESI is loaded earlier }
  787. ((p^.procdefinition^.options and poclassmethod)<>0)then
  788. begin
  789. new(r);
  790. reset_reference(r^);
  791. r^.base:=R_ESI;
  792. end
  793. else
  794. begin
  795. new(r);
  796. reset_reference(r^);
  797. r^.base:=R_ESI;
  798. { this is one point where we need vmt_offset (PM) }
  799. r^.offset:= p^.procdefinition^._class^.vmt_offset;
  800. exprasmlist^.concat(new(pai386,op_ref_reg(A_MOV,S_L,r,R_EDI)));
  801. new(r);
  802. reset_reference(r^);
  803. r^.base:=R_EDI;
  804. end;
  805. end
  806. else
  807. { aktprocsym should be assigned, also in main program }
  808. internalerror(12345);
  809. {
  810. begin
  811. new(r);
  812. reset_reference(r^);
  813. r^.base:=R_ESI;
  814. exprasmlist^.concat(new(pai386,op_ref_reg(A_MOV,S_L,r,R_EDI)));
  815. new(r);
  816. reset_reference(r^);
  817. r^.base:=R_EDI;
  818. end;
  819. }
  820. if p^.procdefinition^.extnumber=-1 then
  821. internalerror($Da);
  822. r^.offset:=p^.procdefinition^.extnumber*4+12;
  823. {$ifndef TESTOBJEXT}
  824. if (cs_check_range in aktlocalswitches) then
  825. begin
  826. exprasmlist^.concat(new(pai386,op_reg(A_PUSH,S_L,r^.base)));
  827. emitcall('FPC_CHECK_OBJECT',true);
  828. end;
  829. {$else TESTOBJEXT}
  830. if (cs_check_range in aktlocalswitches) then
  831. begin
  832. exprasmlist^.concat(new(pai386,op_sym(A_PUSH,S_L,
  833. newasmsymbol(p^.procdefinition^._class^.vmt_mangledname,0))));
  834. exprasmlist^.concat(new(pai386,op_reg(A_PUSH,S_L,r^.base)));
  835. emitcall('FPC_CHECK_OBJECT_EXT',true);
  836. end;
  837. {$endif TESTOBJEXT}
  838. exprasmlist^.concat(new(pai386,op_ref(A_CALL,S_NO,r)));
  839. end
  840. else if not inlined then
  841. emitcall(p^.procdefinition^.mangledname,
  842. (p^.symtableproc^.symtabletype=unitsymtable) or
  843. ((p^.symtableproc^.symtabletype=objectsymtable) and
  844. (pobjectdef(p^.symtableproc^.defowner)^.owner^.symtabletype=unitsymtable))or
  845. ((p^.symtableproc^.symtabletype=withsymtable) and
  846. (pobjectdef(p^.symtableproc^.defowner)^.owner^.symtabletype=unitsymtable)))
  847. else { inlined proc }
  848. { inlined code is in inlinecode }
  849. begin
  850. secondpass(inlinecode);
  851. { set poinline again }
  852. p^.procdefinition^.options:=p^.procdefinition^.options or poinline;
  853. { free the args }
  854. ungetpersistanttemp(p^.procdefinition^.parast^.call_offset,
  855. p^.procdefinition^.parast^.datasize);
  856. end;
  857. end
  858. else
  859. { now procedure variable case }
  860. begin
  861. secondpass(p^.right);
  862. { method pointer ? }
  863. if (p^.procdefinition^.options and pomethodpointer)<>0 then
  864. begin
  865. { method pointer can't be in a register }
  866. hregister:=R_NO;
  867. { do some hacking if we call a method pointer }
  868. { which is a class member }
  869. { else ESI is overwritten ! }
  870. if (p^.right^.location.reference.base=R_ESI) or
  871. (p^.right^.location.reference.index=R_ESI) then
  872. begin
  873. del_reference(p^.right^.location.reference);
  874. exprasmlist^.concat(new(pai386,op_ref_reg(A_MOV,S_L,
  875. newreference(p^.right^.location.reference),R_EDI)));
  876. hregister:=R_EDI;
  877. end;
  878. inc(p^.right^.location.reference.offset,4);
  879. { load ESI }
  880. exprasmlist^.concat(new(pai386,op_ref_reg(A_MOV,S_L,
  881. newreference(p^.right^.location.reference),R_ESI)));
  882. { push self pointer }
  883. exprasmlist^.concat(new(pai386,op_reg(A_PUSH,S_L,R_ESI)));
  884. dec(p^.right^.location.reference.offset,4);
  885. if hregister=R_NO then
  886. exprasmlist^.concat(new(pai386,op_ref(A_CALL,S_NO,newreference(p^.right^.location.reference))))
  887. else
  888. exprasmlist^.concat(new(pai386,op_reg(A_CALL,S_NO,hregister)));
  889. del_reference(p^.right^.location.reference);
  890. end
  891. else
  892. begin
  893. case p^.right^.location.loc of
  894. LOC_REGISTER,LOC_CREGISTER:
  895. begin
  896. exprasmlist^.concat(new(pai386,op_reg(A_CALL,S_NO,p^.right^.location.register)));
  897. ungetregister32(p^.right^.location.register);
  898. end
  899. else
  900. exprasmlist^.concat(new(pai386,op_ref(A_CALL,S_NO,newreference(p^.right^.location.reference))));
  901. del_reference(p^.right^.location.reference);
  902. end;
  903. end;
  904. end;
  905. { this was only for normal functions
  906. displaced here so we also get
  907. it to work for procvars PM }
  908. if (not inlined) and ((p^.procdefinition^.options and poclearstack)<>0) then
  909. begin
  910. { consider the alignment with the rest (PM) }
  911. inc(pushedparasize,pop_size);
  912. pop_size:=0;
  913. { better than an add on all processors }
  914. if pushedparasize=4 then
  915. exprasmlist^.concat(new(pai386,op_reg(A_POP,S_L,R_EDI)))
  916. { the pentium has two pipes and pop reg is pairable }
  917. { but the registers must be different! }
  918. else if (pushedparasize=8) and
  919. not(cs_littlesize in aktglobalswitches) and
  920. (aktoptprocessor=ClassP5) and
  921. (procinfo._class=nil) then
  922. begin
  923. exprasmlist^.concat(new(pai386,op_reg(A_POP,S_L,R_EDI)));
  924. exprasmlist^.concat(new(pai386,op_reg(A_POP,S_L,R_ESI)));
  925. end
  926. else exprasmlist^.concat(new(pai386,op_const_reg(A_ADD,S_L,pushedparasize,R_ESP)));
  927. end;
  928. dont_call:
  929. pushedparasize:=oldpushedparasize;
  930. unused:=unusedregisters;
  931. { handle function results }
  932. { structured results are easy to handle.... }
  933. { needed also when result_no_used !! }
  934. if (p^.resulttype<>pdef(voiddef)) and ret_in_param(p^.resulttype) then
  935. begin
  936. p^.location.loc:=LOC_MEM;
  937. p^.location.reference.symbol:=nil;
  938. p^.location.reference:=funcretref;
  939. end;
  940. { we have only to handle the result if it is used, but }
  941. { ansi/widestrings must be registered, so we can dispose them }
  942. if (p^.resulttype<>pdef(voiddef)) and (p^.return_value_used or
  943. is_ansistring(p^.resulttype) or is_widestring(p^.resulttype)) then
  944. begin
  945. { a contructor could be a function with boolean result }
  946. if (p^.right=nil) and
  947. ((p^.procdefinition^.options and poconstructor)<>0) and
  948. { quick'n'dirty check if it is a class or an object }
  949. (p^.resulttype^.deftype=orddef) then
  950. begin
  951. p^.location.loc:=LOC_FLAGS;
  952. p^.location.resflags:=F_NE;
  953. if extended_new then
  954. begin
  955. {$ifdef test_dest_loc}
  956. if dest_loc_known and (dest_loc_tree=p) then
  957. mov_reg_to_dest(p,S_L,R_EAX)
  958. else
  959. {$endif test_dest_loc}
  960. begin
  961. hregister:=getexplicitregister32(R_EAX);
  962. emit_reg_reg(A_MOV,S_L,R_EAX,hregister);
  963. p^.location.register:=hregister;
  964. end;
  965. end;
  966. end
  967. { structed results are easy to handle.... }
  968. else if ret_in_param(p^.resulttype) then
  969. begin
  970. {p^.location.loc:=LOC_MEM;
  971. stringdispose(p^.location.reference.symbol);
  972. p^.location.reference:=funcretref;
  973. already done above (PM) }
  974. end
  975. else
  976. begin
  977. if (p^.resulttype^.deftype=orddef) then
  978. begin
  979. p^.location.loc:=LOC_REGISTER;
  980. case porddef(p^.resulttype)^.typ of
  981. s32bit,u32bit,bool32bit :
  982. begin
  983. {$ifdef test_dest_loc}
  984. if dest_loc_known and (dest_loc_tree=p) then
  985. mov_reg_to_dest(p,S_L,R_EAX)
  986. else
  987. {$endif test_dest_loc}
  988. begin
  989. hregister:=getexplicitregister32(R_EAX);
  990. emit_reg_reg(A_MOV,S_L,R_EAX,hregister);
  991. p^.location.register:=hregister;
  992. end;
  993. end;
  994. uchar,u8bit,bool8bit,s8bit:
  995. begin
  996. {$ifdef test_dest_loc}
  997. if dest_loc_known and (dest_loc_tree=p) then
  998. mov_reg_to_dest(p,S_B,R_AL)
  999. else
  1000. {$endif test_dest_loc}
  1001. begin
  1002. hregister:=getexplicitregister32(R_EAX);
  1003. emit_reg_reg(A_MOV,S_B,R_AL,reg32toreg8(hregister));
  1004. p^.location.register:=reg32toreg8(hregister);
  1005. end;
  1006. end;
  1007. s16bit,u16bit,bool16bit :
  1008. begin
  1009. {$ifdef test_dest_loc}
  1010. if dest_loc_known and (dest_loc_tree=p) then
  1011. mov_reg_to_dest(p,S_W,R_AX)
  1012. else
  1013. {$endif test_dest_loc}
  1014. begin
  1015. hregister:=getexplicitregister32(R_EAX);
  1016. emit_reg_reg(A_MOV,S_W,R_AX,reg32toreg16(hregister));
  1017. p^.location.register:=reg32toreg16(hregister);
  1018. end;
  1019. end;
  1020. s64bitint,u64bit:
  1021. begin
  1022. {$ifdef test_dest_loc}
  1023. {$error Don't know what to do here}
  1024. {$endif test_dest_loc}
  1025. hregister:=getexplicitregister32(R_EAX);
  1026. hregister2:=getexplicitregister32(R_EDX);
  1027. emit_reg_reg(A_MOV,S_L,R_EAX,hregister);
  1028. emit_reg_reg(A_MOV,S_L,R_EDX,hregister2);
  1029. p^.location.registerlow:=hregister;
  1030. p^.location.registerhigh:=hregister2;
  1031. end;
  1032. else internalerror(7);
  1033. end
  1034. end
  1035. else if (p^.resulttype^.deftype=floatdef) then
  1036. case pfloatdef(p^.resulttype)^.typ of
  1037. f32bit:
  1038. begin
  1039. p^.location.loc:=LOC_REGISTER;
  1040. {$ifdef test_dest_loc}
  1041. if dest_loc_known and (dest_loc_tree=p) then
  1042. mov_reg_to_dest(p,S_L,R_EAX)
  1043. else
  1044. {$endif test_dest_loc}
  1045. begin
  1046. hregister:=getexplicitregister32(R_EAX);
  1047. emit_reg_reg(A_MOV,S_L,R_EAX,hregister);
  1048. p^.location.register:=hregister;
  1049. end;
  1050. end;
  1051. else
  1052. p^.location.loc:=LOC_FPU;
  1053. end
  1054. else
  1055. begin
  1056. p^.location.loc:=LOC_REGISTER;
  1057. {$ifdef test_dest_loc}
  1058. if dest_loc_known and (dest_loc_tree=p) then
  1059. mov_reg_to_dest(p,S_L,R_EAX)
  1060. else
  1061. {$endif test_dest_loc}
  1062. begin
  1063. hregister:=getexplicitregister32(R_EAX);
  1064. emit_reg_reg(A_MOV,S_L,R_EAX,hregister);
  1065. p^.location.register:=hregister;
  1066. if is_ansistring(p^.resulttype) or
  1067. is_widestring(p^.resulttype) then
  1068. begin
  1069. gettempansistringreference(hr);
  1070. exprasmlist^.concat(new(pai386,op_reg_ref(A_MOV,S_L,p^.location.register,
  1071. newreference(hr))));
  1072. { unnessary ansi/wide strings are imm. disposed }
  1073. if not(p^.return_value_used) then
  1074. begin
  1075. pushusedregisters(pushedregs,$ff);
  1076. emitpushreferenceaddr(exprasmlist,hr);
  1077. if is_ansistring(p^.resulttype) then
  1078. begin
  1079. exprasmlist^.concat(new(pai386,
  1080. op_sym(A_CALL,S_NO,newasmsymbol('FPC_ANSISTR_DECR_REF'))));
  1081. if not (cs_compilesystem in aktmoduleswitches) then
  1082. concat_external('FPC_ANSISTR_DECR_REF',EXT_NEAR);
  1083. end
  1084. else
  1085. begin
  1086. exprasmlist^.concat(new(pai386,
  1087. op_sym(A_CALL,S_NO,newasmsymbol('FPC_WIDESTR_DECR_REF'))));
  1088. if not (cs_compilesystem in aktmoduleswitches) then
  1089. concat_external('FPC_WIDESTR_DECR_REF',EXT_NEAR);
  1090. end;
  1091. ungetiftemp(hr);
  1092. popusedregisters(pushedregs);
  1093. end
  1094. else
  1095. oldrl^.concat(new(ptemptodestroy,init(hr,p^.resulttype)));
  1096. end;
  1097. end;
  1098. end;
  1099. end;
  1100. end;
  1101. { perhaps i/o check ? }
  1102. if iolabel<>nil then
  1103. begin
  1104. exprasmlist^.concat(new(pai386,op_sym(A_PUSH,S_L,newasmsymbol(lab2str(iolabel)))));
  1105. emitcall('FPC_IOCHECK',true);
  1106. end;
  1107. if pop_size>0 then
  1108. exprasmlist^.concat(new(pai386,op_const_reg(A_ADD,S_L,pop_size,R_ESP)));
  1109. { release temp. ansi strings }
  1110. removetemps(exprasmlist,temptoremove);
  1111. dispose(temptoremove,done);
  1112. temptoremove:=oldrl;
  1113. { restore registers }
  1114. popusedregisters(pushed);
  1115. { at last, restore instance pointer (SELF) }
  1116. if loadesi then
  1117. maybe_loadesi;
  1118. pp:=params;
  1119. while assigned(pp) do
  1120. begin
  1121. if assigned(pp^.left) then
  1122. begin
  1123. if pp^.left^.location.loc in [LOC_REFERENCE,LOC_MEM] then
  1124. ungetiftemp(pp^.left^.location.reference);
  1125. { process also all nodes of an array of const }
  1126. if pp^.left^.treetype=arrayconstructn then
  1127. begin
  1128. if assigned(pp^.left^.left) then
  1129. begin
  1130. hp:=pp^.left;
  1131. while assigned(hp) do
  1132. begin
  1133. if hp^.left^.location.loc in [LOC_REFERENCE,LOC_MEM] then
  1134. ungetiftemp(hp^.left^.location.reference);
  1135. hp:=hp^.right;
  1136. end;
  1137. end;
  1138. end;
  1139. end;
  1140. pp:=pp^.right;
  1141. end;
  1142. if inlined then
  1143. ungetpersistanttemp(inlinecode^.retoffset,4);
  1144. disposetree(params);
  1145. { from now on the result can be freed normally }
  1146. if inlined and ret_in_param(p^.resulttype) then
  1147. persistanttemptonormal(funcretref.offset);
  1148. { if return value is not used }
  1149. if (not p^.return_value_used) and (p^.resulttype<>pdef(voiddef)) then
  1150. begin
  1151. if p^.location.loc in [LOC_MEM,LOC_REFERENCE] then
  1152. { release unused temp }
  1153. ungetiftemp(p^.location.reference)
  1154. else if p^.location.loc=LOC_FPU then
  1155. { release FPU stack }
  1156. exprasmlist^.concat(new(pai386,op_none(A_FDECSTP,S_NO)));
  1157. end;
  1158. end;
  1159. {*****************************************************************************
  1160. SecondProcInlineN
  1161. *****************************************************************************}
  1162. { implementation not complete yet }
  1163. var
  1164. addr_correction : longint;
  1165. procedure correct_address(p : psym);{$ifndef FPC}far;{$endif}
  1166. begin
  1167. if p^.typ=varsym then
  1168. begin
  1169. inc(pvarsym(p)^.address,addr_correction);
  1170. {$ifdef extdebug}
  1171. Comment(V_debug,pvarsym(p)^.name+' is at offset -'
  1172. +tostr(pvarsym(p)^.address));
  1173. exprasmlist^.concat(new(pai_asm_comment,init(
  1174. strpnew(pvarsym(p)^.name+' is at offset -'
  1175. +tostr(pvarsym(p)^.address)))));
  1176. {$endif extdebug}
  1177. end;
  1178. end;
  1179. procedure secondprocinline(var p : ptree);
  1180. var st : psymtable;
  1181. oldprocsym : pprocsym;
  1182. para_size : longint;
  1183. oldprocinfo : tprocinfo;
  1184. { just dummies for genentrycode }
  1185. nostackframe,make_global : boolean;
  1186. proc_names : tstringcontainer;
  1187. inlineentrycode,inlineexitcode : paasmoutput;
  1188. oldexitlabel,oldexit2label,oldquickexitlabel:Plabel;
  1189. begin
  1190. oldexitlabel:=aktexitlabel;
  1191. oldexit2label:=aktexit2label;
  1192. oldquickexitlabel:=quickexitlabel;
  1193. getlabel(aktexitlabel);
  1194. getlabel(aktexit2label);
  1195. oldprocsym:=aktprocsym;
  1196. oldprocinfo:=procinfo;
  1197. { set the return value }
  1198. procinfo.retdef:=p^.inlineprocdef^.retdef;
  1199. procinfo.retoffset:=p^.retoffset;
  1200. { arg space has been filled by the parent secondcall }
  1201. st:=p^.inlineprocdef^.localst;
  1202. { set it to the same lexical level }
  1203. st^.symtablelevel:=
  1204. oldprocsym^.definition^.localst^.symtablelevel;
  1205. if st^.datasize>0 then
  1206. st^.call_offset:=gettempofsizepersistant(st^.datasize);
  1207. {$ifdef extdebug}
  1208. Comment(V_debug,'local symtable is at offset '
  1209. +tostr(st^.call_offset));
  1210. exprasmlist^.concat(new(pai_asm_comment,init(
  1211. strpnew('local symtable is at offset '
  1212. +tostr(st^.call_offset)))));
  1213. {$endif extdebug}
  1214. addr_correction:=-st^.call_offset-st^.datasize;
  1215. st^.foreach(correct_address);
  1216. {$ifdef extdebug}
  1217. exprasmlist^.concat(new(pai_asm_comment,init('Start of inlined proc')));
  1218. {$endif extdebug}
  1219. { takes care of local data initialization }
  1220. inlineentrycode:=new(paasmoutput,init);
  1221. inlineexitcode:=new(paasmoutput,init);
  1222. proc_names.init;
  1223. para_size:=p^.para_size;
  1224. make_global:=false; { to avoid warning }
  1225. genentrycode(inlineentrycode,proc_names,make_global,0,para_size,nostackframe,true);
  1226. exprasmlist^.concatlist(inlineentrycode);
  1227. secondpass(p^.left);
  1228. genexitcode(inlineexitcode,0,false,true);
  1229. exprasmlist^.concatlist(inlineexitcode);
  1230. {$ifdef extdebug}
  1231. exprasmlist^.concat(new(pai_asm_comment,init('End of inlined proc')));
  1232. {$endif extdebug}
  1233. {we can free the local data now }
  1234. if st^.datasize>0 then
  1235. ungetpersistanttemp(st^.call_offset,st^.datasize);
  1236. { set the real address again }
  1237. addr_correction:=-addr_correction;
  1238. st^.foreach(correct_address);
  1239. aktprocsym:=oldprocsym;
  1240. freelabel(aktexitlabel);
  1241. freelabel(aktexit2label);
  1242. aktexitlabel:=oldexitlabel;
  1243. aktexit2label:=oldexit2label;
  1244. quickexitlabel:=oldquickexitlabel;
  1245. procinfo:=oldprocinfo;
  1246. end;
  1247. end.
  1248. {
  1249. $Log$
  1250. Revision 1.69 1999-02-25 21:02:21 peter
  1251. * ag386bin updates
  1252. + coff writer
  1253. Revision 1.68 1999/02/22 02:15:04 peter
  1254. * updates for ag386bin
  1255. Revision 1.67 1999/02/11 09:46:21 pierre
  1256. * fix for normal method calls inside static methods :
  1257. WARNING there were both parser and codegen errors !!
  1258. added static_call boolean to calln tree
  1259. Revision 1.66 1999/02/09 15:45:46 florian
  1260. + complex results for assembler functions, fixes bug0155
  1261. Revision 1.65 1999/02/08 11:29:04 pierre
  1262. * fix for bug0214
  1263. several problems where combined
  1264. search_class_member did not set srsymtable
  1265. => in do_member_read the call node got a wrong symtable
  1266. in cg386cal the vmt was pushed twice without chacking if it exists
  1267. now %esi is set to zero and pushed if not vmt
  1268. (not very efficient but should work !)
  1269. Revision 1.64 1999/02/04 10:49:39 florian
  1270. + range checking for ansi- and widestrings
  1271. * made it compilable with TP
  1272. Revision 1.63 1999/02/03 10:18:14 pierre
  1273. * conditionnal code for extended check of virtual methods
  1274. Revision 1.62 1999/02/02 23:52:32 florian
  1275. * problem with calls to method pointers in methods fixed
  1276. - double ansistrings temp management removed
  1277. Revision 1.61 1999/02/02 11:04:36 florian
  1278. * class destructors fixed, class instances weren't disposed correctly
  1279. Revision 1.60 1999/01/28 23:56:44 florian
  1280. * the reference in the result location of a function call wasn't resetted =>
  1281. problem with unallowed far pointer, is solved now
  1282. Revision 1.59 1999/01/27 00:13:52 florian
  1283. * "procedure of object"-stuff fixed
  1284. Revision 1.58 1999/01/21 22:10:35 peter
  1285. * fixed array of const
  1286. * generic platform independent high() support
  1287. Revision 1.57 1999/01/21 16:40:51 pierre
  1288. * fix for constructor inside with statements
  1289. Revision 1.56 1998/12/30 13:41:05 peter
  1290. * released valuepara
  1291. Revision 1.55 1998/12/22 13:10:58 florian
  1292. * memory leaks for ansistring type casts fixed
  1293. Revision 1.54 1998/12/19 00:23:41 florian
  1294. * ansistring memory leaks fixed
  1295. Revision 1.53 1998/12/11 00:02:47 peter
  1296. + globtype,tokens,version unit splitted from globals
  1297. Revision 1.52 1998/12/10 14:39:29 florian
  1298. * bug with p(const a : ansistring) fixed
  1299. * duplicate constant ansistrings were handled wrong, fixed
  1300. Revision 1.51 1998/12/10 09:47:15 florian
  1301. + basic operations with int64/qord (compiler with -dint64)
  1302. + rtti of enumerations extended: names are now written
  1303. Revision 1.50 1998/12/06 13:12:44 florian
  1304. * better code generation for classes which are passed as parameters to
  1305. subroutines
  1306. Revision 1.49 1998/11/30 09:43:00 pierre
  1307. * some range check bugs fixed (still not working !)
  1308. + added DLL writing support for win32 (also accepts variables)
  1309. + TempAnsi for code that could be used for Temporary ansi strings
  1310. handling
  1311. Revision 1.48 1998/11/27 14:50:30 peter
  1312. + open strings, $P switch support
  1313. Revision 1.47 1998/11/26 21:30:03 peter
  1314. * fix for valuepara
  1315. Revision 1.46 1998/11/26 14:39:10 peter
  1316. * ansistring -> pchar fixed
  1317. * ansistring constants fixed
  1318. * ansistring constants are now written once
  1319. Revision 1.45 1998/11/18 15:44:07 peter
  1320. * VALUEPARA for tp7 compatible value parameters
  1321. Revision 1.44 1998/11/16 15:35:36 peter
  1322. * rename laod/copystring -> load/copyshortstring
  1323. * fixed int-bool cnv bug
  1324. + char-ansistring conversion
  1325. Revision 1.43 1998/11/15 16:32:33 florian
  1326. * some stuff of Pavel implement (win32 dll creation)
  1327. * bug with ansistring function results fixed
  1328. Revision 1.42 1998/11/13 15:40:13 pierre
  1329. + added -Se in Makefile cvstest target
  1330. + lexlevel cleanup
  1331. normal_function_level main_program_level and unit_init_level defined
  1332. * tins_cache grown to A_EMMS (gave range check error in asm readers)
  1333. (test added in code !)
  1334. * -Un option was wrong
  1335. * _FAIL and _SELF only keyword inside
  1336. constructors and methods respectively
  1337. Revision 1.41 1998/11/12 11:19:40 pierre
  1338. * fix for first line of function break
  1339. Revision 1.40 1998/11/10 10:09:08 peter
  1340. * va_list -> array of const
  1341. Revision 1.39 1998/11/09 11:44:33 peter
  1342. + va_list for printf support
  1343. Revision 1.38 1998/10/21 15:12:49 pierre
  1344. * bug fix for IOCHECK inside a procedure with iocheck modifier
  1345. * removed the GPF for unexistant overloading
  1346. (firstcall was called with procedinition=nil !)
  1347. * changed typen to what Florian proposed
  1348. gentypenode(p : pdef) sets the typenodetype field
  1349. and resulttype is only set if inside bt_type block !
  1350. Revision 1.37 1998/10/21 08:39:57 florian
  1351. + ansistring operator +
  1352. + $h and string[n] for n>255 added
  1353. * small problem with TP fixed
  1354. Revision 1.36 1998/10/20 08:06:39 pierre
  1355. * several memory corruptions due to double freemem solved
  1356. => never use p^.loc.location:=p^.left^.loc.location;
  1357. + finally I added now by default
  1358. that ra386dir translates global and unit symbols
  1359. + added a first field in tsymtable and
  1360. a nextsym field in tsym
  1361. (this allows to obtain ordered type info for
  1362. records and objects in gdb !)
  1363. Revision 1.35 1998/10/16 08:51:45 peter
  1364. + target_os.stackalignment
  1365. + stack can be aligned at 2 or 4 byte boundaries
  1366. Revision 1.34 1998/10/09 08:56:22 pierre
  1367. * several memory leaks fixed
  1368. Revision 1.33 1998/10/06 17:16:39 pierre
  1369. * some memory leaks fixed (thanks to Peter for heaptrc !)
  1370. Revision 1.32 1998/10/01 09:22:52 peter
  1371. * fixed value openarray
  1372. * ungettemp of arrayconstruct
  1373. Revision 1.31 1998/09/28 16:57:15 pierre
  1374. * changed all length(p^.value_str^) into str_length(p)
  1375. to get it work with and without ansistrings
  1376. * changed sourcefiles field of tmodule to a pointer
  1377. Revision 1.30 1998/09/26 15:03:02 florian
  1378. * small problems with DOM and excpetions fixed (code generation
  1379. of raise was wrong and self was sometimes destroyed :()
  1380. Revision 1.29 1998/09/25 00:04:00 florian
  1381. * problems when calling class methods fixed
  1382. Revision 1.28 1998/09/24 14:27:37 peter
  1383. * some better support for openarray
  1384. Revision 1.27 1998/09/24 09:02:13 peter
  1385. * rewritten isconvertable to use case
  1386. * array of .. and single variable are compatible
  1387. Revision 1.26 1998/09/21 08:45:06 pierre
  1388. + added vmt_offset in tobjectdef.write for fututre use
  1389. (first steps to have objects without vmt if no virtual !!)
  1390. + added fpu_used field for tabstractprocdef :
  1391. sets this level to 2 if the functions return with value in FPU
  1392. (is then set to correct value at parsing of implementation)
  1393. THIS MIGHT refuse some code with FPU expression too complex
  1394. that were accepted before and even in some cases
  1395. that don't overflow in fact
  1396. ( like if f : float; is a forward that finally in implementation
  1397. only uses one fpu register !!)
  1398. Nevertheless I think that it will improve security on
  1399. FPU operations !!
  1400. * most other changes only for UseBrowser code
  1401. (added symtable references for record and objects)
  1402. local switch for refs to args and local of each function
  1403. (static symtable still missing)
  1404. UseBrowser still not stable and probably broken by
  1405. the definition hash array !!
  1406. Revision 1.25 1998/09/20 12:26:35 peter
  1407. * merged fixes
  1408. Revision 1.24 1998/09/17 09:42:10 peter
  1409. + pass_2 for cg386
  1410. * Message() -> CGMessage() for pass_1/pass_2
  1411. Revision 1.23 1998/09/14 10:43:45 peter
  1412. * all internal RTL functions start with FPC_
  1413. Revision 1.22.2.1 1998/09/20 12:20:06 peter
  1414. * Fixed stack not on 4 byte boundary when doing a call
  1415. Revision 1.22 1998/09/04 08:41:37 peter
  1416. * updated some error CGMessages
  1417. Revision 1.21 1998/09/01 12:47:57 peter
  1418. * use pdef^.size instead of orddef^.typ
  1419. Revision 1.20 1998/08/31 12:22:15 peter
  1420. * secondinline moved to cg386inl
  1421. Revision 1.19 1998/08/31 08:52:03 peter
  1422. * fixed error 10 with succ() and pref()
  1423. Revision 1.18 1998/08/20 21:36:38 peter
  1424. * fixed 'with object do' bug
  1425. Revision 1.17 1998/08/19 16:07:36 jonas
  1426. * changed optimizer switches + cleanup of DestroyRefs in daopt386.pas
  1427. Revision 1.16 1998/08/18 09:24:36 pierre
  1428. * small warning position bug fixed
  1429. * support_mmx switches splitting was missing
  1430. * rhide error and warning output corrected
  1431. Revision 1.15 1998/08/13 11:00:09 peter
  1432. * fixed procedure<>procedure construct
  1433. Revision 1.14 1998/08/11 14:05:33 peter
  1434. * fixed sizeof(array of char)
  1435. Revision 1.13 1998/08/10 14:49:45 peter
  1436. + localswitches, moduleswitches, globalswitches splitting
  1437. Revision 1.12 1998/07/30 13:30:31 florian
  1438. * final implemenation of exception support, maybe it needs
  1439. some fixes :)
  1440. Revision 1.11 1998/07/24 22:16:52 florian
  1441. * internal error 10 together with array access fixed. I hope
  1442. that's the final fix.
  1443. Revision 1.10 1998/07/18 22:54:23 florian
  1444. * some ansi/wide/longstring support fixed:
  1445. o parameter passing
  1446. o returning as result from functions
  1447. Revision 1.9 1998/07/07 17:40:37 peter
  1448. * packrecords 4 works
  1449. * word aligning of parameters
  1450. Revision 1.8 1998/07/06 15:51:15 michael
  1451. Added length checking for string reading
  1452. Revision 1.7 1998/07/06 14:19:51 michael
  1453. + Added calls for reading/writing ansistrings
  1454. Revision 1.6 1998/07/01 15:28:48 peter
  1455. + better writeln/readln handling, now 100% like tp7
  1456. Revision 1.5 1998/06/25 14:04:17 peter
  1457. + internal inc/dec
  1458. Revision 1.4 1998/06/25 08:48:06 florian
  1459. * first version of rtti support
  1460. Revision 1.3 1998/06/09 16:01:33 pierre
  1461. + added procedure directive parsing for procvars
  1462. (accepted are popstack cdecl and pascal)
  1463. + added C vars with the following syntax
  1464. var C calias 'true_c_name';(can be followed by external)
  1465. reason is that you must add the Cprefix
  1466. which is target dependent
  1467. Revision 1.2 1998/06/08 13:13:29 pierre
  1468. + temporary variables now in temp_gen.pas unit
  1469. because it is processor independent
  1470. * mppc68k.bat modified to undefine i386 and support_mmx
  1471. (which are defaults for i386)
  1472. Revision 1.1 1998/06/05 17:44:10 peter
  1473. * splitted cgi386
  1474. }