n386util.pas 65 KB

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