gen: move the management of ds[] to gen.c
[neatcc.git] / gen.c
blobdcbda919aa17d03cb529a3ecbc8e13a702d1e2fe
1 #include <stdlib.h>
2 #include <stdio.h>
3 #include <string.h>
4 #include "gen.h"
5 #include "ncc.h"
6 #include "out.h"
7 #include "reg.h"
8 #include "tok.h"
10 /* variable location */
11 #define LOC_REG 0x01
12 #define LOC_MEM 0x02
13 #define LOC_NUM 0x04
14 #define LOC_SYM 0x08
15 #define LOC_LOCAL 0x10
17 #define MIN(a, b) ((a) < (b) ? (a) : (b))
18 #define ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1))
20 char cs[SECLEN]; /* code segment */
21 int cslen;
22 static char ds[SECLEN]; /* data segment */
23 static int dslen;
24 static long bsslen; /* bss segment size */
26 static long sp; /* stack pointer offset from R_RBP */
27 static long sp_max; /* maximum stack pointer offset */
28 static long sp_tmp; /* sp for the first tmp on the stack */
29 static int localoff[NLOCALS]; /* the offset of locals on the stack */
30 static int nlocals; /* number of locals */
32 /* function info */
33 static int func_beg;
34 static int func_argc;
35 static int func_varg;
37 /* function statistics */
38 int pass1; /* collect statistics; 1st pass */
39 static int stat_calls; /* # of function calls */
40 static int stat_tmps; /* # of stack temporaries */
41 static int stat_regs; /* mask of used registers */
43 /* optimization info */
44 static int pass2; /* use the collected statistics in the 1st pass */
45 static int tmp_mask; /* registers that can be used for tmps */
47 /* register allocation for locals */
48 #define TMP_ISLREG(t) (!(t)->bt && (t)->loc == LOC_LOCAL && r_regmap((t)->id) >= 0)
49 #define TMP_LREG(t) (r_regmap((t)->id))
51 #define TMP(i) (((i) < ntmp) ? &tmps[ntmp - 1 - (i)] : NULL)
53 static struct tmp {
54 long addr;
55 char sym[NAMELEN];
56 long off; /* offset from a symbol or a local */
57 unsigned loc; /* variable location */
58 unsigned bt; /* type of address; zero when not a pointer */
59 int id; /* local variable id */
60 } tmps[NTMPS];
61 static int ntmp;
63 static struct tmp *regs[N_REGS];
65 /* labels and jmps */
66 static long labels[NJMPS];
67 static int nlabels;
68 static long jmp_loc[NJMPS];
69 static int jmp_goal[NJMPS];
70 static int jmp_len[NJMPS];
71 static int njmps;
73 void o_label(int id)
75 r_label(id);
76 if (id > nlabels)
77 nlabels = id + 1;
78 labels[id] = cslen;
81 /* the number of bytes needed for holding jmp displacement */
82 static int jmp_sz(int id)
84 long n = jmp_len[id] > 0 ? jmp_len[id] : -jmp_len[id];
85 if (!pass2)
86 return 4;
87 if (n < 0x70)
88 return n == 0 ? 0 : 1;
89 return n < 0x7000 ? 2 : 4;
92 static void jmp_add(int id, int rn, int z)
94 r_jmp(id);
95 if (njmps >= NJMPS)
96 err("nomem: NJMPS reached!\n");
97 i_jmp(rn, z, jmp_sz(njmps));
98 jmp_loc[njmps] = cslen;
99 jmp_goal[njmps] = id;
100 njmps++;
103 static void jmp_fill(void)
105 int i;
106 for (i = 0; i < njmps; i++)
107 jmp_len[i] = i_fill(jmp_loc[i], labels[jmp_goal[i]], jmp_sz(i));
110 /* generating code */
112 void os(void *s, int n)
114 while (n--)
115 cs[cslen++] = *(char *) (s++);
118 void oi(long n, int l)
120 while (l--) {
121 cs[cslen++] = n;
122 n >>= 8;
126 static long sp_push(int sz)
128 sp -= ALIGN(sz, LONGSZ);
129 if (sp < sp_max)
130 sp_max = sp;
131 return sp;
134 static void tmp_mem(struct tmp *tmp)
136 int src = tmp->addr;
137 if (tmp->loc != LOC_REG || (1 << src) & r_lregs())
138 return;
139 if (sp_tmp == -1)
140 sp_tmp = sp;
141 tmp->addr = sp_push(LONGSZ);
142 i_save(src, REG_FP, tmp->addr, LONGSZ);
143 stat_tmps++;
144 regs[src] = NULL;
145 tmp->loc = LOC_MEM;
148 static void num_cast(struct tmp *t, unsigned bt)
150 if (!(bt & BT_SIGNED) && BT_SZ(bt) != LONGSZ)
151 t->addr &= ((1l << (long) (BT_SZ(bt) * 8)) - 1);
152 if (bt & BT_SIGNED && BT_SZ(bt) != LONGSZ &&
153 t->addr > (1l << (BT_SZ(bt) * 8 - 1)))
154 t->addr = -((1l << (BT_SZ(bt) * 8)) - t->addr);
157 static void tmp_reg(struct tmp *tmp, int dst, int deref)
159 int bt = tmp->bt;
160 if (!tmp->bt)
161 deref = 0;
162 if (deref)
163 tmp->bt = 0;
164 if (tmp->loc == LOC_NUM) {
165 i_num(dst, tmp->addr);
166 tmp->addr = dst;
167 regs[dst] = tmp;
168 tmp->loc = LOC_REG;
170 if (tmp->loc == LOC_SYM) {
171 i_sym(dst, tmp->sym, tmp->off);
172 tmp->addr = dst;
173 regs[dst] = tmp;
174 tmp->loc = LOC_REG;
176 if (tmp->loc == LOC_REG) {
177 if (deref)
178 i_load(dst, tmp->addr, 0, bt);
179 else if (dst != tmp->addr)
180 i_mov(dst, tmp->addr);
181 regs[tmp->addr] = NULL;
183 if (tmp->loc == LOC_LOCAL) {
184 if (deref)
185 r_read(tmp->id);
186 else
187 r_addr(tmp->id);
188 if (deref)
189 i_load(dst, REG_FP, tmp->addr + tmp->off, bt);
190 else
191 i_op_imm(O_ADD, dst, REG_FP, tmp->addr + tmp->off);
193 if (tmp->loc == LOC_MEM) {
194 i_load(dst, REG_FP, tmp->addr, LONGSZ);
195 if (deref)
196 i_load(dst, dst, 0, bt);
198 tmp->addr = dst;
199 stat_regs |= 1 << dst;
200 regs[dst] = tmp;
201 tmp->loc = LOC_REG;
204 /* empty the given register, but never touch the registers in rsrvd mask */
205 static void reg_free(int reg, int rsrvd)
207 int i;
208 if (!regs[reg])
209 return;
210 rsrvd |= ~tmp_mask;
211 for (i = 0; i < N_TMPS; i++)
212 if (!regs[tmpregs[i]] && ~rsrvd & (1 << tmpregs[i])) {
213 tmp_reg(regs[reg], tmpregs[i], 0);
214 return;
216 tmp_mem(regs[reg]);
219 static void reg_for(int reg, struct tmp *t)
221 if (regs[reg] && regs[reg] != t)
222 reg_free(reg, 0);
225 static void tmp_mv(struct tmp *t, int reg)
227 reg_for(reg, t);
228 tmp_reg(t, reg, 0);
231 static void tmp_to(struct tmp *t, int reg)
233 reg_for(reg, t);
234 if (t->loc == LOC_LOCAL && TMP_ISLREG(t)) {
235 t->loc = LOC_REG;
236 t->addr = TMP_LREG(t);
237 t->bt = 0;
239 tmp_reg(t, reg, 1);
242 static void tmp_drop(int n)
244 int i;
245 for (i = ntmp - n; i < ntmp; i++)
246 if (tmps[i].loc == LOC_REG)
247 regs[tmps[i].addr] = NULL;
248 ntmp -= n;
251 static void tmp_pop(int reg)
253 struct tmp *t = TMP(0);
254 tmp_to(t, reg);
255 tmp_drop(1);
258 static struct tmp *tmp_new(void)
260 return &tmps[ntmp++];
263 static void tmp_push(int reg)
265 struct tmp *t = tmp_new();
266 t->addr = reg;
267 t->bt = 0;
268 stat_regs |= 1 << reg;
269 t->loc = LOC_REG;
270 regs[reg] = t;
273 void o_local(long addr)
275 struct tmp *t = tmp_new();
276 t->addr = localoff[addr];
277 t->id = addr;
278 t->loc = LOC_LOCAL;
279 t->bt = 0;
280 t->off = 0;
283 void o_num(long num)
285 struct tmp *t = tmp_new();
286 t->addr = num;
287 t->bt = 0;
288 t->loc = LOC_NUM;
291 void o_sym(char *name)
293 struct tmp *t = tmp_new();
294 strcpy(t->sym, name);
295 t->loc = LOC_SYM;
296 t->bt = 0;
297 t->off = 0;
300 void o_tmpdrop(int n)
302 if (n == -1 || n > ntmp)
303 n = ntmp;
304 tmp_drop(n);
305 if (!ntmp) {
306 if (sp_tmp != -1)
307 sp = sp_tmp;
308 sp_tmp = -1;
312 /* make sure tmps remain intact after a conditional expression */
313 void o_fork(void)
315 int i;
316 for (i = 0; i < ntmp - 1; i++)
317 tmp_mem(&tmps[i]);
320 void o_forkpush(void)
322 tmp_pop(REG_FORK);
325 void o_forkjoin(void)
327 tmp_push(REG_FORK);
330 void o_tmpswap(void)
332 struct tmp *t1 = TMP(0);
333 struct tmp *t2 = TMP(1);
334 struct tmp t;
335 memcpy(&t, t1, sizeof(t));
336 memcpy(t1, t2, sizeof(t));
337 memcpy(t2, &t, sizeof(t));
338 if (t1->loc == LOC_REG)
339 regs[t1->addr] = t1;
340 if (t2->loc == LOC_REG)
341 regs[t2->addr] = t2;
344 static int reg_get(int mask)
346 int i;
347 mask &= tmp_mask;
348 for (i = 0; i < N_TMPS; i++)
349 if ((1 << tmpregs[i]) & mask && !regs[tmpregs[i]]) {
350 stat_regs |= 1 << tmpregs[i];
351 return tmpregs[i];
353 for (i = 0; i < N_TMPS; i++)
354 if ((1 << tmpregs[i]) & mask) {
355 reg_free(tmpregs[i], 0);
356 stat_regs |= 1 << tmpregs[i];
357 return tmpregs[i];
359 die("reg_get: out of registers!\n");
360 return 0;
363 static int reg_tmp(struct tmp *t, int mask, int readonly)
365 if (t->loc == LOC_REG && (mask & (1 << t->addr)))
366 if (!(r_lregs() & (1 << t->addr)) || (readonly && !t->bt))
367 return t->addr;
368 return reg_get(mask);
371 static int reg_tmpn(struct tmp *t, int notmask, int readonly)
373 if (t->loc == LOC_REG && !(notmask & (1 << t->addr)))
374 if (!(r_lregs() & (1 << t->addr)) || (readonly && !t->bt))
375 return t->addr;
376 return reg_get(~notmask);
379 static void tmp_copy(struct tmp *t1)
381 struct tmp *t2 = tmp_new();
382 memcpy(t2, t1, sizeof(*t1));
383 if (!(t1->loc & (LOC_REG | LOC_MEM)))
384 return;
385 if (t1->loc == LOC_MEM) {
386 tmp_mv(t2, reg_get(R_TMPS));
387 } else if (t1->loc == LOC_REG) {
388 t2->addr = reg_tmpn(t2, 1 << t1->addr, 0);
389 i_mov(t2->addr, t1->addr);
390 regs[t2->addr] = t2;
391 stat_regs |= 1 << t2->addr;
395 void o_tmpcopy(void)
397 tmp_copy(TMP(0));
400 void o_deref(unsigned bt)
402 struct tmp *t = TMP(0);
403 if (TMP_ISLREG(t)) {
404 t->loc = LOC_REG;
405 t->addr = TMP_LREG(t);
406 } else {
407 if (t->bt)
408 tmp_to(t, reg_tmp(t, R_TMPS, 0));
409 t->bt = bt;
413 void o_load(void)
415 struct tmp *t = TMP(0);
416 tmp_to(t, reg_tmp(t, R_TMPS, 0));
419 #define TMP_NUM(t) ((t)->loc == LOC_NUM && !(t)->bt)
420 #define LOCAL_PTR(t) ((t)->loc == LOC_LOCAL && !(t)->bt)
421 #define SYM_PTR(t) ((t)->loc == LOC_SYM && !(t)->bt)
423 int o_popnum(long *c)
425 struct tmp *t = TMP(0);
426 if (!TMP_NUM(t))
427 return 1;
428 *c = t->addr;
429 tmp_drop(1);
430 return 0;
433 void o_ret(int rets)
435 if (rets)
436 tmp_pop(REG_RET);
437 else
438 i_num(REG_RET, 0);
439 o_jmp(0);
442 long o_mklocal(int sz)
444 r_mk(sz);
445 localoff[nlocals] = sp_push(ALIGN(sz, LONGSZ));
446 return nlocals++;
449 void o_rmlocal(long addr, int sz)
451 r_rm(addr);
454 long o_arg2loc(int i)
456 return i;
459 #define MOVXX(bt) ((BT_SZ(bt) == LONGSZ ? O_MOV : ((bt) & BT_SIGNED ? O_SX : O_ZX)))
461 void o_assign(unsigned bt)
463 struct tmp *t1 = TMP(0);
464 struct tmp *t2 = TMP(1);
465 int r1 = reg_tmp(t1, BT_SZ(bt) > 1 ? R_TMPS : R_BYTE, 1);
466 int r2 = reg_tmpn(t2, 1 << r1, 1);
467 int off = 0;
468 tmp_to(t1, r1);
469 if (TMP_ISLREG(t2)) {
470 i_op_imm(MOVXX(bt), TMP_LREG(t2), r1, BT_SZ(bt) * 8);
471 goto done;
473 if (t2->bt)
474 tmp_to(t2, r2);
475 if (t2->loc == LOC_LOCAL) {
476 r2 = REG_FP;
477 off = t2->addr + t2->off;
478 r_read(t2->id);
479 } else {
480 tmp_to(t2, r2);
482 i_save(r1, r2, off, bt);
483 done:
484 tmp_drop(2);
485 tmp_push(r1);
488 static long cu(int op, long i)
490 switch (op & 0xff) {
491 case O_NEG:
492 return -i;
493 case O_NOT:
494 return ~i;
495 case O_LNOT:
496 return !i;
498 return 0;
501 static int c_uop(int op)
503 struct tmp *t1 = TMP(0);
504 if (!TMP_NUM(t1))
505 return 1;
506 tmp_drop(1);
507 o_num(cu(op, t1->addr));
508 return 0;
511 static long cb(int op, long a, long b)
513 switch (op & 0xff) {
514 case O_ADD:
515 return a + b;
516 case O_SUB:
517 return a - b;
518 case O_AND:
519 return a & b;
520 case O_OR:
521 return a | b;
522 case O_XOR:
523 return a ^ b;
524 case O_MUL:
525 return a * b;
526 case O_DIV:
527 return a / b;
528 case O_MOD:
529 return a % b;
530 case O_SHL:
531 return a << b;
532 case O_SHR:
533 if (op & O_SIGNED)
534 return a >> b;
535 else
536 return (unsigned long) a >> b;
537 case O_LT:
538 return a < b;
539 case O_GT:
540 return a > b;
541 case O_LE:
542 return a <= b;
543 case O_GE:
544 return a >= b;
545 case O_EQ:
546 return a == b;
547 case O_NEQ:
548 return a != b;
550 return 0;
553 static int c_bop(int op)
555 struct tmp *t1 = TMP(0);
556 struct tmp *t2 = TMP(1);
557 int locs = LOCAL_PTR(t1) + LOCAL_PTR(t2);
558 int syms = SYM_PTR(t1) + SYM_PTR(t2);
559 int nums = TMP_NUM(t1) + TMP_NUM(t2);
560 if (syms + locs == 2 || syms + nums + locs != 2)
561 return 1;
562 if (nums == 1)
563 if ((op & 0xff) != O_ADD && ((op & 0xff) != O_SUB || TMP_NUM(t2)))
564 return 1;
565 if (nums == 1) {
566 long o1 = TMP_NUM(t1) ? t1->addr : t1->off;
567 long o2 = TMP_NUM(t2) ? t2->addr : t2->off;
568 long ret = cb(op, o2, o1);
569 if (!TMP_NUM(t1))
570 o_tmpswap();
571 if (t2->loc == LOC_LOCAL)
572 r_addr(t2->id);
573 t2->off = ret;
574 tmp_drop(1);
575 } else {
576 long ret = cb(op, t2->addr, t1->addr);
577 tmp_drop(2);
578 o_num(ret);
580 return 0;
583 /* allocate registers for the given binary or unary instruction */
584 static void regs2(int op, int *rd, int *r1, int *r2)
586 int md, m1, m2, mt;
587 int all = 0;
588 int i;
589 i_reg(op, &md, &m1, &m2, &mt);
590 if (m2) {
591 struct tmp *t2 = TMP(0);
592 *r2 = reg_tmp(t2, m2, 1);
593 tmp_to(t2, *r2);
594 all |= (1 << *r2);
596 if (m1) {
597 struct tmp *t1 = TMP(m2 ? 1 : 0);
598 *r1 = reg_tmp(t1, m1 & ~all, md ? 1 : 0);
599 tmp_to(t1, *r1);
600 all |= (1 << *r1);
602 if (md) {
603 if (m2 && md & tmp_mask & (1 << *r2))
604 *rd = *r2;
605 else if (m1 && md & tmp_mask & (1 << *r1))
606 *rd = *r1;
607 else
608 *rd = reg_get(md & ~all);
609 all |= (1 << *rd);
610 } else {
611 *rd = *r1;
613 if (mt & ~all) {
614 for (i = 0; i < N_TMPS; i++)
615 if (mt & ~all & (1 << tmpregs[i]))
616 reg_free(tmpregs[i], all | mt);
618 stat_regs |= mt;
619 tmp_drop(m2 ? 2 : 1);
622 /* allocate registers for a 3 operand instruction */
623 static void regs3(int op, int *r0, int *r1, int *r2)
625 int m0, m1, m2, mt;
626 struct tmp *t0 = TMP(2);
627 struct tmp *t1 = TMP(1);
628 struct tmp *t2 = TMP(0);
629 int all = 0;
630 int i;
631 i_reg(op, &m0, &m1, &m2, &mt);
632 if (m2) {
633 *r2 = reg_tmp(t2, m2, 1);
634 tmp_to(t2, *r2);
635 all |= (1 << *r2);
637 if (m1) {
638 *r1 = reg_tmp(t1, m1 & ~(1 << *r2), 1);
639 tmp_to(t1, *r1);
640 all |= (1 << *r1);
642 if (m0) {
643 *r0 = reg_tmp(t0, m0 & ~((1 << *r2) | (1 << *r1)), 1);
644 tmp_to(t0, *r0);
645 all |= (1 << *r0);
647 if (mt & ~all) {
648 for (i = 0; i < N_TMPS; i++)
649 if (mt & ~all & (1 << tmpregs[i]))
650 reg_free(tmpregs[i], all | mt);
652 stat_regs |= mt;
653 tmp_drop(3);
656 static void op_imm(int op, long n)
658 int rd, r1, r2;
659 regs2(op | O_IMM, &rd, &r1, &r2);
660 i_op_imm(op | O_IMM, rd, r1, n);
661 tmp_push(rd);
664 void o_uop(int op)
666 int rd, r1, r2;
667 if (!c_uop(op))
668 return;
669 regs2(op, &rd, &r1, &r2);
670 i_op(op, rd, r1, r2);
671 tmp_push(rd);
674 static int bop_imm(int op, long *n, int swap)
676 struct tmp *t1 = TMP(0);
677 struct tmp *t2 = TMP(1);
678 if (!TMP_NUM(t1) && (!swap || !TMP_NUM(t2)))
679 return 1;
680 *n = TMP_NUM(t1) ? t1->addr : t2->addr;
681 if (!i_imm(op, *n))
682 return 1;
683 if (!TMP_NUM(t1))
684 o_tmpswap();
685 tmp_drop(1);
686 return 0;
689 static void bin_op(int op, int swap)
691 int rd, r1, r2;
692 long n;
693 if (!bop_imm(op, &n, swap)) {
694 regs2(op | O_IMM, &rd, &r1, &r2);
695 i_op_imm(op, rd, r1, n);
696 } else {
697 regs2(op, &rd, &r1, &r2);
698 i_op(op, rd, r1, r2);
700 tmp_push(rd);
703 static int log2a(unsigned long n)
705 int i = 0;
706 for (i = 0; i < LONGSZ * 8; i++)
707 if (n & (1u << i))
708 break;
709 if (i == LONGSZ * 8 || !(n >> (i + 1)))
710 return i;
711 return -1;
714 /* optimized version of mul/div/mod for powers of two */
715 static int mul_2(int op)
717 struct tmp *t1 = TMP(0);
718 struct tmp *t2 = TMP(1);
719 long n;
720 int p;
721 if ((op & 0xff) == O_MUL && t2->loc == LOC_NUM && !t2->bt)
722 o_tmpswap();
723 if (t1->loc != LOC_NUM || t1->bt)
724 return 1;
725 n = t1->addr;
726 p = log2a(n);
727 if (n && p == -1)
728 return 1;
729 if ((op & 0xff) == O_MUL) {
730 tmp_drop(1);
731 if (n == 1)
732 return 0;
733 if (n == 0) {
734 tmp_drop(1);
735 o_num(0);
736 return 0;
738 op_imm(O_SHL, p);
739 return 0;
741 if (op == O_DIV) {
742 tmp_drop(1);
743 if (n == 1)
744 return 0;
745 op_imm((op & O_SIGNED) | O_SHR, p);
746 return 0;
748 if (op == O_MOD) {
749 tmp_drop(1);
750 if (n == 1) {
751 tmp_drop(1);
752 o_num(0);
753 return 0;
755 op_imm(O_ZX, p);
756 return 0;
758 return 1;
761 void o_bop(int op)
763 if (!c_bop(op))
764 return;
765 if ((op & 0xf0) == 0x00) /* add */
766 bin_op(op, (op & 0xff) != O_SUB);
767 if ((op & 0xf0) == 0x10) /* shx */
768 bin_op(op, 0);
769 if ((op & 0xf0) == 0x20) { /* mul */
770 if (!mul_2(op))
771 return;
772 bin_op(op, (op & 0xff) == O_MUL);
774 if ((op & 0xf0) == 0x30)
775 bin_op(op, (op & 0xff) == O_EQ || (op & 0xff) == O_NEQ);
778 void o_memcpy(void)
780 int r0, r1, r2;
781 regs3(O_MCPY, &r0, &r1, &r2);
782 i_memcpy(r0, r1, r2);
785 void o_memset(void)
787 int r0, r1, r2;
788 regs3(O_MSET, &r0, &r1, &r2);
789 i_memset(r0, r1, r2);
792 void o_cast(unsigned bt)
794 struct tmp *t = TMP(0);
795 if (!t->bt && t->loc == LOC_NUM) {
796 num_cast(t, bt);
797 return;
799 if (BT_SZ(bt) != LONGSZ)
800 op_imm(MOVXX(bt), BT_SZ(bt) * 8);
803 static void jxz(int id, int z)
805 int r = reg_tmp(TMP(0), R_TMPS, 1);
806 tmp_pop(r);
807 jmp_add(id, r, z);
810 void o_jz(int id)
812 jxz(id, 1);
815 void o_jnz(int id)
817 jxz(id, 0);
820 void o_jmp(int id)
822 jmp_add(id, -1, 0);
825 void o_call(int argc, int rets)
827 struct tmp *t;
828 int i;
829 int aregs = MIN(N_ARGS, argc);
830 for (i = 0; i < N_TMPS; i++)
831 if (regs[tmpregs[i]] && regs[tmpregs[i]] - tmps < ntmp - argc)
832 tmp_mem(regs[tmpregs[i]]);
833 if (argc > aregs) {
834 sp_push(LONGSZ * (argc - aregs));
835 for (i = argc - 1; i >= aregs; --i) {
836 int reg = reg_tmp(TMP(0), R_TMPS, 1);
837 tmp_pop(reg);
838 i_save(reg, REG_SP, (i - aregs) * LONGSZ, LONGSZ);
841 for (i = aregs - 1; i >= 0; --i)
842 tmp_to(TMP(aregs - i - 1), argregs[i]);
843 tmp_drop(aregs);
844 t = TMP(0);
845 if (t->loc == LOC_SYM && !t->bt) {
846 i_call(t->sym, t->off);
847 tmp_drop(1);
848 } else {
849 int reg = reg_tmp(t, R_TMPS, 1);
850 tmp_pop(reg);
851 i_call_reg(reg);
853 if (rets)
854 tmp_push(REG_RET);
855 stat_calls++;
858 void o_bsnew(char *name, int size, int global)
860 if (pass1)
861 return;
862 out_sym(name, OUT_BSS | (global ? OUT_GLOB : 0), bsslen, size);
863 bsslen += ALIGN(size, OUT_ALIGNMENT);
866 static char dat_names[NDATS][NAMELEN];
867 static int dat_offs[NDATS];
868 static int ndats;
870 long o_dsnew(char *name, int size, int global)
872 int idx;
873 if (pass1)
874 return dslen;
875 idx = ndats++;
876 if (idx >= NDATS)
877 err("nomem: NDATS reached!\n");
878 strcpy(dat_names[idx], name);
879 dat_offs[idx] = dslen;
880 out_sym(name, OUT_DS | (global ? OUT_GLOB : 0), dslen, size);
881 dslen += ALIGN(size, OUT_ALIGNMENT);
882 return dat_offs[idx];
885 void o_dscpy(long addr, void *buf, int len)
887 memcpy(ds + addr, buf, len);
890 static int dat_off(char *name)
892 int i;
893 for (i = 0; i < ndats; i++)
894 if (!strcmp(name, dat_names[i]))
895 return dat_offs[i];
896 return 0;
899 void o_dsset(char *name, int off, unsigned bt)
901 struct tmp *t = TMP(0);
902 int sym_off = dat_off(name) + off;
903 if (pass1) {
904 tmp_drop(1);
905 return;
907 if (t->loc == LOC_NUM && !t->bt) {
908 num_cast(t, bt);
909 memcpy(ds + sym_off, &t->addr, BT_SZ(bt));
911 if (t->loc == LOC_SYM && !t->bt) {
912 out_rel(t->sym, OUT_DS, sym_off);
913 memcpy(ds + sym_off, &t->off, BT_SZ(bt));
915 tmp_drop(1);
918 void o_write(int fd)
920 i_done();
921 out_write(fd, cs, cslen, ds, dslen);
924 static void func_reset(void)
926 int i;
927 int argaddr = 0;
928 memset(regs, 0, sizeof(regs));
929 sp = i_sp();
930 sp_max = sp;
931 ntmp = 0;
932 sp_tmp = -1;
933 nlabels = 0;
934 njmps = 0;
935 nlocals = 0;
936 stat_calls = 0;
937 stat_tmps = 0;
938 stat_regs = 1 << REG_RET;
939 for (i = 0; i < func_argc; i++) {
940 localoff[nlocals++] = i_args() + argaddr;
941 if (i >= N_ARGS || r_sargs() & (1 << argregs[i]))
942 argaddr += LONGSZ;
946 void o_func_beg(char *name, int argc, int global, int varg)
948 func_argc = argc;
949 func_varg = varg;
950 func_beg = cslen;
951 pass1 = 0;
952 pass2 = 0;
953 tmp_mask = N_TMPS > 6 ? R_TMPS & ~R_SAVED : R_TMPS;
954 r_func(argc, varg);
955 out_sym(name, (global ? OUT_GLOB : 0) | OUT_CS, cslen, 0);
956 i_prolog(argc, varg, r_sargs(), tmp_mask & R_SAVED, 1, 1);
957 func_reset();
960 void o_pass1(void)
962 pass1 = 1;
965 void o_pass2(void)
967 int locregs, leaf;
968 int initfp, subsp, sregs;
969 int i;
970 o_label(0);
971 jmp_fill();
972 leaf = !stat_calls;
973 cslen = func_beg;
974 locregs = r_alloc(leaf, stat_regs);
975 subsp = nlocals > locregs || !leaf;
976 initfp = subsp || stat_tmps || func_argc > N_ARGS;
977 sregs = (r_lregs() | stat_regs) & R_SAVED;
978 tmp_mask = stat_regs;
979 pass1 = 0;
980 pass2 = 1;
981 i_prolog(func_argc, func_varg, r_sargs(), sregs, initfp, subsp);
982 func_reset();
983 for (i = 0; i < MIN(func_argc, N_ARGS); i++)
984 if (r_regmap(i) >= 0 && r_regmap(i) != argregs[i])
985 i_mov(r_regmap(i), argregs[i]);
986 for (i = N_ARGS; i < func_argc; i++)
987 if (r_regmap(i) >= 0)
988 i_load(r_regmap(i), REG_FP, localoff[i], LONGSZ);
991 void o_func_end(void)
993 o_label(0);
994 jmp_fill();
995 i_epilog(sp_max);