n386util.pas 60 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499
  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,symbase,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. var
  890. neglabel,
  891. poslabel,
  892. endlabel: pasmlabel;
  893. href : preference;
  894. hreg : tregister;
  895. hdef : porddef;
  896. fromdef : pdef;
  897. oldregisterdef: boolean;
  898. from_signed,to_signed: boolean;
  899. begin
  900. fromdef:=p.resulttype;
  901. if is_64bitint(todef) then
  902. CGMessage(cg_w_64bit_range_check_not_supported)
  903. else
  904. begin
  905. oldregisterdef := registerdef;
  906. registerdef := false;
  907. from_signed := is_signed(fromdef);
  908. to_signed := is_signed(todef);
  909. { get the high dword in a register }
  910. if p.location.loc in [LOC_REGISTER,LOC_CREGISTER] then
  911. hreg := p.location.registerhigh
  912. else
  913. begin
  914. hreg := getexplicitregister32(R_EDI);
  915. href := newreference(p.location.reference);
  916. inc(href^.offset,4);
  917. emit_ref_reg(A_MOV,S_L,href,hreg);
  918. end;
  919. getlabel(poslabel);
  920. { check high dword, must be 0 (for positive numbers) }
  921. emit_reg_reg(A_TEST,S_L,hreg,hreg);
  922. emitjmp(C_E,poslabel);
  923. { It can also be $ffffffff, but only for negative numbers }
  924. if from_signed and to_signed then
  925. begin
  926. getlabel(neglabel);
  927. emit_const_reg(A_CMP,S_L,$ffffffff,hreg);
  928. emitjmp(C_E,neglabel);
  929. end;
  930. if hreg = R_EDI then
  931. ungetregister32(hreg);
  932. { For all other values we have a range check error }
  933. emitcall('FPC_RANGEERROR');
  934. { if the high dword = 0, the low dword can be considered a }
  935. { simple cardinal }
  936. emitlab(poslabel);
  937. new(hdef,init(u32bit,0,$ffffffff));
  938. { the real p.resulttype is already saved in fromdef }
  939. p.resulttype := hdef;
  940. emitrangecheck(p,todef);
  941. dispose(hdef,done);
  942. { restore original resulttype }
  943. p.resulttype := todef;
  944. if from_signed and to_signed then
  945. begin
  946. getlabel(endlabel);
  947. emitjmp(C_NO,endlabel);
  948. { if the high dword = $ffffffff, then the low dword (when }
  949. { considered as a longint) must be < 0 (JM) }
  950. emitlab(neglabel);
  951. if p.location.loc in [LOC_REGISTER,LOC_CREGISTER] then
  952. hreg := p.location.registerlow
  953. else
  954. begin
  955. hreg := getexplicitregister32(R_EDI);
  956. emit_ref_reg(A_MOV,S_L,
  957. newreference(p.location.reference),hreg);
  958. end;
  959. { get a new neglabel (JM) }
  960. getlabel(neglabel);
  961. emit_reg_reg(A_TEST,S_L,hreg,hreg);
  962. if hreg = R_EDI then
  963. ungetregister32(hreg);
  964. emitjmp(C_L,neglabel);
  965. emitcall('FPC_RANGEERROR');
  966. { if we get here, the 64bit value lies between }
  967. { longint($80000000) and -1 (JM) }
  968. emitlab(neglabel);
  969. new(hdef,init(s32bit,$80000000,-1));
  970. p.resulttype := hdef;
  971. emitrangecheck(p,todef);
  972. dispose(hdef,done);
  973. emitlab(endlabel);
  974. { restore p's resulttype }
  975. p.resulttype := fromdef;
  976. end;
  977. registerdef := oldregisterdef;
  978. end;
  979. end;
  980. { produces if necessary rangecheckcode }
  981. procedure emitrangecheck(p:tnode;todef:pdef);
  982. {
  983. generate range checking code for the value at location t. The
  984. type used is the checked against todefs ranges. fromdef (p.resulttype)
  985. is the original type used at that location, when both defs are
  986. equal the check is also insert (needed for succ,pref,inc,dec)
  987. }
  988. var
  989. neglabel,
  990. poslabel : pasmlabel;
  991. href : treference;
  992. rstr : string;
  993. hreg : tregister;
  994. opsize : topsize;
  995. op : tasmop;
  996. fromdef : pdef;
  997. lto,hto,
  998. lfrom,hfrom : longint;
  999. doublebound,
  1000. is_reg,
  1001. popecx : boolean;
  1002. begin
  1003. { range checking on and range checkable value? }
  1004. if not(cs_check_range in aktlocalswitches) or
  1005. not(todef^.deftype in [orddef,enumdef,arraydef]) then
  1006. exit;
  1007. { only check when assigning to scalar, subranges are different,
  1008. when todef=fromdef then the check is always generated }
  1009. fromdef:=p.resulttype;
  1010. if is_64bitint(fromdef) or is_64bitint(todef) then
  1011. begin
  1012. emitrangecheck64(p,todef);
  1013. exit;
  1014. end;
  1015. {we also need lto and hto when checking if we need to use doublebound!
  1016. (JM)}
  1017. getrange(todef,lto,hto);
  1018. if todef<>fromdef then
  1019. begin
  1020. getrange(p.resulttype,lfrom,hfrom);
  1021. { first check for not being u32bit, then if the to is bigger than
  1022. from }
  1023. if (lto<hto) and (lfrom<hfrom) and
  1024. (lto<=lfrom) and (hto>=hfrom) then
  1025. exit;
  1026. end;
  1027. { generate the rangecheck code for the def where we are going to
  1028. store the result }
  1029. doublebound:=false;
  1030. case todef^.deftype of
  1031. orddef :
  1032. begin
  1033. porddef(todef)^.genrangecheck;
  1034. rstr:=porddef(todef)^.getrangecheckstring;
  1035. doublebound:=
  1036. ((porddef(todef)^.typ=u32bit) and (lto>hto)) or
  1037. (is_signed(todef) and (porddef(fromdef)^.typ=u32bit)) or
  1038. (is_signed(fromdef) and (porddef(todef)^.typ=u32bit));
  1039. end;
  1040. enumdef :
  1041. begin
  1042. penumdef(todef)^.genrangecheck;
  1043. rstr:=penumdef(todef)^.getrangecheckstring;
  1044. end;
  1045. arraydef :
  1046. begin
  1047. parraydef(todef)^.genrangecheck;
  1048. rstr:=parraydef(todef)^.getrangecheckstring;
  1049. doublebound:=(lto>hto);
  1050. end;
  1051. end;
  1052. { get op and opsize }
  1053. opsize:=def2def_opsize(fromdef,u32bitdef);
  1054. if opsize in [S_B,S_W,S_L] then
  1055. op:=A_MOV
  1056. else
  1057. if is_signed(fromdef) then
  1058. op:=A_MOVSX
  1059. else
  1060. op:=A_MOVZX;
  1061. is_reg:=(p.location.loc in [LOC_REGISTER,LOC_CREGISTER]);
  1062. if is_reg then
  1063. hreg:=p.location.register;
  1064. if not target_os.use_bound_instruction then
  1065. begin
  1066. { FPC_BOUNDCHECK needs to be called with
  1067. %ecx - value
  1068. %edi - pointer to the ranges }
  1069. popecx:=false;
  1070. if not(is_reg) or
  1071. (p.location.register<>R_ECX) then
  1072. begin
  1073. if not(R_ECX in unused) then
  1074. begin
  1075. exprasmlist^.concat(new(paicpu,op_reg(A_PUSH,S_L,R_ECX)));
  1076. popecx:=true;
  1077. end
  1078. else exprasmlist^.concat(new(pairegalloc,alloc(R_ECX)));
  1079. if is_reg then
  1080. emit_reg_reg(op,opsize,p.location.register,R_ECX)
  1081. else
  1082. emit_ref_reg(op,opsize,newreference(p.location.reference),R_ECX);
  1083. end;
  1084. if doublebound then
  1085. begin
  1086. getlabel(neglabel);
  1087. getlabel(poslabel);
  1088. emit_reg_reg(A_OR,S_L,R_ECX,R_ECX);
  1089. emitjmp(C_L,neglabel);
  1090. end;
  1091. { insert bound instruction only }
  1092. getexplicitregister32(R_EDI);
  1093. exprasmlist^.concat(new(paicpu,op_sym_ofs_reg(A_MOV,S_L,newasmsymbol(rstr),0,R_EDI)));
  1094. emitcall('FPC_BOUNDCHECK');
  1095. ungetregister32(R_EDI);
  1096. { u32bit needs 2 checks }
  1097. if doublebound then
  1098. begin
  1099. emitjmp(C_None,poslabel);
  1100. emitlab(neglabel);
  1101. { if a cardinal is > $7fffffff, this is an illegal longint }
  1102. { value (and vice versa)! (JM) }
  1103. if ((todef^.deftype = orddef) and
  1104. ((is_signed(todef) and (porddef(fromdef)^.typ=u32bit)) or
  1105. (is_signed(fromdef) and (porddef(todef)^.typ=u32bit)))) or
  1106. { similar for array indexes (JM) }
  1107. ((todef^.deftype = arraydef) and
  1108. (((lto < 0) and (porddef(fromdef)^.typ=u32bit)) or
  1109. ((lto >= 0) and is_signed(fromdef)))) then
  1110. emitcall('FPC_RANGEERROR')
  1111. else
  1112. begin
  1113. getexplicitregister32(R_EDI);
  1114. exprasmlist^.concat(new(paicpu,op_sym_ofs_reg(A_MOV,S_L,newasmsymbol(rstr),8,R_EDI)));
  1115. emitcall('FPC_BOUNDCHECK');
  1116. ungetregister32(R_EDI);
  1117. end;
  1118. emitlab(poslabel);
  1119. end;
  1120. if popecx then
  1121. exprasmlist^.concat(new(paicpu,op_reg(A_POP,S_L,R_ECX)))
  1122. else exprasmlist^.concat(new(pairegalloc,dealloc(R_ECX)));
  1123. end
  1124. else
  1125. begin
  1126. reset_reference(href);
  1127. href.symbol:=newasmsymbol(rstr);
  1128. { load the value in a register }
  1129. if is_reg then
  1130. begin
  1131. { be sure that hreg is a 32 bit reg, if not load it in %edi }
  1132. if p.location.register in [R_EAX..R_EDI] then
  1133. hreg:=p.location.register
  1134. else
  1135. begin
  1136. getexplicitregister32(R_EDI);
  1137. emit_reg_reg(op,opsize,p.location.register,R_EDI);
  1138. hreg:=R_EDI;
  1139. end;
  1140. end
  1141. else
  1142. begin
  1143. getexplicitregister32(R_EDI);
  1144. emit_ref_reg(op,opsize,newreference(p.location.reference),R_EDI);
  1145. hreg:=R_EDI;
  1146. end;
  1147. if doublebound then
  1148. begin
  1149. getlabel(neglabel);
  1150. getlabel(poslabel);
  1151. emit_reg_reg(A_TEST,S_L,hreg,hreg);
  1152. emitjmp(C_L,neglabel);
  1153. end;
  1154. { insert bound instruction only }
  1155. exprasmlist^.concat(new(paicpu,op_reg_ref(A_BOUND,S_L,hreg,newreference(href))));
  1156. { u32bit needs 2 checks }
  1157. if doublebound then
  1158. begin
  1159. href.offset:=8;
  1160. emitjmp(C_None,poslabel);
  1161. emitlab(neglabel);
  1162. exprasmlist^.concat(new(paicpu,op_reg_ref(A_BOUND,S_L,hreg,newreference(href))));
  1163. emitlab(poslabel);
  1164. end;
  1165. if hreg = R_EDI then
  1166. ungetregister32(R_EDI);
  1167. end;
  1168. end;
  1169. { DO NOT RELY on the fact that the tnode is not yet swaped
  1170. because of inlining code PM }
  1171. procedure firstcomplex(p : tbinarynode);
  1172. var
  1173. hp : tnode;
  1174. begin
  1175. { always calculate boolean AND and OR from left to right }
  1176. if (p.nodetype in [orn,andn]) and
  1177. (p.left.resulttype^.deftype=orddef) and
  1178. (porddef(p.left.resulttype)^.typ in [bool8bit,bool16bit,bool32bit]) then
  1179. begin
  1180. { p.swaped:=false}
  1181. if nf_swaped in p.flags then
  1182. internalerror(234234);
  1183. end
  1184. else
  1185. if (p.left.registers32<p.right.registers32) and
  1186. { the following check is appropriate, because all }
  1187. { 4 registers are rarely used and it is thereby }
  1188. { achieved that the extra code is being dropped }
  1189. { by exchanging not commutative operators }
  1190. (p.right.registers32<=4) then
  1191. begin
  1192. hp:=p.left;
  1193. p.left:=p.right;
  1194. p.right:=hp;
  1195. if nf_swaped in p.flags then
  1196. exclude(p.flags,nf_swaped)
  1197. else
  1198. include(p.flags,nf_swaped);
  1199. end;
  1200. {else
  1201. p.swaped:=false; do not modify }
  1202. end;
  1203. {*****************************************************************************
  1204. Emit Functions
  1205. *****************************************************************************}
  1206. procedure push_shortstring_length(p:tnode);
  1207. var
  1208. hightree : tnode;
  1209. begin
  1210. if is_open_string(p.resulttype) then
  1211. begin
  1212. getsymonlyin(tloadnode(p).symtable,'high'+pvarsym(tloadnode(p).symtableentry)^.name);
  1213. hightree:=genloadnode(pvarsym(srsym),tloadnode(p).symtable);
  1214. firstpass(hightree);
  1215. secondpass(hightree);
  1216. push_value_para(hightree,false,false,0,4);
  1217. hightree.free;
  1218. hightree:=nil;
  1219. end
  1220. else
  1221. begin
  1222. push_int(pstringdef(p.resulttype)^.len);
  1223. end;
  1224. end;
  1225. {*****************************************************************************
  1226. String functions
  1227. *****************************************************************************}
  1228. procedure loadshortstring(source,dest : tnode);
  1229. {
  1230. Load a string, handles stringdef and orddef (char) types
  1231. }
  1232. begin
  1233. case source.resulttype^.deftype of
  1234. stringdef:
  1235. begin
  1236. if (source.nodetype=stringconstn) and
  1237. (str_length(source)=0) then
  1238. emit_const_ref(
  1239. A_MOV,S_B,0,newreference(dest.location.reference))
  1240. else
  1241. begin
  1242. emitpushreferenceaddr(dest.location.reference);
  1243. emitpushreferenceaddr(source.location.reference);
  1244. push_shortstring_length(dest);
  1245. emitcall('FPC_SHORTSTR_COPY');
  1246. maybe_loadesi;
  1247. end;
  1248. end;
  1249. orddef:
  1250. begin
  1251. if source.nodetype=ordconstn then
  1252. emit_const_ref(
  1253. A_MOV,S_W,tordconstnode(source).value*256+1,newreference(dest.location.reference))
  1254. else
  1255. begin
  1256. { not so elegant (goes better with extra register }
  1257. {$ifndef noAllocEdi}
  1258. getexplicitregister32(R_EDI);
  1259. {$endif noAllocEdi}
  1260. if (source.location.loc in [LOC_REGISTER,LOC_CREGISTER]) then
  1261. begin
  1262. emit_reg_reg(A_MOV,S_L,makereg32(source.location.register),R_EDI);
  1263. ungetregister(source.location.register);
  1264. end
  1265. else
  1266. begin
  1267. emit_ref_reg(A_MOV,S_L,newreference(source.location.reference),R_EDI);
  1268. del_reference(source.location.reference);
  1269. end;
  1270. emit_const_reg(A_SHL,S_L,8,R_EDI);
  1271. emit_const_reg(A_OR,S_L,1,R_EDI);
  1272. emit_reg_ref(A_MOV,S_W,R_DI,newreference(dest.location.reference));
  1273. {$ifndef noAllocEdi}
  1274. ungetregister32(R_EDI);
  1275. {$endif noAllocEdi}
  1276. end;
  1277. end;
  1278. else
  1279. CGMessage(type_e_mismatch);
  1280. end;
  1281. end;
  1282. procedure loadlongstring(p:tbinarynode);
  1283. {
  1284. Load a string, handles stringdef and orddef (char) types
  1285. }
  1286. var
  1287. r : preference;
  1288. begin
  1289. case p.right.resulttype^.deftype of
  1290. stringdef:
  1291. begin
  1292. if (p.right.nodetype=stringconstn) and
  1293. (str_length(p.right)=0) then
  1294. emit_const_ref(A_MOV,S_L,0,newreference(p.left.location.reference))
  1295. else
  1296. begin
  1297. emitpushreferenceaddr(p.left.location.reference);
  1298. emitpushreferenceaddr(p.right.location.reference);
  1299. push_shortstring_length(p.left);
  1300. emitcall('FPC_LONGSTR_COPY');
  1301. maybe_loadesi;
  1302. end;
  1303. end;
  1304. orddef:
  1305. begin
  1306. emit_const_ref(A_MOV,S_L,1,newreference(p.left.location.reference));
  1307. r:=newreference(p.left.location.reference);
  1308. inc(r^.offset,4);
  1309. if p.right.nodetype=ordconstn then
  1310. emit_const_ref(A_MOV,S_B,tordconstnode(p.right).value,r)
  1311. else
  1312. begin
  1313. case p.right.location.loc of
  1314. LOC_REGISTER,LOC_CREGISTER:
  1315. begin
  1316. emit_reg_ref(A_MOV,S_B,p.right.location.register,r);
  1317. ungetregister(p.right.location.register);
  1318. end;
  1319. LOC_MEM,LOC_REFERENCE:
  1320. begin
  1321. if not(R_EAX in unused) then
  1322. emit_reg(A_PUSH,S_L,R_EAX);
  1323. emit_ref_reg(A_MOV,S_B,newreference(p.right.location.reference),R_AL);
  1324. emit_reg_ref(A_MOV,S_B,R_AL,r);
  1325. if not(R_EAX in unused) then
  1326. emit_reg(A_POP,S_L,R_EAX);
  1327. del_reference(p.right.location.reference);
  1328. end
  1329. else
  1330. internalerror(20799);
  1331. end;
  1332. end;
  1333. end;
  1334. else
  1335. CGMessage(type_e_mismatch);
  1336. end;
  1337. end;
  1338. procedure loadansi2short(source,dest : tnode);
  1339. var
  1340. pushed : tpushed;
  1341. regs_to_push: byte;
  1342. begin
  1343. { Find out which registers have to be pushed (JM) }
  1344. regs_to_push := $ff;
  1345. remove_non_regvars_from_loc(source.location,regs_to_push);
  1346. { Push them (JM) }
  1347. pushusedregisters(pushed,regs_to_push);
  1348. case source.location.loc of
  1349. LOC_REFERENCE,LOC_MEM:
  1350. begin
  1351. { Now release the location and registers (see cgai386.pas: }
  1352. { loadansistring for more info on the order) (JM) }
  1353. ungetiftemp(source.location.reference);
  1354. del_reference(source.location.reference);
  1355. emit_push_mem(source.location.reference);
  1356. end;
  1357. LOC_REGISTER,LOC_CREGISTER:
  1358. begin
  1359. emit_reg(A_PUSH,S_L,source.location.register);
  1360. { Now release the register (JM) }
  1361. ungetregister32(source.location.register);
  1362. end;
  1363. end;
  1364. push_shortstring_length(dest);
  1365. emitpushreferenceaddr(dest.location.reference);
  1366. emitcall('FPC_ANSISTR_TO_SHORTSTR');
  1367. popusedregisters(pushed);
  1368. maybe_loadesi;
  1369. end;
  1370. procedure loadinterfacecom(p: tbinarynode);
  1371. {
  1372. copies an com interface from n.right to n.left, we
  1373. assume, that both sides are com interface, firstassignement have
  1374. to take care of that, an com interface can't be a register variable
  1375. }
  1376. var
  1377. pushed : tpushed;
  1378. ungettemp : boolean;
  1379. begin
  1380. { before pushing any parameter, we have to save all used }
  1381. { registers, but before that we have to release the }
  1382. { registers of that node to save uneccessary pushed }
  1383. { so be careful, if you think you can optimize that code (FK) }
  1384. { nevertheless, this has to be changed, because otherwise the }
  1385. { register is released before it's contents are pushed -> }
  1386. { problems with the optimizer (JM) }
  1387. del_reference(p.left.location.reference);
  1388. ungettemp:=false;
  1389. case p.right.location.loc of
  1390. LOC_REGISTER,LOC_CREGISTER:
  1391. begin
  1392. pushusedregisters(pushed, $ff xor ($80 shr byte(p.right.location.register)));
  1393. exprasmlist^.concat(new(paicpu,op_reg(A_PUSH,S_L,p.right.location.register)));
  1394. ungetregister32(p.right.location.register);
  1395. end;
  1396. LOC_REFERENCE,LOC_MEM:
  1397. begin
  1398. pushusedregisters(pushed,$ff
  1399. xor ($80 shr byte(p.right.location.reference.base))
  1400. xor ($80 shr byte(p.right.location.reference.index)));
  1401. emit_push_mem(p.right.location.reference);
  1402. del_reference(p.right.location.reference);
  1403. ungettemp:=true;
  1404. end;
  1405. end;
  1406. emitpushreferenceaddr(p.left.location.reference);
  1407. del_reference(p.left.location.reference);
  1408. emitcall('FPC_INTF_ASSIGN');
  1409. maybe_loadesi;
  1410. popusedregisters(pushed);
  1411. if ungettemp then
  1412. ungetiftemp(p.right.location.reference);
  1413. end;
  1414. end.
  1415. {
  1416. $Log$
  1417. Revision 1.4 2000-11-13 14:47:46 jonas
  1418. * support for range checking when converting from 64bit to something
  1419. smaller (32bit, 16bit, 8bit)
  1420. * fixed range checking between longint/cardinal and for array indexing
  1421. with cardinal (values > $7fffffff were considered negative)
  1422. Revision 1.3 2000/11/04 14:25:25 florian
  1423. + merged Attila's changes for interfaces, not tested yet
  1424. Revision 1.2 2000/10/31 22:02:57 peter
  1425. * symtable splitted, no real code changes
  1426. Revision 1.1 2000/10/15 09:33:32 peter
  1427. * moved n386*.pas to i386/ cpu_target dir
  1428. Revision 1.3 2000/10/14 21:52:54 peter
  1429. * fixed memory leaks
  1430. Revision 1.2 2000/10/14 10:14:50 peter
  1431. * moehrendorf oct 2000 rewrite
  1432. Revision 1.1 2000/10/01 19:58:40 peter
  1433. * new file
  1434. }