gen: move the register allocation to reg.c
[neatcc.git] / gen.c
blob09b7112ca830ae17b207364a285cfe1e508a8f8a
1 #include <stdlib.h>
2 #include <stdio.h>
3 #include <string.h>
4 #include "gen.h"
5 #include "out.h"
6 #include "reg.h"
7 #include "tok.h"
9 /* variable location */
10 #define LOC_REG 0x01
11 #define LOC_MEM 0x02
12 #define LOC_NUM 0x04
13 #define LOC_SYM 0x08
14 #define LOC_LOCAL 0x10
16 #define MIN(a, b) ((a) < (b) ? (a) : (b))
17 #define ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1))
19 char cs[SECSIZE]; /* code segment */
20 int cslen;
21 static char ds[SECSIZE]; /* data segment */
22 static int dslen;
23 static long bsslen; /* bss segment size */
25 static long sp; /* stack pointer offset from R_RBP */
26 static long sp_max; /* maximum stack pointer offset */
27 static long sp_tmp; /* sp for the first tmp on the stack */
28 static int localoff[NLOCALS]; /* the offset of locals on the stack */
29 static int nlocals; /* number of locals */
31 /* function info */
32 static int func_beg;
33 static int func_argc;
34 static int func_varg;
36 /* function statistics */
37 int pass1; /* collect statistics; 1st pass */
38 static int stat_calls; /* # of function calls */
39 static int stat_tmps; /* # of stack temporaries */
40 static int stat_regs; /* mask of used registers */
42 /* optimization info */
43 static int pass2; /* use the collected statistics in the 1st pass */
44 static int tmp_mask; /* registers that can be used for tmps */
46 /* register allocation for locals */
47 #define TMP_ISLREG(t) (!(t)->bt && (t)->loc == LOC_LOCAL && r_regmap((t)->id) >= 0)
48 #define TMP_LREG(t) (r_regmap((t)->id))
50 #define TMP(i) (((i) < ntmp) ? &tmps[ntmp - 1 - (i)] : NULL)
52 static struct tmp {
53 long addr;
54 char sym[NAMELEN];
55 long off; /* offset from a symbol or a local */
56 unsigned loc; /* variable location */
57 unsigned bt; /* type of address; zero when not a pointer */
58 int id; /* local variable id */
59 } tmps[MAXTMP];
60 static int ntmp;
62 static struct tmp *regs[N_REGS];
64 /* labels and jmps */
65 #define MAXJMPS (1 << 14)
67 static long labels[MAXJMPS];
68 static int nlabels;
69 static long jmp_loc[MAXJMPS];
70 static int jmp_goal[MAXJMPS];
71 static int jmp_len[MAXJMPS];
72 static int njmps;
74 void o_label(int id)
76 r_label(id);
77 if (id > nlabels)
78 nlabels = id + 1;
79 labels[id] = cslen;
82 /* the number of bytes needed for holding jmp displacement */
83 static int jmp_sz(int id)
85 long n = jmp_len[id] > 0 ? jmp_len[id] : -jmp_len[id];
86 if (!pass2)
87 return 4;
88 if (n < 0x70)
89 return n == 0 ? 0 : 1;
90 return n < 0x7000 ? 2 : 4;
93 static void jmp_add(int id, int rn, int z)
95 r_jmp(id);
96 if (njmps >= MAXJMPS)
97 err("nomem: MAXJMPS reached!\n");
98 i_jmp(rn, z, jmp_sz(njmps));
99 jmp_loc[njmps] = cslen;
100 jmp_goal[njmps] = id;
101 njmps++;
104 static void jmp_fill(void)
106 int i;
107 for (i = 0; i < njmps; i++)
108 jmp_len[i] = i_fill(jmp_loc[i], labels[jmp_goal[i]], jmp_sz(i));
111 /* generating code */
113 void os(void *s, int n)
115 while (n--)
116 cs[cslen++] = *(char *) (s++);
119 void oi(long n, int l)
121 while (l--) {
122 cs[cslen++] = n;
123 n >>= 8;
127 static long sp_push(int sz)
129 sp -= ALIGN(sz, LONGSZ);
130 if (sp < sp_max)
131 sp_max = sp;
132 return sp;
135 static void tmp_mem(struct tmp *tmp)
137 int src = tmp->addr;
138 if (tmp->loc != LOC_REG || (1 << src) & r_lregs())
139 return;
140 if (sp_tmp == -1)
141 sp_tmp = sp;
142 tmp->addr = sp_push(LONGSZ);
143 i_save(src, REG_FP, tmp->addr, LONGSZ);
144 stat_tmps++;
145 regs[src] = NULL;
146 tmp->loc = LOC_MEM;
149 static void num_cast(struct tmp *t, unsigned bt)
151 if (!(bt & BT_SIGNED) && BT_SZ(bt) != LONGSZ)
152 t->addr &= ((1l << (long) (BT_SZ(bt) * 8)) - 1);
153 if (bt & BT_SIGNED && BT_SZ(bt) != LONGSZ &&
154 t->addr > (1l << (BT_SZ(bt) * 8 - 1)))
155 t->addr = -((1l << (BT_SZ(bt) * 8)) - t->addr);
158 static void tmp_reg(struct tmp *tmp, int dst, int deref)
160 int bt = tmp->bt;
161 if (!tmp->bt)
162 deref = 0;
163 if (deref)
164 tmp->bt = 0;
165 if (tmp->loc == LOC_NUM) {
166 i_num(dst, tmp->addr);
167 tmp->addr = dst;
168 regs[dst] = tmp;
169 tmp->loc = LOC_REG;
171 if (tmp->loc == LOC_SYM) {
172 i_sym(dst, tmp->sym, tmp->off);
173 tmp->addr = dst;
174 regs[dst] = tmp;
175 tmp->loc = LOC_REG;
177 if (tmp->loc == LOC_REG) {
178 if (deref)
179 i_load(dst, tmp->addr, 0, bt);
180 else if (dst != tmp->addr)
181 i_mov(dst, tmp->addr);
182 regs[tmp->addr] = NULL;
184 if (tmp->loc == LOC_LOCAL) {
185 if (deref)
186 r_read(tmp->id);
187 else
188 r_addr(tmp->id);
189 if (deref)
190 i_load(dst, REG_FP, tmp->addr + tmp->off, bt);
191 else
192 i_op_imm(O_ADD, dst, REG_FP, tmp->addr + tmp->off);
194 if (tmp->loc == LOC_MEM) {
195 i_load(dst, REG_FP, tmp->addr, LONGSZ);
196 if (deref)
197 i_load(dst, dst, 0, bt);
199 tmp->addr = dst;
200 stat_regs |= 1 << dst;
201 regs[dst] = tmp;
202 tmp->loc = LOC_REG;
205 /* empty the given register, but never touch the registers in rsrvd mask */
206 static void reg_free(int reg, int rsrvd)
208 int i;
209 if (!regs[reg])
210 return;
211 rsrvd |= ~tmp_mask;
212 for (i = 0; i < N_TMPS; i++)
213 if (!regs[tmpregs[i]] && ~rsrvd & (1 << tmpregs[i])) {
214 tmp_reg(regs[reg], tmpregs[i], 0);
215 return;
217 tmp_mem(regs[reg]);
220 static void reg_for(int reg, struct tmp *t)
222 if (regs[reg] && regs[reg] != t)
223 reg_free(reg, 0);
226 static void tmp_mv(struct tmp *t, int reg)
228 reg_for(reg, t);
229 tmp_reg(t, reg, 0);
232 static void tmp_to(struct tmp *t, int reg)
234 reg_for(reg, t);
235 if (t->loc == LOC_LOCAL && TMP_ISLREG(t)) {
236 t->loc = LOC_REG;
237 t->addr = TMP_LREG(t);
238 t->bt = 0;
240 tmp_reg(t, reg, 1);
243 static void tmp_drop(int n)
245 int i;
246 for (i = ntmp - n; i < ntmp; i++)
247 if (tmps[i].loc == LOC_REG)
248 regs[tmps[i].addr] = NULL;
249 ntmp -= n;
252 static void tmp_pop(int reg)
254 struct tmp *t = TMP(0);
255 tmp_to(t, reg);
256 tmp_drop(1);
259 static struct tmp *tmp_new(void)
261 return &tmps[ntmp++];
264 static void tmp_push(int reg)
266 struct tmp *t = tmp_new();
267 t->addr = reg;
268 t->bt = 0;
269 stat_regs |= 1 << reg;
270 t->loc = LOC_REG;
271 regs[reg] = t;
274 void o_local(long addr)
276 struct tmp *t = tmp_new();
277 t->addr = localoff[addr];
278 t->id = addr;
279 t->loc = LOC_LOCAL;
280 t->bt = 0;
281 t->off = 0;
284 void o_num(long num)
286 struct tmp *t = tmp_new();
287 t->addr = num;
288 t->bt = 0;
289 t->loc = LOC_NUM;
292 void o_sym(char *name)
294 struct tmp *t = tmp_new();
295 strcpy(t->sym, name);
296 t->loc = LOC_SYM;
297 t->bt = 0;
298 t->off = 0;
301 void o_tmpdrop(int n)
303 if (n == -1 || n > ntmp)
304 n = ntmp;
305 tmp_drop(n);
306 if (!ntmp) {
307 if (sp_tmp != -1)
308 sp = sp_tmp;
309 sp_tmp = -1;
313 /* make sure tmps remain intact after a conditional expression */
314 void o_fork(void)
316 int i;
317 for (i = 0; i < ntmp - 1; i++)
318 tmp_mem(&tmps[i]);
321 void o_forkpush(void)
323 tmp_pop(REG_FORK);
326 void o_forkjoin(void)
328 tmp_push(REG_FORK);
331 void o_tmpswap(void)
333 struct tmp *t1 = TMP(0);
334 struct tmp *t2 = TMP(1);
335 struct tmp t;
336 memcpy(&t, t1, sizeof(t));
337 memcpy(t1, t2, sizeof(t));
338 memcpy(t2, &t, sizeof(t));
339 if (t1->loc == LOC_REG)
340 regs[t1->addr] = t1;
341 if (t2->loc == LOC_REG)
342 regs[t2->addr] = t2;
345 static int reg_get(int mask)
347 int i;
348 mask &= tmp_mask;
349 for (i = 0; i < N_TMPS; i++)
350 if ((1 << tmpregs[i]) & mask && !regs[tmpregs[i]]) {
351 stat_regs |= 1 << tmpregs[i];
352 return tmpregs[i];
354 for (i = 0; i < N_TMPS; i++)
355 if ((1 << tmpregs[i]) & mask) {
356 reg_free(tmpregs[i], 0);
357 stat_regs |= 1 << tmpregs[i];
358 return tmpregs[i];
360 die("reg_get: out of registers!\n");
361 return 0;
364 static int reg_tmp(struct tmp *t, int mask, int readonly)
366 if (t->loc == LOC_REG && (mask & (1 << t->addr)))
367 if (!(r_lregs() & (1 << t->addr)) || (readonly && !t->bt))
368 return t->addr;
369 return reg_get(mask);
372 static int reg_tmpn(struct tmp *t, int notmask, int readonly)
374 if (t->loc == LOC_REG && !(notmask & (1 << t->addr)))
375 if (!(r_lregs() & (1 << t->addr)) || (readonly && !t->bt))
376 return t->addr;
377 return reg_get(~notmask);
380 static void tmp_copy(struct tmp *t1)
382 struct tmp *t2 = tmp_new();
383 memcpy(t2, t1, sizeof(*t1));
384 if (!(t1->loc & (LOC_REG | LOC_MEM)))
385 return;
386 if (t1->loc == LOC_MEM) {
387 tmp_mv(t2, reg_get(R_TMPS));
388 } else if (t1->loc == LOC_REG) {
389 t2->addr = reg_tmpn(t2, 1 << t1->addr, 0);
390 i_mov(t2->addr, t1->addr);
391 regs[t2->addr] = t2;
392 stat_regs |= 1 << t2->addr;
396 void o_tmpcopy(void)
398 tmp_copy(TMP(0));
401 void o_deref(unsigned bt)
403 struct tmp *t = TMP(0);
404 if (TMP_ISLREG(t)) {
405 t->loc = LOC_REG;
406 t->addr = TMP_LREG(t);
407 } else {
408 if (t->bt)
409 tmp_to(t, reg_tmp(t, R_TMPS, 0));
410 t->bt = bt;
414 void o_load(void)
416 struct tmp *t = TMP(0);
417 tmp_to(t, reg_tmp(t, R_TMPS, 0));
420 #define TMP_NUM(t) ((t)->loc == LOC_NUM && !(t)->bt)
421 #define LOCAL_PTR(t) ((t)->loc == LOC_LOCAL && !(t)->bt)
422 #define SYM_PTR(t) ((t)->loc == LOC_SYM && !(t)->bt)
424 int o_popnum(long *c)
426 struct tmp *t = TMP(0);
427 if (!TMP_NUM(t))
428 return 1;
429 *c = t->addr;
430 tmp_drop(1);
431 return 0;
434 void o_ret(int rets)
436 if (rets)
437 tmp_pop(REG_RET);
438 else
439 i_num(REG_RET, 0);
440 o_jmp(0);
443 long o_mklocal(int sz)
445 r_mk(sz);
446 localoff[nlocals] = sp_push(ALIGN(sz, LONGSZ));
447 return nlocals++;
450 void o_rmlocal(long addr, int sz)
452 r_rm(addr);
455 long o_arg2loc(int i)
457 return i;
460 #define MOVXX(bt) ((BT_SZ(bt) == LONGSZ ? O_MOV : ((bt) & BT_SIGNED ? O_SX : O_ZX)))
462 void o_assign(unsigned bt)
464 struct tmp *t1 = TMP(0);
465 struct tmp *t2 = TMP(1);
466 int r1 = reg_tmp(t1, BT_SZ(bt) > 1 ? R_TMPS : R_BYTE, 1);
467 int r2 = reg_tmpn(t2, 1 << r1, 1);
468 int off = 0;
469 tmp_to(t1, r1);
470 if (TMP_ISLREG(t2)) {
471 i_op_imm(MOVXX(bt), TMP_LREG(t2), r1, BT_SZ(bt) * 8);
472 goto done;
474 if (t2->bt)
475 tmp_to(t2, r2);
476 if (t2->loc == LOC_LOCAL) {
477 r2 = REG_FP;
478 off = t2->addr + t2->off;
479 r_read(t2->id);
480 } else {
481 tmp_to(t2, r2);
483 i_save(r1, r2, off, bt);
484 done:
485 tmp_drop(2);
486 tmp_push(r1);
489 static long cu(int op, long i)
491 switch (op & 0xff) {
492 case O_NEG:
493 return -i;
494 case O_NOT:
495 return ~i;
496 case O_LNOT:
497 return !i;
499 return 0;
502 static int c_uop(int op)
504 struct tmp *t1 = TMP(0);
505 if (!TMP_NUM(t1))
506 return 1;
507 tmp_drop(1);
508 o_num(cu(op, t1->addr));
509 return 0;
512 static long cb(int op, long a, long b)
514 switch (op & 0xff) {
515 case O_ADD:
516 return a + b;
517 case O_SUB:
518 return a - b;
519 case O_AND:
520 return a & b;
521 case O_OR:
522 return a | b;
523 case O_XOR:
524 return a ^ b;
525 case O_MUL:
526 return a * b;
527 case O_DIV:
528 return a / b;
529 case O_MOD:
530 return a % b;
531 case O_SHL:
532 return a << b;
533 case O_SHR:
534 if (op & O_SIGNED)
535 return a >> b;
536 else
537 return (unsigned long) a >> b;
538 case O_LT:
539 return a < b;
540 case O_GT:
541 return a > b;
542 case O_LE:
543 return a <= b;
544 case O_GE:
545 return a >= b;
546 case O_EQ:
547 return a == b;
548 case O_NEQ:
549 return a != b;
551 return 0;
554 static int c_bop(int op)
556 struct tmp *t1 = TMP(0);
557 struct tmp *t2 = TMP(1);
558 int locs = LOCAL_PTR(t1) + LOCAL_PTR(t2);
559 int syms = SYM_PTR(t1) + SYM_PTR(t2);
560 int nums = TMP_NUM(t1) + TMP_NUM(t2);
561 if (syms + locs == 2 || syms + nums + locs != 2)
562 return 1;
563 if (nums == 1)
564 if ((op & 0xff) != O_ADD && ((op & 0xff) != O_SUB || TMP_NUM(t2)))
565 return 1;
566 if (nums == 1) {
567 long o1 = TMP_NUM(t1) ? t1->addr : t1->off;
568 long o2 = TMP_NUM(t2) ? t2->addr : t2->off;
569 long ret = cb(op, o2, o1);
570 if (!TMP_NUM(t1))
571 o_tmpswap();
572 if (t2->loc == LOC_LOCAL)
573 r_addr(t2->id);
574 t2->off = ret;
575 tmp_drop(1);
576 } else {
577 long ret = cb(op, t2->addr, t1->addr);
578 tmp_drop(2);
579 o_num(ret);
581 return 0;
584 /* allocate registers for the given binary or unary instruction */
585 static void regs2(int op, int *rd, int *r1, int *r2)
587 int md, m1, m2, mt;
588 int all = 0;
589 int i;
590 i_reg(op, &md, &m1, &m2, &mt);
591 if (m2) {
592 struct tmp *t2 = TMP(0);
593 *r2 = reg_tmp(t2, m2, 1);
594 tmp_to(t2, *r2);
595 all |= (1 << *r2);
597 if (m1) {
598 struct tmp *t1 = TMP(m2 ? 1 : 0);
599 *r1 = reg_tmp(t1, m1 & ~all, md ? 1 : 0);
600 tmp_to(t1, *r1);
601 all |= (1 << *r1);
603 if (md) {
604 if (m2 && md & tmp_mask & (1 << *r2))
605 *rd = *r2;
606 else if (m1 && md & tmp_mask & (1 << *r1))
607 *rd = *r1;
608 else
609 *rd = reg_get(md & ~all);
610 all |= (1 << *rd);
611 } else {
612 *rd = *r1;
614 if (mt & ~all) {
615 for (i = 0; i < N_TMPS; i++)
616 if (mt & ~all & (1 << tmpregs[i]))
617 reg_free(tmpregs[i], all | mt);
619 stat_regs |= mt;
620 tmp_drop(m2 ? 2 : 1);
623 /* allocate registers for a 3 operand instruction */
624 static void regs3(int op, int *r0, int *r1, int *r2)
626 int m0, m1, m2, mt;
627 struct tmp *t0 = TMP(2);
628 struct tmp *t1 = TMP(1);
629 struct tmp *t2 = TMP(0);
630 int all = 0;
631 int i;
632 i_reg(op, &m0, &m1, &m2, &mt);
633 if (m2) {
634 *r2 = reg_tmp(t2, m2, 1);
635 tmp_to(t2, *r2);
636 all |= (1 << *r2);
638 if (m1) {
639 *r1 = reg_tmp(t1, m1 & ~(1 << *r2), 1);
640 tmp_to(t1, *r1);
641 all |= (1 << *r1);
643 if (m0) {
644 *r0 = reg_tmp(t0, m0 & ~((1 << *r2) | (1 << *r1)), 1);
645 tmp_to(t0, *r0);
646 all |= (1 << *r0);
648 if (mt & ~all) {
649 for (i = 0; i < N_TMPS; i++)
650 if (mt & ~all & (1 << tmpregs[i]))
651 reg_free(tmpregs[i], all | mt);
653 stat_regs |= mt;
654 tmp_drop(3);
657 static void op_imm(int op, long n)
659 int rd, r1, r2;
660 regs2(op | O_IMM, &rd, &r1, &r2);
661 i_op_imm(op | O_IMM, rd, r1, n);
662 tmp_push(rd);
665 void o_uop(int op)
667 int rd, r1, r2;
668 if (!c_uop(op))
669 return;
670 regs2(op, &rd, &r1, &r2);
671 i_op(op, rd, r1, r2);
672 tmp_push(rd);
675 static int bop_imm(int op, long *n, int swap)
677 struct tmp *t1 = TMP(0);
678 struct tmp *t2 = TMP(1);
679 if (!TMP_NUM(t1) && (!swap || !TMP_NUM(t2)))
680 return 1;
681 *n = TMP_NUM(t1) ? t1->addr : t2->addr;
682 if (!i_imm(op, *n))
683 return 1;
684 if (!TMP_NUM(t1))
685 o_tmpswap();
686 tmp_drop(1);
687 return 0;
690 static void bin_op(int op, int swap)
692 int rd, r1, r2;
693 long n;
694 if (!bop_imm(op, &n, swap)) {
695 regs2(op | O_IMM, &rd, &r1, &r2);
696 i_op_imm(op, rd, r1, n);
697 } else {
698 regs2(op, &rd, &r1, &r2);
699 i_op(op, rd, r1, r2);
701 tmp_push(rd);
704 static int log2a(unsigned long n)
706 int i = 0;
707 for (i = 0; i < LONGSZ * 8; i++)
708 if (n & (1u << i))
709 break;
710 if (i == LONGSZ * 8 || !(n >> (i + 1)))
711 return i;
712 return -1;
715 /* optimized version of mul/div/mod for powers of two */
716 static int mul_2(int op)
718 struct tmp *t1 = TMP(0);
719 struct tmp *t2 = TMP(1);
720 long n;
721 int p;
722 if ((op & 0xff) == O_MUL && t2->loc == LOC_NUM && !t2->bt)
723 o_tmpswap();
724 if (t1->loc != LOC_NUM || t1->bt)
725 return 1;
726 n = t1->addr;
727 p = log2a(n);
728 if (n && p == -1)
729 return 1;
730 if ((op & 0xff) == O_MUL) {
731 tmp_drop(1);
732 if (n == 1)
733 return 0;
734 if (n == 0) {
735 tmp_drop(1);
736 o_num(0);
737 return 0;
739 op_imm(O_SHL, p);
740 return 0;
742 if (op == O_DIV) {
743 tmp_drop(1);
744 if (n == 1)
745 return 0;
746 op_imm((op & O_SIGNED) | O_SHR, p);
747 return 0;
749 if (op == O_MOD) {
750 tmp_drop(1);
751 if (n == 1) {
752 tmp_drop(1);
753 o_num(0);
754 return 0;
756 op_imm(O_ZX, p);
757 return 0;
759 return 1;
762 void o_bop(int op)
764 if (!c_bop(op))
765 return;
766 if ((op & 0xf0) == 0x00) /* add */
767 bin_op(op, (op & 0xff) != O_SUB);
768 if ((op & 0xf0) == 0x10) /* shx */
769 bin_op(op, 0);
770 if ((op & 0xf0) == 0x20) { /* mul */
771 if (!mul_2(op))
772 return;
773 bin_op(op, (op & 0xff) == O_MUL);
775 if ((op & 0xf0) == 0x30)
776 bin_op(op, (op & 0xff) == O_EQ || (op & 0xff) == O_NEQ);
779 void o_memcpy(void)
781 int r0, r1, r2;
782 regs3(O_MCPY, &r0, &r1, &r2);
783 i_memcpy(r0, r1, r2);
786 void o_memset(void)
788 int r0, r1, r2;
789 regs3(O_MSET, &r0, &r1, &r2);
790 i_memset(r0, r1, r2);
793 void o_cast(unsigned bt)
795 struct tmp *t = TMP(0);
796 if (!t->bt && t->loc == LOC_NUM) {
797 num_cast(t, bt);
798 return;
800 if (BT_SZ(bt) != LONGSZ)
801 op_imm(MOVXX(bt), BT_SZ(bt) * 8);
804 static void jxz(int id, int z)
806 int r = reg_tmp(TMP(0), R_TMPS, 1);
807 tmp_pop(r);
808 jmp_add(id, r, z);
811 void o_jz(int id)
813 jxz(id, 1);
816 void o_jnz(int id)
818 jxz(id, 0);
821 void o_jmp(int id)
823 jmp_add(id, -1, 0);
826 void o_call(int argc, int rets)
828 struct tmp *t;
829 int i;
830 int aregs = MIN(N_ARGS, argc);
831 for (i = 0; i < N_TMPS; i++)
832 if (regs[tmpregs[i]] && regs[tmpregs[i]] - tmps < ntmp - argc)
833 tmp_mem(regs[tmpregs[i]]);
834 if (argc > aregs) {
835 sp_push(LONGSZ * (argc - aregs));
836 for (i = argc - 1; i >= aregs; --i) {
837 int reg = reg_tmp(TMP(0), R_TMPS, 1);
838 tmp_pop(reg);
839 i_save(reg, REG_SP, (i - aregs) * LONGSZ, LONGSZ);
842 for (i = aregs - 1; i >= 0; --i)
843 tmp_to(TMP(aregs - i - 1), argregs[i]);
844 tmp_drop(aregs);
845 t = TMP(0);
846 if (t->loc == LOC_SYM && !t->bt) {
847 i_call(t->sym, t->off);
848 tmp_drop(1);
849 } else {
850 int reg = reg_tmp(t, R_TMPS, 1);
851 tmp_pop(reg);
852 i_call_reg(reg);
854 if (rets)
855 tmp_push(REG_RET);
856 stat_calls++;
859 void o_mkbss(char *name, int size, int global)
861 if (pass1)
862 return;
863 out_sym(name, OUT_BSS | (global ? OUT_GLOB : 0), bsslen, size);
864 bsslen += ALIGN(size, OUT_ALIGNMENT);
867 #define MAXDATS (1 << 10)
868 static char dat_names[MAXDATS][NAMELEN];
869 static int dat_offs[MAXDATS];
870 static int ndats;
872 void *o_mkdat(char *name, int size, int global)
874 void *addr = ds + dslen;
875 int idx;
876 if (pass1)
877 return addr;
878 idx = ndats++;
879 if (idx >= MAXDATS)
880 err("nomem: MAXDATS reached!\n");
881 strcpy(dat_names[idx], name);
882 dat_offs[idx] = dslen;
883 out_sym(name, OUT_DS | (global ? OUT_GLOB : 0), dslen, size);
884 dslen += ALIGN(size, OUT_ALIGNMENT);
885 return addr;
888 static int dat_off(char *name)
890 int i;
891 for (i = 0; i < ndats; i++)
892 if (!strcmp(name, dat_names[i]))
893 return dat_offs[i];
894 return 0;
897 void o_datset(char *name, int off, unsigned bt)
899 struct tmp *t = TMP(0);
900 int sym_off = dat_off(name) + off;
901 if (pass1) {
902 tmp_drop(1);
903 return;
905 if (t->loc == LOC_NUM && !t->bt) {
906 num_cast(t, bt);
907 memcpy(ds + sym_off, &t->addr, BT_SZ(bt));
909 if (t->loc == LOC_SYM && !t->bt) {
910 out_rel(t->sym, OUT_DS, sym_off);
911 memcpy(ds + sym_off, &t->off, BT_SZ(bt));
913 tmp_drop(1);
916 void o_write(int fd)
918 i_done();
919 out_write(fd, cs, cslen, ds, dslen);
922 static void func_reset(void)
924 int i;
925 int argaddr = 0;
926 memset(regs, 0, sizeof(regs));
927 sp = i_sp();
928 sp_max = sp;
929 ntmp = 0;
930 sp_tmp = -1;
931 nlabels = 0;
932 njmps = 0;
933 nlocals = 0;
934 stat_calls = 0;
935 stat_tmps = 0;
936 stat_regs = 1 << REG_RET;
937 for (i = 0; i < func_argc; i++) {
938 localoff[nlocals++] = i_args() + argaddr;
939 if (i >= N_ARGS || r_sargs() & (1 << argregs[i]))
940 argaddr += LONGSZ;
944 void o_func_beg(char *name, int argc, int global, int varg)
946 func_argc = argc;
947 func_varg = varg;
948 func_beg = cslen;
949 pass1 = 0;
950 pass2 = 0;
951 tmp_mask = N_TMPS > 6 ? R_TMPS & ~R_SAVED : R_TMPS;
952 r_func(argc, varg);
953 out_sym(name, (global ? OUT_GLOB : 0) | OUT_CS, cslen, 0);
954 i_prolog(argc, varg, r_sargs(), tmp_mask & R_SAVED, 1, 1);
955 func_reset();
958 void o_pass1(void)
960 pass1 = 1;
963 void o_pass2(void)
965 int locregs, leaf;
966 int initfp, subsp, sregs;
967 int i;
968 o_label(0);
969 jmp_fill();
970 leaf = !stat_calls;
971 cslen = func_beg;
972 locregs = r_alloc(leaf, stat_regs);
973 subsp = nlocals > locregs || !leaf;
974 initfp = subsp || stat_tmps || func_argc > N_ARGS;
975 sregs = (r_lregs() | stat_regs) & R_SAVED;
976 tmp_mask = stat_regs;
977 pass1 = 0;
978 pass2 = 1;
979 i_prolog(func_argc, func_varg, r_sargs(), sregs, initfp, subsp);
980 func_reset();
981 for (i = 0; i < MIN(func_argc, N_ARGS); i++)
982 if (r_regmap(i) >= 0 && r_regmap(i) != argregs[i])
983 i_mov(r_regmap(i), argregs[i]);
984 for (i = N_ARGS; i < func_argc; i++)
985 if (r_regmap(i) >= 0)
986 i_load(r_regmap(i), REG_FP, localoff[i], LONGSZ);
989 void o_func_end(void)
991 o_label(0);
992 jmp_fill();
993 i_epilog(sp_max);