ncgutil.pas 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460
  1. {
  2. $Id$
  3. Copyright (c) 1998-2000 by Florian Klaempfl
  4. Helper routines for all code generators
  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 ncgutil;
  19. {$i defines.inc}
  20. interface
  21. uses
  22. node,
  23. cginfo,
  24. cpubase;
  25. type
  26. tloadregvars = (lr_dont_load_regvars, lr_load_regvars);
  27. procedure location_force_reg(var l:tlocation;size:TCGSize;maybeconst:boolean);
  28. procedure location_force_mem(var l:tlocation);
  29. {$ifdef TEMPS_NOT_PUSH}
  30. function maybe_savetotemp(needed : byte;p : tnode;isint64 : boolean) : boolean;
  31. procedure restorefromtemp(p : tnode;isint64 : boolean);
  32. {$endif TEMPS_NOT_PUSH}
  33. procedure maketojumpbool(p : tnode; loadregvars: tloadregvars);
  34. implementation
  35. uses
  36. globals,systems,verbose,
  37. types,
  38. aasm,cgbase,regvars,
  39. ncon,
  40. tgobj,cpuinfo,cgobj,cgcpu,rgobj,cg64f32;
  41. {*****************************************************************************
  42. TLocation
  43. *****************************************************************************}
  44. procedure location_force_reg(var l:tlocation;size:TCGSize;maybeconst:boolean);
  45. var
  46. hregister,
  47. hregisterhi : tregister;
  48. hl : tasmlabel;
  49. begin
  50. { release previous location before demanding a new register }
  51. if (l.loc in [LOC_REFERENCE,LOC_CREFERENCE]) then
  52. begin
  53. location_freetemp(exprasmlist,l);
  54. location_release(exprasmlist,l);
  55. end;
  56. { handle transformations to 64bit separate }
  57. if size in [OS_64,OS_S64] then
  58. begin
  59. if not (l.size in [OS_64,OS_S64]) then
  60. begin
  61. { load a smaller size to OS_64 }
  62. if l.loc=LOC_REGISTER then
  63. hregister:=Changeregsize(l.registerlow,S_L)
  64. else
  65. hregister:=rg.getregisterint(exprasmlist);
  66. { load value in low register }
  67. case l.loc of
  68. LOC_FLAGS :
  69. cg.g_flags2reg(exprasmlist,l.resflags,hregister);
  70. LOC_JUMP :
  71. begin
  72. cg.a_label(exprasmlist,truelabel);
  73. cg.a_load_const_reg(exprasmlist,OS_32,1,hregister);
  74. getlabel(hl);
  75. cg.a_jmp_cond(exprasmlist,OC_NONE,hl);
  76. cg.a_label(exprasmlist,falselabel);
  77. cg.a_load_const_reg(exprasmlist,OS_32,0,hregister);
  78. cg.a_label(exprasmlist,hl);
  79. end;
  80. else
  81. cg.a_load_loc_reg(exprasmlist,l,hregister);
  82. end;
  83. { reset hi part, take care of the signed bit of the current value }
  84. hregisterhi:=rg.getregisterint(exprasmlist);
  85. if (size=OS_S64) and
  86. (l.size in [OS_S8,OS_S16,OS_S32]) then
  87. begin
  88. if l.loc=LOC_CONSTANT then
  89. begin
  90. if (longint(l.value)<0) then
  91. cg.a_load_const_reg(exprasmlist,OS_32,$ffffffff,hregisterhi)
  92. else
  93. cg.a_load_const_reg(exprasmlist,OS_32,0,hregisterhi);
  94. end
  95. else
  96. begin
  97. cg.a_load_reg_reg(exprasmlist,OS_32,hregister,hregisterhi);
  98. cg.a_op_const_reg(exprasmlist,OP_SAR,31,hregisterhi);
  99. end;
  100. end
  101. else
  102. cg.a_load_const_reg(exprasmlist,OS_32,0,hregisterhi);
  103. location_reset(l,LOC_REGISTER,size);
  104. l.registerlow:=hregister;
  105. l.registerhigh:=hregisterhi;
  106. end
  107. else
  108. begin
  109. { 64bit to 64bit }
  110. if (l.loc=LOC_REGISTER) or
  111. ((l.loc=LOC_CREGISTER) and maybeconst) then
  112. begin
  113. hregister:=l.registerlow;
  114. hregisterhi:=l.registerhigh;
  115. end
  116. else
  117. begin
  118. hregister:=rg.getregisterint(exprasmlist);
  119. hregisterhi:=rg.getregisterint(exprasmlist);
  120. end;
  121. { load value in new register }
  122. tcg64f32(cg).a_load64_loc_reg(exprasmlist,l,hregister,hregisterhi);
  123. location_reset(l,LOC_REGISTER,size);
  124. l.registerlow:=hregister;
  125. l.registerhigh:=hregisterhi;
  126. end;
  127. end
  128. else
  129. begin
  130. { transformations to 32bit or smaller }
  131. if l.loc=LOC_REGISTER then
  132. begin
  133. { if the previous was 64bit release the high register }
  134. if l.size in [OS_64,OS_S64] then
  135. begin
  136. rg.ungetregisterint(exprasmlist,l.registerhigh);
  137. l.registerhigh:=R_NO;
  138. end;
  139. hregister:=l.register;
  140. end
  141. else
  142. begin
  143. { get new register }
  144. if (l.loc=LOC_CREGISTER) and
  145. maybeconst and
  146. (TCGSize2Size[size]=TCGSize2Size[l.size]) then
  147. hregister:=l.register
  148. else
  149. hregister:=rg.getregisterint(exprasmlist);
  150. end;
  151. {$ifdef i386}
  152. hregister:=Changeregsize(hregister,TCGSize2Opsize[size]);
  153. {$endif i386}
  154. { load value in new register }
  155. case l.loc of
  156. LOC_FLAGS :
  157. cg.g_flags2reg(exprasmlist,l.resflags,hregister);
  158. LOC_JUMP :
  159. begin
  160. cg.a_label(exprasmlist,truelabel);
  161. cg.a_load_const_reg(exprasmlist,size,1,hregister);
  162. getlabel(hl);
  163. cg.a_jmp_cond(exprasmlist,OC_NONE,hl);
  164. cg.a_label(exprasmlist,falselabel);
  165. cg.a_load_const_reg(exprasmlist,size,0,hregister);
  166. cg.a_label(exprasmlist,hl);
  167. end;
  168. else
  169. begin
  170. { load_loc_reg can only handle size >= l.size, when the
  171. new size is smaller then we need to adjust the size
  172. of the orignal and maybe recalculate l.register for i386 }
  173. if (TCGSize2Size[size]<TCGSize2Size[l.size]) then
  174. begin
  175. {$ifdef i386}
  176. if (l.loc in [LOC_REGISTER,LOC_CREGISTER]) then
  177. l.register:=Changeregsize(l.register,TCGSize2Opsize[size]);
  178. {$endif i386}
  179. l.size:=size;
  180. end;
  181. cg.a_load_loc_reg(exprasmlist,l,hregister);
  182. end;
  183. end;
  184. location_reset(l,LOC_REGISTER,size);
  185. l.register:=hregister;
  186. end;
  187. end;
  188. procedure location_force_mem(var l:tlocation);
  189. var
  190. r : treference;
  191. begin
  192. case l.loc of
  193. LOC_FPUREGISTER,
  194. LOC_CFPUREGISTER :
  195. begin
  196. cg.a_loadfpu_reg_ref(exprasmlist,l.size,l.register,r);
  197. location_reset(l,LOC_REFERENCE,l.size);
  198. l.reference:=r;
  199. end;
  200. LOC_CONSTANT,
  201. LOC_REGISTER,
  202. LOC_CREGISTER :
  203. begin
  204. tg.gettempofsizereference(exprasmlist,TCGSize2Size[l.size],r);
  205. if l.size in [OS_64,OS_S64] then
  206. tcg64f32(cg).a_load64_loc_ref(exprasmlist,l,r)
  207. else
  208. cg.a_load_loc_ref(exprasmlist,l,r);
  209. location_reset(l,LOC_REFERENCE,l.size);
  210. l.reference:=r;
  211. end;
  212. LOC_CREFERENCE,
  213. LOC_REFERENCE : ;
  214. else
  215. internalerror(200203219);
  216. end;
  217. end;
  218. {*****************************************************************************
  219. SaveToTemp
  220. *****************************************************************************}
  221. {$ifdef TEMPS_NOT_PUSH}
  222. function maybe_savetotemp(needed : byte;p : tnode;isint64 : boolean) : boolean;
  223. var
  224. href : treference;
  225. scratchreg : tregister;
  226. saved : boolean;
  227. begin
  228. if needed>rg.countunusedregsint then
  229. begin
  230. if (p.location.loc=LOC_REGISTER) then
  231. begin
  232. if isint64 then
  233. begin
  234. tg.gettempofsizereference(exprasmlist,8,href);
  235. p.temp_offset:=href.offset;
  236. { do we have a 64bit processor? }
  237. if sizeof(aword) < 8 then
  238. begin
  239. tcg64f32(cg).a_load64_reg_ref(exprasmlist,
  240. p.location.registerlow,p.location.registerhigh,
  241. href);
  242. rg.ungetregister(exprasmlist,p.location.registerhigh);
  243. rg.ungetregister(exprasmlist,p.location.registerlow);
  244. end
  245. else
  246. begin
  247. cg.a_load_reg_ref(exprasmlist,OS_64,
  248. p.location.register,href);
  249. rg.ungetregister(exprasmlist,p.location.register);
  250. end;
  251. end
  252. else
  253. begin
  254. tg.gettempofsizereference(exprasmlist,4,href);
  255. p.temp_offset:=href.offset;
  256. cg.a_load_reg_ref(exprasmlist,OS_32,
  257. p.location.register,href);
  258. rg.ungetregister(exprasmlist,p.location.register);
  259. end;
  260. saved:=true;
  261. end
  262. else if (p.location.loc in [LOC_CREFERENCE,LOC_REFERENCE]) and
  263. ((p.location.reference.base<>R_NO) or
  264. (p.location.reference.index<>R_NO)
  265. ) then
  266. begin
  267. scratchreg := cg.get_scratch_reg(exprasmlist);
  268. cg.a_loadaddr_ref_reg(exprasmlist,p.location.reference,
  269. scratchreg);
  270. reference_release(exprasmlist,p.location.reference);
  271. tg.gettempofsizereference(exprasmlist,pointer_size,href);
  272. cg.a_load_reg_ref(exprasmlist,OS_ADDR,scratchreg,href);
  273. cg.free_scratch_reg(exprasmlist,scratchreg);
  274. p.temp_offset:=href.offset;
  275. saved:=true;
  276. end
  277. else saved:=false;
  278. end
  279. else saved:=false;
  280. maybe_savetotemp:=saved;
  281. end;
  282. procedure restorefromtemp(p : tnode;isint64 : boolean);
  283. var
  284. hregister : tregister;
  285. href : treference;
  286. begin
  287. hregister:=rg.getregisterint(exprasmlist);
  288. reset_reference(href);
  289. href.base:=procinfo^.framepointer;
  290. href.offset:=p.temp_offset;
  291. if (p.location.loc in [LOC_REGISTER,LOC_CREGISTER]) then
  292. begin
  293. p.location.registerlow:=hregister;
  294. if isint64 then
  295. begin
  296. if sizeof(aword) < 8 then
  297. begin
  298. p.location.registerhigh:=rg.getregisterint(exprasmlist);
  299. tcg64f32(cg).a_load64_ref_reg(exprasmlist,
  300. href,p.location.registerlow,p.location.registerhigh);
  301. end
  302. else
  303. cg.a_load_ref_reg(exprasmlist,OS_64,href,
  304. p.location.register);
  305. end
  306. else
  307. cg.a_load_ref_reg(exprasmlist,OS_32,href,p.location.register);
  308. end
  309. else
  310. begin
  311. reset_reference(p.location.reference);
  312. p.location.reference.base:=hregister;
  313. { Why is this done? We can never be sure about p^.left
  314. because otherwise secondload fails PM
  315. set_location(p^.left^.location,p^.location);}
  316. end;
  317. tg.ungetiftemp(exprasmlist,href);
  318. end;
  319. {$endif TEMPS_NOT_PUSH}
  320. procedure maketojumpbool(p : tnode; loadregvars: tloadregvars);
  321. {
  322. produces jumps to true respectively false labels using boolean expressions
  323. depending on whether the loading of regvars is currently being
  324. synchronized manually (such as in an if-node) or automatically (most of
  325. the other cases where this procedure is called), loadregvars can be
  326. "lr_load_regvars" or "lr_dont_load_regvars"
  327. }
  328. var
  329. opsize : tcgsize;
  330. storepos : tfileposinfo;
  331. begin
  332. if nf_error in p.flags then
  333. exit;
  334. storepos:=aktfilepos;
  335. aktfilepos:=p.fileinfo;
  336. if is_boolean(p.resulttype.def) then
  337. begin
  338. if loadregvars = lr_load_regvars then
  339. load_all_regvars(exprasmlist);
  340. if is_constboolnode(p) then
  341. begin
  342. if tordconstnode(p).value<>0 then
  343. cg.a_jmp_cond(exprasmlist,OC_NONE,truelabel)
  344. else
  345. cg.a_jmp_cond(exprasmlist,OC_NONE,falselabel)
  346. end
  347. else
  348. begin
  349. opsize:=def_cgsize(p.resulttype.def);
  350. case p.location.loc of
  351. LOC_CREGISTER,LOC_REGISTER,LOC_CREFERENCE,LOC_REFERENCE :
  352. begin
  353. if (p.location.loc = LOC_CREGISTER) then
  354. load_regvar_reg(exprasmlist,p.location.register);
  355. cg.a_cmp_const_loc_label(exprasmlist,opsize,OC_NE,
  356. 0,p.location,truelabel);
  357. { !!! should happen right after cmp (JM) }
  358. location_release(exprasmlist,p.location);
  359. cg.a_jmp_cond(exprasmlist,OC_NONE,falselabel);
  360. end;
  361. LOC_FLAGS :
  362. begin
  363. cg.a_jmp_flags(exprasmlist,p.location.resflags,
  364. truelabel);
  365. cg.a_jmp_cond(exprasmlist,OC_None,falselabel);
  366. end;
  367. end;
  368. end;
  369. end
  370. else
  371. internalerror(200112305);
  372. aktfilepos:=storepos;
  373. end;
  374. end.
  375. {
  376. $Log$
  377. Revision 1.8 2002-04-19 15:39:34 peter
  378. * removed some more routines from cga
  379. * moved location_force_reg/mem to ncgutil
  380. * moved arrayconstructnode secondpass to ncgld
  381. Revision 1.7 2002/04/15 18:58:47 carl
  382. + target_info.size_of_pointer -> pointer_Size
  383. Revision 1.6 2002/04/06 18:10:42 jonas
  384. * several powerpc-related additions and fixes
  385. Revision 1.5 2002/04/04 19:05:57 peter
  386. * removed unused units
  387. * use tlocation.size in cg.a_*loc*() routines
  388. Revision 1.4 2002/04/02 17:11:28 peter
  389. * tlocation,treference update
  390. * LOC_CONSTANT added for better constant handling
  391. * secondadd splitted in multiple routines
  392. * location_force_reg added for loading a location to a register
  393. of a specified size
  394. * secondassignment parses now first the right and then the left node
  395. (this is compatible with Kylix). This saves a lot of push/pop especially
  396. with string operations
  397. * adapted some routines to use the new cg methods
  398. Revision 1.3 2002/03/31 20:26:34 jonas
  399. + a_loadfpu_* and a_loadmm_* methods in tcg
  400. * register allocation is now handled by a class and is mostly processor
  401. independent (+rgobj.pas and i386/rgcpu.pas)
  402. * temp allocation is now handled by a class (+tgobj.pas, -i386\tgcpu.pas)
  403. * some small improvements and fixes to the optimizer
  404. * some register allocation fixes
  405. * some fpuvaroffset fixes in the unary minus node
  406. * push/popusedregisters is now called rg.save/restoreusedregisters and
  407. (for i386) uses temps instead of push/pop's when using -Op3 (that code is
  408. also better optimizable)
  409. * fixed and optimized register saving/restoring for new/dispose nodes
  410. * LOC_FPU locations now also require their "register" field to be set to
  411. R_ST, not R_ST0 (the latter is used for LOC_CFPUREGISTER locations only)
  412. - list field removed of the tnode class because it's not used currently
  413. and can cause hard-to-find bugs
  414. Revision 1.2 2002/03/04 19:10:11 peter
  415. * removed compiler warnings
  416. Revision 1.1 2001/12/30 17:24:48 jonas
  417. * range checking is now processor independent (part in cgobj,
  418. part in cg64f32) and should work correctly again (it needed
  419. some changes after the changes of the low and high of
  420. tordef's to int64)
  421. * maketojumpbool() is now processor independent (in ncgutil)
  422. * getregister32 is now called getregisterint
  423. }