out: exit if there is no room for more relocations or symbols
[neatcc.git] / gen.c
blobc394c12ded755f942f697764c069ea8c1f963e25
1 /* neatcc code generation */
2 #include <stdlib.h>
3 #include <stdio.h>
4 #include <string.h>
5 #include "gen.h"
6 #include "mem.h"
7 #include "ncc.h"
8 #include "out.h"
9 #include "reg.h"
10 #include "tok.h"
12 /* variable location */
13 #define LOC_REG 0x01
14 #define LOC_MEM 0x02
15 #define LOC_NUM 0x04
16 #define LOC_SYM 0x08
17 #define LOC_LOCAL 0x10
19 #define MIN(a, b) ((a) < (b) ? (a) : (b))
20 #define ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1))
22 char cs[SECLEN]; /* code segment */
23 int cslen;
24 static struct mem ds; /* data segment */
25 static long bsslen; /* bss segment size */
27 static long sp; /* stack pointer offset from R_RBP */
28 static long sp_max; /* maximum stack pointer offset */
29 static long sp_tmp; /* sp for the first tmp on the stack */
30 static int localoff[NLOCALS]; /* the offset of locals on the stack */
31 static int nlocals; /* number of locals */
33 /* function info */
34 static int func_beg;
35 static int func_argc;
36 static int func_varg;
38 /* function statistics */
39 int pass1; /* collect statistics; 1st pass */
40 static int stat_calls; /* # of function calls */
41 static int stat_tmps; /* # of stack temporaries */
42 static int stat_regs; /* mask of used registers */
44 /* optimization info */
45 static int pass2; /* use the collected statistics in the 1st pass */
46 static int tmp_mask; /* registers that can be used for tmps */
48 /* register allocation for locals */
49 #define TMP_ISLREG(t) (!(t)->bt && (t)->loc == LOC_LOCAL && r_regmap((t)->id) >= 0)
50 #define TMP_LREG(t) (r_regmap((t)->id))
52 #define TMP(i) (((i) < ntmp) ? &tmps[ntmp - 1 - (i)] : NULL)
54 static struct tmp {
55 long addr;
56 char sym[NAMELEN];
57 long off; /* offset from a symbol or a local */
58 unsigned loc; /* variable location */
59 unsigned bt; /* type of address; zero when not a pointer */
60 int id; /* local variable id */
61 } tmps[NTMPS];
62 static int ntmp;
64 static struct tmp *regs[N_REGS];
66 /* labels and jmps */
67 static long labels[NJMPS];
68 static int nlabels;
69 static long jmp_loc[NJMPS];
70 static int jmp_goal[NJMPS];
71 static int jmp_len[NJMPS];
72 static int njmps;
74 void o_label(int id)
76 r_label(id);
77 if (id >= NJMPS)
78 err("nomem: NJMPS reached!\n");
79 if (id > nlabels)
80 nlabels = id + 1;
81 labels[id] = cslen;
84 /* the number of bytes needed for holding jmp displacement */
85 static int jmp_sz(int id)
87 long n = jmp_len[id] > 0 ? jmp_len[id] : -jmp_len[id];
88 if (!pass2)
89 return 4;
90 if (n < 0x70)
91 return n == 0 ? 0 : 1;
92 return n < 0x7000 ? 2 : 4;
95 static void jmp_add(int id, int rn, int z)
97 r_jmp(id);
98 if (njmps >= NJMPS)
99 err("nomem: NJMPS reached!\n");
100 i_jmp(rn, z, jmp_sz(njmps));
101 jmp_loc[njmps] = cslen;
102 jmp_goal[njmps] = id;
103 njmps++;
106 static void jmp_fill(void)
108 int i;
109 for (i = 0; i < njmps; i++)
110 jmp_len[i] = i_fill(jmp_loc[i], labels[jmp_goal[i]], jmp_sz(i));
113 /* generating code */
115 void os(void *s, int n)
117 while (n--)
118 cs[cslen++] = *(char *) (s++);
121 void oi(long n, int l)
123 while (l--) {
124 cs[cslen++] = n;
125 n >>= 8;
129 static long sp_push(int sz)
131 sp -= ALIGN(sz, LONGSZ);
132 if (sp < sp_max)
133 sp_max = sp;
134 return sp;
137 static void tmp_mem(struct tmp *tmp)
139 int src = tmp->addr;
140 if (tmp->loc != LOC_REG || (1 << src) & r_lregs())
141 return;
142 if (sp_tmp == -1)
143 sp_tmp = sp;
144 tmp->addr = sp_push(LONGSZ);
145 i_save(src, REG_FP, tmp->addr, LONGSZ);
146 stat_tmps++;
147 regs[src] = NULL;
148 tmp->loc = LOC_MEM;
151 static void num_cast(struct tmp *t, unsigned bt)
153 if (!(bt & BT_SIGNED) && BT_SZ(bt) != LONGSZ)
154 t->addr &= ((1l << (long) (BT_SZ(bt) * 8)) - 1);
155 if (bt & BT_SIGNED && BT_SZ(bt) != LONGSZ &&
156 t->addr > (1l << (BT_SZ(bt) * 8 - 1)))
157 t->addr = -((1l << (BT_SZ(bt) * 8)) - t->addr);
160 static void tmp_reg(struct tmp *tmp, int dst, int deref)
162 int bt = tmp->bt;
163 if (!tmp->bt)
164 deref = 0;
165 if (deref)
166 tmp->bt = 0;
167 if (tmp->loc == LOC_NUM) {
168 i_num(dst, tmp->addr);
169 tmp->addr = dst;
170 regs[dst] = tmp;
171 tmp->loc = LOC_REG;
173 if (tmp->loc == LOC_SYM) {
174 i_sym(dst, tmp->sym, tmp->off);
175 tmp->addr = dst;
176 regs[dst] = tmp;
177 tmp->loc = LOC_REG;
179 if (tmp->loc == LOC_REG) {
180 if (deref)
181 i_load(dst, tmp->addr, 0, bt);
182 else if (dst != tmp->addr)
183 i_mov(dst, tmp->addr);
184 regs[tmp->addr] = NULL;
186 if (tmp->loc == LOC_LOCAL) {
187 if (deref)
188 r_read(tmp->id);
189 else
190 r_addr(tmp->id);
191 if (deref)
192 i_load(dst, REG_FP, tmp->addr + tmp->off, bt);
193 else
194 i_op_imm(O_ADD, dst, REG_FP, tmp->addr + tmp->off);
196 if (tmp->loc == LOC_MEM) {
197 i_load(dst, REG_FP, tmp->addr, LONGSZ);
198 if (deref)
199 i_load(dst, dst, 0, bt);
201 tmp->addr = dst;
202 stat_regs |= 1 << dst;
203 regs[dst] = tmp;
204 tmp->loc = LOC_REG;
207 /* empty the given register, but never touch the registers in rsrvd mask */
208 static void reg_free(int reg, int rsrvd)
210 int i;
211 if (!regs[reg])
212 return;
213 rsrvd |= ~tmp_mask;
214 for (i = 0; i < N_TMPS; i++)
215 if (!regs[tmpregs[i]] && ~rsrvd & (1 << tmpregs[i])) {
216 tmp_reg(regs[reg], tmpregs[i], 0);
217 return;
219 tmp_mem(regs[reg]);
222 static void reg_for(int reg, struct tmp *t)
224 if (regs[reg] && regs[reg] != t)
225 reg_free(reg, 0);
228 static void tmp_mv(struct tmp *t, int reg)
230 reg_for(reg, t);
231 tmp_reg(t, reg, 0);
234 static void tmp_to(struct tmp *t, int reg)
236 reg_for(reg, t);
237 if (t->loc == LOC_LOCAL && TMP_ISLREG(t)) {
238 t->loc = LOC_REG;
239 t->addr = TMP_LREG(t);
240 t->bt = 0;
242 tmp_reg(t, reg, 1);
245 static void tmp_drop(int n)
247 int i;
248 for (i = ntmp - n; i < ntmp; i++)
249 if (tmps[i].loc == LOC_REG)
250 regs[tmps[i].addr] = NULL;
251 ntmp -= n;
254 static void tmp_pop(int reg)
256 struct tmp *t = TMP(0);
257 tmp_to(t, reg);
258 tmp_drop(1);
261 static struct tmp *tmp_new(void)
263 return &tmps[ntmp++];
266 static void tmp_push(int reg)
268 struct tmp *t = tmp_new();
269 t->addr = reg;
270 t->bt = 0;
271 stat_regs |= 1 << reg;
272 t->loc = LOC_REG;
273 regs[reg] = t;
276 void o_local(long addr)
278 struct tmp *t = tmp_new();
279 t->addr = localoff[addr];
280 t->id = addr;
281 t->loc = LOC_LOCAL;
282 t->bt = 0;
283 t->off = 0;
286 void o_num(long num)
288 struct tmp *t = tmp_new();
289 t->addr = num;
290 t->bt = 0;
291 t->loc = LOC_NUM;
294 void o_sym(char *name)
296 struct tmp *t = tmp_new();
297 strcpy(t->sym, name);
298 t->loc = LOC_SYM;
299 t->bt = 0;
300 t->off = 0;
303 void o_tmpdrop(int n)
305 if (n == -1 || n > ntmp)
306 n = ntmp;
307 tmp_drop(n);
308 if (!ntmp) {
309 if (sp_tmp != -1)
310 sp = sp_tmp;
311 sp_tmp = -1;
315 /* make sure tmps remain intact after a conditional expression */
316 void o_fork(void)
318 int i;
319 for (i = 0; i < ntmp - 1; i++)
320 tmp_mem(&tmps[i]);
323 void o_forkpush(void)
325 tmp_pop(REG_FORK);
328 void o_forkjoin(void)
330 tmp_push(REG_FORK);
333 void o_tmpswap(void)
335 struct tmp *t1 = TMP(0);
336 struct tmp *t2 = TMP(1);
337 struct tmp t;
338 memcpy(&t, t1, sizeof(t));
339 memcpy(t1, t2, sizeof(t));
340 memcpy(t2, &t, sizeof(t));
341 if (t1->loc == LOC_REG)
342 regs[t1->addr] = t1;
343 if (t2->loc == LOC_REG)
344 regs[t2->addr] = t2;
347 static int reg_get(int mask)
349 int i;
350 mask &= tmp_mask;
351 for (i = 0; i < N_TMPS; i++)
352 if ((1 << tmpregs[i]) & mask && !regs[tmpregs[i]]) {
353 stat_regs |= 1 << tmpregs[i];
354 return tmpregs[i];
356 for (i = 0; i < N_TMPS; i++)
357 if ((1 << tmpregs[i]) & mask) {
358 reg_free(tmpregs[i], 0);
359 stat_regs |= 1 << tmpregs[i];
360 return tmpregs[i];
362 die("reg_get: out of registers!\n");
363 return 0;
366 static int reg_tmp(struct tmp *t, int mask, int readonly)
368 if (t->loc == LOC_REG && (mask & (1 << t->addr)))
369 if (!(r_lregs() & (1 << t->addr)) || (readonly && !t->bt))
370 return t->addr;
371 return reg_get(mask);
374 static int reg_tmpn(struct tmp *t, int notmask, int readonly)
376 if (t->loc == LOC_REG && !(notmask & (1 << t->addr)))
377 if (!(r_lregs() & (1 << t->addr)) || (readonly && !t->bt))
378 return t->addr;
379 return reg_get(~notmask);
382 static void tmp_copy(struct tmp *t1)
384 struct tmp *t2 = tmp_new();
385 memcpy(t2, t1, sizeof(*t1));
386 if (!(t1->loc & (LOC_REG | LOC_MEM)))
387 return;
388 if (t1->loc == LOC_MEM) {
389 tmp_mv(t2, reg_get(R_TMPS));
390 } else if (t1->loc == LOC_REG) {
391 t2->addr = reg_tmpn(t2, 1 << t1->addr, 0);
392 i_mov(t2->addr, t1->addr);
393 regs[t2->addr] = t2;
394 stat_regs |= 1 << t2->addr;
398 void o_tmpcopy(void)
400 tmp_copy(TMP(0));
403 void o_deref(unsigned bt)
405 struct tmp *t = TMP(0);
406 if (TMP_ISLREG(t)) {
407 t->loc = LOC_REG;
408 t->addr = TMP_LREG(t);
409 } else {
410 if (t->bt)
411 tmp_to(t, reg_tmp(t, R_TMPS, 0));
412 t->bt = bt;
416 void o_load(void)
418 struct tmp *t = TMP(0);
419 tmp_to(t, reg_tmp(t, R_TMPS, 0));
422 #define TMP_NUM(t) ((t)->loc == LOC_NUM && !(t)->bt)
423 #define LOCAL_PTR(t) ((t)->loc == LOC_LOCAL && !(t)->bt)
424 #define SYM_PTR(t) ((t)->loc == LOC_SYM && !(t)->bt)
426 int o_popnum(long *c)
428 struct tmp *t = TMP(0);
429 if (!TMP_NUM(t))
430 return 1;
431 *c = t->addr;
432 tmp_drop(1);
433 return 0;
436 void o_ret(int rets)
438 if (rets)
439 tmp_pop(REG_RET);
440 else
441 i_num(REG_RET, 0);
442 o_jmp(0);
445 long o_mklocal(int sz)
447 r_mk(sz);
448 localoff[nlocals] = sp_push(ALIGN(sz, LONGSZ));
449 return nlocals++;
452 void o_rmlocal(long addr, int sz)
454 r_rm(addr);
457 long o_arg2loc(int i)
459 return i;
462 #define MOVXX(bt) ((BT_SZ(bt) == LONGSZ ? O_MOV : ((bt) & BT_SIGNED ? O_SX : O_ZX)))
464 void o_assign(unsigned bt)
466 struct tmp *t1 = TMP(0);
467 struct tmp *t2 = TMP(1);
468 int r1 = reg_tmp(t1, BT_SZ(bt) > 1 ? R_TMPS : R_BYTE, 1);
469 int r2 = reg_tmpn(t2, 1 << r1, 1);
470 int off = 0;
471 tmp_to(t1, r1);
472 if (TMP_ISLREG(t2)) {
473 i_op_imm(MOVXX(bt), TMP_LREG(t2), r1, BT_SZ(bt) * 8);
474 goto done;
476 if (t2->bt)
477 tmp_to(t2, r2);
478 if (t2->loc == LOC_LOCAL) {
479 r2 = REG_FP;
480 off = t2->addr + t2->off;
481 r_read(t2->id);
482 } else {
483 tmp_to(t2, r2);
485 i_save(r1, r2, off, bt);
486 done:
487 tmp_drop(2);
488 tmp_push(r1);
491 static long cu(int op, long i)
493 switch (op & 0xff) {
494 case O_NEG:
495 return -i;
496 case O_NOT:
497 return ~i;
498 case O_LNOT:
499 return !i;
501 return 0;
504 static int c_uop(int op)
506 struct tmp *t1 = TMP(0);
507 if (!TMP_NUM(t1))
508 return 1;
509 tmp_drop(1);
510 o_num(cu(op, t1->addr));
511 return 0;
514 static long cb(int op, long a, long b)
516 switch (op & 0xff) {
517 case O_ADD:
518 return a + b;
519 case O_SUB:
520 return a - b;
521 case O_AND:
522 return a & b;
523 case O_OR:
524 return a | b;
525 case O_XOR:
526 return a ^ b;
527 case O_MUL:
528 return a * b;
529 case O_DIV:
530 return a / b;
531 case O_MOD:
532 return a % b;
533 case O_SHL:
534 return a << b;
535 case O_SHR:
536 if (op & O_SIGNED)
537 return a >> b;
538 else
539 return (unsigned long) a >> b;
540 case O_LT:
541 return a < b;
542 case O_GT:
543 return a > b;
544 case O_LE:
545 return a <= b;
546 case O_GE:
547 return a >= b;
548 case O_EQ:
549 return a == b;
550 case O_NEQ:
551 return a != b;
553 return 0;
556 static int c_bop(int op)
558 struct tmp *t1 = TMP(0);
559 struct tmp *t2 = TMP(1);
560 int locs = LOCAL_PTR(t1) + LOCAL_PTR(t2);
561 int syms = SYM_PTR(t1) + SYM_PTR(t2);
562 int nums = TMP_NUM(t1) + TMP_NUM(t2);
563 if (syms + locs == 2 || syms + nums + locs != 2)
564 return 1;
565 if (nums == 1)
566 if ((op & 0xff) != O_ADD && ((op & 0xff) != O_SUB || TMP_NUM(t2)))
567 return 1;
568 if (nums == 1) {
569 long o1 = TMP_NUM(t1) ? t1->addr : t1->off;
570 long o2 = TMP_NUM(t2) ? t2->addr : t2->off;
571 long ret = cb(op, o2, o1);
572 if (!TMP_NUM(t1))
573 o_tmpswap();
574 if (t2->loc == LOC_LOCAL)
575 r_addr(t2->id);
576 t2->off = ret;
577 tmp_drop(1);
578 } else {
579 long ret = cb(op, t2->addr, t1->addr);
580 tmp_drop(2);
581 o_num(ret);
583 return 0;
586 /* allocate registers for the given binary or unary instruction */
587 static void regs2(int op, int *rd, int *r1, int *r2)
589 int md, m1, m2, mt;
590 int all = 0;
591 int i;
592 i_reg(op, &md, &m1, &m2, &mt);
593 if (m2) {
594 struct tmp *t2 = TMP(0);
595 *r2 = reg_tmp(t2, m2, 1);
596 tmp_to(t2, *r2);
597 all |= (1 << *r2);
599 if (m1) {
600 struct tmp *t1 = TMP(m2 ? 1 : 0);
601 *r1 = reg_tmp(t1, m1 & ~all, md ? 1 : 0);
602 tmp_to(t1, *r1);
603 all |= (1 << *r1);
605 if (md) {
606 if (m2 && md & tmp_mask & (1 << *r2))
607 *rd = *r2;
608 else if (m1 && md & tmp_mask & (1 << *r1))
609 *rd = *r1;
610 else
611 *rd = reg_get(md & ~all);
612 all |= (1 << *rd);
613 } else {
614 *rd = *r1;
616 if (mt & ~all) {
617 for (i = 0; i < N_TMPS; i++)
618 if (mt & ~all & (1 << tmpregs[i]))
619 reg_free(tmpregs[i], all | mt);
621 stat_regs |= mt;
622 tmp_drop(m2 ? 2 : 1);
625 /* allocate registers for a 3 operand instruction */
626 static void regs3(int op, int *r0, int *r1, int *r2)
628 int m0, m1, m2, mt;
629 struct tmp *t0 = TMP(2);
630 struct tmp *t1 = TMP(1);
631 struct tmp *t2 = TMP(0);
632 int all = 0;
633 int i;
634 i_reg(op, &m0, &m1, &m2, &mt);
635 if (m2) {
636 *r2 = reg_tmp(t2, m2, 1);
637 tmp_to(t2, *r2);
638 all |= (1 << *r2);
640 if (m1) {
641 *r1 = reg_tmp(t1, m1 & ~(1 << *r2), 1);
642 tmp_to(t1, *r1);
643 all |= (1 << *r1);
645 if (m0) {
646 *r0 = reg_tmp(t0, m0 & ~((1 << *r2) | (1 << *r1)), 1);
647 tmp_to(t0, *r0);
648 all |= (1 << *r0);
650 if (mt & ~all) {
651 for (i = 0; i < N_TMPS; i++)
652 if (mt & ~all & (1 << tmpregs[i]))
653 reg_free(tmpregs[i], all | mt);
655 stat_regs |= mt;
656 tmp_drop(3);
659 static void op_imm(int op, long n)
661 int rd, r1, r2;
662 regs2(op | O_IMM, &rd, &r1, &r2);
663 i_op_imm(op | O_IMM, rd, r1, n);
664 tmp_push(rd);
667 void o_uop(int op)
669 int rd, r1, r2;
670 if (!c_uop(op))
671 return;
672 regs2(op, &rd, &r1, &r2);
673 i_op(op, rd, r1, r2);
674 tmp_push(rd);
677 static int bop_imm(int op, long *n, int swap)
679 struct tmp *t1 = TMP(0);
680 struct tmp *t2 = TMP(1);
681 if (!TMP_NUM(t1) && (!swap || !TMP_NUM(t2)))
682 return 1;
683 *n = TMP_NUM(t1) ? t1->addr : t2->addr;
684 if (!i_imm(op, *n))
685 return 1;
686 if (!TMP_NUM(t1))
687 o_tmpswap();
688 tmp_drop(1);
689 return 0;
692 static void bin_op(int op, int swap)
694 int rd, r1, r2;
695 long n;
696 if (!bop_imm(op, &n, swap)) {
697 regs2(op | O_IMM, &rd, &r1, &r2);
698 i_op_imm(op, rd, r1, n);
699 } else {
700 regs2(op, &rd, &r1, &r2);
701 i_op(op, rd, r1, r2);
703 tmp_push(rd);
706 static int log2a(unsigned long n)
708 int i = 0;
709 for (i = 0; i < LONGSZ * 8; i++)
710 if (n & (1u << i))
711 break;
712 if (i == LONGSZ * 8 || !(n >> (i + 1)))
713 return i;
714 return -1;
717 /* optimized version of mul/div/mod for powers of two */
718 static int mul_2(int op)
720 struct tmp *t1 = TMP(0);
721 struct tmp *t2 = TMP(1);
722 long n;
723 int p;
724 if ((op & 0xff) == O_MUL && t2->loc == LOC_NUM && !t2->bt)
725 o_tmpswap();
726 if (t1->loc != LOC_NUM || t1->bt)
727 return 1;
728 n = t1->addr;
729 p = log2a(n);
730 if (n && p == -1)
731 return 1;
732 if ((op & 0xff) == O_MUL) {
733 tmp_drop(1);
734 if (n == 1)
735 return 0;
736 if (n == 0) {
737 tmp_drop(1);
738 o_num(0);
739 return 0;
741 op_imm(O_SHL, p);
742 return 0;
744 if (op == O_DIV) {
745 tmp_drop(1);
746 if (n == 1)
747 return 0;
748 op_imm((op & O_SIGNED) | O_SHR, p);
749 return 0;
751 if (op == O_MOD) {
752 tmp_drop(1);
753 if (n == 1) {
754 tmp_drop(1);
755 o_num(0);
756 return 0;
758 op_imm(O_ZX, p);
759 return 0;
761 return 1;
764 void o_bop(int op)
766 if (!c_bop(op))
767 return;
768 if ((op & 0xf0) == 0x00) /* add */
769 bin_op(op, (op & 0xff) != O_SUB);
770 if ((op & 0xf0) == 0x10) /* shx */
771 bin_op(op, 0);
772 if ((op & 0xf0) == 0x20) { /* mul */
773 if (!mul_2(op))
774 return;
775 bin_op(op, (op & 0xff) == O_MUL);
777 if ((op & 0xf0) == 0x30)
778 bin_op(op, (op & 0xff) == O_EQ || (op & 0xff) == O_NEQ);
781 void o_memcpy(void)
783 int r0, r1, r2;
784 regs3(O_MCPY, &r0, &r1, &r2);
785 i_memcpy(r0, r1, r2);
788 void o_memset(void)
790 int r0, r1, r2;
791 regs3(O_MSET, &r0, &r1, &r2);
792 i_memset(r0, r1, r2);
795 void o_cast(unsigned bt)
797 struct tmp *t = TMP(0);
798 if (!t->bt && t->loc == LOC_NUM) {
799 num_cast(t, bt);
800 return;
802 if (BT_SZ(bt) != LONGSZ)
803 op_imm(MOVXX(bt), BT_SZ(bt) * 8);
806 static void jxz(int id, int z)
808 int r = reg_tmp(TMP(0), R_TMPS, 1);
809 tmp_pop(r);
810 jmp_add(id, r, z);
813 void o_jz(int id)
815 jxz(id, 1);
818 void o_jnz(int id)
820 jxz(id, 0);
823 void o_jmp(int id)
825 jmp_add(id, -1, 0);
828 void o_call(int argc, int rets)
830 struct tmp *t;
831 int i;
832 int aregs = MIN(N_ARGS, argc);
833 for (i = 0; i < N_TMPS; i++)
834 if (regs[tmpregs[i]] && regs[tmpregs[i]] - tmps < ntmp - argc)
835 tmp_mem(regs[tmpregs[i]]);
836 if (argc > aregs) {
837 sp_push(LONGSZ * (argc - aregs));
838 for (i = argc - 1; i >= aregs; --i) {
839 int reg = reg_tmp(TMP(0), R_TMPS, 1);
840 tmp_pop(reg);
841 i_save(reg, REG_SP, (i - aregs) * LONGSZ, LONGSZ);
844 for (i = aregs - 1; i >= 0; --i)
845 tmp_to(TMP(aregs - i - 1), argregs[i]);
846 tmp_drop(aregs);
847 t = TMP(0);
848 if (t->loc == LOC_SYM && !t->bt) {
849 i_call(t->sym, t->off);
850 tmp_drop(1);
851 } else {
852 int reg = reg_tmp(t, R_TMPS, 1);
853 tmp_pop(reg);
854 i_call_reg(reg);
856 if (rets)
857 tmp_push(REG_RET);
858 stat_calls++;
861 void o_bsnew(char *name, int size, int global)
863 if (pass1)
864 return;
865 out_sym(name, OUT_BSS | (global ? OUT_GLOB : 0), bsslen, size);
866 bsslen += ALIGN(size, OUT_ALIGNMENT);
869 static char dat_names[NDATS][NAMELEN];
870 static int dat_offs[NDATS];
871 static int ndats;
873 long o_dsnew(char *name, int size, int global)
875 int idx;
876 if (pass1)
877 return mem_len(&ds);
878 idx = ndats++;
879 if (idx >= NDATS)
880 err("nomem: NDATS reached!\n");
881 strcpy(dat_names[idx], name);
882 dat_offs[idx] = mem_len(&ds);
883 out_sym(name, OUT_DS | (global ? OUT_GLOB : 0), mem_len(&ds), size);
884 mem_putz(&ds, ALIGN(size, OUT_ALIGNMENT));
885 return dat_offs[idx];
888 void o_dscpy(long addr, void *buf, int len)
890 if (!pass1)
891 mem_cpy(&ds, addr, buf, len);
894 static int dat_off(char *name)
896 int i;
897 for (i = 0; i < ndats; i++)
898 if (!strcmp(name, dat_names[i]))
899 return dat_offs[i];
900 return 0;
903 void o_dsset(char *name, int off, unsigned bt)
905 struct tmp *t = TMP(0);
906 int sym_off = dat_off(name) + off;
907 if (pass1) {
908 tmp_drop(1);
909 return;
911 if (t->loc == LOC_NUM && !t->bt) {
912 num_cast(t, bt);
913 mem_cpy(&ds, sym_off, &t->addr, BT_SZ(bt));
915 if (t->loc == LOC_SYM && !t->bt) {
916 out_rel(t->sym, OUT_DS, sym_off);
917 mem_cpy(&ds, sym_off, &t->off, BT_SZ(bt));
919 tmp_drop(1);
922 void o_write(int fd)
924 i_done();
925 out_write(fd, cs, cslen, mem_buf(&ds), mem_len(&ds));
928 static void func_reset(void)
930 int i;
931 int argaddr = 0;
932 memset(regs, 0, sizeof(regs));
933 sp = i_sp();
934 sp_max = sp;
935 ntmp = 0;
936 sp_tmp = -1;
937 nlabels = 0;
938 njmps = 0;
939 nlocals = 0;
940 stat_calls = 0;
941 stat_tmps = 0;
942 stat_regs = 1 << REG_RET;
943 for (i = 0; i < func_argc; i++) {
944 localoff[nlocals++] = i_args() + argaddr;
945 if (i >= N_ARGS || r_sargs() & (1 << argregs[i]))
946 argaddr += LONGSZ;
950 void o_func_beg(char *name, int argc, int global, int varg)
952 func_argc = argc;
953 func_varg = varg;
954 func_beg = cslen;
955 pass1 = 0;
956 pass2 = 0;
957 tmp_mask = N_TMPS > 6 ? R_TMPS & ~R_SAVED : R_TMPS;
958 r_func(argc, varg);
959 out_sym(name, (global ? OUT_GLOB : 0) | OUT_CS, cslen, 0);
960 i_prolog(argc, varg, r_sargs(), tmp_mask & R_SAVED, 1, 1);
961 func_reset();
964 void o_pass1(void)
966 pass1 = 1;
969 void o_pass2(void)
971 int locregs, leaf;
972 int initfp, subsp, sregs;
973 int i;
974 o_label(0);
975 jmp_fill();
976 leaf = !stat_calls;
977 cslen = func_beg;
978 locregs = r_alloc(leaf, stat_regs);
979 subsp = nlocals > locregs || !leaf;
980 initfp = subsp || stat_tmps || func_argc > N_ARGS;
981 sregs = (r_lregs() | stat_regs) & R_SAVED;
982 tmp_mask = stat_regs;
983 pass1 = 0;
984 pass2 = 1;
985 i_prolog(func_argc, func_varg, r_sargs(), sregs, initfp, subsp);
986 func_reset();
987 for (i = 0; i < MIN(func_argc, N_ARGS); i++)
988 if (r_regmap(i) >= 0 && r_regmap(i) != argregs[i])
989 i_mov(r_regmap(i), argregs[i]);
990 for (i = N_ARGS; i < func_argc; i++)
991 if (r_regmap(i) >= 0)
992 i_load(r_regmap(i), REG_FP, localoff[i], LONGSZ);
995 void o_func_end(void)
997 o_label(0);
998 jmp_fill();
999 i_epilog(sp_max);