ncgutil.pas 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450
  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. tg.gettempofsizereference(exprasmlist,TCGSize2Size[l.size],r);
  282. cg.a_loadfpu_reg_ref(exprasmlist,l.size,l.register,r);
  283. location_reset(l,LOC_REFERENCE,l.size);
  284. l.reference:=r;
  285. end;
  286. LOC_CONSTANT,
  287. LOC_REGISTER,
  288. LOC_CREGISTER :
  289. begin
  290. tg.gettempofsizereference(exprasmlist,TCGSize2Size[l.size],r);
  291. if l.size in [OS_64,OS_S64] then
  292. tcg64f32(cg).a_load64_loc_ref(exprasmlist,l,r)
  293. else
  294. cg.a_load_loc_ref(exprasmlist,l,r);
  295. location_reset(l,LOC_REFERENCE,l.size);
  296. l.reference:=r;
  297. end;
  298. LOC_CREFERENCE,
  299. LOC_REFERENCE : ;
  300. else
  301. internalerror(200203219);
  302. end;
  303. end;
  304. procedure maketojumpbool(p : tnode; loadregvars: tloadregvars);
  305. {
  306. produces jumps to true respectively false labels using boolean expressions
  307. depending on whether the loading of regvars is currently being
  308. synchronized manually (such as in an if-node) or automatically (most of
  309. the other cases where this procedure is called), loadregvars can be
  310. "lr_load_regvars" or "lr_dont_load_regvars"
  311. }
  312. var
  313. opsize : tcgsize;
  314. storepos : tfileposinfo;
  315. begin
  316. if nf_error in p.flags then
  317. exit;
  318. storepos:=aktfilepos;
  319. aktfilepos:=p.fileinfo;
  320. if is_boolean(p.resulttype.def) then
  321. begin
  322. if loadregvars = lr_load_regvars then
  323. load_all_regvars(exprasmlist);
  324. if is_constboolnode(p) then
  325. begin
  326. if tordconstnode(p).value<>0 then
  327. cg.a_jmp_always(exprasmlist,truelabel)
  328. else
  329. cg.a_jmp_always(exprasmlist,falselabel)
  330. end
  331. else
  332. begin
  333. opsize:=def_cgsize(p.resulttype.def);
  334. case p.location.loc of
  335. LOC_CREGISTER,LOC_REGISTER,LOC_CREFERENCE,LOC_REFERENCE :
  336. begin
  337. if (p.location.loc = LOC_CREGISTER) then
  338. load_regvar_reg(exprasmlist,p.location.register);
  339. cg.a_cmp_const_loc_label(exprasmlist,opsize,OC_NE,
  340. 0,p.location,truelabel);
  341. { !!! should happen right after cmp (JM) }
  342. location_release(exprasmlist,p.location);
  343. cg.a_jmp_always(exprasmlist,falselabel);
  344. end;
  345. LOC_FLAGS :
  346. begin
  347. cg.a_jmp_flags(exprasmlist,p.location.resflags,
  348. truelabel);
  349. cg.a_jmp_always(exprasmlist,falselabel);
  350. end;
  351. end;
  352. end;
  353. end
  354. else
  355. internalerror(200112305);
  356. aktfilepos:=storepos;
  357. end;
  358. end.
  359. {
  360. $Log$
  361. Revision 1.10 2002-04-21 19:02:03 peter
  362. * removed newn and disposen nodes, the code is now directly
  363. inlined from pexpr
  364. * -an option that will write the secondpass nodes to the .s file, this
  365. requires EXTDEBUG define to actually write the info
  366. * fixed various internal errors and crashes due recent code changes
  367. Revision 1.9 2002/04/21 15:24:38 carl
  368. + a_jmp_cond -> a_jmp_always (a_jmp_cond is NOT portable)
  369. + changeregsize -> rg.makeregsize
  370. Revision 1.8 2002/04/19 15:39:34 peter
  371. * removed some more routines from cga
  372. * moved location_force_reg/mem to ncgutil
  373. * moved arrayconstructnode secondpass to ncgld
  374. Revision 1.7 2002/04/15 18:58:47 carl
  375. + target_info.size_of_pointer -> pointer_Size
  376. Revision 1.6 2002/04/06 18:10:42 jonas
  377. * several powerpc-related additions and fixes
  378. Revision 1.5 2002/04/04 19:05:57 peter
  379. * removed unused units
  380. * use tlocation.size in cg.a_*loc*() routines
  381. Revision 1.4 2002/04/02 17:11:28 peter
  382. * tlocation,treference update
  383. * LOC_CONSTANT added for better constant handling
  384. * secondadd splitted in multiple routines
  385. * location_force_reg added for loading a location to a register
  386. of a specified size
  387. * secondassignment parses now first the right and then the left node
  388. (this is compatible with Kylix). This saves a lot of push/pop especially
  389. with string operations
  390. * adapted some routines to use the new cg methods
  391. Revision 1.3 2002/03/31 20:26:34 jonas
  392. + a_loadfpu_* and a_loadmm_* methods in tcg
  393. * register allocation is now handled by a class and is mostly processor
  394. independent (+rgobj.pas and i386/rgcpu.pas)
  395. * temp allocation is now handled by a class (+tgobj.pas, -i386\tgcpu.pas)
  396. * some small improvements and fixes to the optimizer
  397. * some register allocation fixes
  398. * some fpuvaroffset fixes in the unary minus node
  399. * push/popusedregisters is now called rg.save/restoreusedregisters and
  400. (for i386) uses temps instead of push/pop's when using -Op3 (that code is
  401. also better optimizable)
  402. * fixed and optimized register saving/restoring for new/dispose nodes
  403. * LOC_FPU locations now also require their "register" field to be set to
  404. R_ST, not R_ST0 (the latter is used for LOC_CFPUREGISTER locations only)
  405. - list field removed of the tnode class because it's not used currently
  406. and can cause hard-to-find bugs
  407. Revision 1.2 2002/03/04 19:10:11 peter
  408. * removed compiler warnings
  409. Revision 1.1 2001/12/30 17:24:48 jonas
  410. * range checking is now processor independent (part in cgobj,
  411. part in cg64f32) and should work correctly again (it needed
  412. some changes after the changes of the low and high of
  413. tordef's to int64)
  414. * maketojumpbool() is now processor independent (in ncgutil)
  415. * getregister32 is now called getregisterint
  416. }