n386util.pas 55 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384
  1. {
  2. $Id$
  3. Copyright (c) 1998-2000 by Florian Klaempfl
  4. Helper routines for the i386 code generator
  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 n386util;
  19. {$i defines.inc}
  20. interface
  21. uses
  22. symtype,node;
  23. function maybe_push(needed : byte;p : tnode;isint64 : boolean) : boolean;
  24. {$ifdef TEMPS_NOT_PUSH}
  25. function maybe_savetotemp(needed : byte;p : tnode;isint64 : boolean) : boolean;
  26. {$endif TEMPS_NOT_PUSH}
  27. procedure restore(p : tnode;isint64 : boolean);
  28. {$ifdef TEMPS_NOT_PUSH}
  29. procedure restorefromtemp(p : tnode;isint64 : boolean);
  30. {$endif TEMPS_NOT_PUSH}
  31. procedure pushsetelement(p : tnode);
  32. procedure push_value_para(p:tnode;inlined,is_cdecl:boolean;
  33. para_offset:longint;alignment : longint);
  34. procedure loadshortstring(source,dest : tnode);
  35. procedure loadlongstring(p:tbinarynode);
  36. procedure loadansi2short(source,dest : tnode);
  37. procedure loadinterfacecom(p: tbinarynode);
  38. procedure maketojumpbool(p : tnode);
  39. procedure emitoverflowcheck(p:tnode);
  40. procedure emitrangecheck(p:tnode;todef:pdef);
  41. procedure firstcomplex(p : tbinarynode);
  42. implementation
  43. uses
  44. globtype,globals,systems,verbose,
  45. cutils,cobjects,
  46. aasm,cpubase,cpuasm,
  47. symconst,symdef,symsym,symtable,
  48. {$ifdef GDB}
  49. gdb,
  50. {$endif GDB}
  51. types,
  52. ncon,nld,
  53. pass_1,pass_2,
  54. hcodegen,tgeni386,temp_gen,
  55. cgai386;
  56. {*****************************************************************************
  57. Emit Push Functions
  58. *****************************************************************************}
  59. function maybe_push(needed : byte;p : tnode;isint64 : boolean) : boolean;
  60. var
  61. pushed : boolean;
  62. {hregister : tregister; }
  63. {$ifdef TEMPS_NOT_PUSH}
  64. href : treference;
  65. {$endif TEMPS_NOT_PUSH}
  66. begin
  67. if needed>usablereg32 then
  68. begin
  69. if (p.location.loc=LOC_REGISTER) then
  70. begin
  71. if isint64 then
  72. begin
  73. {$ifdef TEMPS_NOT_PUSH}
  74. gettempofsizereference(href,8);
  75. p.temp_offset:=href.offset;
  76. href.offset:=href.offset+4;
  77. exprasmlist^.concat(new(paicpu,op_reg(A_MOV,S_L,p.location.registerhigh,href)));
  78. href.offset:=href.offset-4;
  79. {$else TEMPS_NOT_PUSH}
  80. exprasmlist^.concat(new(paicpu,op_reg(A_PUSH,S_L,p.location.registerhigh)));
  81. {$endif TEMPS_NOT_PUSH}
  82. ungetregister32(p.location.registerhigh);
  83. end
  84. {$ifdef TEMPS_NOT_PUSH}
  85. else
  86. begin
  87. gettempofsizereference(href,4);
  88. p.temp_offset:=href.offset;
  89. end
  90. {$endif TEMPS_NOT_PUSH}
  91. ;
  92. pushed:=true;
  93. {$ifdef TEMPS_NOT_PUSH}
  94. exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,S_L,p.location.register,href)));
  95. {$else TEMPS_NOT_PUSH}
  96. exprasmlist^.concat(new(paicpu,op_reg(A_PUSH,S_L,p.location.register)));
  97. {$endif TEMPS_NOT_PUSH}
  98. ungetregister32(p.location.register);
  99. end
  100. else if (p.location.loc in [LOC_MEM,LOC_REFERENCE]) and
  101. ((p.location.reference.base<>R_NO) or
  102. (p.location.reference.index<>R_NO)
  103. ) then
  104. begin
  105. del_reference(p.location.reference);
  106. getexplicitregister32(R_EDI);
  107. emit_ref_reg(A_LEA,S_L,newreference(p.location.reference),R_EDI);
  108. {$ifdef TEMPS_NOT_PUSH}
  109. gettempofsizereference(href,4);
  110. exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,S_L,R_EDI,href)));
  111. p.temp_offset:=href.offset;
  112. {$else TEMPS_NOT_PUSH}
  113. exprasmlist^.concat(new(paicpu,op_reg(A_PUSH,S_L,R_EDI)));
  114. {$endif TEMPS_NOT_PUSH}
  115. ungetregister32(R_EDI);
  116. pushed:=true;
  117. end
  118. else pushed:=false;
  119. end
  120. else pushed:=false;
  121. maybe_push:=pushed;
  122. end;
  123. {$ifdef TEMPS_NOT_PUSH}
  124. function maybe_savetotemp(needed : byte;p : tnode;isint64 : boolean) : boolean;
  125. var
  126. pushed : boolean;
  127. href : treference;
  128. begin
  129. if needed>usablereg32 then
  130. begin
  131. if (p^.location.loc=LOC_REGISTER) then
  132. begin
  133. if isint64(p^.resulttype) then
  134. begin
  135. gettempofsizereference(href,8);
  136. p^.temp_offset:=href.offset;
  137. href.offset:=href.offset+4;
  138. exprasmlist^.concat(new(paicpu,op_reg(A_MOV,S_L,p^.location.registerhigh,href)));
  139. href.offset:=href.offset-4;
  140. ungetregister32(p^.location.registerhigh);
  141. end
  142. else
  143. begin
  144. gettempofsizereference(href,4);
  145. p^.temp_offset:=href.offset;
  146. end;
  147. pushed:=true;
  148. exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,S_L,p^.location.register,href)));
  149. ungetregister32(p^.location.register);
  150. end
  151. else if (p^.location.loc in [LOC_MEM,LOC_REFERENCE]) and
  152. ((p^.location.reference.base<>R_NO) or
  153. (p^.location.reference.index<>R_NO)
  154. ) then
  155. begin
  156. del_reference(p^.location.reference);
  157. getexplicitregister32(R_EDI);
  158. emit_ref_reg(A_LEA,S_L,newreference(p^.location.reference),
  159. R_EDI);
  160. gettempofsizereference(href,4);
  161. exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,S_L,R_EDI,href)));
  162. ungetregister32(R_EDI);
  163. p^.temp_offset:=href.offset;
  164. pushed:=true;
  165. end
  166. else pushed:=false;
  167. end
  168. else pushed:=false;
  169. maybe_push:=pushed;
  170. end;
  171. {$endif TEMPS_NOT_PUSH}
  172. procedure restore(p : tnode;isint64 : boolean);
  173. var
  174. hregister : tregister;
  175. {$ifdef TEMPS_NOT_PUSH}
  176. href : treference;
  177. {$endif TEMPS_NOT_PUSH}
  178. begin
  179. hregister:=getregister32;
  180. {$ifdef TEMPS_NOT_PUSH}
  181. reset_reference(href);
  182. href.base:=procinfo^.frame_pointer;
  183. href.offset:=p.temp_offset;
  184. emit_ref_reg(A_MOV,S_L,href,hregister);
  185. {$else TEMPS_NOT_PUSH}
  186. exprasmlist^.concat(new(paicpu,op_reg(A_POP,S_L,hregister)));
  187. {$endif TEMPS_NOT_PUSH}
  188. if (p.location.loc in [LOC_REGISTER,LOC_CREGISTER]) then
  189. begin
  190. p.location.register:=hregister;
  191. if isint64 then
  192. begin
  193. p.location.registerhigh:=getregister32;
  194. {$ifdef TEMPS_NOT_PUSH}
  195. href.offset:=p.temp_offset+4;
  196. emit_ref_reg(A_MOV,S_L,p.location.registerhigh);
  197. { set correctly for release ! }
  198. href.offset:=p.temp_offset;
  199. {$else TEMPS_NOT_PUSH}
  200. exprasmlist^.concat(new(paicpu,op_reg(A_POP,S_L,p.location.registerhigh)));
  201. {$endif TEMPS_NOT_PUSH}
  202. end;
  203. end
  204. else
  205. begin
  206. reset_reference(p.location.reference);
  207. { any reasons why this was moved into the index register ? }
  208. { normally usage of base register is much better (FK) }
  209. p.location.reference.base:=hregister;
  210. { Why is this done? We can never be sure about p.left
  211. because otherwise secondload fails !!!
  212. set_location(p.left^.location,p.location);}
  213. end;
  214. {$ifdef TEMPS_NOT_PUSH}
  215. ungetiftemp(href);
  216. {$endif TEMPS_NOT_PUSH}
  217. end;
  218. {$ifdef TEMPS_NOT_PUSH}
  219. procedure restorefromtemp(p : tnode;isint64 : boolean);
  220. var
  221. hregister : tregister;
  222. href : treference;
  223. begin
  224. hregister:=getregister32;
  225. reset_reference(href);
  226. href.base:=procinfo^.frame_pointer;
  227. href.offset:=p.temp_offset;
  228. emit_ref_reg(A_MOV,S_L,href,hregister);
  229. if (p.location.loc in [LOC_REGISTER,LOC_CREGISTER]) then
  230. begin
  231. p.location.register:=hregister;
  232. if isint64 then
  233. begin
  234. p.location.registerhigh:=getregister32;
  235. href.offset:=p.temp_offset+4;
  236. emit_ref_reg(A_MOV,S_L,p.location.registerhigh);
  237. { set correctly for release ! }
  238. href.offset:=p.temp_offset;
  239. end;
  240. end
  241. else
  242. begin
  243. reset_reference(p.location.reference);
  244. p.location.reference.base:=hregister;
  245. { Why is this done? We can never be sure about p^.left
  246. because otherwise secondload fails PM
  247. set_location(p^.left^.location,p^.location);}
  248. end;
  249. ungetiftemp(href);
  250. end;
  251. {$endif TEMPS_NOT_PUSH}
  252. procedure pushsetelement(p : tnode);
  253. var
  254. hr,hr16,hr32 : tregister;
  255. begin
  256. { copy the element on the stack, slightly complicated }
  257. if p.nodetype=ordconstn then
  258. begin
  259. if target_os.stackalignment=4 then
  260. exprasmlist^.concat(new(paicpu,op_const(A_PUSH,S_L,tordconstnode(p).value)))
  261. else
  262. exprasmlist^.concat(new(paicpu,op_const(A_PUSH,S_W,tordconstnode(p).value)));
  263. end
  264. else
  265. begin
  266. case p.location.loc of
  267. LOC_REGISTER,
  268. LOC_CREGISTER :
  269. begin
  270. hr:=p.location.register;
  271. case hr of
  272. R_EAX,R_EBX,R_ECX,R_EDX,R_EDI,R_ESI,R_ESP :
  273. begin
  274. hr16:=reg32toreg16(hr);
  275. hr32:=hr;
  276. end;
  277. R_AX,R_BX,R_CX,R_DX,R_DI,R_SI,R_SP :
  278. begin
  279. hr16:=hr;
  280. hr32:=reg16toreg32(hr);
  281. end;
  282. R_AL,R_BL,R_CL,R_DL :
  283. begin
  284. hr16:=reg8toreg16(hr);
  285. hr32:=reg8toreg32(hr);
  286. end;
  287. end;
  288. if target_os.stackalignment=4 then
  289. exprasmlist^.concat(new(paicpu,op_reg(A_PUSH,S_L,hr32)))
  290. else
  291. exprasmlist^.concat(new(paicpu,op_reg(A_PUSH,S_W,hr16)));
  292. ungetregister32(hr32);
  293. end;
  294. else
  295. begin
  296. { you can't push more bytes than the size of the element, }
  297. { because this may cross a page boundary and you'll get a }
  298. { sigsegv (JM) }
  299. emit_push_mem_size(p.location.reference,1);
  300. del_reference(p.location.reference);
  301. end;
  302. end;
  303. end;
  304. end;
  305. procedure push_value_para(p:tnode;inlined,is_cdecl:boolean;
  306. para_offset:longint;alignment : longint);
  307. var
  308. tempreference : treference;
  309. r : preference;
  310. opsize : topsize;
  311. op : tasmop;
  312. hreg : tregister;
  313. size : longint;
  314. hlabel : pasmlabel;
  315. begin
  316. case p.location.loc of
  317. LOC_REGISTER,
  318. LOC_CREGISTER:
  319. begin
  320. case p.location.register of
  321. R_EAX,R_EBX,R_ECX,R_EDX,R_ESI,
  322. R_EDI,R_ESP,R_EBP :
  323. begin
  324. if p.resulttype^.size=8 then
  325. begin
  326. inc(pushedparasize,8);
  327. if inlined then
  328. begin
  329. r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
  330. exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,S_L,
  331. p.location.registerlow,r)));
  332. r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize+4);
  333. exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,S_L,
  334. p.location.registerhigh,r)));
  335. end
  336. else
  337. exprasmlist^.concat(new(paicpu,op_reg(A_PUSH,S_L,p.location.registerhigh)));
  338. ungetregister32(p.location.registerhigh);
  339. exprasmlist^.concat(new(paicpu,op_reg(A_PUSH,S_L,p.location.registerlow)));
  340. ungetregister32(p.location.registerlow);
  341. end
  342. else
  343. begin
  344. inc(pushedparasize,4);
  345. if inlined then
  346. begin
  347. r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
  348. exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,S_L,
  349. p.location.register,r)));
  350. end
  351. else
  352. exprasmlist^.concat(new(paicpu,op_reg(A_PUSH,S_L,p.location.register)));
  353. ungetregister32(p.location.register);
  354. end;
  355. end;
  356. R_AX,R_BX,R_CX,R_DX,R_SI,R_DI:
  357. begin
  358. if alignment=4 then
  359. begin
  360. opsize:=S_L;
  361. hreg:=reg16toreg32(p.location.register);
  362. inc(pushedparasize,4);
  363. end
  364. else
  365. begin
  366. opsize:=S_W;
  367. hreg:=p.location.register;
  368. inc(pushedparasize,2);
  369. end;
  370. if inlined then
  371. begin
  372. r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
  373. exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,opsize,hreg,r)));
  374. end
  375. else
  376. exprasmlist^.concat(new(paicpu,op_reg(A_PUSH,opsize,hreg)));
  377. ungetregister32(reg16toreg32(p.location.register));
  378. end;
  379. R_AL,R_BL,R_CL,R_DL:
  380. begin
  381. if alignment=4 then
  382. begin
  383. opsize:=S_L;
  384. hreg:=reg8toreg32(p.location.register);
  385. inc(pushedparasize,4);
  386. end
  387. else
  388. begin
  389. opsize:=S_W;
  390. hreg:=reg8toreg16(p.location.register);
  391. inc(pushedparasize,2);
  392. end;
  393. { we must push always 16 bit }
  394. if inlined then
  395. begin
  396. r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
  397. exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,opsize,hreg,r)));
  398. end
  399. else
  400. exprasmlist^.concat(new(paicpu,op_reg(A_PUSH,opsize,hreg)));
  401. ungetregister32(reg8toreg32(p.location.register));
  402. end;
  403. else internalerror(1899);
  404. end;
  405. end;
  406. LOC_FPU:
  407. begin
  408. size:=align(pfloatdef(p.resulttype)^.size,alignment);
  409. inc(pushedparasize,size);
  410. if not inlined then
  411. emit_const_reg(A_SUB,S_L,size,R_ESP);
  412. {$ifdef GDB}
  413. if (cs_debuginfo in aktmoduleswitches) and
  414. (exprasmlist^.first=exprasmlist^.last) then
  415. exprasmlist^.concat(new(pai_force_line,init));
  416. {$endif GDB}
  417. r:=new_reference(R_ESP,0);
  418. floatstoreops(pfloatdef(p.resulttype)^.typ,op,opsize);
  419. { this is the easiest case for inlined !! }
  420. if inlined then
  421. begin
  422. r^.base:=procinfo^.framepointer;
  423. r^.offset:=para_offset-pushedparasize;
  424. end;
  425. exprasmlist^.concat(new(paicpu,op_ref(op,opsize,r)));
  426. dec(fpuvaroffset);
  427. end;
  428. LOC_CFPUREGISTER:
  429. begin
  430. exprasmlist^.concat(new(paicpu,op_reg(A_FLD,S_NO,
  431. correct_fpuregister(p.location.register,fpuvaroffset))));
  432. size:=align(pfloatdef(p.resulttype)^.size,alignment);
  433. inc(pushedparasize,size);
  434. if not inlined then
  435. emit_const_reg(A_SUB,S_L,size,R_ESP);
  436. {$ifdef GDB}
  437. if (cs_debuginfo in aktmoduleswitches) and
  438. (exprasmlist^.first=exprasmlist^.last) then
  439. exprasmlist^.concat(new(pai_force_line,init));
  440. {$endif GDB}
  441. r:=new_reference(R_ESP,0);
  442. floatstoreops(pfloatdef(p.resulttype)^.typ,op,opsize);
  443. { this is the easiest case for inlined !! }
  444. if inlined then
  445. begin
  446. r^.base:=procinfo^.framepointer;
  447. r^.offset:=para_offset-pushedparasize;
  448. end;
  449. exprasmlist^.concat(new(paicpu,op_ref(op,opsize,r)));
  450. end;
  451. LOC_REFERENCE,LOC_MEM:
  452. begin
  453. tempreference:=p.location.reference;
  454. del_reference(p.location.reference);
  455. case p.resulttype^.deftype of
  456. enumdef,
  457. orddef :
  458. begin
  459. case p.resulttype^.size of
  460. 8 : begin
  461. inc(pushedparasize,8);
  462. if inlined then
  463. begin
  464. getexplicitregister32(R_EDI);
  465. emit_ref_reg(A_MOV,S_L,
  466. newreference(tempreference),R_EDI);
  467. r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
  468. exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,S_L,R_EDI,r)));
  469. ungetregister32(R_EDI);
  470. getexplicitregister32(R_EDI);
  471. inc(tempreference.offset,4);
  472. emit_ref_reg(A_MOV,S_L,
  473. newreference(tempreference),R_EDI);
  474. r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize+4);
  475. exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,S_L,R_EDI,r)));
  476. ungetregister32(R_EDI);
  477. end
  478. else
  479. begin
  480. inc(tempreference.offset,4);
  481. emit_push_mem(tempreference);
  482. dec(tempreference.offset,4);
  483. emit_push_mem(tempreference);
  484. end;
  485. end;
  486. 4 : begin
  487. inc(pushedparasize,4);
  488. if inlined then
  489. begin
  490. getexplicitregister32(R_EDI);
  491. emit_ref_reg(A_MOV,S_L,
  492. newreference(tempreference),R_EDI);
  493. r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
  494. exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,S_L,R_EDI,r)));
  495. ungetregister32(R_EDI);
  496. end
  497. else
  498. emit_push_mem(tempreference);
  499. end;
  500. 1,2 : begin
  501. if alignment=4 then
  502. begin
  503. opsize:=S_L;
  504. hreg:=R_EDI;
  505. inc(pushedparasize,4);
  506. end
  507. else
  508. begin
  509. opsize:=S_W;
  510. hreg:=R_DI;
  511. inc(pushedparasize,2);
  512. end;
  513. if inlined then
  514. begin
  515. getexplicitregister32(R_EDI);
  516. emit_ref_reg(A_MOV,opsize,
  517. newreference(tempreference),hreg);
  518. r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
  519. exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,opsize,hreg,r)));
  520. ungetregister32(R_EDI);
  521. end
  522. else
  523. emit_push_mem_size(tempreference,p.resulttype^.size);
  524. end;
  525. else
  526. internalerror(234231);
  527. end;
  528. end;
  529. floatdef :
  530. begin
  531. case pfloatdef(p.resulttype)^.typ of
  532. f32bit,
  533. s32real :
  534. begin
  535. inc(pushedparasize,4);
  536. if inlined then
  537. begin
  538. getexplicitregister32(R_EDI);
  539. emit_ref_reg(A_MOV,S_L,
  540. newreference(tempreference),R_EDI);
  541. r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
  542. exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,S_L,R_EDI,r)));
  543. ungetregister32(R_EDI);
  544. end
  545. else
  546. emit_push_mem(tempreference);
  547. end;
  548. s64real,
  549. s64comp :
  550. begin
  551. inc(pushedparasize,4);
  552. inc(tempreference.offset,4);
  553. if inlined then
  554. begin
  555. getexplicitregister32(R_EDI);
  556. emit_ref_reg(A_MOV,S_L,
  557. newreference(tempreference),R_EDI);
  558. r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
  559. exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,S_L,R_EDI,r)));
  560. ungetregister32(R_EDI);
  561. end
  562. else
  563. emit_push_mem(tempreference);
  564. inc(pushedparasize,4);
  565. dec(tempreference.offset,4);
  566. if inlined then
  567. begin
  568. getexplicitregister32(R_EDI);
  569. emit_ref_reg(A_MOV,S_L,
  570. newreference(tempreference),R_EDI);
  571. r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
  572. exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,S_L,R_EDI,r)));
  573. ungetregister32(R_EDI);
  574. end
  575. else
  576. emit_push_mem(tempreference);
  577. end;
  578. s80real :
  579. begin
  580. inc(pushedparasize,4);
  581. if alignment=4 then
  582. inc(tempreference.offset,8)
  583. else
  584. inc(tempreference.offset,6);
  585. if inlined then
  586. begin
  587. getexplicitregister32(R_EDI);
  588. emit_ref_reg(A_MOV,S_L,
  589. newreference(tempreference),R_EDI);
  590. r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
  591. exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,S_L,R_EDI,r)));
  592. ungetregister32(R_EDI);
  593. end
  594. else
  595. emit_push_mem(tempreference);
  596. dec(tempreference.offset,4);
  597. inc(pushedparasize,4);
  598. if inlined then
  599. begin
  600. getexplicitregister32(R_EDI);
  601. emit_ref_reg(A_MOV,S_L,
  602. newreference(tempreference),R_EDI);
  603. r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
  604. exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,S_L,R_EDI,r)));
  605. ungetregister32(R_EDI);
  606. end
  607. else
  608. emit_push_mem(tempreference);
  609. if alignment=4 then
  610. begin
  611. opsize:=S_L;
  612. hreg:=R_EDI;
  613. inc(pushedparasize,4);
  614. dec(tempreference.offset,4);
  615. end
  616. else
  617. begin
  618. opsize:=S_W;
  619. hreg:=R_DI;
  620. inc(pushedparasize,2);
  621. dec(tempreference.offset,2);
  622. end;
  623. if inlined then
  624. begin
  625. getexplicitregister32(R_EDI);
  626. emit_ref_reg(A_MOV,opsize,
  627. newreference(tempreference),hreg);
  628. r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
  629. exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,opsize,hreg,r)));
  630. ungetregister32(R_EDI);
  631. end
  632. else
  633. exprasmlist^.concat(new(paicpu,op_ref(A_PUSH,opsize,
  634. newreference(tempreference))));
  635. end;
  636. end;
  637. end;
  638. pointerdef,
  639. procvardef,
  640. classrefdef:
  641. begin
  642. inc(pushedparasize,4);
  643. if inlined then
  644. begin
  645. getexplicitregister32(R_EDI);
  646. emit_ref_reg(A_MOV,S_L,
  647. newreference(tempreference),R_EDI);
  648. r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
  649. exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,S_L,R_EDI,r)));
  650. ungetregister32(R_EDI);
  651. end
  652. else
  653. emit_push_mem(tempreference);
  654. end;
  655. arraydef,
  656. recorddef,
  657. stringdef,
  658. setdef,
  659. objectdef :
  660. begin
  661. { even some structured types are 32 bit }
  662. if is_widestring(p.resulttype) or
  663. is_ansistring(p.resulttype) or
  664. is_smallset(p.resulttype) or
  665. ((p.resulttype^.deftype in [recorddef,arraydef]) and
  666. (
  667. (p.resulttype^.deftype<>arraydef) or not
  668. (parraydef(p.resulttype)^.IsConstructor or
  669. parraydef(p.resulttype)^.isArrayOfConst or
  670. is_open_array(p.resulttype))
  671. ) and
  672. (p.resulttype^.size<=4)
  673. ) or
  674. is_class(p.resulttype) or
  675. is_interface(p.resulttype) then
  676. begin
  677. if (p.resulttype^.size>2) or
  678. ((alignment=4) and (p.resulttype^.size>0)) then
  679. begin
  680. inc(pushedparasize,4);
  681. if inlined then
  682. begin
  683. r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
  684. concatcopy(tempreference,r^,4,false,false);
  685. end
  686. else
  687. emit_push_mem(tempreference);
  688. end
  689. else
  690. begin
  691. if p.resulttype^.size>0 then
  692. begin
  693. inc(pushedparasize,2);
  694. if inlined then
  695. begin
  696. r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
  697. concatcopy(tempreference,r^,2,false,false);
  698. end
  699. else
  700. exprasmlist^.concat(new(paicpu,op_ref(A_PUSH,S_W,newreference(tempreference))));
  701. end;
  702. end;
  703. end
  704. { call by value open array ? }
  705. else if is_cdecl then
  706. begin
  707. { push on stack }
  708. size:=align(p.resulttype^.size,alignment);
  709. inc(pushedparasize,size);
  710. emit_const_reg(A_SUB,S_L,size,R_ESP);
  711. r:=new_reference(R_ESP,0);
  712. concatcopy(tempreference,r^,size,false,false);
  713. end
  714. else
  715. internalerror(8954);
  716. end;
  717. else
  718. CGMessage(cg_e_illegal_expression);
  719. end;
  720. end;
  721. LOC_JUMP:
  722. begin
  723. getlabel(hlabel);
  724. if alignment=4 then
  725. begin
  726. opsize:=S_L;
  727. inc(pushedparasize,4);
  728. end
  729. else
  730. begin
  731. opsize:=S_W;
  732. inc(pushedparasize,2);
  733. end;
  734. emitlab(truelabel);
  735. if inlined then
  736. begin
  737. r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
  738. emit_const_ref(A_MOV,opsize,1,r);
  739. end
  740. else
  741. exprasmlist^.concat(new(paicpu,op_const(A_PUSH,opsize,1)));
  742. emitjmp(C_None,hlabel);
  743. emitlab(falselabel);
  744. if inlined then
  745. begin
  746. r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
  747. emit_const_ref(A_MOV,opsize,0,r);
  748. end
  749. else
  750. exprasmlist^.concat(new(paicpu,op_const(A_PUSH,opsize,0)));
  751. emitlab(hlabel);
  752. end;
  753. LOC_FLAGS:
  754. begin
  755. if not(R_EAX in unused) then
  756. begin
  757. getexplicitregister32(R_EDI);
  758. emit_reg_reg(A_MOV,S_L,R_EAX,R_EDI);
  759. end;
  760. emit_flag2reg(p.location.resflags,R_AL);
  761. emit_reg_reg(A_MOVZX,S_BW,R_AL,R_AX);
  762. if alignment=4 then
  763. begin
  764. opsize:=S_L;
  765. hreg:=R_EAX;
  766. inc(pushedparasize,4);
  767. end
  768. else
  769. begin
  770. opsize:=S_W;
  771. hreg:=R_AX;
  772. inc(pushedparasize,2);
  773. end;
  774. if inlined then
  775. begin
  776. r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
  777. exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,opsize,hreg,r)));
  778. end
  779. else
  780. exprasmlist^.concat(new(paicpu,op_reg(A_PUSH,opsize,hreg)));
  781. if not(R_EAX in unused) then
  782. begin
  783. emit_reg_reg(A_MOV,S_L,R_EDI,R_EAX);
  784. ungetregister32(R_EDI);
  785. end;
  786. end;
  787. {$ifdef SUPPORT_MMX}
  788. LOC_MMXREGISTER,
  789. LOC_CMMXREGISTER:
  790. begin
  791. inc(pushedparasize,8); { was missing !!! (PM) }
  792. emit_const_reg(
  793. A_SUB,S_L,8,R_ESP);
  794. {$ifdef GDB}
  795. if (cs_debuginfo in aktmoduleswitches) and
  796. (exprasmlist^.first=exprasmlist^.last) then
  797. exprasmlist^.concat(new(pai_force_line,init));
  798. {$endif GDB}
  799. if inlined then
  800. begin
  801. r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
  802. exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOVQ,S_NO,
  803. p.location.register,r)));
  804. end
  805. else
  806. begin
  807. r:=new_reference(R_ESP,0);
  808. exprasmlist^.concat(new(paicpu,op_reg_ref(
  809. A_MOVQ,S_NO,p.location.register,r)));
  810. end;
  811. end;
  812. {$endif SUPPORT_MMX}
  813. end;
  814. end;
  815. {*****************************************************************************
  816. Emit Functions
  817. *****************************************************************************}
  818. procedure maketojumpbool(p : tnode);
  819. {
  820. produces jumps to true respectively false labels using boolean expressions
  821. }
  822. var
  823. opsize : topsize;
  824. storepos : tfileposinfo;
  825. begin
  826. if nf_error in p.flags then
  827. exit;
  828. storepos:=aktfilepos;
  829. aktfilepos:=p.fileinfo;
  830. if is_boolean(p.resulttype) then
  831. begin
  832. if is_constboolnode(p) then
  833. begin
  834. if tordconstnode(p).value<>0 then
  835. emitjmp(C_None,truelabel)
  836. else
  837. emitjmp(C_None,falselabel);
  838. end
  839. else
  840. begin
  841. opsize:=def_opsize(p.resulttype);
  842. case p.location.loc of
  843. LOC_CREGISTER,LOC_REGISTER : begin
  844. emit_reg_reg(A_OR,opsize,p.location.register,
  845. p.location.register);
  846. ungetregister(p.location.register);
  847. emitjmp(C_NZ,truelabel);
  848. emitjmp(C_None,falselabel);
  849. end;
  850. LOC_MEM,LOC_REFERENCE : begin
  851. emit_const_ref(
  852. A_CMP,opsize,0,newreference(p.location.reference));
  853. del_reference(p.location.reference);
  854. emitjmp(C_NZ,truelabel);
  855. emitjmp(C_None,falselabel);
  856. end;
  857. LOC_FLAGS : begin
  858. emitjmp(flag_2_cond[p.location.resflags],truelabel);
  859. emitjmp(C_None,falselabel);
  860. end;
  861. end;
  862. end;
  863. end
  864. else
  865. CGMessage(type_e_mismatch);
  866. aktfilepos:=storepos;
  867. end;
  868. { produces if necessary overflowcode }
  869. procedure emitoverflowcheck(p:tnode);
  870. var
  871. hl : pasmlabel;
  872. begin
  873. if not(cs_check_overflow in aktlocalswitches) then
  874. exit;
  875. getlabel(hl);
  876. if not ((p.resulttype^.deftype=pointerdef) or
  877. ((p.resulttype^.deftype=orddef) and
  878. (porddef(p.resulttype)^.typ in [u64bit,u16bit,u32bit,u8bit,uchar,
  879. bool8bit,bool16bit,bool32bit]))) then
  880. emitjmp(C_NO,hl)
  881. else
  882. emitjmp(C_NB,hl);
  883. emitcall('FPC_OVERFLOW');
  884. emitlab(hl);
  885. end;
  886. { produces range check code, while one of the operands is a 64 bit
  887. integer }
  888. procedure emitrangecheck64(p : tnode;todef : pdef);
  889. begin
  890. CGMessage(cg_w_64bit_range_check_not_supported);
  891. {internalerror(28699);}
  892. end;
  893. { produces if necessary rangecheckcode }
  894. procedure emitrangecheck(p:tnode;todef:pdef);
  895. {
  896. generate range checking code for the value at location t. The
  897. type used is the checked against todefs ranges. fromdef (p.resulttype)
  898. is the original type used at that location, when both defs are
  899. equal the check is also insert (needed for succ,pref,inc,dec)
  900. }
  901. var
  902. neglabel,
  903. poslabel : pasmlabel;
  904. href : treference;
  905. rstr : string;
  906. hreg : tregister;
  907. opsize : topsize;
  908. op : tasmop;
  909. fromdef : pdef;
  910. lto,hto,
  911. lfrom,hfrom : longint;
  912. doublebound,
  913. is_reg,
  914. popecx : boolean;
  915. begin
  916. { range checking on and range checkable value? }
  917. if not(cs_check_range in aktlocalswitches) or
  918. not(todef^.deftype in [orddef,enumdef,arraydef]) then
  919. exit;
  920. { only check when assigning to scalar, subranges are different,
  921. when todef=fromdef then the check is always generated }
  922. fromdef:=p.resulttype;
  923. if is_64bitint(fromdef) or is_64bitint(todef) then
  924. begin
  925. emitrangecheck64(p,todef);
  926. exit;
  927. end;
  928. {we also need lto and hto when checking if we need to use doublebound!
  929. (JM)}
  930. getrange(todef,lto,hto);
  931. if todef<>fromdef then
  932. begin
  933. getrange(p.resulttype,lfrom,hfrom);
  934. { first check for not being u32bit, then if the to is bigger than
  935. from }
  936. if (lto<hto) and (lfrom<hfrom) and
  937. (lto<=lfrom) and (hto>=hfrom) then
  938. exit;
  939. end;
  940. { generate the rangecheck code for the def where we are going to
  941. store the result }
  942. doublebound:=false;
  943. case todef^.deftype of
  944. orddef :
  945. begin
  946. porddef(todef)^.genrangecheck;
  947. rstr:=porddef(todef)^.getrangecheckstring;
  948. doublebound:=(porddef(todef)^.typ=u32bit) and (lto>hto);
  949. end;
  950. enumdef :
  951. begin
  952. penumdef(todef)^.genrangecheck;
  953. rstr:=penumdef(todef)^.getrangecheckstring;
  954. end;
  955. arraydef :
  956. begin
  957. parraydef(todef)^.genrangecheck;
  958. rstr:=parraydef(todef)^.getrangecheckstring;
  959. doublebound:=(lto>hto);
  960. end;
  961. end;
  962. { get op and opsize }
  963. opsize:=def2def_opsize(fromdef,u32bitdef);
  964. if opsize in [S_B,S_W,S_L] then
  965. op:=A_MOV
  966. else
  967. if is_signed(fromdef) then
  968. op:=A_MOVSX
  969. else
  970. op:=A_MOVZX;
  971. is_reg:=(p.location.loc in [LOC_REGISTER,LOC_CREGISTER]);
  972. if is_reg then
  973. hreg:=p.location.register;
  974. if not target_os.use_bound_instruction then
  975. begin
  976. { FPC_BOUNDCHECK needs to be called with
  977. %ecx - value
  978. %edi - pointer to the ranges }
  979. popecx:=false;
  980. if not(is_reg) or
  981. (p.location.register<>R_ECX) then
  982. begin
  983. if not(R_ECX in unused) then
  984. begin
  985. exprasmlist^.concat(new(paicpu,op_reg(A_PUSH,S_L,R_ECX)));
  986. popecx:=true;
  987. end
  988. else exprasmlist^.concat(new(pairegalloc,alloc(R_ECX)));
  989. if is_reg then
  990. emit_reg_reg(op,opsize,p.location.register,R_ECX)
  991. else
  992. emit_ref_reg(op,opsize,newreference(p.location.reference),R_ECX);
  993. end;
  994. if doublebound then
  995. begin
  996. getlabel(neglabel);
  997. getlabel(poslabel);
  998. emit_reg_reg(A_OR,S_L,R_ECX,R_ECX);
  999. emitjmp(C_L,neglabel);
  1000. end;
  1001. { insert bound instruction only }
  1002. getexplicitregister32(R_EDI);
  1003. exprasmlist^.concat(new(paicpu,op_sym_ofs_reg(A_MOV,S_L,newasmsymbol(rstr),0,R_EDI)));
  1004. emitcall('FPC_BOUNDCHECK');
  1005. ungetregister32(R_EDI);
  1006. { u32bit needs 2 checks }
  1007. if doublebound then
  1008. begin
  1009. emitjmp(C_None,poslabel);
  1010. emitlab(neglabel);
  1011. getexplicitregister32(R_EDI);
  1012. exprasmlist^.concat(new(paicpu,op_sym_ofs_reg(A_MOV,S_L,newasmsymbol(rstr),8,R_EDI)));
  1013. emitcall('FPC_BOUNDCHECK');
  1014. ungetregister32(R_EDI);
  1015. emitlab(poslabel);
  1016. end;
  1017. if popecx then
  1018. exprasmlist^.concat(new(paicpu,op_reg(A_POP,S_L,R_ECX)))
  1019. else exprasmlist^.concat(new(pairegalloc,dealloc(R_ECX)));
  1020. end
  1021. else
  1022. begin
  1023. reset_reference(href);
  1024. href.symbol:=newasmsymbol(rstr);
  1025. { load the value in a register }
  1026. if is_reg then
  1027. begin
  1028. { be sure that hreg is a 32 bit reg, if not load it in %edi }
  1029. if p.location.register in [R_EAX..R_EDI] then
  1030. hreg:=p.location.register
  1031. else
  1032. begin
  1033. getexplicitregister32(R_EDI);
  1034. emit_reg_reg(op,opsize,p.location.register,R_EDI);
  1035. hreg:=R_EDI;
  1036. end;
  1037. end
  1038. else
  1039. begin
  1040. getexplicitregister32(R_EDI);
  1041. emit_ref_reg(op,opsize,newreference(p.location.reference),R_EDI);
  1042. hreg:=R_EDI;
  1043. end;
  1044. if doublebound then
  1045. begin
  1046. getlabel(neglabel);
  1047. getlabel(poslabel);
  1048. emit_reg_reg(A_TEST,S_L,hreg,hreg);
  1049. emitjmp(C_L,neglabel);
  1050. end;
  1051. { insert bound instruction only }
  1052. exprasmlist^.concat(new(paicpu,op_reg_ref(A_BOUND,S_L,hreg,newreference(href))));
  1053. { u32bit needs 2 checks }
  1054. if doublebound then
  1055. begin
  1056. href.offset:=8;
  1057. emitjmp(C_None,poslabel);
  1058. emitlab(neglabel);
  1059. exprasmlist^.concat(new(paicpu,op_reg_ref(A_BOUND,S_L,hreg,newreference(href))));
  1060. emitlab(poslabel);
  1061. end;
  1062. if hreg = R_EDI then
  1063. ungetregister32(R_EDI);
  1064. end;
  1065. end;
  1066. { DO NOT RELY on the fact that the tnode is not yet swaped
  1067. because of inlining code PM }
  1068. procedure firstcomplex(p : tbinarynode);
  1069. var
  1070. hp : tnode;
  1071. begin
  1072. { always calculate boolean AND and OR from left to right }
  1073. if (p.nodetype in [orn,andn]) and
  1074. (p.left.resulttype^.deftype=orddef) and
  1075. (porddef(p.left.resulttype)^.typ in [bool8bit,bool16bit,bool32bit]) then
  1076. begin
  1077. { p.swaped:=false}
  1078. if nf_swaped in p.flags then
  1079. internalerror(234234);
  1080. end
  1081. else
  1082. if (p.left.registers32<p.right.registers32) and
  1083. { the following check is appropriate, because all }
  1084. { 4 registers are rarely used and it is thereby }
  1085. { achieved that the extra code is being dropped }
  1086. { by exchanging not commutative operators }
  1087. (p.right.registers32<=4) then
  1088. begin
  1089. hp:=p.left;
  1090. p.left:=p.right;
  1091. p.right:=hp;
  1092. if nf_swaped in p.flags then
  1093. exclude(p.flags,nf_swaped)
  1094. else
  1095. include(p.flags,nf_swaped);
  1096. end;
  1097. {else
  1098. p.swaped:=false; do not modify }
  1099. end;
  1100. {*****************************************************************************
  1101. Emit Functions
  1102. *****************************************************************************}
  1103. procedure push_shortstring_length(p:tnode);
  1104. var
  1105. hightree : tnode;
  1106. begin
  1107. if is_open_string(p.resulttype) then
  1108. begin
  1109. getsymonlyin(tloadnode(p).symtable,'high'+pvarsym(tloadnode(p).symtableentry)^.name);
  1110. hightree:=genloadnode(pvarsym(srsym),tloadnode(p).symtable);
  1111. firstpass(hightree);
  1112. secondpass(hightree);
  1113. push_value_para(hightree,false,false,0,4);
  1114. hightree.free;
  1115. hightree:=nil;
  1116. end
  1117. else
  1118. begin
  1119. push_int(pstringdef(p.resulttype)^.len);
  1120. end;
  1121. end;
  1122. {*****************************************************************************
  1123. String functions
  1124. *****************************************************************************}
  1125. procedure loadshortstring(source,dest : tnode);
  1126. {
  1127. Load a string, handles stringdef and orddef (char) types
  1128. }
  1129. begin
  1130. case source.resulttype^.deftype of
  1131. stringdef:
  1132. begin
  1133. if (source.nodetype=stringconstn) and
  1134. (str_length(source)=0) then
  1135. emit_const_ref(
  1136. A_MOV,S_B,0,newreference(dest.location.reference))
  1137. else
  1138. begin
  1139. emitpushreferenceaddr(dest.location.reference);
  1140. emitpushreferenceaddr(source.location.reference);
  1141. push_shortstring_length(dest);
  1142. emitcall('FPC_SHORTSTR_COPY');
  1143. maybe_loadesi;
  1144. end;
  1145. end;
  1146. orddef:
  1147. begin
  1148. if source.nodetype=ordconstn then
  1149. emit_const_ref(
  1150. A_MOV,S_W,tordconstnode(source).value*256+1,newreference(dest.location.reference))
  1151. else
  1152. begin
  1153. { not so elegant (goes better with extra register }
  1154. {$ifndef noAllocEdi}
  1155. getexplicitregister32(R_EDI);
  1156. {$endif noAllocEdi}
  1157. if (source.location.loc in [LOC_REGISTER,LOC_CREGISTER]) then
  1158. begin
  1159. emit_reg_reg(A_MOV,S_L,makereg32(source.location.register),R_EDI);
  1160. ungetregister(source.location.register);
  1161. end
  1162. else
  1163. begin
  1164. emit_ref_reg(A_MOV,S_L,newreference(source.location.reference),R_EDI);
  1165. del_reference(source.location.reference);
  1166. end;
  1167. emit_const_reg(A_SHL,S_L,8,R_EDI);
  1168. emit_const_reg(A_OR,S_L,1,R_EDI);
  1169. emit_reg_ref(A_MOV,S_W,R_DI,newreference(dest.location.reference));
  1170. {$ifndef noAllocEdi}
  1171. ungetregister32(R_EDI);
  1172. {$endif noAllocEdi}
  1173. end;
  1174. end;
  1175. else
  1176. CGMessage(type_e_mismatch);
  1177. end;
  1178. end;
  1179. procedure loadlongstring(p:tbinarynode);
  1180. {
  1181. Load a string, handles stringdef and orddef (char) types
  1182. }
  1183. var
  1184. r : preference;
  1185. begin
  1186. case p.right.resulttype^.deftype of
  1187. stringdef:
  1188. begin
  1189. if (p.right.nodetype=stringconstn) and
  1190. (str_length(p.right)=0) then
  1191. emit_const_ref(A_MOV,S_L,0,newreference(p.left.location.reference))
  1192. else
  1193. begin
  1194. emitpushreferenceaddr(p.left.location.reference);
  1195. emitpushreferenceaddr(p.right.location.reference);
  1196. push_shortstring_length(p.left);
  1197. emitcall('FPC_LONGSTR_COPY');
  1198. maybe_loadesi;
  1199. end;
  1200. end;
  1201. orddef:
  1202. begin
  1203. emit_const_ref(A_MOV,S_L,1,newreference(p.left.location.reference));
  1204. r:=newreference(p.left.location.reference);
  1205. inc(r^.offset,4);
  1206. if p.right.nodetype=ordconstn then
  1207. emit_const_ref(A_MOV,S_B,tordconstnode(p.right).value,r)
  1208. else
  1209. begin
  1210. case p.right.location.loc of
  1211. LOC_REGISTER,LOC_CREGISTER:
  1212. begin
  1213. emit_reg_ref(A_MOV,S_B,p.right.location.register,r);
  1214. ungetregister(p.right.location.register);
  1215. end;
  1216. LOC_MEM,LOC_REFERENCE:
  1217. begin
  1218. if not(R_EAX in unused) then
  1219. emit_reg(A_PUSH,S_L,R_EAX);
  1220. emit_ref_reg(A_MOV,S_B,newreference(p.right.location.reference),R_AL);
  1221. emit_reg_ref(A_MOV,S_B,R_AL,r);
  1222. if not(R_EAX in unused) then
  1223. emit_reg(A_POP,S_L,R_EAX);
  1224. del_reference(p.right.location.reference);
  1225. end
  1226. else
  1227. internalerror(20799);
  1228. end;
  1229. end;
  1230. end;
  1231. else
  1232. CGMessage(type_e_mismatch);
  1233. end;
  1234. end;
  1235. procedure loadansi2short(source,dest : tnode);
  1236. var
  1237. pushed : tpushed;
  1238. regs_to_push: byte;
  1239. begin
  1240. { Find out which registers have to be pushed (JM) }
  1241. regs_to_push := $ff;
  1242. remove_non_regvars_from_loc(source.location,regs_to_push);
  1243. { Push them (JM) }
  1244. pushusedregisters(pushed,regs_to_push);
  1245. case source.location.loc of
  1246. LOC_REFERENCE,LOC_MEM:
  1247. begin
  1248. { Now release the location and registers (see cgai386.pas: }
  1249. { loadansistring for more info on the order) (JM) }
  1250. ungetiftemp(source.location.reference);
  1251. del_reference(source.location.reference);
  1252. emit_push_mem(source.location.reference);
  1253. end;
  1254. LOC_REGISTER,LOC_CREGISTER:
  1255. begin
  1256. emit_reg(A_PUSH,S_L,source.location.register);
  1257. { Now release the register (JM) }
  1258. ungetregister32(source.location.register);
  1259. end;
  1260. end;
  1261. push_shortstring_length(dest);
  1262. emitpushreferenceaddr(dest.location.reference);
  1263. emitcall('FPC_ANSISTR_TO_SHORTSTR');
  1264. popusedregisters(pushed);
  1265. maybe_loadesi;
  1266. end;
  1267. procedure loadinterfacecom(p: tbinarynode);
  1268. {
  1269. copies an com interface from n.right to n.left, we
  1270. assume, that both sides are com interface, firstassignement have
  1271. to take care of that, an com interface can't be a register variable
  1272. }
  1273. var
  1274. pushed : tpushed;
  1275. ungettemp : boolean;
  1276. begin
  1277. { before pushing any parameter, we have to save all used }
  1278. { registers, but before that we have to release the }
  1279. { registers of that node to save uneccessary pushed }
  1280. { so be careful, if you think you can optimize that code (FK) }
  1281. { nevertheless, this has to be changed, because otherwise the }
  1282. { register is released before it's contents are pushed -> }
  1283. { problems with the optimizer (JM) }
  1284. del_reference(p.left.location.reference);
  1285. ungettemp:=false;
  1286. case p.right.location.loc of
  1287. LOC_REGISTER,LOC_CREGISTER:
  1288. begin
  1289. pushusedregisters(pushed, $ff xor ($80 shr byte(p.right.location.register)));
  1290. exprasmlist^.concat(new(paicpu,op_reg(A_PUSH,S_L,p.right.location.register)));
  1291. ungetregister32(p.right.location.register);
  1292. end;
  1293. LOC_REFERENCE,LOC_MEM:
  1294. begin
  1295. pushusedregisters(pushed,$ff
  1296. xor ($80 shr byte(p.right.location.reference.base))
  1297. xor ($80 shr byte(p.right.location.reference.index)));
  1298. emit_push_mem(p.right.location.reference);
  1299. del_reference(p.right.location.reference);
  1300. ungettemp:=true;
  1301. end;
  1302. end;
  1303. emitpushreferenceaddr(p.left.location.reference);
  1304. del_reference(p.left.location.reference);
  1305. emitcall('FPC_INTF_ASSIGN');
  1306. maybe_loadesi;
  1307. popusedregisters(pushed);
  1308. if ungettemp then
  1309. ungetiftemp(p.right.location.reference);
  1310. end;
  1311. end.
  1312. {
  1313. $Log$
  1314. Revision 1.3 2000-11-04 14:25:25 florian
  1315. + merged Attila's changes for interfaces, not tested yet
  1316. Revision 1.2 2000/10/31 22:02:57 peter
  1317. * symtable splitted, no real code changes
  1318. Revision 1.1 2000/10/15 09:33:32 peter
  1319. * moved n386*.pas to i386/ cpu_target dir
  1320. Revision 1.3 2000/10/14 21:52:54 peter
  1321. * fixed memory leaks
  1322. Revision 1.2 2000/10/14 10:14:50 peter
  1323. * moehrendorf oct 2000 rewrite
  1324. Revision 1.1 2000/10/01 19:58:40 peter
  1325. * new file
  1326. }