ncgutil.pas 16 KB

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