ncc: define __i386__ for x86 builds
[neatcc.git] / arm.c
blobc62a49615ab64bdbf22bfd8a7b48b412736cbb2b
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 long sp;
35 static long func_beg;
36 static long maxsp;
38 #define TMP(i) (((i) < ntmp) ? &tmps[ntmp - 1 - (i)] : NULL)
40 static struct tmp {
41 long addr;
42 char sym[NAMELEN];
43 long off; /* offset from a symbol or a local */
44 unsigned loc; /* variable location */
45 unsigned bt; /* type of address; zero when not a pointer */
46 } tmps[MAXTMP];
47 static int ntmp;
49 static int tmpsp;
51 /* arch-specific functions */
52 static void i_ldr(int l, int rd, int rn, int off, int bt);
53 static void i_mov(int rd, int rn);
54 static void i_add(int op, int rd, int rn, int rm);
55 static void i_shl(int op, int rd, int rm, int rs);
56 static void i_mul(int rd, int rn, int rm);
57 static void i_cmp(int rn, int rm);
58 static int i_decodeable(long imm);
59 static void i_add_imm(int op, int rd, int rn, long n);
60 static void i_shl_imm(int op, int rd, int rn, long n);
61 static void i_cmp_imm(int rn, long n);
62 static void i_add_anyimm(int rd, int rn, long n);
63 static void i_num(int rd, long n);
64 static void i_sym(int rd, char *sym, int off);
65 static void i_set(int op, int rd);
66 static void i_neg(int rd);
67 static void i_not(int rd);
68 static void i_lnot(int rd);
69 static void i_zx(int rd, int bits);
70 static void i_sx(int rd, int bits);
71 static void i_b(long addr);
72 static void i_b_fill(long *dst, int diff);
73 static void i_b_if(long addr, int rn, int z);
74 static void i_memcpy(int rd, int rs, int rn);
75 static void i_memset(int rd, int rs, int rn);
76 static void i_call(char *sym, int off);
77 static void i_call_reg(int rd);
78 static void i_prolog(void);
79 static void i_epilog(void);
81 static struct tmp *regs[NREGS];
82 static int tmpregs[] = {4, 5, 6, 7, 8, 9, 0, 1, 2, 3};
83 static int argregs[] = {0, 1, 2, 3};
85 #define MAXRET (1 << 8)
87 static long ret[MAXRET];
88 static int nret;
90 /* output div/mod functions */
91 static int putdiv = 0;
93 static void os(void *s, int n)
95 memcpy(cs + cslen, s, n);
96 cslen += n;
99 static void oi(long n)
101 *(int *) (cs + cslen) = n;
102 cslen += 4;
105 static long sp_push(int size)
107 sp += size;
108 if (sp > maxsp)
109 maxsp = sp;
110 return sp;
113 static void tmp_mem(struct tmp *tmp)
115 int src = tmp->addr;
116 if (!(tmp->loc == LOC_REG))
117 return;
118 if (tmpsp == -1)
119 tmpsp = sp;
120 tmp->addr = -sp_push(LONGSZ);
121 i_ldr(0, src, REG_FP, tmp->addr, LONGSZ);
122 regs[src] = NULL;
123 tmp->loc = LOC_MEM;
126 static void num_cast(struct tmp *t, unsigned bt)
128 if (!(bt & BT_SIGNED) && BT_SZ(bt) != LONGSZ)
129 t->addr &= ((1l << (long) (BT_SZ(bt) * 8)) - 1);
130 if (bt & BT_SIGNED && BT_SZ(bt) != LONGSZ &&
131 t->addr > (1l << (BT_SZ(bt) * 8 - 1)))
132 t->addr = -((1l << (BT_SZ(bt) * 8)) - t->addr);
135 static void tmp_reg(struct tmp *tmp, int dst, int deref)
137 int bt = tmp->bt;
138 if (!tmp->bt)
139 deref = 0;
140 if (deref)
141 tmp->bt = 0;
142 if (tmp->loc == LOC_NUM) {
143 i_num(dst, tmp->addr);
144 tmp->addr = dst;
145 regs[dst] = tmp;
146 tmp->loc = LOC_REG;
148 if (tmp->loc == LOC_SYM) {
149 i_sym(dst, tmp->sym, tmp->off);
150 tmp->addr = dst;
151 regs[dst] = tmp;
152 tmp->loc = LOC_REG;
154 if (tmp->loc == LOC_REG) {
155 if (deref)
156 i_ldr(1, dst, tmp->addr, 0, bt);
157 else if (dst != tmp->addr)
158 i_mov(dst, tmp->addr);
159 regs[tmp->addr] = NULL;
161 if (tmp->loc == LOC_LOCAL) {
162 if (deref)
163 i_ldr(1, dst, REG_FP, tmp->addr + tmp->off, bt);
164 else
165 i_add_anyimm(dst, REG_FP, tmp->addr + tmp->off);
167 if (tmp->loc == LOC_MEM) {
168 i_ldr(1, dst, REG_FP, tmp->addr, LONGSZ);
169 if (deref)
170 i_ldr(1, dst, dst, 0, bt);
172 tmp->addr = dst;
173 regs[dst] = tmp;
174 tmp->loc = LOC_REG;
177 static void reg_free(int reg)
179 int i;
180 if (!regs[reg])
181 return;
182 for (i = 0; i < ARRAY_SIZE(tmpregs); i++)
183 if (!regs[tmpregs[i]]) {
184 tmp_reg(regs[reg], tmpregs[i], 0);
185 return;
187 tmp_mem(regs[reg]);
190 static void reg_for(int reg, struct tmp *t)
192 if (regs[reg] && regs[reg] != t)
193 reg_free(reg);
196 static void tmp_mv(struct tmp *t, int reg)
198 reg_for(reg, t);
199 tmp_reg(t, reg, 0);
202 static void tmp_to(struct tmp *t, int reg)
204 reg_for(reg, t);
205 tmp_reg(t, reg, 1);
208 static void tmp_drop(int n)
210 int i;
211 for (i = ntmp - n; i < ntmp; i++)
212 if (tmps[i].loc == LOC_REG)
213 regs[tmps[i].addr] = NULL;
214 ntmp -= n;
217 static void tmp_pop(int reg)
219 struct tmp *t = TMP(0);
220 tmp_to(t, reg);
221 tmp_drop(1);
224 static struct tmp *tmp_new(void)
226 return &tmps[ntmp++];
229 static void tmp_push(int reg)
231 struct tmp *t = tmp_new();
232 t->addr = reg;
233 t->bt = 0;
234 t->loc = LOC_REG;
235 regs[reg] = t;
238 void o_local(long addr)
240 struct tmp *t = tmp_new();
241 t->addr = -addr;
242 t->loc = LOC_LOCAL;
243 t->bt = 0;
244 t->off = 0;
247 void o_num(long num)
249 struct tmp *t = tmp_new();
250 t->addr = num;
251 t->bt = 0;
252 t->loc = LOC_NUM;
255 void o_sym(char *name)
257 struct tmp *t = tmp_new();
258 strcpy(t->sym, name);
259 t->loc = LOC_SYM;
260 t->bt = 0;
261 t->off = 0;
264 void o_tmpdrop(int n)
266 if (n == -1 || n > ntmp)
267 n = ntmp;
268 tmp_drop(n);
269 if (!ntmp) {
270 if (tmpsp != -1)
271 sp = tmpsp;
272 tmpsp = -1;
276 /* make sure tmps remain intact after a conditional expression */
277 void o_fork(void)
279 int i;
280 for (i = 0; i < ntmp - 1; i++)
281 tmp_mem(&tmps[i]);
284 void o_forkpush(void)
286 tmp_pop(REG_FORK);
289 void o_forkjoin(void)
291 tmp_push(REG_FORK);
294 void o_tmpswap(void)
296 struct tmp *t1 = TMP(0);
297 struct tmp *t2 = TMP(1);
298 struct tmp t;
299 memcpy(&t, t1, sizeof(t));
300 memcpy(t1, t2, sizeof(t));
301 memcpy(t2, &t, sizeof(t));
302 if (t1->loc == LOC_REG)
303 regs[t1->addr] = t1;
304 if (t2->loc == LOC_REG)
305 regs[t2->addr] = t2;
308 static int reg_get(int mask)
310 int i;
311 for (i = 0; i < ARRAY_SIZE(tmpregs); i++)
312 if ((1 << tmpregs[i]) & mask && !regs[tmpregs[i]])
313 return tmpregs[i];
314 for (i = 0; i < ARRAY_SIZE(tmpregs); i++)
315 if ((1 << tmpregs[i]) & mask) {
316 reg_free(tmpregs[i]);
317 return tmpregs[i];
319 return 0;
322 static int reg_fortmp(struct tmp *t, int notmask)
324 if (t->loc == LOC_REG && !(notmask & (1 << t->addr)))
325 return t->addr;
326 return reg_get(~notmask);
329 static void tmp_copy(struct tmp *t1)
331 struct tmp *t2 = tmp_new();
332 memcpy(t2, t1, sizeof(*t1));
333 if (!(t1->loc & (LOC_REG | LOC_MEM)))
334 return;
335 if (t1->loc == LOC_MEM) {
336 tmp_mv(t2, reg_get(~0));
337 } else if (t1->loc == LOC_REG) {
338 t2->addr = reg_fortmp(t2, 1 << t1->addr);
339 i_mov(t2->addr, t1->addr);
340 regs[t2->addr] = t2;
344 void o_tmpcopy(void)
346 tmp_copy(TMP(0));
349 void o_cast(unsigned bt)
351 struct tmp *t = TMP(0);
352 if (!t->bt && t->loc == LOC_NUM) {
353 num_cast(t, bt);
354 return;
356 if (BT_SZ(bt) != LONGSZ) {
357 int reg = reg_fortmp(t, 0);
358 tmp_to(t, reg);
359 if (bt & BT_SIGNED)
360 i_sx(reg, BT_SZ(bt) * 8);
361 else
362 i_zx(reg, BT_SZ(bt) * 8);
366 void o_func_beg(char *name, int argc, int global, int vararg)
368 out_sym(name, (global ? OUT_GLOB : 0) | OUT_CS, cslen, 0);
369 i_prolog();
370 sp = 0;
371 maxsp = sp;
372 ntmp = 0;
373 tmpsp = -1;
374 nret = 0;
375 memset(regs, 0, sizeof(regs));
378 void o_deref(unsigned bt)
380 struct tmp *t = TMP(0);
381 if (t->bt)
382 tmp_to(t, reg_fortmp(t, 0));
383 t->bt = bt;
386 void o_load(void)
388 struct tmp *t = TMP(0);
389 tmp_to(t, reg_fortmp(t, 0));
392 #define TMP_NUM(t) ((t)->loc == LOC_NUM && !(t)->bt)
393 #define LOCAL_PTR(t) ((t)->loc == LOC_LOCAL && !(t)->bt)
394 #define SYM_PTR(t) ((t)->loc == LOC_SYM && !(t)->bt)
396 int o_popnum(long *c)
398 struct tmp *t = TMP(0);
399 if (!TMP_NUM(t))
400 return 1;
401 *c = t->addr;
402 tmp_drop(1);
403 return 0;
406 void o_ret(int rets)
408 if (rets)
409 tmp_pop(REG_RET);
410 else
411 i_num(REG_RET, 0);
412 ret[nret++] = o_jmp(0);
415 void o_func_end(void)
417 int i;
418 for (i = 0; i < nret; i++)
419 o_filljmp(ret[i]);
420 i_epilog();
423 long o_mklocal(int size)
425 return sp_push(ALIGN(size, LONGSZ));
428 void o_rmlocal(long addr, int sz)
430 sp = addr - sz;
433 long o_arg2loc(int i)
435 return -(10 + i) << 2;
438 void o_assign(unsigned bt)
440 struct tmp *t1 = TMP(0);
441 struct tmp *t2 = TMP(1);
442 int r1 = reg_fortmp(t1, 0);
443 int r2 = reg_fortmp(t2, 1 << r1);
444 int off = 0;
445 tmp_to(t1, r1);
446 if (t2->bt)
447 tmp_to(t2, r2);
448 if (t2->loc == LOC_LOCAL) {
449 r2 = REG_FP;
450 off = t2->addr + t2->off;
451 } else {
452 tmp_to(t2, r2);
454 tmp_drop(2);
455 i_ldr(0, r1, r2, off, bt);
456 tmp_push(r1);
459 static long cu(int op, long i)
461 switch (op & 0xff) {
462 case O_NEG:
463 return -i;
464 case O_NOT:
465 return ~i;
466 case O_LNOT:
467 return !i;
469 return 0;
472 static int c_uop(int op)
474 struct tmp *t1 = TMP(0);
475 if (!TMP_NUM(t1))
476 return 1;
477 tmp_drop(1);
478 o_num(cu(op, t1->addr));
479 return 0;
482 static long cb(int op, long a, long b)
484 switch (op & 0xff) {
485 case O_ADD:
486 return a + b;
487 case O_SUB:
488 return a - b;
489 case O_AND:
490 return a & b;
491 case O_OR:
492 return a | b;
493 case O_XOR:
494 return a ^ b;
495 case O_MUL:
496 return a * b;
497 case O_DIV:
498 return a / b;
499 case O_MOD:
500 return a % b;
501 case O_SHL:
502 return a << b;
503 case O_SHR:
504 if (op & O_SIGNED)
505 return a >> b;
506 else
507 return (unsigned long) a >> b;
508 case O_LT:
509 return a < b;
510 case O_GT:
511 return a > b;
512 case O_LE:
513 return a <= b;
514 case O_GE:
515 return a >= b;
516 case O_EQ:
517 return a == b;
518 case O_NEQ:
519 return a != b;
521 return 0;
524 static int c_bop(int op)
526 struct tmp *t1 = TMP(0);
527 struct tmp *t2 = TMP(1);
528 int locals = LOCAL_PTR(t1) + LOCAL_PTR(t2);
529 int syms = SYM_PTR(t1) + SYM_PTR(t2);
530 int nums = TMP_NUM(t1) + TMP_NUM(t2);
531 if (syms + locals == 2 || syms + nums + locals != 2)
532 return 1;
533 if (nums == 1)
534 if ((op & 0xff) != O_ADD && ((op & 0xff) != O_SUB || TMP_NUM(t2)))
535 return 1;
536 if (nums == 1) {
537 long o1 = TMP_NUM(t1) ? t1->addr : t1->off;
538 long o2 = TMP_NUM(t2) ? t2->addr : t2->off;
539 long ret = cb(op, o2, o1);
540 if (!TMP_NUM(t1))
541 o_tmpswap();
542 t2->off = ret;
543 tmp_drop(1);
544 } else {
545 long ret = cb(op, t2->addr, t1->addr);
546 tmp_drop(2);
547 o_num(ret);
549 return 0;
552 void o_uop(int op)
554 int r1 = reg_fortmp(TMP(0), 0);
555 if (!c_uop(op))
556 return;
557 tmp_to(TMP(0), r1);
558 switch (op & 0xff) {
559 case O_NEG:
560 i_neg(r1);
561 break;
562 case O_NOT:
563 i_not(r1);
564 break;
565 case O_LNOT:
566 i_lnot(r1);
567 break;
571 static void bin_regs(int *r1, int *r2)
573 struct tmp *t2 = TMP(0);
574 struct tmp *t1 = TMP(1);
575 *r2 = reg_fortmp(t2, 0);
576 tmp_to(t2, *r2);
577 *r1 = reg_fortmp(t1, 1 << *r2);
578 tmp_pop(*r2);
579 tmp_pop(*r1);
582 static int bop_imm(int *r1, long *n, int swap)
584 struct tmp *t1 = TMP(0);
585 struct tmp *t2 = TMP(1);
586 if (!TMP_NUM(t1) && (!swap || !TMP_NUM(t2)))
587 return 1;
588 *n = TMP_NUM(t1) ? t1->addr : t2->addr;
589 if (!i_decodeable(*n))
590 return 1;
591 if (!TMP_NUM(t1))
592 o_tmpswap();
593 *r1 = reg_fortmp(t2, 0);
594 tmp_drop(1);
595 tmp_pop(*r1);
596 return 0;
599 static void bin_add(int op)
601 int r1, r2;
602 long n;
603 if (!bop_imm(&r1, &n, (op & 0xff) != O_SUB)) {
604 i_add_imm(op, r1, r1, n);
605 } else {
606 bin_regs(&r1, &r2);
607 i_add(op, r1, r1, r2);
609 tmp_push(r1);
612 static void bin_shx(int op)
614 int r1, r2;
615 long n;
616 if (!bop_imm(&r1, &n, 0)) {
617 i_shl_imm(op, r1, r1, n);
618 } else {
619 bin_regs(&r1, &r2);
620 i_shl(op, r1, r1, r2);
622 tmp_push(r1);
625 static int log2a(unsigned long n)
627 int i = 0;
628 for (i = 0; i < LONGSZ * 8; i++)
629 if (n & (1u << i))
630 break;
631 if (i == LONGSZ * 8 || !(n >> (i + 1)))
632 return i;
633 return -1;
636 /* optimized version of mul/div/mod for powers of two */
637 static int mul_2(int op)
639 struct tmp *t1 = TMP(0);
640 struct tmp *t2 = TMP(1);
641 long n;
642 int r2;
643 int p;
644 if ((op & 0xff) == O_MUL && t2->loc == LOC_NUM && !t2->bt)
645 o_tmpswap();
646 if (t1->loc != LOC_NUM || t1->bt)
647 return 1;
648 n = t1->addr;
649 p = log2a(n);
650 if (n && p == -1)
651 return 1;
652 if ((op & 0xff) == O_MUL) {
653 tmp_drop(1);
654 if (n == 1)
655 return 0;
656 if (n == 0) {
657 tmp_drop(1);
658 o_num(0);
659 return 0;
661 r2 = reg_fortmp(t2, 0);
662 tmp_to(t2, r2);
663 i_shl_imm(O_SHL, r2, r2, p);
664 return 0;
666 if (op == O_DIV) {
667 tmp_drop(1);
668 if (n == 1)
669 return 0;
670 r2 = reg_fortmp(t2, 0);
671 tmp_to(t2, r2);
672 i_shl_imm((op & O_SIGNED) | O_SHR, r2, r2, p);
673 return 0;
675 if (op == O_MOD) {
676 tmp_drop(1);
677 if (n == 1) {
678 tmp_drop(1);
679 o_num(0);
680 return 0;
682 r2 = reg_fortmp(t2, 0);
683 tmp_to(t2, r2);
684 i_zx(r2, p);
685 return 0;
687 return 1;
690 static void bin_div(int op)
692 struct tmp *t2 = TMP(0);
693 struct tmp *t1 = TMP(1);
694 char *func;
695 int i;
696 putdiv = 1;
697 if ((op & 0xff) == O_DIV)
698 func = op & O_SIGNED ? "__divdi3" : "__udivdi3";
699 else
700 func = op & O_SIGNED ? "__moddi3" : "__umoddi3";
701 for (i = 0; i < ARRAY_SIZE(argregs); i++)
702 if (regs[argregs[i]] && regs[argregs[i]] - tmps < ntmp - 2)
703 tmp_mem(regs[argregs[i]]);
704 tmp_to(t1, argregs[0]);
705 tmp_to(t2, argregs[1]);
706 tmp_drop(2);
707 i_call(func, 0);
708 tmp_push(REG_RET);
711 static void bin_mul(int op)
713 int r1, r2;
714 if (!mul_2(op))
715 return;
716 if ((op & 0xff) == O_DIV || (op & 0xff) == O_MOD) {
717 bin_div(op);
718 } else {
719 bin_regs(&r1, &r2);
720 i_mul(r1, r1, r2);
721 tmp_push(r1);
725 static void bin_cmp(int op)
727 int r1, r2;
728 long n;
729 if (!bop_imm(&r1, &n, (op & 0xff) == O_EQ || (op & 0xff) == O_NEQ)) {
730 i_cmp_imm(r1, n);
731 } else {
732 bin_regs(&r1, &r2);
733 i_cmp(r1, r2);
735 i_set(op, r1);
736 tmp_push(r1);
739 void o_bop(int op)
741 if (!c_bop(op))
742 return;
743 if ((op & 0xf0) == 0x00)
744 bin_add(op);
745 if ((op & 0xf0) == 0x10)
746 bin_shx(op);
747 if ((op & 0xf0) == 0x20)
748 bin_mul(op);
749 if ((op & 0xf0) == 0x30)
750 bin_cmp(op);
753 static void load_regs2(int *r0, int *r1, int *r2)
755 struct tmp *t0 = TMP(0);
756 struct tmp *t1 = TMP(1);
757 struct tmp *t2 = TMP(2);
758 *r0 = reg_fortmp(t0, 0);
759 *r1 = reg_fortmp(t1, 1 << *r0);
760 *r2 = reg_fortmp(t2, (1 << *r0) | (1 << *r1));
761 tmp_to(t0, *r0);
762 tmp_to(t1, *r1);
763 tmp_to(t2, *r2);
766 void o_memcpy(void)
768 int rd, rs, rn;
769 load_regs2(&rn, &rs, &rd);
770 i_memcpy(rd, rs, rn);
771 tmp_drop(2);
774 void o_memset(void)
776 int rd, rs, rn;
777 load_regs2(&rn, &rs, &rd);
778 i_memset(rd, rs, rn);
779 tmp_drop(2);
782 long o_mklabel(void)
784 return cslen;
787 static long jxz(long addr, int z)
789 int r = reg_fortmp(TMP(0), 0);
790 tmp_pop(r);
791 i_b_if(addr, r, z);
792 return cslen - 4;
795 long o_jz(long addr)
797 return jxz(addr, 1);
800 long o_jnz(long addr)
802 return jxz(addr, 0);
805 long o_jmp(long addr)
807 i_b(addr);
808 return cslen - 4;
811 void o_filljmp2(long addr, long jmpdst)
813 i_b_fill((void *) cs + addr, jmpdst - addr);
816 void o_filljmp(long addr)
818 o_filljmp2(addr, cslen);
821 void o_call(int argc, int rets)
823 struct tmp *t;
824 int i;
825 int aregs = MIN(ARRAY_SIZE(argregs), argc);
826 for (i = 0; i < ARRAY_SIZE(argregs); i++)
827 if (regs[argregs[i]] && regs[argregs[i]] - tmps < ntmp - argc)
828 tmp_mem(regs[argregs[i]]);
829 if (argc > aregs) {
830 sp_push(LONGSZ * (argc - aregs));
831 for (i = argc - 1; i >= aregs; --i) {
832 int reg = reg_fortmp(TMP(0), 0);
833 tmp_pop(reg);
834 i_ldr(0, reg, REG_SP, (i - aregs) * LONGSZ, LONGSZ);
837 for (i = aregs - 1; i >= 0; --i)
838 tmp_to(TMP(aregs - i - 1), argregs[i]);
839 tmp_drop(aregs);
840 t = TMP(0);
841 if (t->loc == LOC_SYM && !t->bt) {
842 i_call(t->sym, t->off);
843 tmp_drop(1);
844 } else {
845 int reg = t->loc == LOC_REG ? t->addr : REG_TMP;
846 tmp_pop(reg);
847 i_call_reg(reg);
849 if (rets)
850 tmp_push(REG_RET);
853 void o_mkbss(char *name, int size, int global)
855 out_sym(name, OUT_BSS | (global ? OUT_GLOB : 0), bsslen, size);
856 bsslen += ALIGN(size, OUT_ALIGNMENT);
859 #define MAXDATS (1 << 10)
860 static char dat_names[MAXDATS][NAMELEN];
861 static int dat_offs[MAXDATS];
862 static int ndats;
864 void err(char *msg);
865 void *o_mkdat(char *name, int size, int global)
867 void *addr = ds + dslen;
868 int idx = ndats++;
869 if (idx >= MAXDATS)
870 err("nomem: MAXDATS reached!\n");
871 strcpy(dat_names[idx], name);
872 dat_offs[idx] = dslen;
873 out_sym(name, OUT_DS | (global ? OUT_GLOB : 0), dslen, size);
874 dslen += ALIGN(size, OUT_ALIGNMENT);
875 return addr;
878 static int dat_off(char *name)
880 int i;
881 for (i = 0; i < ndats; i++)
882 if (!strcmp(name, dat_names[i]))
883 return dat_offs[i];
884 return 0;
887 void o_datset(char *name, int off, unsigned bt)
889 struct tmp *t = TMP(0);
890 int sym_off = dat_off(name) + off;
891 if (t->loc == LOC_NUM && !t->bt) {
892 num_cast(t, bt);
893 memcpy(ds + sym_off, &t->addr, BT_SZ(bt));
895 if (t->loc == LOC_SYM && !t->bt) {
896 out_rel(t->sym, OUT_DS, sym_off);
897 memcpy(ds + sym_off, &t->off, BT_SZ(bt));
899 tmp_drop(1);
902 /* compiled division functions; div.s contains the source */
903 static int udivdi3[] = {
904 0xe3a02000, 0xe3a03000, 0xe1110001, 0x0a00000a,
905 0xe1b0c211, 0xe2822001, 0x5afffffc, 0xe3a0c001,
906 0xe2522001, 0x4a000004, 0xe1500211, 0x3afffffb,
907 0xe0400211, 0xe083321c, 0xeafffff8, 0xe1a01000,
908 0xe1a00003, 0xe1a0f00e,
910 static int umoddi3[] = {
911 0xe92d4000, 0xebffffeb, 0xe1a00001, 0xe8bd8000,
913 static int divdi3[] = {
914 0xe92d4030, 0xe1a04000, 0xe1a05001, 0xe1100000,
915 0x42600000, 0xe1110001, 0x42611000, 0xebffffe1,
916 0xe1340005, 0x42600000, 0xe1140004, 0x42611000,
917 0xe8bd8030,
919 static int moddi3[] = {
920 0xe92d4000, 0xebfffff0, 0xe1a00001, 0xe8bd8000,
923 void o_write(int fd)
925 if (putdiv) {
926 out_sym("__udivdi3", OUT_CS, cslen, 0);
927 os(udivdi3, sizeof(udivdi3));
928 out_sym("__umoddi3", OUT_CS, cslen, 0);
929 os(umoddi3, sizeof(umoddi3));
930 out_sym("__divdi3", OUT_CS, cslen, 0);
931 os(divdi3, sizeof(divdi3));
932 out_sym("__moddi3", OUT_CS, cslen, 0);
933 os(moddi3, sizeof(moddi3));
935 out_write(fd, cs, cslen, ds, dslen);
938 /* ARM arch specific functions */
940 #define I_AND 0x00
941 #define I_EOR 0x01
942 #define I_SUB 0x02
943 #define I_RSB 0x03
944 #define I_ADD 0x04
945 #define I_TST 0x08
946 #define I_CMP 0x0a
947 #define I_ORR 0x0c
948 #define I_MOV 0x0d
949 #define I_MVN 0x0f
951 /* for optimizing cmp + bcc */
952 #define OPT_ISCMP() (last_cmp + 12 == cslen && last_set + 4 == cslen)
953 #define OPT_CCOND() (*(unsigned int *) ((void *) cs + last_set) >> 28)
955 static long last_cmp = -1;
956 static long last_set = -1;
958 #define MAXNUMS 1024
960 /* data pool */
961 static long num_offs[MAXNUMS]; /* data immediate value */
962 static char num_names[MAXNUMS][NAMELEN]; /* relocation data symbol name */
963 static int nums;
965 static int pool_find(char *name, int off)
967 int i;
968 for (i = 0; i < nums; i++)
969 if (!strcmp(name, num_names[i]) && off == num_offs[i])
970 return i;
971 return -1;
974 static int pool_num(long num)
976 int idx = pool_find("", num);
977 if (idx < 0) {
978 idx = nums++;
979 num_offs[idx] = num;
980 num_names[idx][0] = '\0';
982 return idx << 2;
985 static int pool_reloc(char *name, long off)
987 int idx = pool_find(name, off);
988 if (idx < 0) {
989 idx = nums++;
990 num_offs[idx] = off;
991 strcpy(num_names[idx], name);
993 return idx << 2;
996 static void pool_write(void)
998 int i;
999 for (i = 0; i < nums; i++) {
1000 if (num_names[i])
1001 out_rel(num_names[i], OUT_CS, cslen);
1002 oi(num_offs[i]);
1007 * data processing:
1008 * +---------------------------------------+
1009 * |COND|00|I| op |S| Rn | Rd | operand2 |
1010 * +---------------------------------------+
1012 * S: set condition code
1013 * Rn: first operand
1014 * Rd: destination operand
1016 * I=0 operand2=| shift | Rm |
1017 * I=1 operand2=|rota| imm |
1019 #define ADD(op, rd, rn, s, i, cond) \
1020 (((cond) << 28) | ((i) << 25) | ((s) << 20) | \
1021 ((op) << 21) | ((rn) << 16) | ((rd) << 12))
1023 static int add_encimm(unsigned n)
1025 int i = 0;
1026 while (i < 12 && (n >> ((4 + i) << 1)))
1027 i++;
1028 return (n >> (i << 1)) | (((16 - i) & 0x0f) << 8);
1031 static unsigned add_decimm(int n)
1033 int rot = (16 - ((n >> 8) & 0x0f)) & 0x0f;
1034 return (n & 0xff) << (rot << 1);
1037 static int add_rndimm(unsigned n)
1039 int rot = (n >> 8) & 0x0f;
1040 int num = n & 0xff;
1041 if (rot == 0)
1042 return n;
1043 if (num == 0xff) {
1044 num = 0;
1045 rot = (rot + 12) & 0x0f;
1047 return ((num + 1) & 0xff) | (rot << 8);
1050 static int opcode_add(int op)
1052 /* opcode for O_ADD, O_SUB, O_AND, O_OR, O_XOR */
1053 static int rx[] = {I_ADD, I_SUB, I_AND, I_ORR, I_EOR};
1054 return rx[op & 0x0f];
1057 static void i_add(int op, int rd, int rn, int rm)
1059 oi(ADD(opcode_add(op), rd, rn, 0, 0, 14) | rm);
1062 static int i_decodeable(long imm)
1064 return add_decimm(add_encimm(imm)) == imm;
1067 static void i_add_imm(int op, int rd, int rn, long n)
1069 oi(ADD(opcode_add(op), rd, rn, 0, 1, 14) | add_encimm(n));
1072 static void i_num(int rd, long n)
1074 int enc = add_encimm(n);
1075 if (n == add_decimm(enc)) {
1076 oi(ADD(I_MOV, rd, 0, 0, 1, 14) | enc);
1077 return;
1079 enc = add_encimm(-n - 1);
1080 if (~n == add_decimm(enc)) {
1081 oi(ADD(I_MVN, rd, 0, 0, 1, 14) | enc);
1082 return;
1084 i_ldr(1, rd, REG_DP, pool_num(n), LONGSZ);
1087 static void i_add_anyimm(int rd, int rn, long n)
1089 int neg = n < 0;
1090 int imm = add_encimm(neg ? -n : n);
1091 if (imm == add_decimm(neg ? -n : n)) {
1092 oi(ADD(neg ? I_SUB : I_ADD, rd, rn, 0, 1, 14) | imm);
1093 } else {
1094 i_num(rd, n);
1095 i_add(O_ADD, rd, rd, rn);
1100 * multiply
1101 * +----------------------------------------+
1102 * |COND|000000|A|S| Rd | Rn | Rs |1001| Rm |
1103 * +----------------------------------------+
1105 * Rd: destination
1106 * A: accumulate
1107 * C: set condition codes
1109 * I=0 operand2=| shift | Rm |
1110 * I=1 operand2=|rota| imm |
1112 #define MUL(rd, rn, rs) \
1113 ((14 << 28) | ((rd) << 16) | ((0) << 12) | ((rn) << 8) | ((9) << 4) | (rm))
1115 static void i_mul(int rd, int rn, int rm)
1117 oi(MUL(rd, rn, rm));
1120 static int opcode_set(int op)
1122 /* lt, gt, le, ge, eq, neq */
1123 static int ucond[] = {3, 8, 9, 2, 0, 1};
1124 static int scond[] = {11, 12, 13, 10, 0, 1};
1125 return op & O_SIGNED ? scond[op & 0x0f] : ucond[op & 0x0f];
1128 static void i_tst(int rn, int rm)
1130 oi(ADD(I_TST, 0, rn, 1, 0, 14) | rm);
1133 static void i_cmp(int rn, int rm)
1135 last_cmp = cslen;
1136 oi(ADD(I_CMP, 0, rn, 1, 0, 14) | rm);
1139 static void i_cmp_imm(int rn, long n)
1141 last_cmp = cslen;
1142 oi(ADD(I_CMP, 0, rn, 1, 1, 14) | add_encimm(n));
1145 static void i_set(int cond, int rd)
1147 oi(ADD(I_MOV, rd, 0, 0, 1, 14));
1148 last_set = cslen;
1149 oi(ADD(I_MOV, rd, 0, 0, 1, opcode_set(cond)) | 1);
1152 #define SM_LSL 0
1153 #define SM_LSR 1
1154 #define SM_ASR 2
1156 static int opcode_shl(int op)
1158 if (op & 0x0f)
1159 return op & O_SIGNED ? SM_ASR : SM_LSR;
1160 return SM_LSL;
1163 static void i_shl(int op, int rd, int rm, int rs)
1165 int sm = opcode_shl(op);
1166 oi(ADD(I_MOV, rd, 0, 0, 0, 14) | (rs << 8) | (sm << 5) | (1 << 4) | rm);
1169 static void i_shl_imm(int op, int rd, int rn, long n)
1171 int sm = opcode_shl(op);
1172 oi(ADD(I_MOV, rd, 0, 0, 0, 14) | (n << 7) | (sm << 5) | rn);
1175 static void i_mov(int rd, int rn)
1177 oi(ADD(I_MOV, rd, 0, 0, 0, 14) | rn);
1181 * single data transfer:
1182 * +------------------------------------------+
1183 * |COND|01|I|P|U|B|W|L| Rn | Rd | offset |
1184 * +------------------------------------------+
1186 * I: immediate/offset
1187 * P: post/pre indexing
1188 * U: down/up
1189 * B: byte/word
1190 * W: writeback
1191 * L: store/load
1192 * Rn: base register
1193 * Rd: source/destination register
1195 * I=0 offset=| immediate |
1196 * I=1 offset=| shift | Rm |
1198 * halfword and signed data transfer
1199 * +----------------------------------------------+
1200 * |COND|000|P|U|0|W|L| Rn | Rd |0000|1|S|H|1| Rm |
1201 * +----------------------------------------------+
1203 * +----------------------------------------------+
1204 * |COND|000|P|U|1|W|L| Rn | Rd |off1|1|S|H|1|off2|
1205 * +----------------------------------------------+
1207 * S: singed
1208 * H: halfword
1210 #define LDR(l, rd, rn, b, u, p, w) \
1211 ((14 << 28) | (1 << 26) | ((p) << 24) | ((b) << 22) | ((u) << 23) | \
1212 ((w) << 21) | ((l) << 20) | ((rn) << 16) | ((rd) << 12))
1213 #define LDRH(l, rd, rn, s, h, u, i) \
1214 ((14 << 28) | (1 << 24) | ((u) << 23) | ((i) << 22) | ((l) << 20) | \
1215 ((rn) << 16) | ((rd) << 12) | ((s) << 6) | ((h) << 5) | (9 << 4))
1217 static void i_ldr(int l, int rd, int rn, int off, int bt)
1219 int b = BT_SZ(bt) == 1;
1220 int h = BT_SZ(bt) == 2;
1221 int s = l && (bt & BT_SIGNED);
1222 int half = h || (b && s);
1223 int maximm = half ? 0x100 : 0x1000;
1224 int neg = off < 0;
1225 if (neg)
1226 off = -off;
1227 while (off >= maximm) {
1228 int imm = add_encimm(off);
1229 oi(ADD(neg ? I_SUB : I_ADD, REG_TMP, rn, 0, 1, 14) | imm);
1230 rn = REG_TMP;
1231 off -= add_decimm(imm);
1233 if (!half)
1234 oi(LDR(l, rd, rn, b, !neg, 1, 0) | off);
1235 else
1236 oi(LDRH(l, rd, rn, s, h, !neg, 1) |
1237 ((off & 0xf0) << 4) | (off & 0x0f));
1240 static void i_sym(int rd, char *sym, int off)
1242 int doff = pool_reloc(sym, off);
1243 i_ldr(1, rd, REG_DP, doff, LONGSZ);
1246 static void i_neg(int rd)
1248 oi(ADD(I_RSB, rd, rd, 0, 1, 14));
1251 static void i_not(int rd)
1253 oi(ADD(I_MVN, rd, 0, 0, 0, 14) | rd);
1256 static int cond_nots[] = {1, 0, 3, 2, -1, -1, -1, -1, 9, 8, 11, 10, 13, 12, -1};
1258 static void i_lnot(int rd)
1260 if (OPT_ISCMP()) {
1261 unsigned int *lset = (void *) cs + last_set;
1262 int cond = cond_nots[OPT_CCOND()];
1263 *lset = (*lset & 0x0fffffff) | (cond << 28);
1264 return;
1266 i_tst(rd, rd);
1267 i_set(O_EQ, rd);
1270 /* rd = rd & ((1 << bits) - 1) */
1271 static void i_zx(int rd, int bits)
1273 if (bits <= 8) {
1274 oi(ADD(I_AND, rd, rd, 0, 1, 14) | add_encimm((1 << bits) - 1));
1275 } else {
1276 i_shl_imm(O_SHL, rd, rd, 32 - bits);
1277 i_shl_imm(O_SHR, rd, rd, 32 - bits);
1281 static void i_sx(int rd, int bits)
1283 i_shl_imm(O_SHL, rd, rd, 32 - bits);
1284 i_shl_imm(O_SIGNED | O_SHR, rd, rd, 32 - bits);
1288 * branch:
1289 * +-----------------------------------+
1290 * |COND|101|L| offset |
1291 * +-----------------------------------+
1293 * L: link
1295 #define BL(cond, l, o) (((cond) << 28) | (5 << 25) | ((l) << 24) | \
1296 ((((o) - 8) >> 2) & 0x00ffffff))
1298 static void i_b(long addr)
1300 oi(BL(14, 0, addr - cslen));
1303 static void i_b_if(long addr, int rn, int z)
1305 if (OPT_ISCMP()) {
1306 int cond = OPT_CCOND();
1307 cslen = last_cmp + 4;
1308 last_set = -1;
1309 oi(BL(z ? cond_nots[cond] : cond, 0, addr - cslen));
1310 return;
1312 i_tst(rn, rn);
1313 oi(BL(z ? 0 : 1, 0, addr - cslen));
1316 static void i_b_fill(long *dst, int diff)
1318 *dst = (*dst & 0xff000000) | (((diff - 8) >> 2) & 0x00ffffff);
1321 static void i_memcpy(int rd, int rs, int rn)
1323 oi(ADD(I_SUB, rn, rn, 1, 1, 14) | 1);
1324 oi(BL(4, 0, 16));
1325 oi(LDR(1, REG_TMP, rs, 1, 1, 0, 0) | 1);
1326 oi(LDR(0, REG_TMP, rd, 1, 1, 0, 0) | 1);
1327 oi(BL(14, 0, -16));
1330 static void i_memset(int rd, int rs, int rn)
1332 oi(ADD(I_SUB, rn, rn, 1, 1, 14) | 1);
1333 oi(BL(4, 0, 12));
1334 oi(LDR(0, rs, rd, 1, 1, 0, 0) | 1);
1335 oi(BL(14, 0, -12));
1338 static void i_call_reg(int rd)
1340 i_mov(REG_LR, REG_PC);
1341 i_mov(REG_PC, rd);
1344 static void i_call(char *sym, int off)
1346 out_rel(sym, OUT_CS | OUT_REL24, cslen);
1347 oi(BL(14, 1, off));
1350 static void i_prolog(void)
1352 func_beg = cslen;
1353 last_cmp = -1;
1354 last_set = -1;
1355 nums = 0;
1356 oi(0xe1a0c00d); /* mov r12, sp */
1357 oi(0xe92d000f); /* stmfd sp!, {r0-r3} */
1358 oi(0xe92d5ff0); /* stmfd sp!, {r0-r11, r12, lr} */
1359 oi(0xe1a0b00d); /* mov fp, sp */
1360 oi(0xe24dd000); /* sub sp, sp, xx */
1361 oi(0xe28fa000); /* add dp, pc, xx */
1364 static void i_epilog(void)
1366 int dpoff;
1367 oi(0xe89baff0); /* ldmfd fp, {r4-r11, sp, pc} */
1368 dpoff = add_decimm(add_rndimm(add_encimm(cslen - func_beg - 28)));
1369 cslen = func_beg + dpoff + 28;
1370 maxsp = ALIGN(maxsp, 8);
1371 maxsp = add_decimm(add_rndimm(add_encimm(maxsp)));
1372 /* fill stack sub: sp = sp - xx */
1373 *(long *) (cs + func_beg + 16) |= add_encimm(maxsp);
1374 /* fill data ptr addition: dp = pc + xx */
1375 *(long *) (cs + func_beg + 20) |= add_encimm(dpoff);
1376 pool_write();