cg386cal.pas 80 KB

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