reg68k.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446
  1. /*
  2. * GTools C compiler
  3. * =================
  4. * source file :
  5. * register allocation
  6. *
  7. * Copyright 2001-2004 Paul Froissart.
  8. * Credits to Christoph van Wuellen and Matthew Brandt.
  9. * All commercial rights reserved.
  10. *
  11. * This compiler may be redistributed as long there is no
  12. * commercial interest. The compiler must not be redistributed
  13. * without its full sources. This notice must stay intact.
  14. */
  15. #include "define.h"
  16. _FILE(__FILE__)
  17. #include "c.h"
  18. #include "expr.h"
  19. #include "gen.h"
  20. #include "cglbdec.h"
  21. /*
  22. * Register allocation (for the expression evaluation)
  23. * This modules handles the management of scratch registers.
  24. * It keeps track of the allocated registers and of the stack
  25. */
  26. #ifdef MC680X0
  27. xstatic int next_data CGLOB, next_addr CGLOB;
  28. #ifndef INFINITE_REGISTERS
  29. xstatic char dreg_in_use[MAX_DATA + 1] CGLOBL;
  30. xstatic char areg_in_use[MAX_ADDR + 1] CGLOBL;
  31. xstatic struct reg_struct reg_stack[MAX_REG_STACK + 1] CGLOBL,
  32. reg_alloc[MAX_REG_STACK + 1] CGLOBL;
  33. xstatic int reg_stack_ptr CGLOB;
  34. xstatic int reg_alloc_ptr CGLOB;
  35. #endif
  36. void g_push(int reg, enum(e_am) rmode, int number) {
  37. #ifndef INFINITE_REGISTERS
  38. /*
  39. * this routine generates code to push a register onto the stack
  40. */
  41. struct amode *ap;
  42. ap = (struct amode *) xalloc((int) sizeof(struct amode), AMODE+G_PUSH);
  43. ap->preg = reg;
  44. ap->mode = rmode;
  45. g_code(op_move, 4, ap, push_am);
  46. reg_stack[reg_stack_ptr].mode = rmode;
  47. reg_stack[reg_stack_ptr].reg = reg;
  48. reg_stack[reg_stack_ptr].flag = number;
  49. if (reg_alloc[number].flag)
  50. ierr(G_PUSH,1);
  51. reg_alloc[number].flag = 1;
  52. /* check on stack overflow */
  53. if (++reg_stack_ptr > MAX_REG_STACK)
  54. ierr(G_PUSH,2);
  55. #else
  56. fatal("GPUSH/infinite");
  57. #endif
  58. }
  59. void g_pop(int reg, enum(e_am) rmode, int number) {
  60. #ifndef INFINITE_REGISTERS
  61. /*
  62. * generate code to pop a register from the stack.
  63. */
  64. struct amode *ap;
  65. /* check on stack underflow */
  66. if (reg_stack_ptr-- == 0)
  67. ierr(G_POP,1);
  68. /* check if the desired register really is on stack */
  69. if (reg_stack[reg_stack_ptr].flag != number)
  70. ierr(G_POP,2);
  71. /* check if the register which is restored is really void */
  72. if (rmode == am_dreg) {
  73. if (dreg_in_use[reg] >= 0)
  74. ierr(G_POP,3);
  75. dreg_in_use[reg] = number;
  76. } else {
  77. if (areg_in_use[reg] >= 0)
  78. ierr(G_POP,4);
  79. areg_in_use[reg] = number;
  80. }
  81. ap = (struct amode *) xalloc((int) sizeof(struct amode), AMODE+G_PUSH);
  82. ap->mode = rmode;
  83. ap->preg = reg;
  84. g_code(op_move, 4, pop_am, ap);
  85. /* clear the push_flag */
  86. reg_alloc[number].flag = 0;
  87. #endif
  88. }
  89. void initstack() {
  90. /*
  91. * this routine should be called before each expression is evaluated to make
  92. * sure the stack is balanced and all of the registers are marked free.
  93. * This is also a good place to free all 'pseudo' registers in the
  94. * stack frame by setting act_scratch to zero
  95. */
  96. #ifndef INFINITE_REGISTERS
  97. int i;
  98. next_data = 0;
  99. next_addr = 0;
  100. for (i = 0; i <= MAX_DATA; i++)
  101. dreg_in_use[i] = -1;
  102. for (i = 0; i <= MAX_ADDR; i++)
  103. areg_in_use[i] = -1;
  104. reg_stack_ptr = 0;
  105. reg_alloc_ptr = 0;
  106. #else
  107. next_data = FIRSTREG;
  108. next_addr = FIRSTREG;
  109. #endif
  110. act_scratch = 0;
  111. }
  112. //#if 0
  113. #ifndef __HAVE_STACK_IMAGE
  114. #define __HAVE_STACK_IMAGE
  115. typedef struct _stackimg {
  116. int next_data,next_addr;
  117. #ifndef INFINITE_REGISTERS
  118. int reg_alloc_ptr,reg_stack_ptr;
  119. char dreg_in_use[MAX_DATA+1];
  120. char areg_in_use[MAX_ADDR+1];
  121. struct reg_struct reg_stack[MAX_REG_STACK+1],reg_alloc[MAX_REG_STACK+1];
  122. int act_scratch;
  123. #endif
  124. } STACK_IMAGE;
  125. #endif
  126. void usestack(STACK_IMAGE *img) { /* used by g_expr::en_compound */
  127. img->next_data = next_data;
  128. img->next_addr = next_addr;
  129. #ifndef INFINITE_REGISTERS
  130. img->act_scratch = act_scratch;
  131. img->reg_alloc_ptr = reg_alloc_ptr;
  132. img->reg_stack_ptr = reg_stack_ptr;
  133. memcpy(img->dreg_in_use, dreg_in_use, MAX_DATA+1);
  134. memcpy(img->areg_in_use, areg_in_use, MAX_ADDR+1);
  135. memcpy(img->reg_stack, reg_stack, sizeof(struct reg_struct)*(MAX_REG_STACK+1));
  136. memcpy(img->reg_alloc, reg_alloc, sizeof(struct reg_struct)*(MAX_REG_STACK+1));
  137. #endif
  138. }
  139. void freestack(STACK_IMAGE *img) { /* used by g_expr::en_compound */
  140. next_data = img->next_data;
  141. next_addr = img->next_addr;
  142. #ifndef INFINITE_REGISTERS
  143. act_scratch = img->act_scratch;
  144. reg_alloc_ptr = img->reg_alloc_ptr;
  145. reg_stack_ptr = img->reg_stack_ptr;
  146. memcpy(dreg_in_use, img->dreg_in_use, MAX_DATA+1);
  147. memcpy(areg_in_use, img->areg_in_use, MAX_ADDR+1);
  148. memcpy(reg_stack, img->reg_stack, sizeof(struct reg_struct)*(MAX_REG_STACK+1));
  149. memcpy(reg_alloc, img->reg_alloc, sizeof(struct reg_struct)*(MAX_REG_STACK+1));
  150. #endif
  151. }
  152. //#endif
  153. #ifdef REGPARM
  154. #ifndef __HAVE_REGS_IMAGE
  155. #define __HAVE_REGS_IMAGE
  156. typedef struct _regsimg {
  157. #ifndef INFINITE_REGISTERS
  158. int reg_alloc_ptr,reg_stack_ptr;
  159. int next_data,next_addr;
  160. #endif
  161. } REGS_IMAGE;
  162. #endif
  163. void useregs(REGS_IMAGE *img) { /* used by g_fcall */
  164. #ifndef INFINITE_REGISTERS
  165. img->reg_alloc_ptr = reg_alloc_ptr;
  166. img->reg_stack_ptr = reg_stack_ptr;
  167. img->next_data = next_data;
  168. img->next_addr = next_addr;
  169. next_data = 0;
  170. next_addr = 0;
  171. #endif
  172. }
  173. void freeregs(REGS_IMAGE *img) { /* used by g_fcall */
  174. #ifndef INFINITE_REGISTERS
  175. int i;
  176. for (i = 0; i <= MAX_DATA; i++)
  177. dreg_in_use[i] = -1;
  178. for (i = 0; i <= MAX_ADDR; i++)
  179. areg_in_use[i] = -1;
  180. reg_alloc_ptr = img->reg_alloc_ptr;
  181. reg_stack_ptr = img->reg_stack_ptr;
  182. next_data = img->next_data;
  183. next_addr = img->next_addr;
  184. #endif
  185. }
  186. #endif
  187. #ifdef PC
  188. void checkstack(void) {
  189. #ifndef INFINITE_REGISTERS
  190. /*
  191. * this routines checks if all allocated registers were freed
  192. */
  193. int i;
  194. for (i=0; i<= MAX_DATA; i++)
  195. if (dreg_in_use[i] != -1)
  196. ierr(CHECKSTACK,1);
  197. for (i=0; i<= MAX_ADDR; i++)
  198. if (areg_in_use[i] != -1)
  199. ierr(CHECKSTACK,2);
  200. if (reg_stack_ptr != 0)
  201. ierr(CHECKSTACK,5);
  202. if (reg_alloc_ptr != 0)
  203. ierr(CHECKSTACK,6);
  204. #endif
  205. if (next_data != FIRSTREG)
  206. ierr(CHECKSTACK,3);
  207. if (next_addr != FIRSTREG)
  208. ierr(CHECKSTACK,4);
  209. }
  210. #endif
  211. int ap_hasbeenpushed(struct amode *ap) {
  212. #ifndef INFINITE_REGISTERS
  213. return reg_alloc[(int)(ap)->deep].flag;
  214. #else
  215. return 0;
  216. #endif
  217. }
  218. void validate(struct amode *ap) {
  219. #ifndef INFINITE_REGISTERS
  220. /*
  221. * validate will make sure that if a register within an address mode has been
  222. * pushed onto the stack that it is popped back at this time.
  223. */
  224. switch (ap->mode) {
  225. case am_dreg:
  226. if (ap->preg <= MAX_DATA && reg_alloc[(int)ap->deep].flag) {
  227. g_pop(ap->preg, am_dreg, (int) ap->deep);
  228. }
  229. break;
  230. case am_indx2:
  231. if (ap->sreg <= MAX_DATA && reg_alloc[(int)ap->deep].flag) {
  232. g_pop(ap->sreg, am_dreg, (int) ap->deep);
  233. }
  234. goto common;
  235. case am_indx3:
  236. if (ap->sreg <= MAX_ADDR && reg_alloc[(int)ap->deep].flag) {
  237. g_pop(ap->sreg, am_areg, (int) ap->deep);
  238. }
  239. goto common;
  240. case am_areg:
  241. case am_ind:
  242. case am_indx:
  243. case am_ainc:
  244. case am_adec:
  245. common:
  246. if (ap->preg <= MAX_ADDR && reg_alloc[(int)ap->deep].flag) {
  247. g_pop(ap->preg, am_areg, (int) ap->deep);
  248. }
  249. break;
  250. }
  251. #endif
  252. }
  253. struct amode *temp_data(void) {
  254. /*
  255. * allocate a temporary data register and return it's addressing mode.
  256. */
  257. struct amode *ap;
  258. ap = (struct amode *) xalloc((int) sizeof(struct amode), AMODE+TEMP_DATA);
  259. #ifndef INFINITE_REGISTERS
  260. if (dreg_in_use[next_data] >= 0)
  261. /*
  262. * The next available register is already in use. it must be pushed
  263. */
  264. g_push(next_data, am_dreg, dreg_in_use[next_data]);
  265. dreg_in_use[next_data] = reg_alloc_ptr;
  266. #endif
  267. ap->mode = am_dreg;
  268. ap->preg = next_data;
  269. #ifndef INFINITE_REGISTERS
  270. ap->deep = reg_alloc_ptr;
  271. reg_alloc[reg_alloc_ptr].reg = next_data;
  272. reg_alloc[reg_alloc_ptr].mode = am_dreg;
  273. reg_alloc[reg_alloc_ptr].flag = 0;
  274. if (next_data++ == MAX_DATA)
  275. next_data = 0; /* wrap around */
  276. if (reg_alloc_ptr++ == MAX_REG_STACK)
  277. ierr(TEMP_DATA,1);
  278. #else
  279. next_data++;
  280. #endif
  281. return ap;
  282. }
  283. struct amode *temp_addr(void) {
  284. /*
  285. * allocate a temporary addr register and return it's addressing mode.
  286. */
  287. struct amode *ap;
  288. ap = (struct amode *) xalloc((int) sizeof(struct amode), AMODE+TEMP_ADDR);
  289. #ifndef INFINITE_REGISTERS
  290. if (areg_in_use[next_addr] >= 0)
  291. /*
  292. * The next available register is already in use. it must be pushed
  293. */
  294. g_push(next_addr, am_areg, areg_in_use[next_addr]);
  295. areg_in_use[next_addr] = reg_alloc_ptr;
  296. #endif
  297. ap->mode = am_areg;
  298. ap->preg = next_addr;
  299. #ifndef INFINITE_REGISTERS
  300. ap->deep = reg_alloc_ptr;
  301. reg_alloc[reg_alloc_ptr].reg = next_addr;
  302. reg_alloc[reg_alloc_ptr].mode = am_areg;
  303. reg_alloc[reg_alloc_ptr].flag = 0;
  304. if (next_addr++ == MAX_ADDR)
  305. next_addr = 0; /* wrap around */
  306. if (reg_alloc_ptr++ == MAX_REG_STACK)
  307. ierr(TEMP_ADDR,1);
  308. #else
  309. next_addr++;
  310. #endif
  311. return ap;
  312. }
  313. int free_data(void) {
  314. /*
  315. * returns TRUE if a data register is available at ,,no cost'' (no push).
  316. * Used to determine e.g. wether cmp.w #0,An or move.l An,Dm is better
  317. */
  318. #ifndef INFINITE_REGISTERS
  319. return (dreg_in_use[next_data] < 0);
  320. #else
  321. return 1;
  322. #endif
  323. }
  324. void freeop(struct amode *ap) {
  325. /*
  326. * release any temporary registers used in an addressing mode.
  327. */
  328. int number;
  329. if (ap == 0)
  330. /* This can happen freeing a NOVALUE result */
  331. return;
  332. switch (ap->mode) {
  333. case am_dreg:
  334. if (ap->preg <= MAX_DATA) {
  335. if (next_data-- == 0)
  336. next_data = MAX_DATA;
  337. #ifndef INFINITE_REGISTERS
  338. number = dreg_in_use[(int)ap->preg];
  339. dreg_in_use[(int)ap->preg] = -1;
  340. #endif
  341. break;
  342. }
  343. return;
  344. case am_indx2:
  345. if (ap->sreg <= MAX_DATA) {
  346. if (next_data-- == 0)
  347. next_data = MAX_DATA;
  348. #ifndef INFINITE_REGISTERS
  349. number = dreg_in_use[(int)ap->sreg];
  350. dreg_in_use[(int)ap->sreg] = -1;
  351. #endif
  352. break;
  353. }
  354. goto common;
  355. case am_indx3:
  356. if (ap->sreg <= MAX_ADDR) {
  357. if (next_addr-- == 0)
  358. next_addr = MAX_ADDR;
  359. #ifndef INFINITE_REGISTERS
  360. number = areg_in_use[(int)ap->sreg];
  361. areg_in_use[(int)ap->sreg] = -1;
  362. #endif
  363. break;
  364. }
  365. goto common;
  366. case am_areg:
  367. case am_ind:
  368. case am_indx:
  369. case am_ainc:
  370. case am_adec:
  371. common:
  372. if (ap->preg <= MAX_ADDR) {
  373. if (next_addr-- == 0)
  374. next_addr = MAX_ADDR;
  375. #ifndef INFINITE_REGISTERS
  376. number = areg_in_use[(int)ap->preg];
  377. areg_in_use[(int)ap->preg] = -1;
  378. #endif
  379. break;
  380. }
  381. return;
  382. default:
  383. return;
  384. }
  385. #ifndef INFINITE_REGISTERS
  386. /* some consistency checks */
  387. if (number != ap->deep)
  388. ierr(FREEOP,1);
  389. /* we should only free the most recently allocated register */
  390. if (reg_alloc_ptr-- == 0)
  391. ierr(FREEOP,2);
  392. if (reg_alloc_ptr != number)
  393. ierr(FREEOP,3);
  394. /* the just freed register should not be on stack */
  395. if (reg_alloc[number].flag)
  396. ierr(FREEOP,4);
  397. #endif
  398. }
  399. void temp_inv(void) {
  400. #ifndef INFINITE_REGISTERS
  401. /*
  402. * push any used temporary registers.
  403. * This is necessary across function calls
  404. * The reason for this hacking is actually that temp_inv should dump
  405. * the registers in the correct order,
  406. * the least recently allocated register first.
  407. * the most recently allocated register last.
  408. */
  409. int i;
  410. for (i = 0; i < reg_alloc_ptr; i++)
  411. if (reg_alloc[i].flag == 0) {
  412. g_push(reg_alloc[i].reg, reg_alloc[i].mode, i);
  413. /* mark the register void */
  414. if (reg_alloc[i].mode == am_dreg)
  415. dreg_in_use[reg_alloc[i].reg] = -1;
  416. else
  417. areg_in_use[reg_alloc[i].reg] = -1;
  418. }
  419. #else
  420. g_code(_op_cleanup_for_external_call, 0, NIL_AMODE, NIL_AMODE);
  421. #endif
  422. }
  423. #endif /* MC680X0 */
  424. // vim:ts=4:sw=4