gen: rename FORK_REG to REG_FORK
[neatcc/cc.git] / gen.c
blob1c5b8647719e6b419e29fa41f18650e604b4bcca
1 #include <stdlib.h>
2 #include <stdio.h>
3 #include <string.h>
4 #include "gen.h"
5 #include "out.h"
6 #include "tok.h"
8 #define LOC_REG 0x01
9 #define LOC_MEM 0x02
10 #define LOC_NUM 0x04
11 #define LOC_SYM 0x08
12 #define LOC_LOCAL 0x10
14 #define NREGS 16
16 #define REG_PC 15 /* program counter */
17 #define REG_LR 14 /* link register */
18 #define REG_SP 13 /* stack pointer */
19 #define REG_TMP 12 /* temporary register */
20 #define REG_FP 11 /* frame pointer register */
21 #define REG_DP 10 /* data pointer register */
22 #define REG_RET 0 /* returned value register */
23 #define REG_FORK 0 /* result of conditional branches */
25 #define MIN(a, b) ((a) < (b) ? (a) : (b))
26 #define ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1))
28 static char cs[SECSIZE]; /* code segment */
29 static int cslen;
30 static char ds[SECSIZE]; /* data segment */
31 static int dslen;
32 static long bsslen; /* bss segment size */
34 static int nogen; /* don't generate code */
35 static long sp;
36 static long func_beg;
37 static long maxsp;
39 #define TMP(i) (((i) < ntmp) ? &tmps[ntmp - 1 - (i)] : NULL)
41 static struct tmp {
42 long addr;
43 char sym[NAMELEN];
44 long off; /* offset from a symbol or a local */
45 unsigned loc; /* variable location */
46 unsigned bt; /* type of address; zero when not a pointer */
47 } tmps[MAXTMP];
48 static int ntmp;
50 static int tmpsp;
52 /* arch-specific functions */
53 static void i_ldr(int l, int rd, int rn, int off, int bt);
54 static void i_add(int op, int rd, int rn, int rm);
55 static void i_add_imm(int op, int rd, int rn, long n);
56 static void i_num(int rd, long n);
57 static void i_add_anyimm(int rd, int rn, long n);
58 static void i_mul(int rd, int rn, int rm);
59 static void i_cmp(int op, int rn, int rm);
60 static void i_cmp_imm(int op, int rn, long n);
61 static int i_decodeable(long imm);
62 static void i_set(int op, int rd);
63 static void i_shl(int op, int rd, int rm, int rs);
64 static void i_shl_imm(int op, int rd, int rn, long n);
65 static void i_mov(int rd, int rn);
66 static void i_ldr(int l, int rd, int rn, int off, int bt);
67 static void i_sym(int rd, char *sym, int off);
68 static void i_neg(int rd);
69 static void i_not(int rd);
70 static void i_lnot(int rd);
71 static void i_zx(int rd, int bits);
72 static void i_sx(int rd, int bits);
73 static void i_b(long addr);
74 static void i_b_if(long addr, int rn, int z);
75 static void i_b_fill(long *dst, int diff);
76 static void i_memcpy(int rd, int rs, int rn);
77 static void i_memset(int rd, int rs, int rn);
78 static void i_call_reg(int rd);
79 static void i_call(char *sym, int off);
80 static void i_prolog(void);
81 static void i_epilog(void);
83 static struct tmp *regs[NREGS];
84 static int tmpregs[] = {4, 5, 6, 7, 8, 9, 0, 1, 2, 3};
85 static int argregs[] = {0, 1, 2, 3};
87 #define I_AND 0x00
88 #define I_EOR 0x01
89 #define I_SUB 0x02
90 #define I_RSB 0x03
91 #define I_ADD 0x04
92 #define I_TST 0x08
93 #define I_CMP 0x0a
94 #define I_ORR 0x0c
95 #define I_MOV 0x0d
96 #define I_MVN 0x0f
98 #define MAXRET (1 << 8)
100 static long ret[MAXRET];
101 static int nret;
103 /* output div/mod functions */
104 static int putdiv = 0;
106 static void os(void *s, int n)
108 memcpy(cs + cslen, s, n);
109 cslen += n;
112 static void oi(long n)
114 if (nogen)
115 return;
116 *(int *) (cs + cslen) = n;
117 cslen += 4;
120 static long sp_push(int size)
122 sp += size;
123 if (sp > maxsp)
124 maxsp = sp;
125 return sp;
128 static void tmp_mem(struct tmp *tmp)
130 int src = tmp->addr;
131 if (!(tmp->loc == LOC_REG))
132 return;
133 if (tmpsp == -1)
134 tmpsp = sp;
135 tmp->addr = -sp_push(LONGSZ);
136 i_ldr(0, src, REG_FP, tmp->addr, LONGSZ);
137 regs[src] = NULL;
138 tmp->loc = LOC_MEM;
141 static void num_cast(struct tmp *t, unsigned bt)
143 if (!(bt & BT_SIGNED) && BT_SZ(bt) != LONGSZ)
144 t->addr &= ((1l << (long) (BT_SZ(bt) * 8)) - 1);
145 if (bt & BT_SIGNED && BT_SZ(bt) != LONGSZ &&
146 t->addr > (1l << (BT_SZ(bt) * 8 - 1)))
147 t->addr = -((1l << (BT_SZ(bt) * 8)) - t->addr);
150 static void tmp_reg(struct tmp *tmp, int dst, int deref)
152 int bt = tmp->bt;
153 if (!tmp->bt)
154 deref = 0;
155 if (deref)
156 tmp->bt = 0;
157 if (tmp->loc == LOC_NUM) {
158 i_num(dst, tmp->addr);
159 tmp->addr = dst;
160 regs[dst] = tmp;
161 tmp->loc = LOC_REG;
163 if (tmp->loc == LOC_SYM) {
164 i_sym(dst, tmp->sym, tmp->off);
165 tmp->addr = dst;
166 regs[dst] = tmp;
167 tmp->loc = LOC_REG;
169 if (tmp->loc == LOC_REG) {
170 if (deref)
171 i_ldr(1, dst, tmp->addr, 0, bt);
172 else if (dst != tmp->addr)
173 i_mov(dst, tmp->addr);
174 regs[tmp->addr] = NULL;
176 if (tmp->loc == LOC_LOCAL) {
177 if (deref)
178 i_ldr(1, dst, REG_FP, tmp->addr + tmp->off, bt);
179 else
180 i_add_anyimm(dst, REG_FP, tmp->addr + tmp->off);
182 if (tmp->loc == LOC_MEM) {
183 i_ldr(1, dst, REG_FP, tmp->addr, LONGSZ);
184 if (deref)
185 i_ldr(1, dst, dst, 0, bt);
187 tmp->addr = dst;
188 regs[dst] = tmp;
189 tmp->loc = LOC_REG;
192 static void reg_free(int reg)
194 int i;
195 if (!regs[reg])
196 return;
197 for (i = 0; i < ARRAY_SIZE(tmpregs); i++)
198 if (!regs[tmpregs[i]]) {
199 tmp_reg(regs[reg], tmpregs[i], 0);
200 return;
202 tmp_mem(regs[reg]);
205 static void reg_for(int reg, struct tmp *t)
207 if (regs[reg] && regs[reg] != t)
208 reg_free(reg);
211 static void tmp_mv(struct tmp *t, int reg)
213 reg_for(reg, t);
214 tmp_reg(t, reg, 0);
217 static void tmp_to(struct tmp *t, int reg)
219 reg_for(reg, t);
220 tmp_reg(t, reg, 1);
223 static void tmp_drop(int n)
225 int i;
226 for (i = ntmp - n; i < ntmp; i++)
227 if (tmps[i].loc == LOC_REG)
228 regs[tmps[i].addr] = NULL;
229 ntmp -= n;
232 static void tmp_pop(int reg)
234 struct tmp *t = TMP(0);
235 tmp_to(t, reg);
236 tmp_drop(1);
239 static struct tmp *tmp_new(void)
241 return &tmps[ntmp++];
244 static void tmp_push(int reg)
246 struct tmp *t = tmp_new();
247 t->addr = reg;
248 t->bt = 0;
249 t->loc = LOC_REG;
250 regs[reg] = t;
253 void o_local(long addr)
255 struct tmp *t = tmp_new();
256 t->addr = -addr;
257 t->loc = LOC_LOCAL;
258 t->bt = 0;
259 t->off = 0;
262 void o_num(long num)
264 struct tmp *t = tmp_new();
265 t->addr = num;
266 t->bt = 0;
267 t->loc = LOC_NUM;
270 void o_sym(char *name)
272 struct tmp *t = tmp_new();
273 strcpy(t->sym, name);
274 t->loc = LOC_SYM;
275 t->bt = 0;
276 t->off = 0;
279 void o_tmpdrop(int n)
281 if (n == -1 || n > ntmp)
282 n = ntmp;
283 tmp_drop(n);
284 if (!ntmp) {
285 if (tmpsp != -1)
286 sp = tmpsp;
287 tmpsp = -1;
291 /* make sure tmps remain intact after a conditional expression */
292 void o_fork(void)
294 int i;
295 for (i = 0; i < ntmp - 1; i++)
296 tmp_mem(&tmps[i]);
299 void o_forkpush(void)
301 tmp_pop(REG_FORK);
304 void o_forkjoin(void)
306 tmp_push(REG_FORK);
309 void o_tmpswap(void)
311 struct tmp *t1 = TMP(0);
312 struct tmp *t2 = TMP(1);
313 struct tmp t;
314 memcpy(&t, t1, sizeof(t));
315 memcpy(t1, t2, sizeof(t));
316 memcpy(t2, &t, sizeof(t));
317 if (t1->loc == LOC_REG)
318 regs[t1->addr] = t1;
319 if (t2->loc == LOC_REG)
320 regs[t2->addr] = t2;
323 static int reg_get(int mask)
325 int i;
326 for (i = 0; i < ARRAY_SIZE(tmpregs); i++)
327 if ((1 << tmpregs[i]) & mask && !regs[tmpregs[i]])
328 return tmpregs[i];
329 for (i = 0; i < ARRAY_SIZE(tmpregs); i++)
330 if ((1 << tmpregs[i]) & mask) {
331 reg_free(tmpregs[i]);
332 return tmpregs[i];
334 return 0;
337 static int reg_fortmp(struct tmp *t, int notmask)
339 if (t->loc == LOC_REG && !(notmask & (1 << t->addr)))
340 return t->addr;
341 return reg_get(~notmask);
344 static void tmp_copy(struct tmp *t1)
346 struct tmp *t2 = tmp_new();
347 memcpy(t2, t1, sizeof(*t1));
348 if (!(t1->loc & (LOC_REG | LOC_MEM)))
349 return;
350 if (t1->loc == LOC_MEM) {
351 tmp_mv(t2, reg_get(~0));
352 } else if (t1->loc == LOC_REG) {
353 t2->addr = reg_fortmp(t2, 1 << t1->addr);
354 i_mov(t2->addr, t1->addr);
355 regs[t2->addr] = t2;
359 void o_tmpcopy(void)
361 tmp_copy(TMP(0));
364 void o_cast(unsigned bt)
366 struct tmp *t = TMP(0);
367 if (!t->bt && t->loc == LOC_NUM) {
368 num_cast(t, bt);
369 return;
371 if (BT_SZ(bt) != LONGSZ) {
372 int reg = reg_fortmp(t, 0);
373 tmp_to(t, reg);
374 if (bt & BT_SIGNED)
375 i_sx(reg, BT_SZ(bt) * 8);
376 else
377 i_zx(reg, BT_SZ(bt) * 8);
381 void o_func_beg(char *name, int argc, int global, int vararg)
383 out_sym(name, (global ? OUT_GLOB : 0) | OUT_CS, cslen, 0);
384 i_prolog();
385 sp = 0;
386 maxsp = sp;
387 ntmp = 0;
388 tmpsp = -1;
389 nret = 0;
390 memset(regs, 0, sizeof(regs));
393 void o_deref(unsigned bt)
395 struct tmp *t = TMP(0);
396 if (t->bt)
397 tmp_to(t, reg_fortmp(t, 0));
398 t->bt = bt;
401 void o_load(void)
403 struct tmp *t = TMP(0);
404 tmp_to(t, reg_fortmp(t, 0));
407 #define TMP_NUM(t) ((t)->loc == LOC_NUM && !(t)->bt)
408 #define LOCAL_PTR(t) ((t)->loc == LOC_LOCAL && !(t)->bt)
409 #define SYM_PTR(t) ((t)->loc == LOC_SYM && !(t)->bt)
411 int o_popnum(long *c)
413 struct tmp *t = TMP(0);
414 if (!TMP_NUM(t))
415 return 1;
416 *c = t->addr;
417 tmp_drop(1);
418 return 0;
421 void o_ret(int rets)
423 if (rets)
424 tmp_pop(REG_RET);
425 else
426 i_num(REG_RET, 0);
427 ret[nret++] = o_jmp(0);
430 void o_func_end(void)
432 int i;
433 for (i = 0; i < nret; i++)
434 o_filljmp(ret[i]);
435 i_epilog();
438 long o_mklocal(int size)
440 return sp_push(ALIGN(size, LONGSZ));
443 void o_rmlocal(long addr, int sz)
445 sp = addr - sz;
448 long o_arg2loc(int i)
450 return -(10 + i) << 2;
453 void o_assign(unsigned bt)
455 struct tmp *t1 = TMP(0);
456 struct tmp *t2 = TMP(1);
457 int r1 = reg_fortmp(t1, 0);
458 int r2 = reg_fortmp(t2, 1 << r1);
459 int off = 0;
460 tmp_to(t1, r1);
461 if (t2->bt)
462 tmp_to(t2, r2);
463 if (t2->loc == LOC_LOCAL) {
464 r2 = REG_FP;
465 off = t2->addr + t2->off;
466 } else {
467 tmp_to(t2, r2);
469 tmp_drop(2);
470 i_ldr(0, r1, r2, off, bt);
471 tmp_push(r1);
474 static long cu(int op, long i)
476 switch (op & 0xff) {
477 case O_NEG:
478 return -i;
479 case O_NOT:
480 return ~i;
481 case O_LNOT:
482 return !i;
484 return 0;
487 static int c_uop(int op)
489 struct tmp *t1 = TMP(0);
490 if (!TMP_NUM(t1))
491 return 1;
492 tmp_drop(1);
493 o_num(cu(op, t1->addr));
494 return 0;
497 static long cb(int op, long a, long b)
499 switch (op & 0xff) {
500 case O_ADD:
501 return a + b;
502 case O_SUB:
503 return a - b;
504 case O_AND:
505 return a & b;
506 case O_OR:
507 return a | b;
508 case O_XOR:
509 return a ^ b;
510 case O_MUL:
511 return a * b;
512 case O_DIV:
513 return a / b;
514 case O_MOD:
515 return a % b;
516 case O_SHL:
517 return a << b;
518 case O_SHR:
519 if (op & O_SIGNED)
520 return a >> b;
521 else
522 return (unsigned long) a >> b;
523 case O_LT:
524 return a < b;
525 case O_GT:
526 return a > b;
527 case O_LE:
528 return a <= b;
529 case O_GE:
530 return a >= b;
531 case O_EQ:
532 return a == b;
533 case O_NEQ:
534 return a != b;
536 return 0;
539 static int c_bop(int op)
541 struct tmp *t1 = TMP(0);
542 struct tmp *t2 = TMP(1);
543 int locals = LOCAL_PTR(t1) + LOCAL_PTR(t2);
544 int syms = SYM_PTR(t1) + SYM_PTR(t2);
545 int nums = TMP_NUM(t1) + TMP_NUM(t2);
546 if (syms + locals == 2 || syms + nums + locals != 2)
547 return 1;
548 if (nums == 1)
549 if ((op & 0xff) != O_ADD && ((op & 0xff) != O_SUB || TMP_NUM(t2)))
550 return 1;
551 if (nums == 1) {
552 long o1 = TMP_NUM(t1) ? t1->addr : t1->off;
553 long o2 = TMP_NUM(t2) ? t2->addr : t2->off;
554 long ret = cb(op, o2, o1);
555 if (!TMP_NUM(t1))
556 o_tmpswap();
557 t2->off = ret;
558 tmp_drop(1);
559 } else {
560 long ret = cb(op, t2->addr, t1->addr);
561 tmp_drop(2);
562 o_num(ret);
564 return 0;
567 void o_uop(int op)
569 int r1 = reg_fortmp(TMP(0), 0);
570 if (!c_uop(op))
571 return;
572 tmp_to(TMP(0), r1);
573 switch (op & 0xff) {
574 case O_NEG:
575 i_neg(r1);
576 break;
577 case O_NOT:
578 i_not(r1);
579 break;
580 case O_LNOT:
581 i_lnot(r1);
582 break;
586 static void bin_regs(int *r1, int *r2)
588 struct tmp *t2 = TMP(0);
589 struct tmp *t1 = TMP(1);
590 *r2 = reg_fortmp(t2, 0);
591 tmp_to(t2, *r2);
592 *r1 = reg_fortmp(t1, 1 << *r2);
593 tmp_pop(*r2);
594 tmp_pop(*r1);
597 static int bop_imm(int *r1, long *n, int swap)
599 struct tmp *t1 = TMP(0);
600 struct tmp *t2 = TMP(1);
601 if (!TMP_NUM(t1) && (!swap || !TMP_NUM(t2)))
602 return 1;
603 *n = TMP_NUM(t1) ? t1->addr : t2->addr;
604 if (!i_decodeable(*n))
605 return 1;
606 if (!TMP_NUM(t1))
607 o_tmpswap();
608 *r1 = reg_fortmp(t2, 0);
609 tmp_drop(1);
610 tmp_pop(*r1);
611 return 0;
614 static void bin_add(int op)
616 int r1, r2;
617 long n;
618 if (!bop_imm(&r1, &n, (op & 0xff) != O_SUB)) {
619 i_add_imm(op, r1, r1, n);
620 } else {
621 bin_regs(&r1, &r2);
622 i_add(op, r1, r1, r2);
624 tmp_push(r1);
627 static void bin_shx(int op)
629 int r1, r2;
630 long n;
631 if (!bop_imm(&r1, &n, 0)) {
632 i_shl_imm(op, r1, r1, n);
633 } else {
634 bin_regs(&r1, &r2);
635 i_shl(op, r1, r1, r2);
637 tmp_push(r1);
640 static int log2a(unsigned long n)
642 int i = 0;
643 for (i = 0; i < LONGSZ * 8; i++)
644 if (n & (1u << i))
645 break;
646 if (i == LONGSZ * 8 || !(n >> (i + 1)))
647 return i;
648 return -1;
651 /* optimized version of mul/div/mod for powers of two */
652 static int mul_2(int op)
654 struct tmp *t1 = TMP(0);
655 struct tmp *t2 = TMP(1);
656 long n;
657 int r2;
658 int p;
659 if ((op & 0xff) == O_MUL && t2->loc == LOC_NUM && !t2->bt)
660 o_tmpswap();
661 if (t1->loc != LOC_NUM || t1->bt)
662 return 1;
663 n = t1->addr;
664 p = log2a(n);
665 if (n && p == -1)
666 return 1;
667 if ((op & 0xff) == O_MUL) {
668 tmp_drop(1);
669 if (n == 1)
670 return 0;
671 if (n == 0) {
672 tmp_drop(1);
673 o_num(0);
674 return 0;
676 r2 = reg_fortmp(t2, 0);
677 tmp_to(t2, r2);
678 i_shl_imm(O_SHL, r2, r2, p);
679 return 0;
681 if (op == O_DIV) {
682 tmp_drop(1);
683 if (n == 1)
684 return 0;
685 r2 = reg_fortmp(t2, 0);
686 tmp_to(t2, r2);
687 i_shl_imm((op & O_SIGNED) | O_SHR, r2, r2, p);
688 return 0;
690 if (op == O_MOD) {
691 tmp_drop(1);
692 if (n == 1) {
693 tmp_drop(1);
694 o_num(0);
695 return 0;
697 r2 = reg_fortmp(t2, 0);
698 tmp_to(t2, r2);
699 i_zx(r2, p);
700 return 0;
702 return 1;
705 static void bin_div(int op)
707 struct tmp *t2 = TMP(0);
708 struct tmp *t1 = TMP(1);
709 char *func;
710 int i;
711 putdiv = 1;
712 if ((op & 0xff) == O_DIV)
713 func = op & O_SIGNED ? "__divdi3" : "__udivdi3";
714 else
715 func = op & O_SIGNED ? "__moddi3" : "__umoddi3";
716 for (i = 0; i < ARRAY_SIZE(argregs); i++)
717 if (regs[argregs[i]] && regs[argregs[i]] - tmps < ntmp - 2)
718 tmp_mem(regs[argregs[i]]);
719 tmp_to(t1, argregs[0]);
720 tmp_to(t2, argregs[1]);
721 tmp_drop(2);
722 i_call(func, 0);
723 tmp_push(REG_RET);
726 static void bin_mul(int op)
728 int r1, r2;
729 if (!mul_2(op))
730 return;
731 if ((op & 0xff) == O_DIV || (op & 0xff) == O_MOD) {
732 bin_div(op);
733 } else {
734 bin_regs(&r1, &r2);
735 i_mul(r1, r1, r2);
736 tmp_push(r1);
740 static void bin_cmp(int op)
742 int r1, r2;
743 long n;
744 if (!bop_imm(&r1, &n, (op & 0xff) == O_EQ || (op & 0xff) == O_NEQ)) {
745 i_cmp_imm(I_CMP, r1, n);
746 } else {
747 bin_regs(&r1, &r2);
748 i_cmp(I_CMP, r1, r2);
750 i_set(op, r1);
751 tmp_push(r1);
754 void o_bop(int op)
756 if (!c_bop(op))
757 return;
758 if ((op & 0xf0) == 0x00)
759 bin_add(op);
760 if ((op & 0xf0) == 0x10)
761 bin_shx(op);
762 if ((op & 0xf0) == 0x20)
763 bin_mul(op);
764 if ((op & 0xf0) == 0x30)
765 bin_cmp(op);
768 static void load_regs2(int *r0, int *r1, int *r2)
770 struct tmp *t0 = TMP(0);
771 struct tmp *t1 = TMP(1);
772 struct tmp *t2 = TMP(2);
773 *r0 = reg_fortmp(t0, 0);
774 *r1 = reg_fortmp(t1, 1 << *r0);
775 *r2 = reg_fortmp(t2, (1 << *r0) | (1 << *r1));
776 tmp_to(t0, *r0);
777 tmp_to(t1, *r1);
778 tmp_to(t2, *r2);
781 void o_memcpy(void)
783 int rd, rs, rn;
784 load_regs2(&rn, &rs, &rd);
785 i_memcpy(rd, rs, rn);
786 tmp_drop(2);
789 void o_memset(void)
791 int rd, rs, rn;
792 load_regs2(&rn, &rs, &rd);
793 i_memset(rd, rs, rn);
794 tmp_drop(2);
797 long o_mklabel(void)
799 return cslen;
802 static long jxz(long addr, int z)
804 int r = reg_fortmp(TMP(0), 0);
805 tmp_pop(r);
806 i_b_if(addr, r, z);
807 return cslen - 4;
810 long o_jz(long addr)
812 return jxz(addr, 1);
815 long o_jnz(long addr)
817 return jxz(addr, 0);
820 long o_jmp(long addr)
822 i_b(addr);
823 return cslen - 4;
826 void o_filljmp2(long addr, long jmpdst)
828 i_b_fill((void *) cs + addr, jmpdst - addr);
831 void o_filljmp(long addr)
833 o_filljmp2(addr, cslen);
836 void o_call(int argc, int rets)
838 struct tmp *t;
839 int i;
840 int aregs = MIN(ARRAY_SIZE(argregs), argc);
841 for (i = 0; i < ARRAY_SIZE(argregs); i++)
842 if (regs[argregs[i]] && regs[argregs[i]] - tmps < ntmp - argc)
843 tmp_mem(regs[argregs[i]]);
844 if (argc > aregs) {
845 sp_push(LONGSZ * (argc - aregs));
846 for (i = argc - 1; i >= aregs; --i) {
847 int reg = reg_fortmp(TMP(0), 0);
848 tmp_pop(reg);
849 i_ldr(0, reg, REG_SP, (i - aregs) * LONGSZ, LONGSZ);
852 for (i = aregs - 1; i >= 0; --i)
853 tmp_to(TMP(aregs - i - 1), argregs[i]);
854 tmp_drop(aregs);
855 t = TMP(0);
856 if (t->loc == LOC_SYM && !t->bt) {
857 i_call(t->sym, t->off);
858 tmp_drop(1);
859 } else {
860 int reg = t->loc == LOC_REG ? t->addr : REG_TMP;
861 tmp_pop(reg);
862 i_call_reg(reg);
864 if (rets)
865 tmp_push(REG_RET);
868 void o_nogen(void)
870 nogen++;
873 void o_dogen(void)
875 nogen--;
878 void o_mkbss(char *name, int size, int global)
880 out_sym(name, OUT_BSS | (global ? OUT_GLOB : 0), bsslen, size);
881 bsslen += ALIGN(size, LONGSZ);
884 #define MAXDATS (1 << 10)
885 static char dat_names[MAXDATS][NAMELEN];
886 static int dat_offs[MAXDATS];
887 static int ndats;
889 void err(char *msg);
890 void *o_mkdat(char *name, int size, int global)
892 void *addr = ds + dslen;
893 int idx = ndats++;
894 if (idx >= MAXDATS)
895 err("nomem: MAXDATS reached!\n");
896 strcpy(dat_names[idx], name);
897 dat_offs[idx] = dslen;
898 out_sym(name, OUT_DS | (global ? OUT_GLOB : 0), dslen, size);
899 dslen += ALIGN(size, LONGSZ);
900 return addr;
903 static int dat_off(char *name)
905 int i;
906 for (i = 0; i < ndats; i++)
907 if (!strcmp(name, dat_names[i]))
908 return dat_offs[i];
909 return 0;
912 void o_datset(char *name, int off, unsigned bt)
914 struct tmp *t = TMP(0);
915 int sym_off = dat_off(name) + off;
916 if (t->loc == LOC_NUM && !t->bt) {
917 num_cast(t, bt);
918 memcpy(ds + sym_off, &t->addr, BT_SZ(bt));
920 if (t->loc == LOC_SYM && !t->bt) {
921 out_rel(t->sym, OUT_DS, sym_off);
922 memcpy(ds + sym_off, &t->off, BT_SZ(bt));
924 tmp_drop(1);
927 /* compiled division functions; div.s contains the source */
928 static int udivdi3[] = {
929 0xe3a02000, 0xe3a03000, 0xe1110001, 0x0a00000a,
930 0xe1b0c211, 0xe2822001, 0x5afffffc, 0xe3a0c001,
931 0xe2522001, 0x4a000004, 0xe1500211, 0x3afffffb,
932 0xe0400211, 0xe083321c, 0xeafffff8, 0xe1a01000,
933 0xe1a00003, 0xe1a0f00e,
935 static int umoddi3[] = {
936 0xe92d4000, 0xebffffeb, 0xe1a00001, 0xe8bd8000,
938 static int divdi3[] = {
939 0xe92d4030, 0xe1a04000, 0xe1a05001, 0xe1100000,
940 0x42600000, 0xe1110001, 0x42611000, 0xebffffe1,
941 0xe1340005, 0x42600000, 0xe1140004, 0x42611000,
942 0xe8bd8030,
944 static int moddi3[] = {
945 0xe92d4000, 0xebfffff0, 0xe1a00001, 0xe8bd8000,
948 void o_write(int fd)
950 if (putdiv) {
951 out_sym("__udivdi3", OUT_CS, cslen, 0);
952 os(udivdi3, sizeof(udivdi3));
953 out_sym("__umoddi3", OUT_CS, cslen, 0);
954 os(umoddi3, sizeof(umoddi3));
955 out_sym("__divdi3", OUT_CS, cslen, 0);
956 os(divdi3, sizeof(divdi3));
957 out_sym("__moddi3", OUT_CS, cslen, 0);
958 os(moddi3, sizeof(moddi3));
960 out_write(fd, cs, cslen, ds, dslen);
963 /* arch specific functions */
965 #define MAXNUMS 1024
967 /* data pool */
968 static long num_offs[MAXNUMS]; /* data immediate value */
969 static char num_names[MAXNUMS][NAMELEN]; /* relocation data symbol name */
970 static int nums;
972 static int pool_find(char *name, int off)
974 int i;
975 for (i = 0; i < nums; i++)
976 if (!strcmp(name, num_names[i]) && off == num_offs[i])
977 return i;
978 return -1;
981 static int pool_num(long num)
983 int idx = pool_find("", num);
984 if (idx < 0) {
985 idx = nums++;
986 num_offs[idx] = num;
987 num_names[idx][0] = '\0';
989 return idx << 2;
992 static int pool_reloc(char *name, long off)
994 int idx = pool_find(name, off);
995 if (idx < 0) {
996 idx = nums++;
997 num_offs[idx] = off;
998 strcpy(num_names[idx], name);
1000 return idx << 2;
1003 static void pool_write(void)
1005 int i;
1006 for (i = 0; i < nums; i++) {
1007 if (num_names[i])
1008 out_rel(num_names[i], OUT_CS, cslen);
1009 oi(num_offs[i]);
1014 * data processing:
1015 * +---------------------------------------+
1016 * |COND|00|I| op |S| Rn | Rd | operand2 |
1017 * +---------------------------------------+
1019 * S: set condition code
1020 * Rn: first operand
1021 * Rd: destination operand
1023 * I=0 operand2=| shift | Rm |
1024 * I=1 operand2=|rota| imm |
1026 #define ADD(op, rd, rn, s, i, cond) \
1027 (((cond) << 28) | ((i) << 25) | ((s) << 20) | \
1028 ((op) << 21) | ((rn) << 16) | ((rd) << 12))
1030 static int add_encimm(unsigned n)
1032 int i = 0;
1033 while (i < 12 && (n >> ((4 + i) << 1)))
1034 i++;
1035 return (n >> (i << 1)) | (((16 - i) & 0x0f) << 8);
1038 static unsigned add_decimm(int n)
1040 int rot = (16 - ((n >> 8) & 0x0f)) & 0x0f;
1041 return (n & 0xff) << (rot << 1);
1044 static int add_rndimm(unsigned n)
1046 int rot = (n >> 8) & 0x0f;
1047 int num = n & 0xff;
1048 if (rot == 0)
1049 return n;
1050 if (num == 0xff) {
1051 num = 0;
1052 rot = (rot + 12) & 0x0f;
1054 return ((num + 1) & 0xff) | (rot << 8);
1057 static int opcode_add(int op)
1059 /* opcode for O_ADD, O_SUB, O_AND, O_OR, O_XOR */
1060 static int rx[] = {I_ADD, I_SUB, I_AND, I_ORR, I_EOR};
1061 return rx[op & 0x0f];
1064 static void i_add(int op, int rd, int rn, int rm)
1066 oi(ADD(opcode_add(op), rd, rn, 0, 0, 14) | rm);
1069 static int i_decodeable(long imm)
1071 return add_decimm(add_encimm(imm)) == imm;
1074 static void i_add_imm(int op, int rd, int rn, long n)
1076 oi(ADD(opcode_add(op), rd, rn, 0, 1, 14) | add_encimm(n));
1079 static void i_num(int rd, long n)
1081 int enc = add_encimm(n);
1082 if (n == add_decimm(enc)) {
1083 oi(ADD(I_MOV, rd, 0, 0, 1, 14) | enc);
1084 return;
1086 enc = add_encimm(-n - 1);
1087 if (~n == add_decimm(enc)) {
1088 oi(ADD(I_MVN, rd, 0, 0, 1, 14) | enc);
1089 return;
1091 if (!nogen) {
1092 int off = pool_num(n);
1093 i_ldr(1, rd, REG_DP, off, LONGSZ);
1097 static void i_add_anyimm(int rd, int rn, long n)
1099 int neg = n < 0;
1100 int imm = add_encimm(neg ? -n : n);
1101 if (imm == add_decimm(neg ? -n : n)) {
1102 oi(ADD(neg ? I_SUB : I_ADD, rd, rn, 0, 1, 14) | imm);
1103 } else {
1104 i_num(rd, n);
1105 i_add(O_ADD, rd, rd, rn);
1110 * multiply
1111 * +----------------------------------------+
1112 * |COND|000000|A|S| Rd | Rn | Rs |1001| Rm |
1113 * +----------------------------------------+
1115 * Rd: destination
1116 * A: accumulate
1117 * C: set condition codes
1119 * I=0 operand2=| shift | Rm |
1120 * I=1 operand2=|rota| imm |
1122 #define MUL(rd, rn, rs) \
1123 ((14 << 28) | ((rd) << 16) | ((0) << 12) | ((rn) << 8) | ((9) << 4) | (rm))
1125 static void i_mul(int rd, int rn, int rm)
1127 oi(MUL(rd, rn, rm));
1130 static int opcode_set(int op)
1132 /* lt, gt, le, ge, eq, neq */
1133 static int ucond[] = {3, 8, 9, 2, 0, 1};
1134 static int scond[] = {11, 12, 13, 10, 0, 1};
1135 return op & O_SIGNED ? scond[op & 0x0f] : ucond[op & 0x0f];
1138 static void i_cmp(int op, int rn, int rm)
1140 oi(ADD(op, 0, rn, 1, 0, 14) | rm);
1143 static void i_cmp_imm(int op, int rn, long n)
1145 oi(ADD(op, 0, rn, 1, 1, 14) | add_encimm(n));
1148 static void i_set(int cond, int rd)
1150 oi(ADD(I_MOV, rd, 0, 0, 1, 14));
1151 oi(ADD(I_MOV, rd, 0, 0, 1, opcode_set(cond)) | 1);
1154 #define SM_LSL 0
1155 #define SM_LSR 1
1156 #define SM_ASR 2
1158 static int opcode_shl(int op)
1160 if (op & 0x0f)
1161 return op & O_SIGNED ? SM_ASR : SM_LSR;
1162 return SM_LSL;
1165 static void i_shl(int op, int rd, int rm, int rs)
1167 int sm = opcode_shl(op);
1168 oi(ADD(I_MOV, rd, 0, 0, 0, 14) | (rs << 8) | (sm << 5) | (1 << 4) | rm);
1171 static void i_shl_imm(int op, int rd, int rn, long n)
1173 int sm = opcode_shl(op);
1174 oi(ADD(I_MOV, rd, 0, 0, 0, 14) | (n << 7) | (sm << 5) | rn);
1177 static void i_mov(int rd, int rn)
1179 oi(ADD(I_MOV, rd, 0, 0, 0, 14) | rn);
1183 * single data transfer:
1184 * +------------------------------------------+
1185 * |COND|01|I|P|U|B|W|L| Rn | Rd | offset |
1186 * +------------------------------------------+
1188 * I: immediate/offset
1189 * P: post/pre indexing
1190 * U: down/up
1191 * B: byte/word
1192 * W: writeback
1193 * L: store/load
1194 * Rn: base register
1195 * Rd: source/destination register
1197 * I=0 offset=| immediate |
1198 * I=1 offset=| shift | Rm |
1200 * halfword and signed data transfer
1201 * +----------------------------------------------+
1202 * |COND|000|P|U|0|W|L| Rn | Rd |0000|1|S|H|1| Rm |
1203 * +----------------------------------------------+
1205 * +----------------------------------------------+
1206 * |COND|000|P|U|1|W|L| Rn | Rd |off1|1|S|H|1|off2|
1207 * +----------------------------------------------+
1209 * S: singed
1210 * H: halfword
1212 #define LDR(l, rd, rn, b, u, p, w) \
1213 ((14 << 28) | (1 << 26) | ((p) << 24) | ((b) << 22) | ((u) << 23) | \
1214 ((w) << 21) | ((l) << 20) | ((rn) << 16) | ((rd) << 12))
1215 #define LDRH(l, rd, rn, s, h, u, i) \
1216 ((14 << 28) | (1 << 24) | ((u) << 23) | ((i) << 22) | ((l) << 20) | \
1217 ((rn) << 16) | ((rd) << 12) | ((s) << 6) | ((h) << 5) | (9 << 4))
1219 static void i_ldr(int l, int rd, int rn, int off, int bt)
1221 int b = BT_SZ(bt) == 1;
1222 int h = BT_SZ(bt) == 2;
1223 int s = l && (bt & BT_SIGNED);
1224 int half = h || (b && s);
1225 int maximm = half ? 0x100 : 0x1000;
1226 int neg = off < 0;
1227 if (neg)
1228 off = -off;
1229 while (off >= maximm) {
1230 int imm = add_encimm(off);
1231 oi(ADD(neg ? I_SUB : I_ADD, REG_TMP, rn, 0, 1, 14) | imm);
1232 rn = REG_TMP;
1233 off -= add_decimm(imm);
1235 if (!half)
1236 oi(LDR(l, rd, rn, b, !neg, 1, 0) | off);
1237 else
1238 oi(LDRH(l, rd, rn, s, h, !neg, 1) |
1239 ((off & 0xf0) << 4) | (off & 0x0f));
1242 static void i_sym(int rd, char *sym, int off)
1244 if (!nogen) {
1245 int doff = pool_reloc(sym, off);
1246 i_ldr(1, rd, REG_DP, doff, LONGSZ);
1250 static void i_neg(int rd)
1252 oi(ADD(I_RSB, rd, rd, 0, 1, 14));
1255 static void i_not(int rd)
1257 oi(ADD(I_MVN, rd, 0, 0, 0, 14) | rd);
1260 static void i_lnot(int rd)
1262 i_cmp(I_TST, rd, rd);
1263 i_set(O_EQ, rd);
1266 /* rd = rd & ((1 << bits) - 1) */
1267 static void i_zx(int rd, int bits)
1269 if (bits <= 8) {
1270 oi(ADD(I_AND, rd, rd, 0, 1, 14) | add_encimm((1 << bits) - 1));
1271 } else {
1272 i_shl_imm(O_SHL, rd, rd, 32 - bits);
1273 i_shl_imm(O_SHR, rd, rd, 32 - bits);
1277 static void i_sx(int rd, int bits)
1279 i_shl_imm(O_SHL, rd, rd, 32 - bits);
1280 i_shl_imm(O_SIGNED | O_SHR, rd, rd, 32 - bits);
1284 * branch:
1285 * +-----------------------------------+
1286 * |COND|101|L| offset |
1287 * +-----------------------------------+
1289 * L: link
1291 #define BL(cond, l, o) (((cond) << 28) | (5 << 25) | ((l) << 24) | \
1292 ((((o) - 8) >> 2) & 0x00ffffff))
1294 static void i_b(long addr)
1296 oi(BL(14, 0, addr - cslen));
1299 static void i_b_if(long addr, int rn, int z)
1301 i_cmp(I_TST, rn, rn);
1302 oi(BL(z ? 0 : 1, 0, addr - cslen));
1305 static void i_b_fill(long *dst, int diff)
1307 *dst = (*dst & 0xff000000) | (((diff - 8) >> 2) & 0x00ffffff);
1310 static void i_memcpy(int rd, int rs, int rn)
1312 oi(ADD(I_SUB, rn, rn, 1, 1, 14) | 1);
1313 oi(BL(4, 0, 16));
1314 oi(LDR(1, REG_TMP, rs, 1, 1, 0, 0) | 1);
1315 oi(LDR(0, REG_TMP, rd, 1, 1, 0, 0) | 1);
1316 oi(BL(14, 0, -16));
1319 static void i_memset(int rd, int rs, int rn)
1321 oi(ADD(I_SUB, rn, rn, 1, 1, 14) | 1);
1322 oi(BL(4, 0, 12));
1323 oi(LDR(0, rs, rd, 1, 1, 0, 0) | 1);
1324 oi(BL(14, 0, -12));
1327 static void i_call_reg(int rd)
1329 i_mov(REG_LR, REG_PC);
1330 i_mov(REG_PC, rd);
1333 static void i_call(char *sym, int off)
1335 if (!nogen)
1336 out_rel(sym, OUT_CS | OUT_REL24, cslen);
1337 oi(BL(14, 1, off));
1340 static void i_prolog(void)
1342 func_beg = cslen;
1343 nums = 0;
1344 oi(0xe1a0c00d); /* mov r12, sp */
1345 oi(0xe92d000f); /* stmfd sp!, {r0-r3} */
1346 oi(0xe92d5ff0); /* stmfd sp!, {r0-r11, r12, lr} */
1347 oi(0xe1a0b00d); /* mov fp, sp */
1348 oi(0xe24dd000); /* sub sp, sp, xx */
1349 oi(0xe28fa000); /* add dp, pc, xx */
1352 static void i_epilog(void)
1354 int dpoff;
1355 oi(0xe89baff0); /* ldmfd fp, {r4-r11, sp, pc} */
1356 dpoff = add_decimm(add_rndimm(add_encimm(cslen - func_beg - 28)));
1357 cslen = func_beg + dpoff + 28;
1358 maxsp = ALIGN(maxsp, 8);
1359 maxsp = add_decimm(add_rndimm(add_encimm(maxsp)));
1360 /* fill stack sub: sp = sp - xx */
1361 *(long *) (cs + func_beg + 16) |= add_encimm(maxsp);
1362 /* fill data ptr addition: dp = pc + xx */
1363 *(long *) (cs + func_beg + 20) |= add_encimm(dpoff);
1364 pool_write();