n386util.pas 66 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658
  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. type
  24. tloadregvars = (lr_dont_load_regvars, lr_load_regvars);
  25. function maybe_push(needed : byte;p : tnode;isint64 : boolean) : boolean;
  26. function maybe_pushfpu(needed : byte;p : tnode) : boolean;
  27. {$ifdef TEMPS_NOT_PUSH}
  28. function maybe_savetotemp(needed : byte;p : tnode;isint64 : boolean) : boolean;
  29. {$endif TEMPS_NOT_PUSH}
  30. procedure restore(p : tnode;isint64 : boolean);
  31. {$ifdef TEMPS_NOT_PUSH}
  32. procedure restorefromtemp(p : tnode;isint64 : boolean);
  33. {$endif TEMPS_NOT_PUSH}
  34. procedure pushsetelement(p : tnode);
  35. procedure push_value_para(p:tnode;inlined,is_cdecl:boolean;
  36. para_offset:longint;alignment : longint);
  37. procedure loadshortstring(source,dest : tnode);
  38. procedure loadlongstring(p:tbinarynode);
  39. procedure loadansi2short(source,dest : tnode);
  40. procedure loadwide2short(source,dest : tnode);
  41. procedure loadinterfacecom(p: tbinarynode);
  42. procedure maketojumpbool(p : tnode; loadregvars: tloadregvars);
  43. procedure emitoverflowcheck(p:tnode);
  44. procedure emitrangecheck(p:tnode;todef:tdef);
  45. procedure firstcomplex(p : tbinarynode);
  46. implementation
  47. uses
  48. globtype,globals,systems,verbose,
  49. cutils,
  50. aasm,cpubase,cpuasm,cpuinfo,
  51. symconst,symbase,symdef,symsym,symtable,
  52. {$ifdef GDB}
  53. gdb,
  54. {$endif GDB}
  55. types,
  56. ncon,nld,
  57. pass_1,pass_2,
  58. cgbase,tgcpu,temp_gen,
  59. cga,regvars;
  60. {*****************************************************************************
  61. Emit Push Functions
  62. *****************************************************************************}
  63. function maybe_push(needed : byte;p : tnode;isint64 : boolean) : boolean;
  64. var
  65. pushed : boolean;
  66. {hregister : tregister; }
  67. {$ifdef TEMPS_NOT_PUSH}
  68. href : treference;
  69. {$endif TEMPS_NOT_PUSH}
  70. begin
  71. if p.location.loc = LOC_CREGISTER then
  72. begin
  73. maybe_push := true;
  74. exit;
  75. end;
  76. if needed>usablereg32 then
  77. begin
  78. if (p.location.loc=LOC_REGISTER) then
  79. begin
  80. if isint64 then
  81. begin
  82. {$ifdef TEMPS_NOT_PUSH}
  83. gettempofsizereference(href,8);
  84. p.temp_offset:=href.offset;
  85. href.offset:=href.offset+4;
  86. exprasmList.concat(Taicpu.Op_reg(A_MOV,S_L,p.location.registerhigh,href));
  87. href.offset:=href.offset-4;
  88. {$else TEMPS_NOT_PUSH}
  89. exprasmList.concat(Taicpu.Op_reg(A_PUSH,S_L,p.location.registerhigh));
  90. {$endif TEMPS_NOT_PUSH}
  91. ungetregister32(p.location.registerhigh);
  92. end
  93. {$ifdef TEMPS_NOT_PUSH}
  94. else
  95. begin
  96. gettempofsizereference(href,4);
  97. p.temp_offset:=href.offset;
  98. end
  99. {$endif TEMPS_NOT_PUSH}
  100. ;
  101. pushed:=true;
  102. {$ifdef TEMPS_NOT_PUSH}
  103. exprasmList.concat(Taicpu.Op_reg_ref(A_MOV,S_L,p.location.register,href));
  104. {$else TEMPS_NOT_PUSH}
  105. exprasmList.concat(Taicpu.Op_reg(A_PUSH,S_L,p.location.register));
  106. {$endif TEMPS_NOT_PUSH}
  107. ungetregister32(p.location.register);
  108. end
  109. else if (p.location.loc in [LOC_MEM,LOC_REFERENCE]) and
  110. ((p.location.reference.base<>R_NO) or
  111. (p.location.reference.index<>R_NO)
  112. ) then
  113. begin
  114. del_reference(p.location.reference);
  115. getexplicitregister32(R_EDI);
  116. emit_ref_reg(A_LEA,S_L,newreference(p.location.reference),R_EDI);
  117. {$ifdef TEMPS_NOT_PUSH}
  118. gettempofsizereference(href,4);
  119. exprasmList.concat(Taicpu.Op_reg_ref(A_MOV,S_L,R_EDI,href));
  120. p.temp_offset:=href.offset;
  121. {$else TEMPS_NOT_PUSH}
  122. exprasmList.concat(Taicpu.Op_reg(A_PUSH,S_L,R_EDI));
  123. {$endif TEMPS_NOT_PUSH}
  124. ungetregister32(R_EDI);
  125. pushed:=true;
  126. end
  127. else pushed:=false;
  128. end
  129. else pushed:=false;
  130. maybe_push:=pushed;
  131. end;
  132. function maybe_pushfpu(needed : byte;p : tnode) : boolean;
  133. begin
  134. if needed>=maxfpuregs then
  135. begin
  136. if p.location.loc = LOC_FPU then
  137. begin
  138. emit_to_mem(p.location,p.resulttype.def);
  139. maybe_pushfpu:=true;
  140. end
  141. else
  142. maybe_pushfpu:=false;
  143. end
  144. else
  145. maybe_pushfpu:=false;
  146. end;
  147. {$ifdef TEMPS_NOT_PUSH}
  148. function maybe_savetotemp(needed : byte;p : tnode;isint64 : boolean) : boolean;
  149. var
  150. pushed : boolean;
  151. href : treference;
  152. begin
  153. if needed>usablereg32 then
  154. begin
  155. if (p^.location.loc=LOC_REGISTER) then
  156. begin
  157. if isint64(p^.resulttype.def) then
  158. begin
  159. gettempofsizereference(href,8);
  160. p^.temp_offset:=href.offset;
  161. href.offset:=href.offset+4;
  162. exprasmList.concat(Taicpu.Op_reg(A_MOV,S_L,p^.location.registerhigh,href));
  163. href.offset:=href.offset-4;
  164. ungetregister32(p^.location.registerhigh);
  165. end
  166. else
  167. begin
  168. gettempofsizereference(href,4);
  169. p^.temp_offset:=href.offset;
  170. end;
  171. pushed:=true;
  172. exprasmList.concat(Taicpu.Op_reg_ref(A_MOV,S_L,p^.location.register,href));
  173. ungetregister32(p^.location.register);
  174. end
  175. else if (p^.location.loc in [LOC_MEM,LOC_REFERENCE]) and
  176. ((p^.location.reference.base<>R_NO) or
  177. (p^.location.reference.index<>R_NO)
  178. ) then
  179. begin
  180. del_reference(p^.location.reference);
  181. getexplicitregister32(R_EDI);
  182. emit_ref_reg(A_LEA,S_L,newreference(p^.location.reference),
  183. R_EDI);
  184. gettempofsizereference(href,4);
  185. exprasmList.concat(Taicpu.Op_reg_ref(A_MOV,S_L,R_EDI,href));
  186. ungetregister32(R_EDI);
  187. p^.temp_offset:=href.offset;
  188. pushed:=true;
  189. end
  190. else pushed:=false;
  191. end
  192. else pushed:=false;
  193. maybe_push:=pushed;
  194. end;
  195. {$endif TEMPS_NOT_PUSH}
  196. procedure restore(p : tnode;isint64 : boolean);
  197. var
  198. hregister : tregister;
  199. {$ifdef TEMPS_NOT_PUSH}
  200. href : treference;
  201. {$endif TEMPS_NOT_PUSH}
  202. begin
  203. if p.location.loc = LOC_CREGISTER then
  204. begin
  205. load_regvar_reg(exprasmlist,p.location.register);
  206. exit;
  207. end;
  208. hregister:=getregister32;
  209. {$ifdef TEMPS_NOT_PUSH}
  210. reset_reference(href);
  211. href.base:=procinfo^.frame_pointer;
  212. href.offset:=p.temp_offset;
  213. emit_ref_reg(A_MOV,S_L,href,hregister);
  214. {$else TEMPS_NOT_PUSH}
  215. exprasmList.concat(Taicpu.Op_reg(A_POP,S_L,hregister));
  216. {$endif TEMPS_NOT_PUSH}
  217. if (p.location.loc in [LOC_REGISTER,LOC_CREGISTER]) then
  218. begin
  219. p.location.register:=hregister;
  220. if isint64 then
  221. begin
  222. p.location.registerhigh:=getregister32;
  223. {$ifdef TEMPS_NOT_PUSH}
  224. href.offset:=p.temp_offset+4;
  225. emit_ref_reg(A_MOV,S_L,p.location.registerhigh);
  226. { set correctly for release ! }
  227. href.offset:=p.temp_offset;
  228. {$else TEMPS_NOT_PUSH}
  229. exprasmList.concat(Taicpu.Op_reg(A_POP,S_L,p.location.registerhigh));
  230. {$endif TEMPS_NOT_PUSH}
  231. end;
  232. end
  233. else
  234. begin
  235. reset_reference(p.location.reference);
  236. { any reasons why this was moved into the index register ? }
  237. { normally usage of base register is much better (FK) }
  238. p.location.reference.base:=hregister;
  239. { Why is this done? We can never be sure about p.left
  240. because otherwise secondload fails !!!
  241. set_location(p.left^.location,p.location);}
  242. end;
  243. {$ifdef TEMPS_NOT_PUSH}
  244. ungetiftemp(href);
  245. {$endif TEMPS_NOT_PUSH}
  246. end;
  247. {$ifdef TEMPS_NOT_PUSH}
  248. procedure restorefromtemp(p : tnode;isint64 : boolean);
  249. var
  250. hregister : tregister;
  251. href : treference;
  252. begin
  253. hregister:=getregister32;
  254. reset_reference(href);
  255. href.base:=procinfo^.frame_pointer;
  256. href.offset:=p.temp_offset;
  257. emit_ref_reg(A_MOV,S_L,href,hregister);
  258. if (p.location.loc in [LOC_REGISTER,LOC_CREGISTER]) then
  259. begin
  260. p.location.register:=hregister;
  261. if isint64 then
  262. begin
  263. p.location.registerhigh:=getregister32;
  264. href.offset:=p.temp_offset+4;
  265. emit_ref_reg(A_MOV,S_L,p.location.registerhigh);
  266. { set correctly for release ! }
  267. href.offset:=p.temp_offset;
  268. end;
  269. end
  270. else
  271. begin
  272. reset_reference(p.location.reference);
  273. p.location.reference.base:=hregister;
  274. { Why is this done? We can never be sure about p^.left
  275. because otherwise secondload fails PM
  276. set_location(p^.left^.location,p^.location);}
  277. end;
  278. ungetiftemp(href);
  279. end;
  280. {$endif TEMPS_NOT_PUSH}
  281. procedure pushsetelement(p : tnode);
  282. var
  283. hr,hr16,hr32 : tregister;
  284. begin
  285. { copy the element on the stack, slightly complicated }
  286. if p.nodetype=ordconstn then
  287. begin
  288. if aktalignment.paraalign=4 then
  289. exprasmList.concat(Taicpu.Op_const(A_PUSH,S_L,tordconstnode(p).value))
  290. else
  291. exprasmList.concat(Taicpu.Op_const(A_PUSH,S_W,tordconstnode(p).value));
  292. end
  293. else
  294. begin
  295. case p.location.loc of
  296. LOC_REGISTER,
  297. LOC_CREGISTER :
  298. begin
  299. hr:=p.location.register;
  300. case hr of
  301. R_EAX,R_EBX,R_ECX,R_EDX,R_EDI,R_ESI,R_ESP :
  302. begin
  303. hr16:=reg32toreg16(hr);
  304. hr32:=hr;
  305. end;
  306. R_AX,R_BX,R_CX,R_DX,R_DI,R_SI,R_SP :
  307. begin
  308. hr16:=hr;
  309. hr32:=reg16toreg32(hr);
  310. end;
  311. R_AL,R_BL,R_CL,R_DL :
  312. begin
  313. hr16:=reg8toreg16(hr);
  314. hr32:=reg8toreg32(hr);
  315. end;
  316. end;
  317. if aktalignment.paraalign=4 then
  318. exprasmList.concat(Taicpu.Op_reg(A_PUSH,S_L,hr32))
  319. else
  320. exprasmList.concat(Taicpu.Op_reg(A_PUSH,S_W,hr16));
  321. ungetregister32(hr32);
  322. end;
  323. else
  324. begin
  325. { you can't push more bytes than the size of the element, }
  326. { because this may cross a page boundary and you'll get a }
  327. { sigsegv (JM) }
  328. emit_push_mem_size(p.location.reference,1);
  329. del_reference(p.location.reference);
  330. end;
  331. end;
  332. end;
  333. end;
  334. procedure push_value_para(p:tnode;inlined,is_cdecl:boolean;
  335. para_offset:longint;alignment : longint);
  336. var
  337. tempreference : treference;
  338. r : preference;
  339. opsize : topsize;
  340. op : tasmop;
  341. hreg : tregister;
  342. size : longint;
  343. hlabel : tasmlabel;
  344. begin
  345. case p.location.loc of
  346. LOC_REGISTER,
  347. LOC_CREGISTER:
  348. begin
  349. if p.resulttype.def.size=8 then
  350. begin
  351. inc(pushedparasize,8);
  352. if inlined then
  353. begin
  354. r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
  355. exprasmlist.concat(taicpu.op_reg_ref(A_MOV,S_L,p.location.registerlow,r));
  356. r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize+4);
  357. exprasmlist.concat(taicpu.op_reg_ref(A_MOV,S_L,p.location.registerhigh,r));
  358. end
  359. else
  360. begin
  361. exprasmlist.concat(taicpu.op_reg(A_PUSH,S_L,p.location.registerhigh));
  362. exprasmlist.concat(taicpu.op_reg(A_PUSH,S_L,p.location.registerlow));
  363. end;
  364. ungetregister32(p.location.registerhigh);
  365. ungetregister32(p.location.registerlow);
  366. end
  367. else case p.location.register of
  368. R_EAX,R_EBX,R_ECX,R_EDX,R_ESI,
  369. R_EDI,R_ESP,R_EBP :
  370. begin
  371. inc(pushedparasize,4);
  372. if inlined then
  373. begin
  374. r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
  375. exprasmList.concat(Taicpu.Op_reg_ref(A_MOV,S_L,p.location.register,r));
  376. end
  377. else
  378. exprasmList.concat(Taicpu.Op_reg(A_PUSH,S_L,p.location.register));
  379. ungetregister32(p.location.register);
  380. end;
  381. R_AX,R_BX,R_CX,R_DX,R_SI,R_DI:
  382. begin
  383. if alignment=4 then
  384. begin
  385. opsize:=S_L;
  386. hreg:=reg16toreg32(p.location.register);
  387. inc(pushedparasize,4);
  388. end
  389. else
  390. begin
  391. opsize:=S_W;
  392. hreg:=p.location.register;
  393. inc(pushedparasize,2);
  394. end;
  395. if inlined then
  396. begin
  397. r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
  398. exprasmList.concat(Taicpu.Op_reg_ref(A_MOV,opsize,hreg,r));
  399. end
  400. else
  401. exprasmList.concat(Taicpu.Op_reg(A_PUSH,opsize,hreg));
  402. ungetregister32(reg16toreg32(p.location.register));
  403. end;
  404. R_AL,R_BL,R_CL,R_DL:
  405. begin
  406. if alignment=4 then
  407. begin
  408. opsize:=S_L;
  409. hreg:=reg8toreg32(p.location.register);
  410. inc(pushedparasize,4);
  411. end
  412. else
  413. begin
  414. opsize:=S_W;
  415. hreg:=reg8toreg16(p.location.register);
  416. inc(pushedparasize,2);
  417. end;
  418. { we must push always 16 bit }
  419. if inlined then
  420. begin
  421. r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
  422. exprasmList.concat(Taicpu.Op_reg_ref(A_MOV,opsize,hreg,r));
  423. end
  424. else
  425. exprasmList.concat(Taicpu.Op_reg(A_PUSH,opsize,hreg));
  426. ungetregister32(reg8toreg32(p.location.register));
  427. end;
  428. else internalerror(1899);
  429. end;
  430. end;
  431. LOC_FPU:
  432. begin
  433. size:=align(tfloatdef(p.resulttype.def).size,alignment);
  434. inc(pushedparasize,size);
  435. if not inlined then
  436. emit_const_reg(A_SUB,S_L,size,R_ESP);
  437. {$ifdef GDB}
  438. if (cs_debuginfo in aktmoduleswitches) and
  439. (exprasmList.first=exprasmList.last) then
  440. exprasmList.concat(Tai_force_line.Create);
  441. {$endif GDB}
  442. r:=new_reference(R_ESP,0);
  443. floatstoreops(tfloatdef(p.resulttype.def).typ,op,opsize);
  444. { this is the easiest case for inlined !! }
  445. if inlined then
  446. begin
  447. r^.base:=procinfo^.framepointer;
  448. r^.offset:=para_offset-pushedparasize;
  449. end;
  450. exprasmList.concat(Taicpu.Op_ref(op,opsize,r));
  451. dec(fpuvaroffset);
  452. end;
  453. LOC_CFPUREGISTER:
  454. begin
  455. exprasmList.concat(Taicpu.Op_reg(A_FLD,S_NO,
  456. correct_fpuregister(p.location.register,fpuvaroffset)));
  457. size:=align(tfloatdef(p.resulttype.def).size,alignment);
  458. inc(pushedparasize,size);
  459. if not inlined then
  460. emit_const_reg(A_SUB,S_L,size,R_ESP);
  461. {$ifdef GDB}
  462. if (cs_debuginfo in aktmoduleswitches) and
  463. (exprasmList.first=exprasmList.last) then
  464. exprasmList.concat(Tai_force_line.Create);
  465. {$endif GDB}
  466. r:=new_reference(R_ESP,0);
  467. floatstoreops(tfloatdef(p.resulttype.def).typ,op,opsize);
  468. { this is the easiest case for inlined !! }
  469. if inlined then
  470. begin
  471. r^.base:=procinfo^.framepointer;
  472. r^.offset:=para_offset-pushedparasize;
  473. end;
  474. exprasmList.concat(Taicpu.Op_ref(op,opsize,r));
  475. end;
  476. LOC_REFERENCE,LOC_MEM:
  477. begin
  478. tempreference:=p.location.reference;
  479. del_reference(p.location.reference);
  480. case p.resulttype.def.deftype of
  481. enumdef,
  482. orddef :
  483. begin
  484. case p.resulttype.def.size of
  485. 8 : begin
  486. inc(pushedparasize,8);
  487. if inlined then
  488. begin
  489. getexplicitregister32(R_EDI);
  490. emit_ref_reg(A_MOV,S_L,
  491. newreference(tempreference),R_EDI);
  492. r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
  493. exprasmList.concat(Taicpu.Op_reg_ref(A_MOV,S_L,R_EDI,r));
  494. ungetregister32(R_EDI);
  495. getexplicitregister32(R_EDI);
  496. inc(tempreference.offset,4);
  497. emit_ref_reg(A_MOV,S_L,
  498. newreference(tempreference),R_EDI);
  499. r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize+4);
  500. exprasmList.concat(Taicpu.Op_reg_ref(A_MOV,S_L,R_EDI,r));
  501. ungetregister32(R_EDI);
  502. end
  503. else
  504. begin
  505. inc(tempreference.offset,4);
  506. emit_push_mem(tempreference);
  507. dec(tempreference.offset,4);
  508. emit_push_mem(tempreference);
  509. end;
  510. end;
  511. 4 : begin
  512. inc(pushedparasize,4);
  513. if inlined then
  514. begin
  515. getexplicitregister32(R_EDI);
  516. emit_ref_reg(A_MOV,S_L,
  517. newreference(tempreference),R_EDI);
  518. r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
  519. exprasmList.concat(Taicpu.Op_reg_ref(A_MOV,S_L,R_EDI,r));
  520. ungetregister32(R_EDI);
  521. end
  522. else
  523. emit_push_mem(tempreference);
  524. end;
  525. 1,2 : begin
  526. if alignment=4 then
  527. begin
  528. opsize:=S_L;
  529. hreg:=R_EDI;
  530. inc(pushedparasize,4);
  531. end
  532. else
  533. begin
  534. opsize:=S_W;
  535. hreg:=R_DI;
  536. inc(pushedparasize,2);
  537. end;
  538. if inlined then
  539. begin
  540. getexplicitregister32(R_EDI);
  541. emit_ref_reg(A_MOV,opsize,
  542. newreference(tempreference),hreg);
  543. r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
  544. exprasmList.concat(Taicpu.Op_reg_ref(A_MOV,opsize,hreg,r));
  545. ungetregister32(R_EDI);
  546. end
  547. else
  548. emit_push_mem_size(tempreference,p.resulttype.def.size);
  549. end;
  550. else
  551. internalerror(234231);
  552. end;
  553. end;
  554. floatdef :
  555. begin
  556. case tfloatdef(p.resulttype.def).typ of
  557. s32real :
  558. begin
  559. inc(pushedparasize,4);
  560. if inlined then
  561. begin
  562. getexplicitregister32(R_EDI);
  563. emit_ref_reg(A_MOV,S_L,
  564. newreference(tempreference),R_EDI);
  565. r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
  566. exprasmList.concat(Taicpu.Op_reg_ref(A_MOV,S_L,R_EDI,r));
  567. ungetregister32(R_EDI);
  568. end
  569. else
  570. emit_push_mem(tempreference);
  571. end;
  572. s64real,
  573. s64comp :
  574. begin
  575. inc(pushedparasize,4);
  576. inc(tempreference.offset,4);
  577. if inlined then
  578. begin
  579. getexplicitregister32(R_EDI);
  580. emit_ref_reg(A_MOV,S_L,
  581. newreference(tempreference),R_EDI);
  582. r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
  583. exprasmList.concat(Taicpu.Op_reg_ref(A_MOV,S_L,R_EDI,r));
  584. ungetregister32(R_EDI);
  585. end
  586. else
  587. emit_push_mem(tempreference);
  588. inc(pushedparasize,4);
  589. dec(tempreference.offset,4);
  590. if inlined then
  591. begin
  592. getexplicitregister32(R_EDI);
  593. emit_ref_reg(A_MOV,S_L,
  594. newreference(tempreference),R_EDI);
  595. r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
  596. exprasmList.concat(Taicpu.Op_reg_ref(A_MOV,S_L,R_EDI,r));
  597. ungetregister32(R_EDI);
  598. end
  599. else
  600. emit_push_mem(tempreference);
  601. end;
  602. s80real :
  603. begin
  604. inc(pushedparasize,4);
  605. if alignment=4 then
  606. inc(tempreference.offset,8)
  607. else
  608. inc(tempreference.offset,6);
  609. if inlined then
  610. begin
  611. getexplicitregister32(R_EDI);
  612. emit_ref_reg(A_MOV,S_L,
  613. newreference(tempreference),R_EDI);
  614. r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
  615. exprasmList.concat(Taicpu.Op_reg_ref(A_MOV,S_L,R_EDI,r));
  616. ungetregister32(R_EDI);
  617. end
  618. else
  619. emit_push_mem(tempreference);
  620. dec(tempreference.offset,4);
  621. inc(pushedparasize,4);
  622. if inlined then
  623. begin
  624. getexplicitregister32(R_EDI);
  625. emit_ref_reg(A_MOV,S_L,
  626. newreference(tempreference),R_EDI);
  627. r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
  628. exprasmList.concat(Taicpu.Op_reg_ref(A_MOV,S_L,R_EDI,r));
  629. ungetregister32(R_EDI);
  630. end
  631. else
  632. emit_push_mem(tempreference);
  633. if alignment=4 then
  634. begin
  635. opsize:=S_L;
  636. hreg:=R_EDI;
  637. inc(pushedparasize,4);
  638. dec(tempreference.offset,4);
  639. end
  640. else
  641. begin
  642. opsize:=S_W;
  643. hreg:=R_DI;
  644. inc(pushedparasize,2);
  645. dec(tempreference.offset,2);
  646. end;
  647. if inlined then
  648. begin
  649. getexplicitregister32(R_EDI);
  650. emit_ref_reg(A_MOV,opsize,
  651. newreference(tempreference),hreg);
  652. r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
  653. exprasmList.concat(Taicpu.Op_reg_ref(A_MOV,opsize,hreg,r));
  654. ungetregister32(R_EDI);
  655. end
  656. else
  657. exprasmList.concat(Taicpu.Op_ref(A_PUSH,opsize,
  658. newreference(tempreference)));
  659. end;
  660. end;
  661. end;
  662. pointerdef,
  663. procvardef,
  664. classrefdef:
  665. begin
  666. inc(pushedparasize,4);
  667. if inlined then
  668. begin
  669. getexplicitregister32(R_EDI);
  670. emit_ref_reg(A_MOV,S_L,
  671. newreference(tempreference),R_EDI);
  672. r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
  673. exprasmList.concat(Taicpu.Op_reg_ref(A_MOV,S_L,R_EDI,r));
  674. ungetregister32(R_EDI);
  675. end
  676. else
  677. emit_push_mem(tempreference);
  678. end;
  679. arraydef,
  680. recorddef,
  681. stringdef,
  682. setdef,
  683. objectdef :
  684. begin
  685. { even some structured types are 32 bit }
  686. if is_widestring(p.resulttype.def) or
  687. is_ansistring(p.resulttype.def) or
  688. is_smallset(p.resulttype.def) or
  689. ((p.resulttype.def.deftype in [recorddef,arraydef]) and
  690. (
  691. (p.resulttype.def.deftype<>arraydef) or not
  692. (tarraydef(p.resulttype.def).IsConstructor or
  693. tarraydef(p.resulttype.def).isArrayOfConst or
  694. is_open_array(p.resulttype.def))
  695. ) and
  696. (p.resulttype.def.size<=4)
  697. ) or
  698. is_class(p.resulttype.def) or
  699. is_interface(p.resulttype.def) then
  700. begin
  701. if (p.resulttype.def.size>2) or
  702. ((alignment=4) and (p.resulttype.def.size>0)) then
  703. begin
  704. inc(pushedparasize,4);
  705. if inlined then
  706. begin
  707. r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
  708. concatcopy(tempreference,r^,4,false,false);
  709. end
  710. else
  711. emit_push_mem(tempreference);
  712. end
  713. else
  714. begin
  715. if p.resulttype.def.size>0 then
  716. begin
  717. inc(pushedparasize,2);
  718. if inlined then
  719. begin
  720. r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
  721. concatcopy(tempreference,r^,2,false,false);
  722. end
  723. else
  724. exprasmList.concat(Taicpu.Op_ref(A_PUSH,S_W,newreference(tempreference)));
  725. end;
  726. end;
  727. end
  728. { call by value open array ? }
  729. else if is_cdecl then
  730. begin
  731. { push on stack }
  732. size:=align(p.resulttype.def.size,alignment);
  733. inc(pushedparasize,size);
  734. emit_const_reg(A_SUB,S_L,size,R_ESP);
  735. r:=new_reference(R_ESP,0);
  736. concatcopy(tempreference,r^,size,false,false);
  737. dispose(r);
  738. end
  739. else
  740. internalerror(8954);
  741. end;
  742. else
  743. CGMessage(cg_e_illegal_expression);
  744. end;
  745. end;
  746. LOC_JUMP:
  747. begin
  748. getlabel(hlabel);
  749. if alignment=4 then
  750. begin
  751. opsize:=S_L;
  752. inc(pushedparasize,4);
  753. end
  754. else
  755. begin
  756. opsize:=S_W;
  757. inc(pushedparasize,2);
  758. end;
  759. emitlab(truelabel);
  760. if inlined then
  761. begin
  762. r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
  763. emit_const_ref(A_MOV,opsize,1,r);
  764. end
  765. else
  766. exprasmList.concat(Taicpu.Op_const(A_PUSH,opsize,1));
  767. emitjmp(C_None,hlabel);
  768. emitlab(falselabel);
  769. if inlined then
  770. begin
  771. r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
  772. emit_const_ref(A_MOV,opsize,0,r);
  773. end
  774. else
  775. exprasmList.concat(Taicpu.Op_const(A_PUSH,opsize,0));
  776. emitlab(hlabel);
  777. end;
  778. LOC_FLAGS:
  779. begin
  780. if not(R_EAX in unused) then
  781. begin
  782. getexplicitregister32(R_EDI);
  783. emit_reg_reg(A_MOV,S_L,R_EAX,R_EDI);
  784. end;
  785. emit_flag2reg(p.location.resflags,R_AL);
  786. emit_reg_reg(A_MOVZX,S_BW,R_AL,R_AX);
  787. if alignment=4 then
  788. begin
  789. opsize:=S_L;
  790. hreg:=R_EAX;
  791. inc(pushedparasize,4);
  792. end
  793. else
  794. begin
  795. opsize:=S_W;
  796. hreg:=R_AX;
  797. inc(pushedparasize,2);
  798. end;
  799. if inlined then
  800. begin
  801. r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
  802. exprasmList.concat(Taicpu.Op_reg_ref(A_MOV,opsize,hreg,r));
  803. end
  804. else
  805. exprasmList.concat(Taicpu.Op_reg(A_PUSH,opsize,hreg));
  806. if not(R_EAX in unused) then
  807. begin
  808. emit_reg_reg(A_MOV,S_L,R_EDI,R_EAX);
  809. ungetregister32(R_EDI);
  810. end;
  811. end;
  812. {$ifdef SUPPORT_MMX}
  813. LOC_MMXREGISTER,
  814. LOC_CMMXREGISTER:
  815. begin
  816. inc(pushedparasize,8); { was missing !!! (PM) }
  817. emit_const_reg(
  818. A_SUB,S_L,8,R_ESP);
  819. {$ifdef GDB}
  820. if (cs_debuginfo in aktmoduleswitches) and
  821. (exprasmList.first=exprasmList.last) then
  822. exprasmList.concat(Tai_force_line.Create);
  823. {$endif GDB}
  824. if inlined then
  825. begin
  826. r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
  827. exprasmList.concat(Taicpu.Op_reg_ref(A_MOVQ,S_NO,
  828. p.location.register,r));
  829. end
  830. else
  831. begin
  832. r:=new_reference(R_ESP,0);
  833. exprasmList.concat(Taicpu.Op_reg_ref(
  834. A_MOVQ,S_NO,p.location.register,r));
  835. end;
  836. end;
  837. {$endif SUPPORT_MMX}
  838. end;
  839. end;
  840. {*****************************************************************************
  841. Emit Functions
  842. *****************************************************************************}
  843. procedure maketojumpbool(p : tnode; loadregvars: tloadregvars);
  844. {
  845. produces jumps to true respectively false labels using boolean expressions
  846. depending on whether the loading of regvars is currently being
  847. synchronized manually (such as in an if-node) or automatically (most of
  848. the other cases where this procedure is called), loadregvars can be
  849. "lr_load_regvars" or "lr_dont_load_regvars"
  850. }
  851. var
  852. opsize : topsize;
  853. storepos : tfileposinfo;
  854. begin
  855. if nf_error in p.flags then
  856. exit;
  857. storepos:=aktfilepos;
  858. aktfilepos:=p.fileinfo;
  859. if is_boolean(p.resulttype.def) then
  860. begin
  861. if loadregvars = lr_load_regvars then
  862. load_all_regvars(exprasmlist);
  863. if is_constboolnode(p) then
  864. begin
  865. if tordconstnode(p).value<>0 then
  866. emitjmp(C_None,truelabel)
  867. else
  868. emitjmp(C_None,falselabel);
  869. end
  870. else
  871. begin
  872. opsize:=def_opsize(p.resulttype.def);
  873. case p.location.loc of
  874. LOC_CREGISTER,LOC_REGISTER : begin
  875. if (p.location.loc = LOC_CREGISTER) then
  876. load_regvar_reg(exprasmlist,p.location.register);
  877. emit_reg_reg(A_OR,opsize,p.location.register,
  878. p.location.register);
  879. ungetregister(p.location.register);
  880. emitjmp(C_NZ,truelabel);
  881. emitjmp(C_None,falselabel);
  882. end;
  883. LOC_MEM,LOC_REFERENCE : begin
  884. emit_const_ref(
  885. A_CMP,opsize,0,newreference(p.location.reference));
  886. del_reference(p.location.reference);
  887. emitjmp(C_NZ,truelabel);
  888. emitjmp(C_None,falselabel);
  889. end;
  890. LOC_FLAGS : begin
  891. emitjmp(flag_2_cond[p.location.resflags],truelabel);
  892. emitjmp(C_None,falselabel);
  893. end;
  894. end;
  895. end;
  896. end
  897. else
  898. CGMessage(type_e_mismatch);
  899. aktfilepos:=storepos;
  900. end;
  901. { produces if necessary overflowcode }
  902. procedure emitoverflowcheck(p:tnode);
  903. var
  904. hl : tasmlabel;
  905. begin
  906. if not(cs_check_overflow in aktlocalswitches) then
  907. exit;
  908. getlabel(hl);
  909. if not ((p.resulttype.def.deftype=pointerdef) or
  910. ((p.resulttype.def.deftype=orddef) and
  911. (torddef(p.resulttype.def).typ in [u64bit,u16bit,u32bit,u8bit,uchar,
  912. bool8bit,bool16bit,bool32bit]))) then
  913. emitjmp(C_NO,hl)
  914. else
  915. emitjmp(C_NB,hl);
  916. emitcall('FPC_OVERFLOW');
  917. emitlab(hl);
  918. end;
  919. { produces range check code, while one of the operands is a 64 bit
  920. integer }
  921. procedure emitrangecheck64(p : tnode;todef : tdef);
  922. var
  923. neglabel,
  924. poslabel,
  925. endlabel: tasmlabel;
  926. href : preference;
  927. hreg : tregister;
  928. hdef : torddef;
  929. fromdef : tdef;
  930. opcode : tasmop;
  931. opsize : topsize;
  932. oldregisterdef: boolean;
  933. from_signed,to_signed: boolean;
  934. begin
  935. fromdef:=p.resulttype.def;
  936. from_signed := is_signed(fromdef);
  937. to_signed := is_signed(todef);
  938. if not is_64bitint(todef) then
  939. begin
  940. oldregisterdef := registerdef;
  941. registerdef := false;
  942. { get the high dword in a register }
  943. if p.location.loc in [LOC_REGISTER,LOC_CREGISTER] then
  944. hreg := p.location.registerhigh
  945. else
  946. begin
  947. hreg := getexplicitregister32(R_EDI);
  948. href := newreference(p.location.reference);
  949. inc(href^.offset,4);
  950. emit_ref_reg(A_MOV,S_L,href,hreg);
  951. end;
  952. getlabel(poslabel);
  953. { check high dword, must be 0 (for positive numbers) }
  954. emit_reg_reg(A_TEST,S_L,hreg,hreg);
  955. emitjmp(C_E,poslabel);
  956. { It can also be $ffffffff, but only for negative numbers }
  957. if from_signed and to_signed then
  958. begin
  959. getlabel(neglabel);
  960. emit_const_reg(A_CMP,S_L,longint($ffffffff),hreg);
  961. emitjmp(C_E,neglabel);
  962. end;
  963. if hreg = R_EDI then
  964. ungetregister32(hreg);
  965. { For all other values we have a range check error }
  966. emitcall('FPC_RANGEERROR');
  967. { if the high dword = 0, the low dword can be considered a }
  968. { simple cardinal }
  969. emitlab(poslabel);
  970. hdef:=torddef.create(u32bit,0,longint($ffffffff));
  971. { the real p.resulttype.def is already saved in fromdef }
  972. p.resulttype.def := hdef;
  973. emitrangecheck(p,todef);
  974. hdef.free;
  975. { restore original resulttype.def }
  976. p.resulttype.def := todef;
  977. if from_signed and to_signed then
  978. begin
  979. getlabel(endlabel);
  980. emitjmp(C_None,endlabel);
  981. { if the high dword = $ffffffff, then the low dword (when }
  982. { considered as a longint) must be < 0 }
  983. emitlab(neglabel);
  984. if p.location.loc in [LOC_REGISTER,LOC_CREGISTER] then
  985. hreg := p.location.registerlow
  986. else
  987. begin
  988. hreg := getexplicitregister32(R_EDI);
  989. emit_ref_reg(A_MOV,S_L,
  990. newreference(p.location.reference),hreg);
  991. end;
  992. { get a new neglabel (JM) }
  993. getlabel(neglabel);
  994. emit_reg_reg(A_TEST,S_L,hreg,hreg);
  995. if hreg = R_EDI then
  996. ungetregister32(hreg);
  997. emitjmp(C_L,neglabel);
  998. emitcall('FPC_RANGEERROR');
  999. { if we get here, the 64bit value lies between }
  1000. { longint($80000000) and -1 (JM) }
  1001. emitlab(neglabel);
  1002. hdef:=torddef.create(s32bit,longint($80000000),-1);
  1003. p.resulttype.def := hdef;
  1004. emitrangecheck(p,todef);
  1005. hdef.free;
  1006. emitlab(endlabel);
  1007. end;
  1008. registerdef := oldregisterdef;
  1009. p.resulttype.def := fromdef;
  1010. { restore p's resulttype.def }
  1011. end
  1012. else
  1013. { todef = 64bit int }
  1014. { no 64bit subranges supported, so only a small check is necessary }
  1015. { if both are signed or both are unsigned, no problem! }
  1016. if (from_signed xor to_signed) and
  1017. { also not if the fromdef is unsigned and < 64bit, since that will }
  1018. { always fit in a 64bit int (todef is 64bit) }
  1019. (from_signed or
  1020. (torddef(fromdef).typ = u64bit)) then
  1021. begin
  1022. { in all cases, there is only a problem if the higest bit is set }
  1023. if p.location.loc in [LOC_REGISTER,LOC_CREGISTER] then
  1024. if is_64bitint(fromdef) then
  1025. hreg := p.location.registerhigh
  1026. else
  1027. hreg := p.location.register
  1028. else
  1029. begin
  1030. hreg := getexplicitregister32(R_EDI);
  1031. case p.resulttype.def.size of
  1032. 1: opsize := S_BL;
  1033. 2: opsize := S_WL;
  1034. 4,8: opsize := S_L;
  1035. end;
  1036. if opsize in [S_BL,S_WL] then
  1037. if from_signed then
  1038. opcode := A_MOVSX
  1039. else opcode := A_MOVZX
  1040. else
  1041. opcode := A_MOV;
  1042. href := newreference(p.location.reference);
  1043. if p.resulttype.def.size = 8 then
  1044. inc(href^.offset,4);
  1045. emit_ref_reg(opcode,opsize,href,hreg);
  1046. end;
  1047. getlabel(poslabel);
  1048. emit_reg_reg(A_TEST,regsize(hreg),hreg,hreg);
  1049. if hreg = R_EDI then
  1050. ungetregister32(hreg);
  1051. emitjmp(C_GE,poslabel);
  1052. emitcall('FPC_RANGEERROR');
  1053. emitlab(poslabel);
  1054. end;
  1055. end;
  1056. { produces if necessary rangecheckcode }
  1057. procedure emitrangecheck(p:tnode;todef:tdef);
  1058. {
  1059. generate range checking code for the value at location t. The
  1060. type used is the checked against todefs ranges. fromdef (p.resulttype.def)
  1061. is the original type used at that location, when both defs are
  1062. equal the check is also insert (needed for succ,pref,inc,dec)
  1063. }
  1064. var
  1065. neglabel : tasmlabel;
  1066. opsize : topsize;
  1067. op : tasmop;
  1068. fromdef : tdef;
  1069. lto,hto,
  1070. lfrom,hfrom : TConstExprInt;
  1071. is_reg : boolean;
  1072. begin
  1073. { range checking on and range checkable value? }
  1074. if not(cs_check_range in aktlocalswitches) or
  1075. not(todef.deftype in [orddef,enumdef,arraydef]) then
  1076. exit;
  1077. { only check when assigning to scalar, subranges are different,
  1078. when todef=fromdef then the check is always generated }
  1079. fromdef:=p.resulttype.def;
  1080. { no range check if from and to are equal and are both longint/dword or }
  1081. { int64/qword, since such operations can at most cause overflows (JM) }
  1082. if (fromdef = todef) and
  1083. { then fromdef and todef can only be orddefs }
  1084. (((torddef(fromdef).typ = s32bit) and
  1085. (torddef(fromdef).low = longint($80000000)) and
  1086. (torddef(fromdef).high = $7fffffff)) or
  1087. ((torddef(fromdef).typ = u32bit) and
  1088. (torddef(fromdef).low = 0) and
  1089. (torddef(fromdef).high = longint($ffffffff))) or
  1090. is_64bitint(fromdef)) then
  1091. exit;
  1092. if is_64bitint(fromdef) or is_64bitint(todef) then
  1093. begin
  1094. emitrangecheck64(p,todef);
  1095. exit;
  1096. end;
  1097. {we also need lto and hto when checking if we need to use doublebound!
  1098. (JM)}
  1099. getrange(todef,lto,hto);
  1100. if todef<>fromdef then
  1101. begin
  1102. getrange(p.resulttype.def,lfrom,hfrom);
  1103. { first check for not being u32bit, then if the to is bigger than
  1104. from }
  1105. if (lto<hto) and (lfrom<hfrom) and
  1106. (lto<=lfrom) and (hto>=hfrom) then
  1107. exit;
  1108. end;
  1109. { generate the rangecheck code for the def where we are going to
  1110. store the result }
  1111. { get op and opsize }
  1112. opsize:=def2def_opsize(fromdef,u32bittype.def);
  1113. if opsize in [S_B,S_W,S_L] then
  1114. op:=A_MOV
  1115. else
  1116. if is_signed(fromdef) then
  1117. op:=A_MOVSX
  1118. else
  1119. op:=A_MOVZX;
  1120. is_reg:=(p.location.loc in [LOC_REGISTER,LOC_CREGISTER]);
  1121. { use the trick that }
  1122. { a <= x <= b <=> 0 <= x-a <= b-a <=> cardinal(x-a) <= cardinal(b-a) }
  1123. { To be able to do that, we have to make sure however that either }
  1124. { fromdef and todef are both signed or unsigned, or that we leave }
  1125. { the parts < 0 and > maxlongint out }
  1126. { is_signed now also works for arrays (it checks the rangetype) (JM) }
  1127. if is_signed(fromdef) xor is_signed(todef) then
  1128. if is_signed(fromdef) then
  1129. { from is signed, to is unsigned }
  1130. begin
  1131. { if high(from) < 0 -> always range error }
  1132. if (hfrom < 0) or
  1133. { if low(to) > maxlongint (== < 0, since we only have }
  1134. { longints here), also range error }
  1135. (lto < 0) then
  1136. begin
  1137. emitcall('FPC_RANGEERROR');
  1138. exit
  1139. end;
  1140. { to is unsigned -> hto < 0 == hto > maxlongint }
  1141. { since from is signed, values > maxlongint are < 0 and must }
  1142. { be rejected }
  1143. if hto < 0 then
  1144. hto := maxlongint;
  1145. end
  1146. else
  1147. { from is unsigned, to is signed }
  1148. begin
  1149. if (lfrom < 0) or
  1150. (hto < 0) then
  1151. begin
  1152. emitcall('FPC_RANGEERROR');
  1153. exit
  1154. end;
  1155. { since from is unsigned, values > maxlongint are < 0 and must }
  1156. { be rejected }
  1157. if lto < 0 then
  1158. lto := 0;
  1159. end;
  1160. getexplicitregister32(R_EDI);
  1161. if is_reg and
  1162. (opsize = S_L) then
  1163. emit_ref_reg(A_LEA,opsize,new_reference(p.location.register,-lto),
  1164. R_EDI)
  1165. else
  1166. begin
  1167. if is_reg then
  1168. emit_reg_reg(op,opsize,p.location.register,R_EDI)
  1169. else
  1170. emit_ref_reg(op,opsize,newreference(p.location.reference),R_EDI);
  1171. if lto <> 0 then
  1172. emit_const_reg(A_SUB,S_L,lto,R_EDI);
  1173. end;
  1174. emit_const_reg(A_CMP,S_L,hto-lto,R_EDI);
  1175. ungetregister32(R_EDI);
  1176. getlabel(neglabel);
  1177. emitjmp(C_BE,neglabel);
  1178. emitcall('FPC_RANGEERROR');
  1179. emitlab(neglabel);
  1180. end;
  1181. { DO NOT RELY on the fact that the tnode is not yet swaped
  1182. because of inlining code PM }
  1183. procedure firstcomplex(p : tbinarynode);
  1184. var
  1185. hp : tnode;
  1186. begin
  1187. { always calculate boolean AND and OR from left to right }
  1188. if (p.nodetype in [orn,andn]) and
  1189. (p.left.resulttype.def.deftype=orddef) and
  1190. (torddef(p.left.resulttype.def).typ in [bool8bit,bool16bit,bool32bit]) then
  1191. begin
  1192. { p.swaped:=false}
  1193. if nf_swaped in p.flags then
  1194. internalerror(234234);
  1195. end
  1196. else
  1197. if (((p.location.loc=LOC_FPU) and
  1198. (p.right.registersfpu > p.left.registersfpu)) or
  1199. ((((p.left.registersfpu = 0) and
  1200. (p.right.registersfpu = 0)) or
  1201. (p.location.loc<>LOC_FPU)) and
  1202. (p.left.registers32<p.right.registers32))) and
  1203. { the following check is appropriate, because all }
  1204. { 4 registers are rarely used and it is thereby }
  1205. { achieved that the extra code is being dropped }
  1206. { by exchanging not commutative operators }
  1207. (p.right.registers32<=4) then
  1208. begin
  1209. hp:=p.left;
  1210. p.left:=p.right;
  1211. p.right:=hp;
  1212. if nf_swaped in p.flags then
  1213. exclude(p.flags,nf_swaped)
  1214. else
  1215. include(p.flags,nf_swaped);
  1216. end;
  1217. {else
  1218. p.swaped:=false; do not modify }
  1219. end;
  1220. {*****************************************************************************
  1221. Emit Functions
  1222. *****************************************************************************}
  1223. procedure push_shortstring_length(p:tnode);
  1224. var
  1225. hightree : tnode;
  1226. srsym : tsym;
  1227. begin
  1228. if is_open_string(p.resulttype.def) then
  1229. begin
  1230. srsym:=searchsymonlyin(tloadnode(p).symtable,'high'+tvarsym(tloadnode(p).symtableentry).name);
  1231. hightree:=cloadnode.create(tvarsym(srsym),tloadnode(p).symtable);
  1232. firstpass(hightree);
  1233. secondpass(hightree);
  1234. push_value_para(hightree,false,false,0,4);
  1235. hightree.free;
  1236. hightree:=nil;
  1237. end
  1238. else
  1239. begin
  1240. push_int(tstringdef(p.resulttype.def).len);
  1241. end;
  1242. end;
  1243. {*****************************************************************************
  1244. String functions
  1245. *****************************************************************************}
  1246. procedure loadshortstring(source,dest : tnode);
  1247. {
  1248. Load a string, handles stringdef and orddef (char) types
  1249. }
  1250. var
  1251. href: treference;
  1252. begin
  1253. case source.resulttype.def.deftype of
  1254. stringdef:
  1255. begin
  1256. if (source.nodetype=stringconstn) and
  1257. (str_length(source)=0) then
  1258. emit_const_ref(
  1259. A_MOV,S_B,0,newreference(dest.location.reference))
  1260. else
  1261. begin
  1262. emitpushreferenceaddr(dest.location.reference);
  1263. emitpushreferenceaddr(source.location.reference);
  1264. push_shortstring_length(dest);
  1265. emitcall('FPC_SHORTSTR_COPY');
  1266. maybe_loadself;
  1267. end;
  1268. end;
  1269. orddef:
  1270. begin
  1271. if source.nodetype=ordconstn then
  1272. emit_const_ref(
  1273. A_MOV,S_W,tordconstnode(source).value*256+1,newreference(dest.location.reference))
  1274. else
  1275. begin
  1276. if (source.location.loc in [LOC_REGISTER,LOC_CREGISTER]) then
  1277. begin
  1278. href := dest.location.reference;
  1279. emit_const_ref(A_MOV,S_B,1,newreference(href));
  1280. inc(href.offset,1);
  1281. emit_reg_ref(A_MOV,S_B,makereg8(source.location.register),
  1282. newreference(href));
  1283. ungetregister(source.location.register);
  1284. end
  1285. else
  1286. { not so elegant (goes better with extra register }
  1287. begin
  1288. { not "movl", because then we may read past the }
  1289. { end of the heap! "movw" would be ok too, but }
  1290. { I don't think that would be faster (JM) }
  1291. getexplicitregister32(R_EDI);
  1292. emit_ref_reg(A_MOVZX,S_BL,newreference(source.location.reference),R_EDI);
  1293. del_reference(source.location.reference);
  1294. emit_const_reg(A_SHL,S_L,8,R_EDI);
  1295. emit_const_reg(A_OR,S_L,1,R_EDI);
  1296. emit_reg_ref(A_MOV,S_W,R_DI,newreference(dest.location.reference));
  1297. ungetregister32(R_EDI);
  1298. end;
  1299. end;
  1300. end;
  1301. else
  1302. CGMessage(type_e_mismatch);
  1303. end;
  1304. end;
  1305. procedure loadlongstring(p:tbinarynode);
  1306. {
  1307. Load a string, handles stringdef and orddef (char) types
  1308. }
  1309. var
  1310. r : preference;
  1311. begin
  1312. case p.right.resulttype.def.deftype of
  1313. stringdef:
  1314. begin
  1315. if (p.right.nodetype=stringconstn) and
  1316. (str_length(p.right)=0) then
  1317. emit_const_ref(A_MOV,S_L,0,newreference(p.left.location.reference))
  1318. else
  1319. begin
  1320. emitpushreferenceaddr(p.left.location.reference);
  1321. emitpushreferenceaddr(p.right.location.reference);
  1322. push_shortstring_length(p.left);
  1323. emitcall('FPC_LONGSTR_COPY');
  1324. maybe_loadself;
  1325. end;
  1326. end;
  1327. orddef:
  1328. begin
  1329. emit_const_ref(A_MOV,S_L,1,newreference(p.left.location.reference));
  1330. r:=newreference(p.left.location.reference);
  1331. inc(r^.offset,4);
  1332. if p.right.nodetype=ordconstn then
  1333. emit_const_ref(A_MOV,S_B,tordconstnode(p.right).value,r)
  1334. else
  1335. begin
  1336. case p.right.location.loc of
  1337. LOC_REGISTER,LOC_CREGISTER:
  1338. begin
  1339. emit_reg_ref(A_MOV,S_B,p.right.location.register,r);
  1340. ungetregister(p.right.location.register);
  1341. end;
  1342. LOC_MEM,LOC_REFERENCE:
  1343. begin
  1344. if not(R_EAX in unused) then
  1345. emit_reg(A_PUSH,S_L,R_EAX);
  1346. emit_ref_reg(A_MOV,S_B,newreference(p.right.location.reference),R_AL);
  1347. emit_reg_ref(A_MOV,S_B,R_AL,r);
  1348. if not(R_EAX in unused) then
  1349. emit_reg(A_POP,S_L,R_EAX);
  1350. del_reference(p.right.location.reference);
  1351. end
  1352. else
  1353. internalerror(20799);
  1354. end;
  1355. end;
  1356. end;
  1357. else
  1358. CGMessage(type_e_mismatch);
  1359. end;
  1360. end;
  1361. procedure loadansi2short(source,dest : tnode);
  1362. var
  1363. pushed : tpushed;
  1364. regs_to_push: byte;
  1365. begin
  1366. { Find out which registers have to be pushed (JM) }
  1367. regs_to_push := $ff;
  1368. remove_non_regvars_from_loc(source.location,regs_to_push);
  1369. { Push them (JM) }
  1370. pushusedregisters(pushed,regs_to_push);
  1371. case source.location.loc of
  1372. LOC_REFERENCE,LOC_MEM:
  1373. begin
  1374. { Now release the location and registers (see cgai386.pas: }
  1375. { loadansistring for more info on the order) (JM) }
  1376. ungetiftemp(source.location.reference);
  1377. del_reference(source.location.reference);
  1378. emit_push_mem(source.location.reference);
  1379. end;
  1380. LOC_REGISTER,LOC_CREGISTER:
  1381. begin
  1382. emit_reg(A_PUSH,S_L,source.location.register);
  1383. { Now release the register (JM) }
  1384. ungetregister32(source.location.register);
  1385. end;
  1386. end;
  1387. push_shortstring_length(dest);
  1388. emitpushreferenceaddr(dest.location.reference);
  1389. saveregvars($ff);
  1390. emitcall('FPC_ANSISTR_TO_SHORTSTR');
  1391. popusedregisters(pushed);
  1392. maybe_loadself;
  1393. end;
  1394. procedure loadwide2short(source,dest : tnode);
  1395. var
  1396. pushed : tpushed;
  1397. regs_to_push: byte;
  1398. begin
  1399. { Find out which registers have to be pushed (JM) }
  1400. regs_to_push := $ff;
  1401. remove_non_regvars_from_loc(source.location,regs_to_push);
  1402. { Push them (JM) }
  1403. pushusedregisters(pushed,regs_to_push);
  1404. case source.location.loc of
  1405. LOC_REFERENCE,LOC_MEM:
  1406. begin
  1407. { Now release the location and registers (see cgai386.pas: }
  1408. { loadansistring for more info on the order) (JM) }
  1409. ungetiftemp(source.location.reference);
  1410. del_reference(source.location.reference);
  1411. emit_push_mem(source.location.reference);
  1412. end;
  1413. LOC_REGISTER,LOC_CREGISTER:
  1414. begin
  1415. emit_reg(A_PUSH,S_L,source.location.register);
  1416. { Now release the register (JM) }
  1417. ungetregister32(source.location.register);
  1418. end;
  1419. end;
  1420. push_shortstring_length(dest);
  1421. emitpushreferenceaddr(dest.location.reference);
  1422. saveregvars($ff);
  1423. emitcall('FPC_WIDESTR_TO_SHORTSTR');
  1424. popusedregisters(pushed);
  1425. maybe_loadself;
  1426. end;
  1427. procedure loadinterfacecom(p: tbinarynode);
  1428. {
  1429. copies an com interface from n.right to n.left, we
  1430. assume, that both sides are com interface, firstassignement have
  1431. to take care of that, an com interface can't be a register variable
  1432. }
  1433. var
  1434. pushed : tpushed;
  1435. ungettemp : boolean;
  1436. begin
  1437. { before pushing any parameter, we have to save all used }
  1438. { registers, but before that we have to release the }
  1439. { registers of that node to save uneccessary pushed }
  1440. { so be careful, if you think you can optimize that code (FK) }
  1441. { nevertheless, this has to be changed, because otherwise the }
  1442. { register is released before it's contents are pushed -> }
  1443. { problems with the optimizer (JM) }
  1444. del_reference(p.left.location.reference);
  1445. ungettemp:=false;
  1446. case p.right.location.loc of
  1447. LOC_REGISTER,LOC_CREGISTER:
  1448. begin
  1449. pushusedregisters(pushed, $ff xor ($80 shr byte(p.right.location.register)));
  1450. exprasmList.concat(Taicpu.Op_reg(A_PUSH,S_L,p.right.location.register));
  1451. ungetregister32(p.right.location.register);
  1452. end;
  1453. LOC_REFERENCE,LOC_MEM:
  1454. begin
  1455. pushusedregisters(pushed,$ff
  1456. xor ($80 shr byte(p.right.location.reference.base))
  1457. xor ($80 shr byte(p.right.location.reference.index)));
  1458. emit_push_mem(p.right.location.reference);
  1459. del_reference(p.right.location.reference);
  1460. ungettemp:=true;
  1461. end;
  1462. end;
  1463. emitpushreferenceaddr(p.left.location.reference);
  1464. del_reference(p.left.location.reference);
  1465. saveregvars($ff);
  1466. emitcall('FPC_INTF_ASSIGN');
  1467. maybe_loadself;
  1468. popusedregisters(pushed);
  1469. if ungettemp then
  1470. ungetiftemp(p.right.location.reference);
  1471. end;
  1472. end.
  1473. {
  1474. $Log$
  1475. Revision 1.24 2001-12-03 21:48:43 peter
  1476. * freemem change to value parameter
  1477. * torddef low/high range changed to int64
  1478. Revision 1.23 2001/12/02 16:19:17 jonas
  1479. * less unnecessary regvar loading with if-statements
  1480. Revision 1.22 2001/10/12 13:51:52 jonas
  1481. * fixed internalerror(10) due to previous fpu overflow fixes ("merged")
  1482. * fixed bug in n386add (introduced after compilerproc changes for string
  1483. operations) where calcregisters wasn't called for shortstring addnodes
  1484. * NOTE: from now on, the location of a binary node must now always be set
  1485. before you call calcregisters() for it
  1486. Revision 1.21 2001/09/17 21:29:14 peter
  1487. * merged netbsd, fpu-overflow from fixes branch
  1488. Revision 1.20 2001/08/26 13:37:01 florian
  1489. * some cg reorganisation
  1490. * some PPC updates
  1491. Revision 1.19 2001/08/24 12:22:14 jonas
  1492. * fixed memory leak with coping of array-of-consts as valuepara
  1493. Revision 1.18 2001/07/08 21:00:18 peter
  1494. * various widestring updates, it works now mostly without charset
  1495. mapping supported
  1496. Revision 1.17 2001/07/01 20:16:20 peter
  1497. * alignmentinfo record added
  1498. * -Oa argument supports more alignment settings that can be specified
  1499. per type: PROC,LOOP,VARMIN,VARMAX,CONSTMIN,CONSTMAX,RECORDMIN
  1500. RECORDMAX,LOCALMIN,LOCALMAX. It is possible to set the mimimum
  1501. required alignment and the maximum usefull alignment. The final
  1502. alignment will be choosen per variable size dependent on these
  1503. settings
  1504. Revision 1.16 2001/04/18 22:02:03 peter
  1505. * registration of targets and assemblers
  1506. Revision 1.15 2001/04/13 01:22:19 peter
  1507. * symtable change to classes
  1508. * range check generation and errors fixed, make cycle DEBUG=1 works
  1509. * memory leaks fixed
  1510. Revision 1.14 2001/04/02 21:20:39 peter
  1511. * resulttype rewrite
  1512. Revision 1.13 2001/03/11 22:58:52 peter
  1513. * getsym redesign, removed the globals srsym,srsymtable
  1514. Revision 1.12 2001/03/04 10:26:56 jonas
  1515. * new rangecheck code now handles conversion between signed and cardinal types correctly
  1516. Revision 1.11 2001/03/03 12:41:22 jonas
  1517. * simplified and optimized range checking code, FPC_BOUNDCHECK is no longer necessary
  1518. Revision 1.10 2000/12/31 11:02:12 jonas
  1519. * optimized loadshortstring a bit
  1520. Revision 1.9 2000/12/25 00:07:33 peter
  1521. + new tlinkedlist class (merge of old tstringqueue,tcontainer and
  1522. tlinkedlist objects)
  1523. Revision 1.8 2000/12/11 19:10:19 jonas
  1524. * fixed web bug 1144
  1525. + implemented range checking for 64bit types
  1526. Revision 1.7 2000/12/07 17:19:46 jonas
  1527. * new constant handling: from now on, hex constants >$7fffffff are
  1528. parsed as unsigned constants (otherwise, $80000000 got sign extended
  1529. and became $ffffffff80000000), all constants in the longint range
  1530. become longints, all constants >$7fffffff and <=cardinal($ffffffff)
  1531. are cardinals and the rest are int64's.
  1532. * added lots of longint typecast to prevent range check errors in the
  1533. compiler and rtl
  1534. * type casts of symbolic ordinal constants are now preserved
  1535. * fixed bug where the original resulttype.def wasn't restored correctly
  1536. after doing a 64bit rangecheck
  1537. Revision 1.6 2000/12/05 11:44:34 jonas
  1538. + new integer regvar handling, should be much more efficient
  1539. Revision 1.5 2000/11/29 00:30:49 florian
  1540. * unused units removed from uses clause
  1541. * some changes for widestrings
  1542. Revision 1.4 2000/11/13 14:47:46 jonas
  1543. * support for range checking when converting from 64bit to something
  1544. smaller (32bit, 16bit, 8bit)
  1545. * fixed range checking between longint/cardinal and for array indexing
  1546. with cardinal (values > $7fffffff were considered negative)
  1547. Revision 1.3 2000/11/04 14:25:25 florian
  1548. + merged Attila's changes for interfaces, not tested yet
  1549. Revision 1.2 2000/10/31 22:02:57 peter
  1550. * symtable splitted, no real code changes
  1551. Revision 1.1 2000/10/15 09:33:32 peter
  1552. * moved n386*.pas to i386/ cpu_target dir
  1553. Revision 1.3 2000/10/14 21:52:54 peter
  1554. * fixed memory leaks
  1555. Revision 1.2 2000/10/14 10:14:50 peter
  1556. * moehrendorf oct 2000 rewrite
  1557. Revision 1.1 2000/10/01 19:58:40 peter
  1558. * new file
  1559. }