gen: complain if MAXJMPS is reached
[neatcc/cc.git] / arm.c
blob10ec29befd5729bc6b3b5405a2d3edec1a2a26c6
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))
27 void err(char *msg);
29 static char cs[SECSIZE]; /* code segment */
30 static int cslen;
31 static char ds[SECSIZE]; /* data segment */
32 static int dslen;
33 static long bsslen; /* bss segment size */
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_mov(int rd, int rn);
55 static void i_add(int op, int rd, int rn, int rm);
56 static void i_shl(int op, int rd, int rm, int rs);
57 static void i_mul(int rd, int rn, int rm);
58 static void i_cmp(int rn, int rm);
59 static int i_decodeable(long imm);
60 static void i_add_imm(int op, int rd, int rn, long n);
61 static void i_shl_imm(int op, int rd, int rn, long n);
62 static void i_cmp_imm(int rn, long n);
63 static void i_add_anyimm(int rd, int rn, long n);
64 static void i_num(int rd, long n);
65 static void i_sym(int rd, char *sym, int off);
66 static void i_set(int op, int rd);
67 static void i_neg(int rd);
68 static void i_not(int rd);
69 static void i_lnot(int rd);
70 static void i_zx(int rd, int bits);
71 static void i_sx(int rd, int bits);
72 static void i_b(void);
73 static void i_bz(int rn, int z);
74 static void i_b_fill(long src, long dst);
75 static void i_memcpy(int rd, int rs, int rn);
76 static void i_memset(int rd, int rs, int rn);
77 static void i_call(char *sym, int off);
78 static void i_call_reg(int rd);
79 static void i_prolog(void);
80 static void i_epilog(void);
82 static struct tmp *regs[NREGS];
83 static int tmpregs[] = {4, 5, 6, 7, 8, 9, 0, 1, 2, 3};
84 static int argregs[] = {0, 1, 2, 3};
86 /* labels and jmps */
87 #define MAXJMPS (1 << 14)
89 static long labels[MAXJMPS];
90 static int nlabels;
91 static long jmp_loc[MAXJMPS];
92 static int jmp_goal[MAXJMPS];
93 static int njmps;
95 void o_label(int id)
97 if (id > nlabels)
98 nlabels = id + 1;
99 labels[id] = cslen;
102 static void jmp_add(int id)
104 if (njmps >= MAXJMPS)
105 err("nomem: MAXJMPS reached!\n");
106 jmp_loc[njmps] = cslen - 4;
107 jmp_goal[njmps] = id;
108 njmps++;
111 static void jmp_fill(void)
113 int i;
114 for (i = 0; i < njmps; i++)
115 i_b_fill(jmp_loc[i], labels[jmp_goal[i]]);
118 /* output div/mod functions */
119 static int putdiv = 0;
121 /* generating code */
123 static void os(void *s, int n)
125 memcpy(cs + cslen, s, n);
126 cslen += n;
129 static void oi(long n)
131 *(int *) (cs + cslen) = n;
132 cslen += 4;
135 static long sp_push(int size)
137 sp += size;
138 if (sp > maxsp)
139 maxsp = sp;
140 return sp;
143 static void tmp_mem(struct tmp *tmp)
145 int src = tmp->addr;
146 if (!(tmp->loc == LOC_REG))
147 return;
148 if (tmpsp == -1)
149 tmpsp = sp;
150 tmp->addr = -sp_push(LONGSZ);
151 i_ldr(0, src, REG_FP, tmp->addr, LONGSZ);
152 regs[src] = NULL;
153 tmp->loc = LOC_MEM;
156 static void num_cast(struct tmp *t, unsigned bt)
158 if (!(bt & BT_SIGNED) && BT_SZ(bt) != LONGSZ)
159 t->addr &= ((1l << (long) (BT_SZ(bt) * 8)) - 1);
160 if (bt & BT_SIGNED && BT_SZ(bt) != LONGSZ &&
161 t->addr > (1l << (BT_SZ(bt) * 8 - 1)))
162 t->addr = -((1l << (BT_SZ(bt) * 8)) - t->addr);
165 static void tmp_reg(struct tmp *tmp, int dst, int deref)
167 int bt = tmp->bt;
168 if (!tmp->bt)
169 deref = 0;
170 if (deref)
171 tmp->bt = 0;
172 if (tmp->loc == LOC_NUM) {
173 i_num(dst, tmp->addr);
174 tmp->addr = dst;
175 regs[dst] = tmp;
176 tmp->loc = LOC_REG;
178 if (tmp->loc == LOC_SYM) {
179 i_sym(dst, tmp->sym, tmp->off);
180 tmp->addr = dst;
181 regs[dst] = tmp;
182 tmp->loc = LOC_REG;
184 if (tmp->loc == LOC_REG) {
185 if (deref)
186 i_ldr(1, dst, tmp->addr, 0, bt);
187 else if (dst != tmp->addr)
188 i_mov(dst, tmp->addr);
189 regs[tmp->addr] = NULL;
191 if (tmp->loc == LOC_LOCAL) {
192 if (deref)
193 i_ldr(1, dst, REG_FP, tmp->addr + tmp->off, bt);
194 else
195 i_add_anyimm(dst, REG_FP, tmp->addr + tmp->off);
197 if (tmp->loc == LOC_MEM) {
198 i_ldr(1, dst, REG_FP, tmp->addr, LONGSZ);
199 if (deref)
200 i_ldr(1, dst, dst, 0, bt);
202 tmp->addr = dst;
203 regs[dst] = tmp;
204 tmp->loc = LOC_REG;
207 static void reg_free(int reg)
209 int i;
210 if (!regs[reg])
211 return;
212 for (i = 0; i < ARRAY_SIZE(tmpregs); i++)
213 if (!regs[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);
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 tmp_reg(t, reg, 1);
238 static void tmp_drop(int n)
240 int i;
241 for (i = ntmp - n; i < ntmp; i++)
242 if (tmps[i].loc == LOC_REG)
243 regs[tmps[i].addr] = NULL;
244 ntmp -= n;
247 static void tmp_pop(int reg)
249 struct tmp *t = TMP(0);
250 tmp_to(t, reg);
251 tmp_drop(1);
254 static struct tmp *tmp_new(void)
256 return &tmps[ntmp++];
259 static void tmp_push(int reg)
261 struct tmp *t = tmp_new();
262 t->addr = reg;
263 t->bt = 0;
264 t->loc = LOC_REG;
265 regs[reg] = t;
268 void o_local(long addr)
270 struct tmp *t = tmp_new();
271 t->addr = -addr;
272 t->loc = LOC_LOCAL;
273 t->bt = 0;
274 t->off = 0;
277 void o_num(long num)
279 struct tmp *t = tmp_new();
280 t->addr = num;
281 t->bt = 0;
282 t->loc = LOC_NUM;
285 void o_sym(char *name)
287 struct tmp *t = tmp_new();
288 strcpy(t->sym, name);
289 t->loc = LOC_SYM;
290 t->bt = 0;
291 t->off = 0;
294 void o_tmpdrop(int n)
296 if (n == -1 || n > ntmp)
297 n = ntmp;
298 tmp_drop(n);
299 if (!ntmp) {
300 if (tmpsp != -1)
301 sp = tmpsp;
302 tmpsp = -1;
306 /* make sure tmps remain intact after a conditional expression */
307 void o_fork(void)
309 int i;
310 for (i = 0; i < ntmp - 1; i++)
311 tmp_mem(&tmps[i]);
314 void o_forkpush(void)
316 tmp_pop(REG_FORK);
319 void o_forkjoin(void)
321 tmp_push(REG_FORK);
324 void o_tmpswap(void)
326 struct tmp *t1 = TMP(0);
327 struct tmp *t2 = TMP(1);
328 struct tmp t;
329 memcpy(&t, t1, sizeof(t));
330 memcpy(t1, t2, sizeof(t));
331 memcpy(t2, &t, sizeof(t));
332 if (t1->loc == LOC_REG)
333 regs[t1->addr] = t1;
334 if (t2->loc == LOC_REG)
335 regs[t2->addr] = t2;
338 static int reg_get(int mask)
340 int i;
341 for (i = 0; i < ARRAY_SIZE(tmpregs); i++)
342 if ((1 << tmpregs[i]) & mask && !regs[tmpregs[i]])
343 return tmpregs[i];
344 for (i = 0; i < ARRAY_SIZE(tmpregs); i++)
345 if ((1 << tmpregs[i]) & mask) {
346 reg_free(tmpregs[i]);
347 return tmpregs[i];
349 return 0;
352 static int reg_fortmp(struct tmp *t, int notmask)
354 if (t->loc == LOC_REG && !(notmask & (1 << t->addr)))
355 return t->addr;
356 return reg_get(~notmask);
359 static void tmp_copy(struct tmp *t1)
361 struct tmp *t2 = tmp_new();
362 memcpy(t2, t1, sizeof(*t1));
363 if (!(t1->loc & (LOC_REG | LOC_MEM)))
364 return;
365 if (t1->loc == LOC_MEM) {
366 tmp_mv(t2, reg_get(~0));
367 } else if (t1->loc == LOC_REG) {
368 t2->addr = reg_fortmp(t2, 1 << t1->addr);
369 i_mov(t2->addr, t1->addr);
370 regs[t2->addr] = t2;
374 void o_tmpcopy(void)
376 tmp_copy(TMP(0));
379 void o_cast(unsigned bt)
381 struct tmp *t = TMP(0);
382 if (!t->bt && t->loc == LOC_NUM) {
383 num_cast(t, bt);
384 return;
386 if (BT_SZ(bt) != LONGSZ) {
387 int reg = reg_fortmp(t, 0);
388 tmp_to(t, reg);
389 if (bt & BT_SIGNED)
390 i_sx(reg, BT_SZ(bt) * 8);
391 else
392 i_zx(reg, BT_SZ(bt) * 8);
396 void o_func_beg(char *name, int argc, int global, int vararg)
398 out_sym(name, (global ? OUT_GLOB : 0) | OUT_CS, cslen, 0);
399 i_prolog();
400 sp = 0;
401 maxsp = sp;
402 ntmp = 0;
403 tmpsp = -1;
404 nlabels = 0;
405 njmps = 0;
406 memset(regs, 0, sizeof(regs));
409 void o_deref(unsigned bt)
411 struct tmp *t = TMP(0);
412 if (t->bt)
413 tmp_to(t, reg_fortmp(t, 0));
414 t->bt = bt;
417 void o_load(void)
419 struct tmp *t = TMP(0);
420 tmp_to(t, reg_fortmp(t, 0));
423 #define TMP_NUM(t) ((t)->loc == LOC_NUM && !(t)->bt)
424 #define LOCAL_PTR(t) ((t)->loc == LOC_LOCAL && !(t)->bt)
425 #define SYM_PTR(t) ((t)->loc == LOC_SYM && !(t)->bt)
427 int o_popnum(long *c)
429 struct tmp *t = TMP(0);
430 if (!TMP_NUM(t))
431 return 1;
432 *c = t->addr;
433 tmp_drop(1);
434 return 0;
437 void o_ret(int rets)
439 if (rets)
440 tmp_pop(REG_RET);
441 else
442 i_num(REG_RET, 0);
443 o_jmp(0);
446 void o_func_end(void)
448 o_label(0);
449 jmp_fill();
450 i_epilog();
453 long o_mklocal(int size)
455 return sp_push(ALIGN(size, LONGSZ));
458 void o_rmlocal(long addr, int sz)
460 sp = addr - sz;
463 long o_arg2loc(int i)
465 return -(10 + i) << 2;
468 void o_assign(unsigned bt)
470 struct tmp *t1 = TMP(0);
471 struct tmp *t2 = TMP(1);
472 int r1 = reg_fortmp(t1, 0);
473 int r2 = reg_fortmp(t2, 1 << r1);
474 int off = 0;
475 tmp_to(t1, r1);
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 } else {
482 tmp_to(t2, r2);
484 tmp_drop(2);
485 i_ldr(0, r1, r2, off, bt);
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 locals = 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 + locals == 2 || syms + nums + locals != 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 t2->off = ret;
573 tmp_drop(1);
574 } else {
575 long ret = cb(op, t2->addr, t1->addr);
576 tmp_drop(2);
577 o_num(ret);
579 return 0;
582 void o_uop(int op)
584 int r1 = reg_fortmp(TMP(0), 0);
585 if (!c_uop(op))
586 return;
587 tmp_to(TMP(0), r1);
588 switch (op & 0xff) {
589 case O_NEG:
590 i_neg(r1);
591 break;
592 case O_NOT:
593 i_not(r1);
594 break;
595 case O_LNOT:
596 i_lnot(r1);
597 break;
601 static void bin_regs(int *r1, int *r2)
603 struct tmp *t2 = TMP(0);
604 struct tmp *t1 = TMP(1);
605 *r2 = reg_fortmp(t2, 0);
606 tmp_to(t2, *r2);
607 *r1 = reg_fortmp(t1, 1 << *r2);
608 tmp_pop(*r2);
609 tmp_pop(*r1);
612 static int bop_imm(int *r1, long *n, int swap)
614 struct tmp *t1 = TMP(0);
615 struct tmp *t2 = TMP(1);
616 if (!TMP_NUM(t1) && (!swap || !TMP_NUM(t2)))
617 return 1;
618 *n = TMP_NUM(t1) ? t1->addr : t2->addr;
619 if (!i_decodeable(*n))
620 return 1;
621 if (!TMP_NUM(t1))
622 o_tmpswap();
623 *r1 = reg_fortmp(t2, 0);
624 tmp_drop(1);
625 tmp_pop(*r1);
626 return 0;
629 static void bin_add(int op)
631 int r1, r2;
632 long n;
633 if (!bop_imm(&r1, &n, (op & 0xff) != O_SUB)) {
634 i_add_imm(op, r1, r1, n);
635 } else {
636 bin_regs(&r1, &r2);
637 i_add(op, r1, r1, r2);
639 tmp_push(r1);
642 static void bin_shx(int op)
644 int r1, r2;
645 long n;
646 if (!bop_imm(&r1, &n, 0)) {
647 i_shl_imm(op, r1, r1, n);
648 } else {
649 bin_regs(&r1, &r2);
650 i_shl(op, r1, r1, r2);
652 tmp_push(r1);
655 static int log2a(unsigned long n)
657 int i = 0;
658 for (i = 0; i < LONGSZ * 8; i++)
659 if (n & (1u << i))
660 break;
661 if (i == LONGSZ * 8 || !(n >> (i + 1)))
662 return i;
663 return -1;
666 /* optimized version of mul/div/mod for powers of two */
667 static int mul_2(int op)
669 struct tmp *t1 = TMP(0);
670 struct tmp *t2 = TMP(1);
671 long n;
672 int r2;
673 int p;
674 if ((op & 0xff) == O_MUL && t2->loc == LOC_NUM && !t2->bt)
675 o_tmpswap();
676 if (t1->loc != LOC_NUM || t1->bt)
677 return 1;
678 n = t1->addr;
679 p = log2a(n);
680 if (n && p == -1)
681 return 1;
682 if ((op & 0xff) == O_MUL) {
683 tmp_drop(1);
684 if (n == 1)
685 return 0;
686 if (n == 0) {
687 tmp_drop(1);
688 o_num(0);
689 return 0;
691 r2 = reg_fortmp(t2, 0);
692 tmp_to(t2, r2);
693 i_shl_imm(O_SHL, r2, r2, p);
694 return 0;
696 if (op == O_DIV) {
697 tmp_drop(1);
698 if (n == 1)
699 return 0;
700 r2 = reg_fortmp(t2, 0);
701 tmp_to(t2, r2);
702 i_shl_imm((op & O_SIGNED) | O_SHR, r2, r2, p);
703 return 0;
705 if (op == O_MOD) {
706 tmp_drop(1);
707 if (n == 1) {
708 tmp_drop(1);
709 o_num(0);
710 return 0;
712 r2 = reg_fortmp(t2, 0);
713 tmp_to(t2, r2);
714 i_zx(r2, p);
715 return 0;
717 return 1;
720 static void bin_div(int op)
722 struct tmp *t2 = TMP(0);
723 struct tmp *t1 = TMP(1);
724 char *func;
725 int i;
726 putdiv = 1;
727 if ((op & 0xff) == O_DIV)
728 func = op & O_SIGNED ? "__divdi3" : "__udivdi3";
729 else
730 func = op & O_SIGNED ? "__moddi3" : "__umoddi3";
731 for (i = 0; i < ARRAY_SIZE(argregs); i++)
732 if (regs[argregs[i]] && regs[argregs[i]] - tmps < ntmp - 2)
733 tmp_mem(regs[argregs[i]]);
734 tmp_to(t1, argregs[0]);
735 tmp_to(t2, argregs[1]);
736 tmp_drop(2);
737 i_call(func, 0);
738 tmp_push(REG_RET);
741 static void bin_mul(int op)
743 int r1, r2;
744 if (!mul_2(op))
745 return;
746 if ((op & 0xff) == O_DIV || (op & 0xff) == O_MOD) {
747 bin_div(op);
748 } else {
749 bin_regs(&r1, &r2);
750 i_mul(r1, r1, r2);
751 tmp_push(r1);
755 static void bin_cmp(int op)
757 int r1, r2;
758 long n;
759 if (!bop_imm(&r1, &n, (op & 0xff) == O_EQ || (op & 0xff) == O_NEQ)) {
760 i_cmp_imm(r1, n);
761 } else {
762 bin_regs(&r1, &r2);
763 i_cmp(r1, r2);
765 i_set(op, r1);
766 tmp_push(r1);
769 void o_bop(int op)
771 if (!c_bop(op))
772 return;
773 if ((op & 0xf0) == 0x00)
774 bin_add(op);
775 if ((op & 0xf0) == 0x10)
776 bin_shx(op);
777 if ((op & 0xf0) == 0x20)
778 bin_mul(op);
779 if ((op & 0xf0) == 0x30)
780 bin_cmp(op);
783 static void load_regs2(int *r0, int *r1, int *r2)
785 struct tmp *t0 = TMP(0);
786 struct tmp *t1 = TMP(1);
787 struct tmp *t2 = TMP(2);
788 *r0 = reg_fortmp(t0, 0);
789 *r1 = reg_fortmp(t1, 1 << *r0);
790 *r2 = reg_fortmp(t2, (1 << *r0) | (1 << *r1));
791 tmp_to(t0, *r0);
792 tmp_to(t1, *r1);
793 tmp_to(t2, *r2);
796 void o_memcpy(void)
798 int rd, rs, rn;
799 load_regs2(&rn, &rs, &rd);
800 i_memcpy(rd, rs, rn);
801 tmp_drop(2);
804 void o_memset(void)
806 int rd, rs, rn;
807 load_regs2(&rn, &rs, &rd);
808 i_memset(rd, rs, rn);
809 tmp_drop(2);
812 static void jxz(int id, int z)
814 int r = reg_fortmp(TMP(0), 0);
815 tmp_pop(r);
816 i_bz(r, z);
817 jmp_add(id);
820 void o_jz(int id)
822 jxz(id, 1);
825 void o_jnz(int id)
827 jxz(id, 0);
830 void o_jmp(int id)
832 i_b();
833 jmp_add(id);
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_mkbss(char *name, int size, int global)
870 out_sym(name, OUT_BSS | (global ? OUT_GLOB : 0), bsslen, size);
871 bsslen += ALIGN(size, OUT_ALIGNMENT);
874 #define MAXDATS (1 << 10)
875 static char dat_names[MAXDATS][NAMELEN];
876 static int dat_offs[MAXDATS];
877 static int ndats;
879 void *o_mkdat(char *name, int size, int global)
881 void *addr = ds + dslen;
882 int idx = ndats++;
883 if (idx >= MAXDATS)
884 err("nomem: MAXDATS reached!\n");
885 strcpy(dat_names[idx], name);
886 dat_offs[idx] = dslen;
887 out_sym(name, OUT_DS | (global ? OUT_GLOB : 0), dslen, size);
888 dslen += ALIGN(size, OUT_ALIGNMENT);
889 return addr;
892 static int dat_off(char *name)
894 int i;
895 for (i = 0; i < ndats; i++)
896 if (!strcmp(name, dat_names[i]))
897 return dat_offs[i];
898 return 0;
901 void o_datset(char *name, int off, unsigned bt)
903 struct tmp *t = TMP(0);
904 int sym_off = dat_off(name) + off;
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 /* compiled division functions; div.s contains the source */
917 static int udivdi3[] = {
918 0xe3a02000, 0xe3a03000, 0xe1110001, 0x0a00000a,
919 0xe1b0c211, 0xe2822001, 0x5afffffc, 0xe3a0c001,
920 0xe2522001, 0x4a000004, 0xe1500211, 0x3afffffb,
921 0xe0400211, 0xe083321c, 0xeafffff8, 0xe1a01000,
922 0xe1a00003, 0xe1a0f00e,
924 static int umoddi3[] = {
925 0xe92d4000, 0xebffffeb, 0xe1a00001, 0xe8bd8000,
927 static int divdi3[] = {
928 0xe92d4030, 0xe1a04000, 0xe1a05001, 0xe1100000,
929 0x42600000, 0xe1110001, 0x42611000, 0xebffffe1,
930 0xe1340005, 0x42600000, 0xe1140004, 0x42611000,
931 0xe8bd8030,
933 static int moddi3[] = {
934 0xe92d4000, 0xebfffff0, 0xe1a00001, 0xe8bd8000,
937 void o_write(int fd)
939 if (putdiv) {
940 out_sym("__udivdi3", OUT_CS, cslen, 0);
941 os(udivdi3, sizeof(udivdi3));
942 out_sym("__umoddi3", OUT_CS, cslen, 0);
943 os(umoddi3, sizeof(umoddi3));
944 out_sym("__divdi3", OUT_CS, cslen, 0);
945 os(divdi3, sizeof(divdi3));
946 out_sym("__moddi3", OUT_CS, cslen, 0);
947 os(moddi3, sizeof(moddi3));
949 out_write(fd, cs, cslen, ds, dslen);
952 /* ARM arch specific functions */
954 #define I_AND 0x00
955 #define I_EOR 0x01
956 #define I_SUB 0x02
957 #define I_RSB 0x03
958 #define I_ADD 0x04
959 #define I_TST 0x08
960 #define I_CMP 0x0a
961 #define I_ORR 0x0c
962 #define I_MOV 0x0d
963 #define I_MVN 0x0f
965 /* for optimizing cmp + bcc */
966 #define OPT_ISCMP() (last_cmp + 12 == cslen && last_set + 4 == cslen)
967 #define OPT_CCOND() (*(unsigned int *) ((void *) cs + last_set) >> 28)
969 static long last_cmp = -1;
970 static long last_set = -1;
972 #define MAXNUMS 1024
974 /* data pool */
975 static long num_offs[MAXNUMS]; /* data immediate value */
976 static char num_names[MAXNUMS][NAMELEN]; /* relocation data symbol name */
977 static int nums;
979 static int pool_find(char *name, int off)
981 int i;
982 for (i = 0; i < nums; i++)
983 if (!strcmp(name, num_names[i]) && off == num_offs[i])
984 return i;
985 return -1;
988 static int pool_num(long num)
990 int idx = pool_find("", num);
991 if (idx < 0) {
992 idx = nums++;
993 num_offs[idx] = num;
994 num_names[idx][0] = '\0';
996 return idx << 2;
999 static int pool_reloc(char *name, long off)
1001 int idx = pool_find(name, off);
1002 if (idx < 0) {
1003 idx = nums++;
1004 num_offs[idx] = off;
1005 strcpy(num_names[idx], name);
1007 return idx << 2;
1010 static void pool_write(void)
1012 int i;
1013 for (i = 0; i < nums; i++) {
1014 if (num_names[i])
1015 out_rel(num_names[i], OUT_CS, cslen);
1016 oi(num_offs[i]);
1021 * data processing:
1022 * +---------------------------------------+
1023 * |COND|00|I| op |S| Rn | Rd | operand2 |
1024 * +---------------------------------------+
1026 * S: set condition code
1027 * Rn: first operand
1028 * Rd: destination operand
1030 * I=0 operand2=| shift | Rm |
1031 * I=1 operand2=|rota| imm |
1033 #define ADD(op, rd, rn, s, i, cond) \
1034 (((cond) << 28) | ((i) << 25) | ((s) << 20) | \
1035 ((op) << 21) | ((rn) << 16) | ((rd) << 12))
1037 static int add_encimm(unsigned n)
1039 int i = 0;
1040 while (i < 12 && (n >> ((4 + i) << 1)))
1041 i++;
1042 return (n >> (i << 1)) | (((16 - i) & 0x0f) << 8);
1045 static unsigned add_decimm(int n)
1047 int rot = (16 - ((n >> 8) & 0x0f)) & 0x0f;
1048 return (n & 0xff) << (rot << 1);
1051 static int add_rndimm(unsigned n)
1053 int rot = (n >> 8) & 0x0f;
1054 int num = n & 0xff;
1055 if (rot == 0)
1056 return n;
1057 if (num == 0xff) {
1058 num = 0;
1059 rot = (rot + 12) & 0x0f;
1061 return ((num + 1) & 0xff) | (rot << 8);
1064 static int opcode_add(int op)
1066 /* opcode for O_ADD, O_SUB, O_AND, O_OR, O_XOR */
1067 static int rx[] = {I_ADD, I_SUB, I_AND, I_ORR, I_EOR};
1068 return rx[op & 0x0f];
1071 static void i_add(int op, int rd, int rn, int rm)
1073 oi(ADD(opcode_add(op), rd, rn, 0, 0, 14) | rm);
1076 static int i_decodeable(long imm)
1078 return add_decimm(add_encimm(imm)) == imm;
1081 static void i_add_imm(int op, int rd, int rn, long n)
1083 oi(ADD(opcode_add(op), rd, rn, 0, 1, 14) | add_encimm(n));
1086 static void i_num(int rd, long n)
1088 int enc = add_encimm(n);
1089 if (n == add_decimm(enc)) {
1090 oi(ADD(I_MOV, rd, 0, 0, 1, 14) | enc);
1091 return;
1093 enc = add_encimm(-n - 1);
1094 if (~n == add_decimm(enc)) {
1095 oi(ADD(I_MVN, rd, 0, 0, 1, 14) | enc);
1096 return;
1098 i_ldr(1, rd, REG_DP, pool_num(n), LONGSZ);
1101 static void i_add_anyimm(int rd, int rn, long n)
1103 int neg = n < 0;
1104 int imm = add_encimm(neg ? -n : n);
1105 if (imm == add_decimm(neg ? -n : n)) {
1106 oi(ADD(neg ? I_SUB : I_ADD, rd, rn, 0, 1, 14) | imm);
1107 } else {
1108 i_num(rd, n);
1109 i_add(O_ADD, rd, rd, rn);
1114 * multiply
1115 * +----------------------------------------+
1116 * |COND|000000|A|S| Rd | Rn | Rs |1001| Rm |
1117 * +----------------------------------------+
1119 * Rd: destination
1120 * A: accumulate
1121 * C: set condition codes
1123 * I=0 operand2=| shift | Rm |
1124 * I=1 operand2=|rota| imm |
1126 #define MUL(rd, rn, rs) \
1127 ((14 << 28) | ((rd) << 16) | ((0) << 12) | ((rn) << 8) | ((9) << 4) | (rm))
1129 static void i_mul(int rd, int rn, int rm)
1131 oi(MUL(rd, rn, rm));
1134 static int opcode_set(int op)
1136 /* lt, gt, le, ge, eq, neq */
1137 static int ucond[] = {3, 8, 9, 2, 0, 1};
1138 static int scond[] = {11, 12, 13, 10, 0, 1};
1139 return op & O_SIGNED ? scond[op & 0x0f] : ucond[op & 0x0f];
1142 static void i_tst(int rn, int rm)
1144 oi(ADD(I_TST, 0, rn, 1, 0, 14) | rm);
1147 static void i_cmp(int rn, int rm)
1149 last_cmp = cslen;
1150 oi(ADD(I_CMP, 0, rn, 1, 0, 14) | rm);
1153 static void i_cmp_imm(int rn, long n)
1155 last_cmp = cslen;
1156 oi(ADD(I_CMP, 0, rn, 1, 1, 14) | add_encimm(n));
1159 static void i_set(int cond, int rd)
1161 oi(ADD(I_MOV, rd, 0, 0, 1, 14));
1162 last_set = cslen;
1163 oi(ADD(I_MOV, rd, 0, 0, 1, opcode_set(cond)) | 1);
1166 #define SM_LSL 0
1167 #define SM_LSR 1
1168 #define SM_ASR 2
1170 static int opcode_shl(int op)
1172 if (op & 0x0f)
1173 return op & O_SIGNED ? SM_ASR : SM_LSR;
1174 return SM_LSL;
1177 static void i_shl(int op, int rd, int rm, int rs)
1179 int sm = opcode_shl(op);
1180 oi(ADD(I_MOV, rd, 0, 0, 0, 14) | (rs << 8) | (sm << 5) | (1 << 4) | rm);
1183 static void i_shl_imm(int op, int rd, int rn, long n)
1185 int sm = opcode_shl(op);
1186 oi(ADD(I_MOV, rd, 0, 0, 0, 14) | (n << 7) | (sm << 5) | rn);
1189 static void i_mov(int rd, int rn)
1191 oi(ADD(I_MOV, rd, 0, 0, 0, 14) | rn);
1195 * single data transfer:
1196 * +------------------------------------------+
1197 * |COND|01|I|P|U|B|W|L| Rn | Rd | offset |
1198 * +------------------------------------------+
1200 * I: immediate/offset
1201 * P: post/pre indexing
1202 * U: down/up
1203 * B: byte/word
1204 * W: writeback
1205 * L: store/load
1206 * Rn: base register
1207 * Rd: source/destination register
1209 * I=0 offset=| immediate |
1210 * I=1 offset=| shift | Rm |
1212 * halfword and signed data transfer
1213 * +----------------------------------------------+
1214 * |COND|000|P|U|0|W|L| Rn | Rd |0000|1|S|H|1| Rm |
1215 * +----------------------------------------------+
1217 * +----------------------------------------------+
1218 * |COND|000|P|U|1|W|L| Rn | Rd |off1|1|S|H|1|off2|
1219 * +----------------------------------------------+
1221 * S: singed
1222 * H: halfword
1224 #define LDR(l, rd, rn, b, u, p, w) \
1225 ((14 << 28) | (1 << 26) | ((p) << 24) | ((b) << 22) | ((u) << 23) | \
1226 ((w) << 21) | ((l) << 20) | ((rn) << 16) | ((rd) << 12))
1227 #define LDRH(l, rd, rn, s, h, u, i) \
1228 ((14 << 28) | (1 << 24) | ((u) << 23) | ((i) << 22) | ((l) << 20) | \
1229 ((rn) << 16) | ((rd) << 12) | ((s) << 6) | ((h) << 5) | (9 << 4))
1231 static void i_ldr(int l, int rd, int rn, int off, int bt)
1233 int b = BT_SZ(bt) == 1;
1234 int h = BT_SZ(bt) == 2;
1235 int s = l && (bt & BT_SIGNED);
1236 int half = h || (b && s);
1237 int maximm = half ? 0x100 : 0x1000;
1238 int neg = off < 0;
1239 if (neg)
1240 off = -off;
1241 while (off >= maximm) {
1242 int imm = add_encimm(off);
1243 oi(ADD(neg ? I_SUB : I_ADD, REG_TMP, rn, 0, 1, 14) | imm);
1244 rn = REG_TMP;
1245 off -= add_decimm(imm);
1247 if (!half)
1248 oi(LDR(l, rd, rn, b, !neg, 1, 0) | off);
1249 else
1250 oi(LDRH(l, rd, rn, s, h, !neg, 1) |
1251 ((off & 0xf0) << 4) | (off & 0x0f));
1254 static void i_sym(int rd, char *sym, int off)
1256 int doff = pool_reloc(sym, off);
1257 i_ldr(1, rd, REG_DP, doff, LONGSZ);
1260 static void i_neg(int rd)
1262 oi(ADD(I_RSB, rd, rd, 0, 1, 14));
1265 static void i_not(int rd)
1267 oi(ADD(I_MVN, rd, 0, 0, 0, 14) | rd);
1270 static int cond_nots[] = {1, 0, 3, 2, -1, -1, -1, -1, 9, 8, 11, 10, 13, 12, -1};
1272 static void i_lnot(int rd)
1274 if (OPT_ISCMP()) {
1275 unsigned int *lset = (void *) cs + last_set;
1276 int cond = cond_nots[OPT_CCOND()];
1277 *lset = (*lset & 0x0fffffff) | (cond << 28);
1278 return;
1280 i_tst(rd, rd);
1281 i_set(O_EQ, rd);
1284 /* rd = rd & ((1 << bits) - 1) */
1285 static void i_zx(int rd, int bits)
1287 if (bits <= 8) {
1288 oi(ADD(I_AND, rd, rd, 0, 1, 14) | add_encimm((1 << bits) - 1));
1289 } else {
1290 i_shl_imm(O_SHL, rd, rd, 32 - bits);
1291 i_shl_imm(O_SHR, rd, rd, 32 - bits);
1295 static void i_sx(int rd, int bits)
1297 i_shl_imm(O_SHL, rd, rd, 32 - bits);
1298 i_shl_imm(O_SIGNED | O_SHR, rd, rd, 32 - bits);
1302 * branch:
1303 * +-----------------------------------+
1304 * |COND|101|L| offset |
1305 * +-----------------------------------+
1307 * L: link
1309 #define BL(cond, l, o) (((cond) << 28) | (5 << 25) | ((l) << 24) | \
1310 ((((o) - 8) >> 2) & 0x00ffffff))
1312 static void i_b(void)
1314 oi(BL(14, 0, 0));
1317 static void i_bz(int rn, int z)
1319 if (OPT_ISCMP()) {
1320 int cond = OPT_CCOND();
1321 cslen = last_cmp + 4;
1322 last_set = -1;
1323 oi(BL(z ? cond_nots[cond] : cond, 0, 0));
1324 return;
1326 i_tst(rn, rn);
1327 oi(BL(z ? 0 : 1, 0, 0));
1330 static void i_b_fill(long src, long dst)
1332 long diff = dst - src - 8;
1333 long *m = (long *) (cs + src);
1334 *m = (*m & 0xff000000) | ((diff >> 2) & 0x00ffffff);
1337 static void i_memcpy(int rd, int rs, int rn)
1339 oi(ADD(I_SUB, rn, rn, 1, 1, 14) | 1);
1340 oi(BL(4, 0, 16));
1341 oi(LDR(1, REG_TMP, rs, 1, 1, 0, 0) | 1);
1342 oi(LDR(0, REG_TMP, rd, 1, 1, 0, 0) | 1);
1343 oi(BL(14, 0, -16));
1346 static void i_memset(int rd, int rs, int rn)
1348 oi(ADD(I_SUB, rn, rn, 1, 1, 14) | 1);
1349 oi(BL(4, 0, 12));
1350 oi(LDR(0, rs, rd, 1, 1, 0, 0) | 1);
1351 oi(BL(14, 0, -12));
1354 static void i_call_reg(int rd)
1356 i_mov(REG_LR, REG_PC);
1357 i_mov(REG_PC, rd);
1360 static void i_call(char *sym, int off)
1362 out_rel(sym, OUT_CS | OUT_REL24, cslen);
1363 oi(BL(14, 1, off));
1366 static void i_prolog(void)
1368 func_beg = cslen;
1369 last_cmp = -1;
1370 last_set = -1;
1371 nums = 0;
1372 oi(0xe1a0c00d); /* mov r12, sp */
1373 oi(0xe92d000f); /* stmfd sp!, {r0-r3} */
1374 oi(0xe92d5ff0); /* stmfd sp!, {r0-r11, r12, lr} */
1375 oi(0xe1a0b00d); /* mov fp, sp */
1376 oi(0xe24dd000); /* sub sp, sp, xx */
1377 oi(0xe28fa000); /* add dp, pc, xx */
1380 static void i_epilog(void)
1382 int dpoff;
1383 oi(0xe89baff0); /* ldmfd fp, {r4-r11, sp, pc} */
1384 dpoff = add_decimm(add_rndimm(add_encimm(cslen - func_beg - 28)));
1385 cslen = func_beg + dpoff + 28;
1386 maxsp = ALIGN(maxsp, 8);
1387 maxsp = add_decimm(add_rndimm(add_encimm(maxsp)));
1388 /* fill stack sub: sp = sp - xx */
1389 *(long *) (cs + func_beg + 16) |= add_encimm(maxsp);
1390 /* fill data ptr addition: dp = pc + xx */
1391 *(long *) (cs + func_beg + 20) |= add_encimm(dpoff);
1392 pool_write();