cg386cal.pas 70 KB

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