n386util.pas 44 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085
  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. symtable,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. procedure pushsetelement(p : tnode);
  29. procedure push_value_para(p:tnode;inlined,is_cdecl:boolean;
  30. para_offset:longint;alignment : longint);
  31. procedure maketojumpbool(p : tnode);
  32. procedure emitoverflowcheck(p:tnode);
  33. procedure emitrangecheck(p:tnode;todef:pdef);
  34. procedure firstcomplex(p : tnode);
  35. implementation
  36. uses
  37. ncon;
  38. {*****************************************************************************
  39. Emit Push Functions
  40. *****************************************************************************}
  41. function maybe_push(needed : byte;p : tnode;isint64 : boolean) : boolean;
  42. var
  43. pushed : boolean;
  44. {hregister : tregister; }
  45. {$ifdef TEMPS_NOT_PUSH}
  46. href : treference;
  47. {$endif TEMPS_NOT_PUSH}
  48. begin
  49. if needed>usablereg32 then
  50. begin
  51. if (p.location.loc=LOC_REGISTER) then
  52. begin
  53. if isint64 then
  54. begin
  55. {$ifdef TEMPS_NOT_PUSH}
  56. gettempofsizereference(href,8);
  57. p.temp_offset:=href.offset;
  58. href.offset:=href.offset+4;
  59. exprasmlist^.concat(new(paicpu,op_reg(A_MOV,S_L,p.location.registerhigh,href)));
  60. href.offset:=href.offset-4;
  61. {$else TEMPS_NOT_PUSH}
  62. exprasmlist^.concat(new(paicpu,op_reg(A_PUSH,S_L,p.location.registerhigh)));
  63. {$endif TEMPS_NOT_PUSH}
  64. ungetregister32(p.location.registerhigh);
  65. end
  66. {$ifdef TEMPS_NOT_PUSH}
  67. else
  68. begin
  69. gettempofsizereference(href,4);
  70. p.temp_offset:=href.offset;
  71. end
  72. {$endif TEMPS_NOT_PUSH}
  73. ;
  74. pushed:=true;
  75. {$ifdef TEMPS_NOT_PUSH}
  76. exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,S_L,p.location.register,href)));
  77. {$else TEMPS_NOT_PUSH}
  78. exprasmlist^.concat(new(paicpu,op_reg(A_PUSH,S_L,p.location.register)));
  79. {$endif TEMPS_NOT_PUSH}
  80. ungetregister32(p.location.register);
  81. end
  82. else if (p.location.loc in [LOC_MEM,LOC_REFERENCE]) and
  83. ((p.location.reference.base<>R_NO) or
  84. (p.location.reference.index<>R_NO)
  85. ) then
  86. begin
  87. del_reference(p.location.reference);
  88. getexplicitregister32(R_EDI);
  89. emit_ref_reg(A_LEA,S_L,newreference(p.location.reference),R_EDI);
  90. {$ifdef TEMPS_NOT_PUSH}
  91. gettempofsizereference(href,4);
  92. exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,S_L,R_EDI,href)));
  93. p.temp_offset:=href.offset;
  94. {$else TEMPS_NOT_PUSH}
  95. exprasmlist^.concat(new(paicpu,op_reg(A_PUSH,S_L,R_EDI)));
  96. {$endif TEMPS_NOT_PUSH}
  97. ungetregister32(R_EDI);
  98. pushed:=true;
  99. end
  100. else pushed:=false;
  101. end
  102. else pushed:=false;
  103. maybe_push:=pushed;
  104. end;
  105. {$ifdef TEMPS_NOT_PUSH}
  106. function maybe_savetotemp(needed : byte;p : tnode;isint64 : boolean) : boolean;
  107. var
  108. pushed : boolean;
  109. href : treference;
  110. begin
  111. if needed>usablereg32 then
  112. begin
  113. if (p^.location.loc=LOC_REGISTER) then
  114. begin
  115. if isint64(p^.resulttype) then
  116. begin
  117. gettempofsizereference(href,8);
  118. p^.temp_offset:=href.offset;
  119. href.offset:=href.offset+4;
  120. exprasmlist^.concat(new(paicpu,op_reg(A_MOV,S_L,p^.location.registerhigh,href)));
  121. href.offset:=href.offset-4;
  122. ungetregister32(p^.location.registerhigh);
  123. end
  124. else
  125. begin
  126. gettempofsizereference(href,4);
  127. p^.temp_offset:=href.offset;
  128. end;
  129. pushed:=true;
  130. exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,S_L,p^.location.register,href)));
  131. ungetregister32(p^.location.register);
  132. end
  133. else if (p^.location.loc in [LOC_MEM,LOC_REFERENCE]) and
  134. ((p^.location.reference.base<>R_NO) or
  135. (p^.location.reference.index<>R_NO)
  136. ) then
  137. begin
  138. del_reference(p^.location.reference);
  139. getexplicitregister32(R_EDI);
  140. emit_ref_reg(A_LEA,S_L,newreference(p^.location.reference),
  141. R_EDI);
  142. gettempofsizereference(href,4);
  143. exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,S_L,R_EDI,href)));
  144. ungetregister32(R_EDI);
  145. p^.temp_offset:=href.offset;
  146. pushed:=true;
  147. end
  148. else pushed:=false;
  149. end
  150. else pushed:=false;
  151. maybe_push:=pushed;
  152. end;
  153. {$endif TEMPS_NOT_PUSH}
  154. procedure restore(p : tnode;isint64 : boolean);
  155. var
  156. hregister : tregister;
  157. {$ifdef TEMPS_NOT_PUSH}
  158. href : treference;
  159. {$endif TEMPS_NOT_PUSH}
  160. begin
  161. hregister:=getregister32;
  162. {$ifdef TEMPS_NOT_PUSH}
  163. reset_reference(href);
  164. href.base:=procinfo^.frame_pointer;
  165. href.offset:=p.temp_offset;
  166. emit_ref_reg(A_MOV,S_L,href,hregister);
  167. {$else TEMPS_NOT_PUSH}
  168. exprasmlist^.concat(new(paicpu,op_reg(A_POP,S_L,hregister)));
  169. {$endif TEMPS_NOT_PUSH}
  170. if (p.location.loc in [LOC_REGISTER,LOC_CREGISTER]) then
  171. begin
  172. p.location.register:=hregister;
  173. if isint64 then
  174. begin
  175. p.location.registerhigh:=getregister32;
  176. {$ifdef TEMPS_NOT_PUSH}
  177. href.offset:=p.temp_offset+4;
  178. emit_ref_reg(A_MOV,S_L,p.location.registerhigh);
  179. { set correctly for release ! }
  180. href.offset:=p.temp_offset;
  181. {$else TEMPS_NOT_PUSH}
  182. exprasmlist^.concat(new(paicpu,op_reg(A_POP,S_L,p.location.registerhigh)));
  183. {$endif TEMPS_NOT_PUSH}
  184. end;
  185. end
  186. else
  187. begin
  188. reset_reference(p.location.reference);
  189. { any reasons why this was moved into the index register ? }
  190. { normally usage of base register is much better (FK) }
  191. p.location.reference.base:=hregister;
  192. { Why is this done? We can never be sure about p.left
  193. because otherwise secondload fails !!!
  194. set_location(p.left^.location,p.location);}
  195. end;
  196. {$ifdef TEMPS_NOT_PUSH}
  197. ungetiftemp(href);
  198. {$endif TEMPS_NOT_PUSH}
  199. end;
  200. procedure pushsetelement(p : tnode);
  201. var
  202. hr,hr16,hr32 : tregister;
  203. begin
  204. { copy the element on the stack, slightly complicated }
  205. if p.nodetype=ordconstn then
  206. begin
  207. if target_os.stackalignment=4 then
  208. exprasmlist^.concat(new(paicpu,op_const(A_PUSH,S_L,tordconstnode(p).value)))
  209. else
  210. exprasmlist^.concat(new(paicpu,op_const(A_PUSH,S_W,tordconstnode(p).value)));
  211. end
  212. else
  213. begin
  214. case p.location.loc of
  215. LOC_REGISTER,
  216. LOC_CREGISTER :
  217. begin
  218. hr:=p.location.register;
  219. case hr of
  220. R_EAX,R_EBX,R_ECX,R_EDX,R_EDI,R_ESI,R_ESP :
  221. begin
  222. hr16:=reg32toreg16(hr);
  223. hr32:=hr;
  224. end;
  225. R_AX,R_BX,R_CX,R_DX,R_DI,R_SI,R_SP :
  226. begin
  227. hr16:=hr;
  228. hr32:=reg16toreg32(hr);
  229. end;
  230. R_AL,R_BL,R_CL,R_DL :
  231. begin
  232. hr16:=reg8toreg16(hr);
  233. hr32:=reg8toreg32(hr);
  234. end;
  235. end;
  236. if target_os.stackalignment=4 then
  237. exprasmlist^.concat(new(paicpu,op_reg(A_PUSH,S_L,hr32)))
  238. else
  239. exprasmlist^.concat(new(paicpu,op_reg(A_PUSH,S_W,hr16)));
  240. ungetregister32(hr32);
  241. end;
  242. else
  243. begin
  244. { you can't push more bytes than the size of the element, }
  245. { because this may cross a page boundary and you'll get a }
  246. { sigsegv (JM) }
  247. emit_push_mem_size(p.location.reference,1);
  248. del_reference(p.location.reference);
  249. end;
  250. end;
  251. end;
  252. end;
  253. procedure push_value_para(p:tnode;inlined,is_cdecl:boolean;
  254. para_offset:longint;alignment : longint);
  255. var
  256. tempreference : treference;
  257. r : preference;
  258. opsize : topsize;
  259. op : tasmop;
  260. hreg : tregister;
  261. size : longint;
  262. hlabel : pasmlabel;
  263. begin
  264. case p.location.loc of
  265. LOC_REGISTER,
  266. LOC_CREGISTER:
  267. begin
  268. case p.location.register of
  269. R_EAX,R_EBX,R_ECX,R_EDX,R_ESI,
  270. R_EDI,R_ESP,R_EBP :
  271. begin
  272. if p.resulttype^.size=8 then
  273. begin
  274. inc(pushedparasize,8);
  275. if inlined then
  276. begin
  277. r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
  278. exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,S_L,
  279. p.location.registerlow,r)));
  280. r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize+4);
  281. exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,S_L,
  282. p.location.registerhigh,r)));
  283. end
  284. else
  285. exprasmlist^.concat(new(paicpu,op_reg(A_PUSH,S_L,p.location.registerhigh)));
  286. ungetregister32(p.location.registerhigh);
  287. exprasmlist^.concat(new(paicpu,op_reg(A_PUSH,S_L,p.location.registerlow)));
  288. ungetregister32(p.location.registerlow);
  289. end
  290. else
  291. begin
  292. inc(pushedparasize,4);
  293. if inlined then
  294. begin
  295. r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
  296. exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,S_L,
  297. p.location.register,r)));
  298. end
  299. else
  300. exprasmlist^.concat(new(paicpu,op_reg(A_PUSH,S_L,p.location.register)));
  301. ungetregister32(p.location.register);
  302. end;
  303. end;
  304. R_AX,R_BX,R_CX,R_DX,R_SI,R_DI:
  305. begin
  306. if alignment=4 then
  307. begin
  308. opsize:=S_L;
  309. hreg:=reg16toreg32(p.location.register);
  310. inc(pushedparasize,4);
  311. end
  312. else
  313. begin
  314. opsize:=S_W;
  315. hreg:=p.location.register;
  316. inc(pushedparasize,2);
  317. end;
  318. if inlined then
  319. begin
  320. r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
  321. exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,opsize,hreg,r)));
  322. end
  323. else
  324. exprasmlist^.concat(new(paicpu,op_reg(A_PUSH,opsize,hreg)));
  325. ungetregister32(reg16toreg32(p.location.register));
  326. end;
  327. R_AL,R_BL,R_CL,R_DL:
  328. begin
  329. if alignment=4 then
  330. begin
  331. opsize:=S_L;
  332. hreg:=reg8toreg32(p.location.register);
  333. inc(pushedparasize,4);
  334. end
  335. else
  336. begin
  337. opsize:=S_W;
  338. hreg:=reg8toreg16(p.location.register);
  339. inc(pushedparasize,2);
  340. end;
  341. { we must push always 16 bit }
  342. if inlined then
  343. begin
  344. r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
  345. exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,opsize,hreg,r)));
  346. end
  347. else
  348. exprasmlist^.concat(new(paicpu,op_reg(A_PUSH,opsize,hreg)));
  349. ungetregister32(reg8toreg32(p.location.register));
  350. end;
  351. else internalerror(1899);
  352. end;
  353. end;
  354. LOC_FPU:
  355. begin
  356. size:=align(pfloatdef(p.resulttype)^.size,alignment);
  357. inc(pushedparasize,size);
  358. if not inlined then
  359. emit_const_reg(A_SUB,S_L,size,R_ESP);
  360. {$ifdef GDB}
  361. if (cs_debuginfo in aktmoduleswitches) and
  362. (exprasmlist^.first=exprasmlist^.last) then
  363. exprasmlist^.concat(new(pai_force_line,init));
  364. {$endif GDB}
  365. r:=new_reference(R_ESP,0);
  366. floatstoreops(pfloatdef(p.resulttype)^.typ,op,opsize);
  367. { this is the easiest case for inlined !! }
  368. if inlined then
  369. begin
  370. r^.base:=procinfo^.framepointer;
  371. r^.offset:=para_offset-pushedparasize;
  372. end;
  373. exprasmlist^.concat(new(paicpu,op_ref(op,opsize,r)));
  374. dec(fpuvaroffset);
  375. end;
  376. LOC_CFPUREGISTER:
  377. begin
  378. exprasmlist^.concat(new(paicpu,op_reg(A_FLD,S_NO,
  379. correct_fpuregister(p.location.register,fpuvaroffset))));
  380. size:=align(pfloatdef(p.resulttype)^.size,alignment);
  381. inc(pushedparasize,size);
  382. if not inlined then
  383. emit_const_reg(A_SUB,S_L,size,R_ESP);
  384. {$ifdef GDB}
  385. if (cs_debuginfo in aktmoduleswitches) and
  386. (exprasmlist^.first=exprasmlist^.last) then
  387. exprasmlist^.concat(new(pai_force_line,init));
  388. {$endif GDB}
  389. r:=new_reference(R_ESP,0);
  390. floatstoreops(pfloatdef(p.resulttype)^.typ,op,opsize);
  391. { this is the easiest case for inlined !! }
  392. if inlined then
  393. begin
  394. r^.base:=procinfo^.framepointer;
  395. r^.offset:=para_offset-pushedparasize;
  396. end;
  397. exprasmlist^.concat(new(paicpu,op_ref(op,opsize,r)));
  398. end;
  399. LOC_REFERENCE,LOC_MEM:
  400. begin
  401. tempreference:=p.location.reference;
  402. del_reference(p.location.reference);
  403. case p.resulttype^.deftype of
  404. enumdef,
  405. orddef :
  406. begin
  407. case p.resulttype^.size of
  408. 8 : begin
  409. inc(pushedparasize,8);
  410. if inlined then
  411. begin
  412. getexplicitregister32(R_EDI);
  413. emit_ref_reg(A_MOV,S_L,
  414. newreference(tempreference),R_EDI);
  415. r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
  416. exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,S_L,R_EDI,r)));
  417. ungetregister32(R_EDI);
  418. getexplicitregister32(R_EDI);
  419. inc(tempreference.offset,4);
  420. emit_ref_reg(A_MOV,S_L,
  421. newreference(tempreference),R_EDI);
  422. r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize+4);
  423. exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,S_L,R_EDI,r)));
  424. ungetregister32(R_EDI);
  425. end
  426. else
  427. begin
  428. inc(tempreference.offset,4);
  429. emit_push_mem(tempreference);
  430. dec(tempreference.offset,4);
  431. emit_push_mem(tempreference);
  432. end;
  433. end;
  434. 4 : begin
  435. inc(pushedparasize,4);
  436. if inlined then
  437. begin
  438. getexplicitregister32(R_EDI);
  439. emit_ref_reg(A_MOV,S_L,
  440. newreference(tempreference),R_EDI);
  441. r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
  442. exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,S_L,R_EDI,r)));
  443. ungetregister32(R_EDI);
  444. end
  445. else
  446. emit_push_mem(tempreference);
  447. end;
  448. 1,2 : begin
  449. if alignment=4 then
  450. begin
  451. opsize:=S_L;
  452. hreg:=R_EDI;
  453. inc(pushedparasize,4);
  454. end
  455. else
  456. begin
  457. opsize:=S_W;
  458. hreg:=R_DI;
  459. inc(pushedparasize,2);
  460. end;
  461. if inlined then
  462. begin
  463. getexplicitregister32(R_EDI);
  464. emit_ref_reg(A_MOV,opsize,
  465. newreference(tempreference),hreg);
  466. r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
  467. exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,opsize,hreg,r)));
  468. ungetregister32(R_EDI);
  469. end
  470. else
  471. emit_push_mem_size(tempreference,p.resulttype^.size);
  472. end;
  473. else
  474. internalerror(234231);
  475. end;
  476. end;
  477. floatdef :
  478. begin
  479. case pfloatdef(p.resulttype)^.typ of
  480. f32bit,
  481. s32real :
  482. begin
  483. inc(pushedparasize,4);
  484. if inlined then
  485. begin
  486. getexplicitregister32(R_EDI);
  487. emit_ref_reg(A_MOV,S_L,
  488. newreference(tempreference),R_EDI);
  489. r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
  490. exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,S_L,R_EDI,r)));
  491. ungetregister32(R_EDI);
  492. end
  493. else
  494. emit_push_mem(tempreference);
  495. end;
  496. s64real,
  497. s64comp :
  498. begin
  499. inc(pushedparasize,4);
  500. inc(tempreference.offset,4);
  501. if inlined then
  502. begin
  503. getexplicitregister32(R_EDI);
  504. emit_ref_reg(A_MOV,S_L,
  505. newreference(tempreference),R_EDI);
  506. r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
  507. exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,S_L,R_EDI,r)));
  508. ungetregister32(R_EDI);
  509. end
  510. else
  511. emit_push_mem(tempreference);
  512. inc(pushedparasize,4);
  513. dec(tempreference.offset,4);
  514. if inlined then
  515. begin
  516. getexplicitregister32(R_EDI);
  517. emit_ref_reg(A_MOV,S_L,
  518. newreference(tempreference),R_EDI);
  519. r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
  520. exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,S_L,R_EDI,r)));
  521. ungetregister32(R_EDI);
  522. end
  523. else
  524. emit_push_mem(tempreference);
  525. end;
  526. s80real :
  527. begin
  528. inc(pushedparasize,4);
  529. if alignment=4 then
  530. inc(tempreference.offset,8)
  531. else
  532. inc(tempreference.offset,6);
  533. if inlined then
  534. begin
  535. getexplicitregister32(R_EDI);
  536. emit_ref_reg(A_MOV,S_L,
  537. newreference(tempreference),R_EDI);
  538. r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
  539. exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,S_L,R_EDI,r)));
  540. ungetregister32(R_EDI);
  541. end
  542. else
  543. emit_push_mem(tempreference);
  544. dec(tempreference.offset,4);
  545. inc(pushedparasize,4);
  546. if inlined then
  547. begin
  548. getexplicitregister32(R_EDI);
  549. emit_ref_reg(A_MOV,S_L,
  550. newreference(tempreference),R_EDI);
  551. r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
  552. exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,S_L,R_EDI,r)));
  553. ungetregister32(R_EDI);
  554. end
  555. else
  556. emit_push_mem(tempreference);
  557. if alignment=4 then
  558. begin
  559. opsize:=S_L;
  560. hreg:=R_EDI;
  561. inc(pushedparasize,4);
  562. dec(tempreference.offset,4);
  563. end
  564. else
  565. begin
  566. opsize:=S_W;
  567. hreg:=R_DI;
  568. inc(pushedparasize,2);
  569. dec(tempreference.offset,2);
  570. end;
  571. if inlined then
  572. begin
  573. getexplicitregister32(R_EDI);
  574. emit_ref_reg(A_MOV,opsize,
  575. newreference(tempreference),hreg);
  576. r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
  577. exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,opsize,hreg,r)));
  578. ungetregister32(R_EDI);
  579. end
  580. else
  581. exprasmlist^.concat(new(paicpu,op_ref(A_PUSH,opsize,
  582. newreference(tempreference))));
  583. end;
  584. end;
  585. end;
  586. pointerdef,
  587. procvardef,
  588. classrefdef:
  589. begin
  590. inc(pushedparasize,4);
  591. if inlined then
  592. begin
  593. getexplicitregister32(R_EDI);
  594. emit_ref_reg(A_MOV,S_L,
  595. newreference(tempreference),R_EDI);
  596. r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
  597. exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,S_L,R_EDI,r)));
  598. ungetregister32(R_EDI);
  599. end
  600. else
  601. emit_push_mem(tempreference);
  602. end;
  603. arraydef,
  604. recorddef,
  605. stringdef,
  606. setdef,
  607. objectdef :
  608. begin
  609. { even some structured types are 32 bit }
  610. if is_widestring(p.resulttype) or
  611. is_ansistring(p.resulttype) or
  612. is_smallset(p.resulttype) or
  613. ((p.resulttype^.deftype in [recorddef,arraydef]) and
  614. (
  615. (p.resulttype^.deftype<>arraydef) or not
  616. (parraydef(p.resulttype)^.IsConstructor or
  617. parraydef(p.resulttype)^.isArrayOfConst or
  618. is_open_array(p.resulttype))
  619. ) and
  620. (p.resulttype^.size<=4)
  621. ) or
  622. ((p.resulttype^.deftype=objectdef) and
  623. pobjectdef(p.resulttype)^.is_class) then
  624. begin
  625. if (p.resulttype^.size>2) or
  626. ((alignment=4) and (p.resulttype^.size>0)) then
  627. begin
  628. inc(pushedparasize,4);
  629. if inlined then
  630. begin
  631. r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
  632. concatcopy(tempreference,r^,4,false,false);
  633. end
  634. else
  635. emit_push_mem(tempreference);
  636. end
  637. else
  638. begin
  639. if p.resulttype^.size>0 then
  640. begin
  641. inc(pushedparasize,2);
  642. if inlined then
  643. begin
  644. r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
  645. concatcopy(tempreference,r^,2,false,false);
  646. end
  647. else
  648. exprasmlist^.concat(new(paicpu,op_ref(A_PUSH,S_W,newreference(tempreference))));
  649. end;
  650. end;
  651. end
  652. { call by value open array ? }
  653. else if is_cdecl then
  654. begin
  655. { push on stack }
  656. size:=align(p.resulttype^.size,alignment);
  657. inc(pushedparasize,size);
  658. emit_const_reg(A_SUB,S_L,size,R_ESP);
  659. r:=new_reference(R_ESP,0);
  660. concatcopy(tempreference,r^,size,false,false);
  661. end
  662. else
  663. internalerror(8954);
  664. end;
  665. else
  666. CGMessage(cg_e_illegal_expression);
  667. end;
  668. end;
  669. LOC_JUMP:
  670. begin
  671. getlabel(hlabel);
  672. if alignment=4 then
  673. begin
  674. opsize:=S_L;
  675. inc(pushedparasize,4);
  676. end
  677. else
  678. begin
  679. opsize:=S_W;
  680. inc(pushedparasize,2);
  681. end;
  682. emitlab(truelabel);
  683. if inlined then
  684. begin
  685. r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
  686. emit_const_ref(A_MOV,opsize,1,r);
  687. end
  688. else
  689. exprasmlist^.concat(new(paicpu,op_const(A_PUSH,opsize,1)));
  690. emitjmp(C_None,hlabel);
  691. emitlab(falselabel);
  692. if inlined then
  693. begin
  694. r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
  695. emit_const_ref(A_MOV,opsize,0,r);
  696. end
  697. else
  698. exprasmlist^.concat(new(paicpu,op_const(A_PUSH,opsize,0)));
  699. emitlab(hlabel);
  700. end;
  701. LOC_FLAGS:
  702. begin
  703. if not(R_EAX in unused) then
  704. begin
  705. getexplicitregister32(R_EDI);
  706. emit_reg_reg(A_MOV,S_L,R_EAX,R_EDI);
  707. end;
  708. emit_flag2reg(p.location.resflags,R_AL);
  709. emit_reg_reg(A_MOVZX,S_BW,R_AL,R_AX);
  710. if alignment=4 then
  711. begin
  712. opsize:=S_L;
  713. hreg:=R_EAX;
  714. inc(pushedparasize,4);
  715. end
  716. else
  717. begin
  718. opsize:=S_W;
  719. hreg:=R_AX;
  720. inc(pushedparasize,2);
  721. end;
  722. if inlined then
  723. begin
  724. r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
  725. exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOV,opsize,hreg,r)));
  726. end
  727. else
  728. exprasmlist^.concat(new(paicpu,op_reg(A_PUSH,opsize,hreg)));
  729. if not(R_EAX in unused) then
  730. begin
  731. emit_reg_reg(A_MOV,S_L,R_EDI,R_EAX);
  732. ungetregister32(R_EDI);
  733. end;
  734. end;
  735. {$ifdef SUPPORT_MMX}
  736. LOC_MMXREGISTER,
  737. LOC_CMMXREGISTER:
  738. begin
  739. inc(pushedparasize,8); { was missing !!! (PM) }
  740. emit_const_reg(
  741. A_SUB,S_L,8,R_ESP);
  742. {$ifdef GDB}
  743. if (cs_debuginfo in aktmoduleswitches) and
  744. (exprasmlist^.first=exprasmlist^.last) then
  745. exprasmlist^.concat(new(pai_force_line,init));
  746. {$endif GDB}
  747. if inlined then
  748. begin
  749. r:=new_reference(procinfo^.framepointer,para_offset-pushedparasize);
  750. exprasmlist^.concat(new(paicpu,op_reg_ref(A_MOVQ,S_NO,
  751. p.location.register,r)));
  752. end
  753. else
  754. begin
  755. r:=new_reference(R_ESP,0);
  756. exprasmlist^.concat(new(paicpu,op_reg_ref(
  757. A_MOVQ,S_NO,p.location.register,r)));
  758. end;
  759. end;
  760. {$endif SUPPORT_MMX}
  761. end;
  762. end;
  763. {*****************************************************************************
  764. Emit Functions
  765. *****************************************************************************}
  766. procedure maketojumpbool(p : tnode);
  767. {
  768. produces jumps to true respectively false labels using boolean expressions
  769. }
  770. var
  771. opsize : topsize;
  772. storepos : tfileposinfo;
  773. begin
  774. if p.error then
  775. exit;
  776. storepos:=aktfilepos;
  777. aktfilepos:=p.fileinfo;
  778. if is_boolean(p.resulttype) then
  779. begin
  780. if is_constboolnode(p) then
  781. begin
  782. if p.value<>0 then
  783. emitjmp(C_None,truelabel)
  784. else
  785. emitjmp(C_None,falselabel);
  786. end
  787. else
  788. begin
  789. opsize:=def_opsize(p.resulttype);
  790. case p.location.loc of
  791. LOC_CREGISTER,LOC_REGISTER : begin
  792. emit_reg_reg(A_OR,opsize,p.location.register,
  793. p.location.register);
  794. ungetregister(p.location.register);
  795. emitjmp(C_NZ,truelabel);
  796. emitjmp(C_None,falselabel);
  797. end;
  798. LOC_MEM,LOC_REFERENCE : begin
  799. emit_const_ref(
  800. A_CMP,opsize,0,newreference(p.location.reference));
  801. del_reference(p.location.reference);
  802. emitjmp(C_NZ,truelabel);
  803. emitjmp(C_None,falselabel);
  804. end;
  805. LOC_FLAGS : begin
  806. emitjmp(flag_2_cond[p.location.resflags],truelabel);
  807. emitjmp(C_None,falselabel);
  808. end;
  809. end;
  810. end;
  811. end
  812. else
  813. CGMessage(type_e_mismatch);
  814. aktfilepos:=storepos;
  815. end;
  816. { produces if necessary overflowcode }
  817. procedure emitoverflowcheck(p:tnode);
  818. var
  819. hl : pasmlabel;
  820. begin
  821. if not(cs_check_overflow in aktlocalswitches) then
  822. exit;
  823. getlabel(hl);
  824. if not ((p.resulttype^.deftype=pointerdef) or
  825. ((p.resulttype^.deftype=orddef) and
  826. (porddef(p.resulttype)^.typ in [u64bit,u16bit,u32bit,u8bit,uchar,
  827. bool8bit,bool16bit,bool32bit]))) then
  828. emitjmp(C_NO,hl)
  829. else
  830. emitjmp(C_NB,hl);
  831. emitcall('FPC_OVERFLOW');
  832. emitlab(hl);
  833. end;
  834. { produces range check code, while one of the operands is a 64 bit
  835. integer }
  836. procedure emitrangecheck64(p : tnode;todef : pdef);
  837. begin
  838. CGMessage(cg_w_64bit_range_check_not_supported);
  839. {internalerror(28699);}
  840. end;
  841. { produces if necessary rangecheckcode }
  842. procedure emitrangecheck(p:tnode;todef:pdef);
  843. {
  844. generate range checking code for the value at location t. The
  845. type used is the checked against todefs ranges. fromdef (p.resulttype)
  846. is the original type used at that location, when both defs are
  847. equal the check is also insert (needed for succ,pref,inc,dec)
  848. }
  849. var
  850. neglabel,
  851. poslabel : pasmlabel;
  852. href : treference;
  853. rstr : string;
  854. hreg : tregister;
  855. opsize : topsize;
  856. op : tasmop;
  857. fromdef : pdef;
  858. lto,hto,
  859. lfrom,hfrom : longint;
  860. doublebound,
  861. is_reg,
  862. popecx : boolean;
  863. begin
  864. { range checking on and range checkable value? }
  865. if not(cs_check_range in aktlocalswitches) or
  866. not(todef^.deftype in [orddef,enumdef,arraydef]) then
  867. exit;
  868. { only check when assigning to scalar, subranges are different,
  869. when todef=fromdef then the check is always generated }
  870. fromdef:=p.resulttype;
  871. if is_64bitint(fromdef) or is_64bitint(todef) then
  872. begin
  873. emitrangecheck64(p,todef);
  874. exit;
  875. end;
  876. {we also need lto and hto when checking if we need to use doublebound!
  877. (JM)}
  878. getrange(todef,lto,hto);
  879. if todef<>fromdef then
  880. begin
  881. getrange(p.resulttype,lfrom,hfrom);
  882. { first check for not being u32bit, then if the to is bigger than
  883. from }
  884. if (lto<hto) and (lfrom<hfrom) and
  885. (lto<=lfrom) and (hto>=hfrom) then
  886. exit;
  887. end;
  888. { generate the rangecheck code for the def where we are going to
  889. store the result }
  890. doublebound:=false;
  891. case todef^.deftype of
  892. orddef :
  893. begin
  894. porddef(todef)^.genrangecheck;
  895. rstr:=porddef(todef)^.getrangecheckstring;
  896. doublebound:=(porddef(todef)^.typ=u32bit) and (lto>hto);
  897. end;
  898. enumdef :
  899. begin
  900. penumdef(todef)^.genrangecheck;
  901. rstr:=penumdef(todef)^.getrangecheckstring;
  902. end;
  903. arraydef :
  904. begin
  905. parraydef(todef)^.genrangecheck;
  906. rstr:=parraydef(todef)^.getrangecheckstring;
  907. doublebound:=(lto>hto);
  908. end;
  909. end;
  910. { get op and opsize }
  911. opsize:=def2def_opsize(fromdef,u32bitdef);
  912. if opsize in [S_B,S_W,S_L] then
  913. op:=A_MOV
  914. else
  915. if is_signed(fromdef) then
  916. op:=A_MOVSX
  917. else
  918. op:=A_MOVZX;
  919. is_reg:=(p.location.loc in [LOC_REGISTER,LOC_CREGISTER]);
  920. if is_reg then
  921. hreg:=p.location.register;
  922. if not target_os.use_bound_instruction then
  923. begin
  924. { FPC_BOUNDCHECK needs to be called with
  925. %ecx - value
  926. %edi - pointer to the ranges }
  927. popecx:=false;
  928. if not(is_reg) or
  929. (p.location.register<>R_ECX) then
  930. begin
  931. if not(R_ECX in unused) then
  932. begin
  933. exprasmlist^.concat(new(paicpu,op_reg(A_PUSH,S_L,R_ECX)));
  934. popecx:=true;
  935. end
  936. else exprasmlist^.concat(new(pairegalloc,alloc(R_ECX)));
  937. if is_reg then
  938. emit_reg_reg(op,opsize,p.location.register,R_ECX)
  939. else
  940. emit_ref_reg(op,opsize,newreference(p.location.reference),R_ECX);
  941. end;
  942. if doublebound then
  943. begin
  944. getlabel(neglabel);
  945. getlabel(poslabel);
  946. emit_reg_reg(A_OR,S_L,R_ECX,R_ECX);
  947. emitjmp(C_L,neglabel);
  948. end;
  949. { insert bound instruction only }
  950. getexplicitregister32(R_EDI);
  951. exprasmlist^.concat(new(paicpu,op_sym_ofs_reg(A_MOV,S_L,newasmsymbol(rstr),0,R_EDI)));
  952. emitcall('FPC_BOUNDCHECK');
  953. ungetregister32(R_EDI);
  954. { u32bit needs 2 checks }
  955. if doublebound then
  956. begin
  957. emitjmp(C_None,poslabel);
  958. emitlab(neglabel);
  959. getexplicitregister32(R_EDI);
  960. exprasmlist^.concat(new(paicpu,op_sym_ofs_reg(A_MOV,S_L,newasmsymbol(rstr),8,R_EDI)));
  961. emitcall('FPC_BOUNDCHECK');
  962. ungetregister32(R_EDI);
  963. emitlab(poslabel);
  964. end;
  965. if popecx then
  966. exprasmlist^.concat(new(paicpu,op_reg(A_POP,S_L,R_ECX)))
  967. else exprasmlist^.concat(new(pairegalloc,dealloc(R_ECX)));
  968. end
  969. else
  970. begin
  971. reset_reference(href);
  972. href.symbol:=newasmsymbol(rstr);
  973. { load the value in a register }
  974. if is_reg then
  975. begin
  976. { be sure that hreg is a 32 bit reg, if not load it in %edi }
  977. if p.location.register in [R_EAX..R_EDI] then
  978. hreg:=p.location.register
  979. else
  980. begin
  981. getexplicitregister32(R_EDI);
  982. emit_reg_reg(op,opsize,p.location.register,R_EDI);
  983. hreg:=R_EDI;
  984. end;
  985. end
  986. else
  987. begin
  988. getexplicitregister32(R_EDI);
  989. emit_ref_reg(op,opsize,newreference(p.location.reference),R_EDI);
  990. hreg:=R_EDI;
  991. end;
  992. if doublebound then
  993. begin
  994. getlabel(neglabel);
  995. getlabel(poslabel);
  996. emit_reg_reg(A_TEST,S_L,hreg,hreg);
  997. emitjmp(C_L,neglabel);
  998. end;
  999. { insert bound instruction only }
  1000. exprasmlist^.concat(new(paicpu,op_reg_ref(A_BOUND,S_L,hreg,newreference(href))));
  1001. { u32bit needs 2 checks }
  1002. if doublebound then
  1003. begin
  1004. href.offset:=8;
  1005. emitjmp(C_None,poslabel);
  1006. emitlab(neglabel);
  1007. exprasmlist^.concat(new(paicpu,op_reg_ref(A_BOUND,S_L,hreg,newreference(href))));
  1008. emitlab(poslabel);
  1009. end;
  1010. if hreg = R_EDI then
  1011. ungetregister32(R_EDI);
  1012. end;
  1013. end;
  1014. { DO NOT RELY on the fact that the tnode is not yet swaped
  1015. because of inlining code PM }
  1016. procedure firstcomplex(p : tnode);
  1017. var
  1018. hp : tnode;
  1019. begin
  1020. { always calculate boolean AND and OR from left to right }
  1021. if (p.treetype in [orn,andn]) and
  1022. (p.left^.resulttype^.deftype=orddef) and
  1023. (porddef(p.left^.resulttype)^.typ in [bool8bit,bool16bit,bool32bit]) then
  1024. begin
  1025. { p.swaped:=false}
  1026. if p.swaped then
  1027. internalerror(234234);
  1028. end
  1029. else
  1030. if (p.left^.registers32<p.right^.registers32) and
  1031. { the following check is appropriate, because all }
  1032. { 4 registers are rarely used and it is thereby }
  1033. { achieved that the extra code is being dropped }
  1034. { by exchanging not commutative operators }
  1035. (p.right^.registers32<=4) then
  1036. begin
  1037. hp:=p.left;
  1038. p.left:=p.right;
  1039. p.right:=hp;
  1040. p.swaped:=not p.swaped;
  1041. end;
  1042. {else
  1043. p.swaped:=false; do not modify }
  1044. end;
  1045. {$endif}
  1046. end.
  1047. {
  1048. $Log$
  1049. Revision 1.1 2000-10-01 19:58:40 peter
  1050. * new file
  1051. }