gen: handle large offsets for str
[neatcc.git] / gen.c
blob50e94a96676595e6c0fa83c45300181ae5882c68
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 */
24 #define MIN(a, b) ((a) < (b) ? (a) : (b))
25 #define ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1))
27 static char cs[SECSIZE]; /* code segment */
28 static int cslen;
29 static char ds[SECSIZE]; /* data segment */
30 static int dslen;
31 static long bsslen; /* bss segment size */
33 static int nogen; /* don't generate code */
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 static struct tmp *regs[NREGS];
52 static int tmpregs[] = {4, 5, 6, 7, 8, 9, 0, 1, 2, 3};
53 static int argregs[] = {0, 1, 2, 3};
55 #define I_AND 0x00
56 #define I_EOR 0x01
57 #define I_SUB 0x02
58 #define I_RSB 0x03
59 #define I_ADD 0x04
60 #define I_TST 0x08
61 #define I_CMP 0x0a
62 #define I_ORR 0x0c
63 #define I_MOV 0x0d
64 #define I_MVN 0x0f
66 #define MAXRET (1 << 8)
68 static long ret[MAXRET];
69 static int nret;
71 /* output div/mod functions */
72 static int putdiv = 0;
74 /* for optimizing cmp + bcc */
75 static long last_cmp = -1;
76 static long last_set = -1;
77 static long last_cond;
79 static void os(void *s, int n)
81 memcpy(cs + cslen, s, n);
82 cslen += n;
85 static void oi(long n)
87 if (nogen)
88 return;
89 *(int *) (cs + cslen) = n;
90 cslen += 4;
93 #define MAXNUMS 1024
95 /* data pool */
96 static long num_offs[MAXNUMS]; /* data immediate value */
97 static char num_names[MAXNUMS][NAMELEN]; /* relocation data symbol name */
98 static int nums;
100 static int pool_find(char *name, int off)
102 int i;
103 for (i = 0; i < nums; i++)
104 if (!strcmp(name, num_names[i]) && off == num_offs[i])
105 return i;
106 return -1;
109 static int pool_num(long num)
111 int idx = pool_find("", num);
112 if (idx < 0) {
113 idx = nums++;
114 num_offs[idx] = num;
115 num_names[idx][0] = '\0';
117 return idx << 2;
120 static int pool_reloc(char *name, long off)
122 int idx = pool_find(name, off);
123 if (idx < 0) {
124 idx = nums++;
125 num_offs[idx] = off;
126 strcpy(num_names[idx], name);
128 return idx << 2;
131 static void pool_write(void)
133 int i;
134 for (i = 0; i < nums; i++) {
135 if (num_names[i])
136 out_rel(num_names[i], OUT_CS, cslen);
137 oi(num_offs[i]);
142 * data processing:
143 * +---------------------------------------+
144 * |COND|00|I| op |S| Rn | Rd | operand2 |
145 * +---------------------------------------+
147 * S: set condition code
148 * Rn: first operand
149 * Rd: destination operand
151 * I=0 operand2=| shift | Rm |
152 * I=1 operand2=|rota| imm |
154 #define ADD(op, rd, rn, s, i, cond) \
155 (((cond) << 28) | ((i) << 25) | ((s) << 20) | \
156 ((op) << 21) | ((rn) << 16) | ((rd) << 12))
158 static void i_add(int op, int rd, int rn, int rm)
160 oi(ADD(op, rd, rn, 0, 0, 14) | rm);
163 static int add_encimm(unsigned n)
165 int i = 0;
166 while (i < 12 && (n >> ((4 + i) << 1)))
167 i++;
168 return (n >> (i << 1)) | (((16 - i) & 0x0f) << 8);
171 static int add_decimm(unsigned n)
173 int rot = (16 - ((n >> 8) & 0x0f)) & 0x0f;
174 return (n & 0xff) << (rot << 1);
177 static int add_rndimm(unsigned n)
179 int rot = (n >> 8) & 0x0f;
180 int num = n & 0xff;
181 if (rot == 0)
182 return n;
183 if (num == 0xff) {
184 num = 0;
185 rot = (rot + 12) & 0x0f;
187 return ((num + 1) & 0xff) | (rot << 8);
190 static void i_ldr(int l, int rd, int rn, int off, int bt);
192 static void i_num(int rd, long n)
194 int neg = n < 0;
195 int p = neg ? -n - 1 : n;
196 int enc = add_encimm(p);
197 if (p == add_decimm(enc)) {
198 oi(ADD(neg ? I_MVN : I_MOV, rd, 0, 0, 1, 14) | enc);
199 } else {
200 if (!nogen) {
201 int off = pool_num(n);
202 i_ldr(1, rd, REG_DP, off, LONGSZ);
207 static void i_add_imm(int op, int rd, int rn, int n)
209 int neg = n < 0;
210 int imm = add_encimm(neg ? -n : n);
211 if (imm == add_decimm(neg ? -n : n)) {
212 oi(ADD(neg ? I_SUB : I_ADD, rd, rn, 0, 1, 14) | imm);
213 } else {
214 i_num(rd, n);
215 i_add(I_ADD, rd, rd, rn);
220 * multiply
221 * +----------------------------------------+
222 * |COND|000000|A|S| Rd | Rn | Rs |1001| Rm |
223 * +----------------------------------------+
225 * Rd: destination
226 * A: accumulate
227 * C: set condition codes
229 * I=0 operand2=| shift | Rm |
230 * I=1 operand2=|rota| imm |
232 #define MUL(rd, rn, rs) \
233 ((14 << 28) | ((rd) << 16) | ((0) << 12) | ((rn) << 8) | ((9) << 4) | (rm))
235 static void i_mul(int rd, int rn, int rm)
237 oi(MUL(rd, rn, rm));
240 static void i_cmp(int op, int rn, int rm)
242 oi(ADD(op, 0, rn, 1, 0, 14) | rm);
243 last_cmp = cslen;
246 static void i_set(int cond, int rd)
248 last_set = cslen;
249 last_cond = cond;
250 oi(ADD(I_MOV, rd, 0, 0, 1, 14));
251 oi(ADD(I_MOV, rd, 0, 0, 1, cond) | 1);
254 #define SM_LSL 0
255 #define SM_LSR 1
256 #define SM_ASR 2
258 static void i_shl(int sm, int rd, int rm, int rs)
260 oi(ADD(I_MOV, rd, 0, 0, 0, 14) | (rs << 8) | (sm << 5) | (1 << 4) | rm);
263 static void i_shl_imm(int sm, int rd, int n)
265 oi(ADD(I_MOV, rd, 0, 0, 0, 14) | (n << 7) | (sm << 5) | rd);
268 static void i_mov(int op, int rd, int rn)
270 oi(ADD(op, rd, 0, 0, 0, 14) | rn);
274 * single data transfer:
275 * +------------------------------------------+
276 * |COND|01|I|P|U|B|W|L| Rn | Rd | offset |
277 * +------------------------------------------+
279 * I: immediate/offset
280 * P: post/pre indexing
281 * U: down/up
282 * B: byte/word
283 * W: writeback
284 * L: store/load
285 * Rn: base register
286 * Rd: source/destination register
288 * I=0 offset=| immediate |
289 * I=1 offset=| shift | Rm |
291 * halfword and signed data transfer
292 * +----------------------------------------------+
293 * |COND|000|P|U|0|W|L| Rn | Rd |0000|1|S|H|1| Rm |
294 * +----------------------------------------------+
296 * +----------------------------------------------+
297 * |COND|000|P|U|1|W|L| Rn | Rd |off1|1|S|H|1|off2|
298 * +----------------------------------------------+
300 * S: singed
301 * H: halfword
303 #define LDR(l, rd, rn, b, u, p, w) \
304 ((14 << 28) | (1 << 26) | ((p) << 24) | ((b) << 22) | ((u) << 23) | \
305 ((w) << 21) | ((l) << 20) | ((rn) << 16) | ((rd) << 12))
306 #define LDRH(l, rd, rn, s, h, u, i) \
307 ((14 << 28) | (1 << 24) | ((u) << 23) | ((i) << 22) | ((l) << 20) | \
308 ((rn) << 16) | ((rd) << 12) | ((s) << 6) | ((h) << 5) | (9 << 4))
310 static void i_ldr(int l, int rd, int rn, int off, int bt)
312 int b = BT_SZ(bt) == 1;
313 int h = BT_SZ(bt) == 2;
314 int s = l && (bt & BT_SIGNED);
315 int half = h || (b && s);
316 int maximm = half ? 0x100 : 0x1000;
317 int neg = off < 0;
318 if (neg)
319 off = -off;
320 while (off >= maximm) {
321 int imm = add_encimm(off);
322 oi(ADD(neg ? I_SUB : I_ADD, REG_TMP, rn, 0, 1, 14) | imm);
323 rn = REG_TMP;
324 off -= add_decimm(imm);
326 if (!half)
327 oi(LDR(l, rd, rn, b, !neg, 1, 0) | off);
328 else
329 oi(LDRH(l, rd, rn, s, h, !neg, 1) |
330 ((off & 0xf0) << 4) | (off & 0x0f));
333 static void i_sym(int rd, char *sym, int off)
335 if (!nogen) {
336 int doff = pool_reloc(sym, off);
337 i_ldr(1, rd, REG_DP, doff, LONGSZ);
341 static void i_neg(int rd)
343 oi(ADD(I_RSB, rd, rd, 0, 1, 14));
346 static void i_not(int rd)
348 oi(ADD(I_MVN, rd, 0, rd, 1, 14));
351 static void i_lnot(int rd)
353 i_cmp(I_TST, rd, rd);
354 oi(ADD(I_MOV, rd, 0, 0, 1, 14));
355 oi(ADD(I_MOV, rd, 0, 0, 1, 0) | 1);
358 /* rd = rd & ((1 << bits) - 1) */
359 static void i_zx(int rd, int bits)
361 if (bits <= 8) {
362 oi(ADD(I_AND, rd, rd, 0, 1, 14) | add_encimm((1 << bits) - 1));
363 } else {
364 i_shl_imm(SM_LSL, rd, 32 - bits);
365 i_shl_imm(SM_LSR, rd, 32 - bits);
369 static void i_sx(int rd, int bits)
371 i_shl_imm(SM_LSL, rd, 32 - bits);
372 i_shl_imm(SM_ASR, rd, 32 - bits);
376 * branch:
377 * +-----------------------------------+
378 * |COND|101|L| offset |
379 * +-----------------------------------+
381 * L: link
383 #define BL(cond, l, o) (((cond) << 28) | (5 << 25) | ((l) << 24) | \
384 ((((o) - 8) >> 2) & 0x00ffffff))
386 static void i_b(long addr)
388 oi(BL(14, 0, addr - cslen));
391 static void i_b_if(long addr, int rn, int z)
393 static int nots[] = {1, 0, 3, 2, -1, -1, -1, -1, 9, 8, 11, 10, 13, 12, -1};
394 if (last_cmp + 8 != cslen || last_set != last_cmp) {
395 i_cmp(I_TST, rn, rn);
396 oi(BL(z ? 0 : 1, 0, addr - cslen));
397 return;
399 cslen = last_cmp;
400 oi(BL(z ? nots[last_cond] : last_cond, 0, addr - cslen));
403 static void i_b_fill(long *dst, int diff)
405 *dst = (*dst & 0xff000000) | (((diff - 8) >> 2) & 0x00ffffff);
408 static void i_memcpy(int rd, int rs, int rn)
410 oi(ADD(I_SUB, rn, rn, 1, 1, 14) | 1);
411 oi(BL(4, 0, 16));
412 oi(LDR(1, REG_TMP, rs, 1, 1, 0, 0) | 1);
413 oi(LDR(0, REG_TMP, rd, 1, 1, 0, 0) | 1);
414 oi(BL(14, 0, -16));
417 static void i_memset(int rd, int rs, int rn)
419 oi(ADD(I_SUB, rn, rn, 1, 1, 14) | 1);
420 oi(BL(4, 0, 12));
421 oi(LDR(0, rs, rd, 1, 1, 0, 0) | 1);
422 oi(BL(14, 0, -12));
425 static void i_call_reg(int rd)
427 i_mov(I_MOV, REG_LR, REG_PC);
428 i_mov(I_MOV, REG_PC, rd);
431 static void i_call(char *sym)
433 if (!nogen)
434 out_rel(sym, OUT_CS | OUT_REL24, cslen);
435 oi(BL(14, 1, 0));
438 static void i_prolog(void)
440 func_beg = cslen;
441 nums = 0;
442 oi(0xe1a0c00d); /* mov r12, sp */
443 oi(0xe92d000f); /* stmfd sp!, {r0-r3} */
444 oi(0xe92d5ff0); /* stmfd sp!, {r0-r11, r12, lr} */
445 oi(0xe1a0b00d); /* mov fp, sp */
446 oi(0xe24dd000); /* sub sp, sp, xx */
447 oi(0xe28fa000); /* add dp, pc, xx */
450 static void i_epilog(void)
452 int dpoff;
453 oi(0xe89baff0); /* ldmfd fp, {r4-r11, sp, pc} */
454 dpoff = add_decimm(add_rndimm(add_encimm(cslen - func_beg - 28)));
455 cslen = func_beg + dpoff + 28;
456 maxsp = ALIGN(maxsp, 8);
457 maxsp = add_decimm(add_rndimm(add_encimm(maxsp)));
458 /* fill stack sub: sp = sp - xx */
459 *(long *) (cs + func_beg + 16) |= add_encimm(maxsp);
460 /* fill data ptr addition: dp = pc + xx */
461 *(long *) (cs + func_beg + 20) |= add_encimm(dpoff);
462 pool_write();
465 static long sp_push(int size)
467 sp += size;
468 if (sp > maxsp)
469 maxsp = sp;
470 return sp;
473 static void tmp_mem(struct tmp *tmp)
475 int src = tmp->addr;
476 if (!(tmp->loc == LOC_REG))
477 return;
478 if (tmpsp == -1)
479 tmpsp = sp;
480 tmp->addr = -sp_push(LONGSZ);
481 i_ldr(0, src, REG_FP, tmp->addr, LONGSZ);
482 regs[src] = NULL;
483 tmp->loc = LOC_MEM;
486 static void num_cast(struct tmp *t, unsigned bt)
488 if (!(bt & BT_SIGNED) && BT_SZ(bt) != LONGSZ)
489 t->addr &= ((1l << (long) (BT_SZ(bt) * 8)) - 1);
490 if (bt & BT_SIGNED && BT_SZ(bt) != LONGSZ &&
491 t->addr > (1l << (BT_SZ(bt) * 8 - 1)))
492 t->addr = -((1l << (BT_SZ(bt) * 8)) - t->addr);
495 static void tmp_reg(struct tmp *tmp, int dst, int deref)
497 int bt = tmp->bt;
498 if (!tmp->bt)
499 deref = 0;
500 if (deref)
501 tmp->bt = 0;
502 if (tmp->loc == LOC_NUM) {
503 i_num(dst, tmp->addr);
504 tmp->addr = dst;
505 regs[dst] = tmp;
506 tmp->loc = LOC_REG;
508 if (tmp->loc == LOC_SYM) {
509 i_sym(dst, tmp->sym, tmp->off);
510 tmp->addr = dst;
511 regs[dst] = tmp;
512 tmp->loc = LOC_REG;
514 if (tmp->loc == LOC_REG) {
515 if (deref)
516 i_ldr(1, dst, tmp->addr, 0, bt);
517 else if (dst != tmp->addr)
518 i_mov(I_MOV, dst, tmp->addr);
519 regs[tmp->addr] = NULL;
521 if (tmp->loc == LOC_LOCAL) {
522 if (deref)
523 i_ldr(1, dst, REG_FP, tmp->addr + tmp->off, bt);
524 else
525 i_add_imm(I_ADD, dst, REG_FP, tmp->addr + tmp->off);
527 if (tmp->loc == LOC_MEM) {
528 i_ldr(1, dst, REG_FP, tmp->addr, LONGSZ);
529 if (deref)
530 i_ldr(1, dst, dst, 0, bt);
532 tmp->addr = dst;
533 regs[dst] = tmp;
534 tmp->loc = LOC_REG;
537 static void reg_free(int reg)
539 int i;
540 if (!regs[reg])
541 return;
542 for (i = 0; i < ARRAY_SIZE(tmpregs); i++)
543 if (!regs[tmpregs[i]]) {
544 tmp_reg(regs[reg], tmpregs[i], 0);
545 return;
547 tmp_mem(regs[reg]);
550 static void reg_for(int reg, struct tmp *t)
552 if (regs[reg] && regs[reg] != t)
553 reg_free(reg);
556 static void tmp_mv(struct tmp *t, int reg)
558 reg_for(reg, t);
559 tmp_reg(t, reg, 0);
562 static void tmp_to(struct tmp *t, int reg)
564 reg_for(reg, t);
565 tmp_reg(t, reg, 1);
568 static void tmp_drop(int n)
570 int i;
571 for (i = ntmp - n; i < ntmp; i++)
572 if (tmps[i].loc == LOC_REG)
573 regs[tmps[i].addr] = NULL;
574 ntmp -= n;
577 static void tmp_pop(int reg)
579 struct tmp *t = TMP(0);
580 tmp_to(t, reg);
581 tmp_drop(1);
584 static struct tmp *tmp_new(void)
586 return &tmps[ntmp++];
589 static void tmp_push(int reg)
591 struct tmp *t = tmp_new();
592 t->addr = reg;
593 t->bt = 0;
594 t->loc = LOC_REG;
595 regs[reg] = t;
598 void o_local(long addr)
600 struct tmp *t = tmp_new();
601 t->addr = -addr;
602 t->loc = LOC_LOCAL;
603 t->bt = 0;
604 t->off = 0;
607 void o_num(long num)
609 struct tmp *t = tmp_new();
610 t->addr = num;
611 t->bt = 0;
612 t->loc = LOC_NUM;
615 void o_sym(char *name)
617 struct tmp *t = tmp_new();
618 strcpy(t->sym, name);
619 t->loc = LOC_SYM;
620 t->bt = 0;
621 t->off = 0;
624 void o_tmpdrop(int n)
626 if (n == -1 || n > ntmp)
627 n = ntmp;
628 tmp_drop(n);
629 if (!ntmp) {
630 if (tmpsp != -1)
631 sp = tmpsp;
632 tmpsp = -1;
636 #define FORK_REG 0x00
638 /* make sure tmps remain intact after a conditional expression */
639 void o_fork(void)
641 int i;
642 for (i = 0; i < ntmp - 1; i++)
643 tmp_mem(&tmps[i]);
646 void o_forkpush(void)
648 tmp_pop(FORK_REG);
651 void o_forkjoin(void)
653 tmp_push(FORK_REG);
656 void o_tmpswap(void)
658 struct tmp *t1 = TMP(0);
659 struct tmp *t2 = TMP(1);
660 struct tmp t;
661 memcpy(&t, t1, sizeof(t));
662 memcpy(t1, t2, sizeof(t));
663 memcpy(t2, &t, sizeof(t));
664 if (t1->loc == LOC_REG)
665 regs[t1->addr] = t1;
666 if (t2->loc == LOC_REG)
667 regs[t2->addr] = t2;
670 static int reg_get(int mask)
672 int i;
673 for (i = 0; i < ARRAY_SIZE(tmpregs); i++)
674 if ((1 << tmpregs[i]) & mask && !regs[tmpregs[i]])
675 return tmpregs[i];
676 for (i = 0; i < ARRAY_SIZE(tmpregs); i++)
677 if ((1 << tmpregs[i]) & mask) {
678 reg_free(tmpregs[i]);
679 return tmpregs[i];
681 return 0;
684 static int reg_fortmp(struct tmp *t, int notmask)
686 if (t->loc == LOC_REG && !(notmask & (1 << t->addr)))
687 return t->addr;
688 return reg_get(~notmask);
691 static void tmp_copy(struct tmp *t1)
693 struct tmp *t2 = tmp_new();
694 memcpy(t2, t1, sizeof(*t1));
695 if (!(t1->loc & (LOC_REG | LOC_MEM)))
696 return;
697 if (t1->loc == LOC_MEM) {
698 tmp_mv(t2, reg_get(~0));
699 } else if (t1->loc == LOC_REG) {
700 t2->addr = reg_fortmp(t2, 1 << t1->addr);
701 i_mov(I_MOV, t2->addr, t1->addr);
702 regs[t2->addr] = t2;
706 void o_tmpcopy(void)
708 tmp_copy(TMP(0));
711 void o_cast(unsigned bt)
713 struct tmp *t = TMP(0);
714 if (t->bt) {
715 t->bt = bt;
716 return;
718 if (t->loc == LOC_NUM) {
719 num_cast(t, bt);
720 return;
722 if (BT_SZ(bt) != LONGSZ) {
723 int reg = reg_fortmp(t, 0);
724 tmp_to(t, reg);
725 if (bt & BT_SIGNED)
726 i_sx(reg, BT_SZ(bt) * 8);
727 else
728 i_zx(reg, BT_SZ(bt) * 8);
732 void o_func_beg(char *name, int global)
734 out_sym(name, (global ? OUT_GLOB : 0) | OUT_CS, cslen, 0);
735 i_prolog();
736 sp = 0;
737 maxsp = sp;
738 ntmp = 0;
739 tmpsp = -1;
740 nret = 0;
741 memset(regs, 0, sizeof(regs));
744 void o_deref(unsigned bt)
746 struct tmp *t = TMP(0);
747 if (t->bt)
748 tmp_to(t, reg_fortmp(t, 0));
749 t->bt = bt;
752 void o_load(void)
754 struct tmp *t = TMP(0);
755 tmp_to(t, reg_fortmp(t, 0));
758 #define TMP_NUM(t) ((t)->loc == LOC_NUM && !(t)->bt)
759 #define LOCAL_PTR(t) ((t)->loc == LOC_LOCAL && !(t)->bt)
760 #define SYM_PTR(t) ((t)->loc == LOC_SYM && !(t)->bt)
762 int o_popnum(long *c)
764 struct tmp *t = TMP(0);
765 if (!TMP_NUM(t))
766 return 1;
767 *c = t->addr;
768 tmp_drop(1);
769 return 0;
772 void o_ret(int rets)
774 if (rets)
775 tmp_pop(REG_RET);
776 else
777 i_num(REG_RET, 0);
778 ret[nret++] = o_jmp(0);
781 void o_func_end(void)
783 int i;
784 if (nret && ret[nret - 1] == cslen - 4) {
785 cslen -= 4;
786 nret--;
788 for (i = 0; i < nret; i++)
789 o_filljmp(ret[i]);
790 i_epilog();
793 long o_mklocal(int size)
795 return sp_push(ALIGN(size, LONGSZ));
798 void o_rmlocal(long addr, int sz)
800 sp = addr - sz;
803 long o_arg(int i)
805 return -(10 + i) << 2;
808 void o_assign(unsigned bt)
810 struct tmp *t1 = TMP(0);
811 struct tmp *t2 = TMP(1);
812 int r1 = reg_fortmp(t1, 0);
813 int r2 = reg_fortmp(t2, 1 << r1);
814 int off = 0;
815 tmp_to(t1, r1);
816 if (t2->bt)
817 tmp_to(t2, r2);
818 if (t2->loc == LOC_LOCAL) {
819 r2 = REG_FP;
820 off = t2->addr + t2->off;
821 } else {
822 tmp_to(t2, r2);
824 tmp_drop(2);
825 i_ldr(0, r1, r2, off, bt);
826 tmp_push(r1);
829 static long cu(int op, long i)
831 switch (op & 0xff) {
832 case O_NEG:
833 return -i;
834 case O_NOT:
835 return ~i;
836 case O_LNOT:
837 return !i;
839 return 0;
842 static int c_uop(int op)
844 struct tmp *t1 = TMP(0);
845 if (!TMP_NUM(t1))
846 return 1;
847 tmp_drop(1);
848 o_num(cu(op, t1->addr));
849 return 0;
852 static long cb(int op, long a, long b)
854 switch (op & 0xff) {
855 case O_ADD:
856 return a + b;
857 case O_SUB:
858 return a - b;
859 case O_AND:
860 return a & b;
861 case O_OR:
862 return a | b;
863 case O_XOR:
864 return a ^ b;
865 case O_MUL:
866 return a * b;
867 case O_DIV:
868 return a / b;
869 case O_MOD:
870 return a % b;
871 case O_SHL:
872 return a << b;
873 case O_SHR:
874 if (op & O_SIGNED)
875 return a >> b;
876 else
877 return (unsigned long) a >> b;
878 case O_LT:
879 return a < b;
880 case O_GT:
881 return a > b;
882 case O_LE:
883 return a <= b;
884 case O_GE:
885 return a >= b;
886 case O_EQ:
887 return a == b;
888 case O_NEQ:
889 return a != b;
891 return 0;
894 static int c_bop(int op)
896 struct tmp *t1 = TMP(0);
897 struct tmp *t2 = TMP(1);
898 int locals = LOCAL_PTR(t1) + LOCAL_PTR(t2);
899 int syms = SYM_PTR(t1) + SYM_PTR(t2);
900 int nums = TMP_NUM(t1) + TMP_NUM(t2);
901 if (syms + locals == 2 || syms + nums + locals != 2)
902 return 1;
903 if (nums == 1)
904 if ((op & 0xff) != O_ADD && ((op & 0xff) != O_SUB || TMP_NUM(t2)))
905 return 1;
906 if (nums == 1) {
907 long o1 = TMP_NUM(t1) ? t1->addr : t1->off;
908 long o2 = TMP_NUM(t2) ? t2->addr : t2->off;
909 long ret = cb(op, o2, o1);
910 if (!TMP_NUM(t1))
911 o_tmpswap();
912 t2->off = ret;
913 tmp_drop(1);
914 } else {
915 long ret = cb(op, t2->addr, t1->addr);
916 tmp_drop(2);
917 o_num(ret);
919 return 0;
922 void o_uop(int op)
924 int r1 = reg_fortmp(TMP(0), 0);
925 if (!c_uop(op))
926 return;
927 tmp_to(TMP(0), r1);
928 switch (op & 0xff) {
929 case O_NEG:
930 i_neg(r1);
931 break;
932 case O_NOT:
933 i_not(r1);
934 break;
935 case O_LNOT:
936 i_lnot(r1);
937 break;
941 static void bin_regs(int *r1, int *r2)
943 struct tmp *t2 = TMP(0);
944 struct tmp *t1 = TMP(1);
945 *r2 = reg_fortmp(t2, 0);
946 tmp_to(t2, *r2);
947 *r1 = reg_fortmp(t1, 1 << *r2);
948 tmp_pop(*r2);
949 tmp_pop(*r1);
952 static void bin_add(int op)
954 /* opcode for O_ADD, O_SUB, O_AND, O_OR, O_XOR */
955 static int rx[] = {I_ADD, I_SUB, I_AND, I_ORR, I_EOR};
956 int r1, r2;
957 bin_regs(&r1, &r2);
958 i_add(rx[op & 0x0f], r1, r1, r2);
959 tmp_push(r1);
962 static void bin_shx(int op)
964 int sm = SM_LSL;
965 int r1, r2;
966 bin_regs(&r1, &r2);
967 if ((op & 0x0f) == 1)
968 sm = op & O_SIGNED ? SM_ASR : SM_LSR;
969 i_shl(sm, r1, r1, r2);
970 tmp_push(r1);
973 static int log2a(unsigned long n)
975 int i = 0;
976 for (i = 0; i < LONGSZ * 8; i++)
977 if (n & (1u << i))
978 break;
979 if (i == LONGSZ * 8 || !(n >> (i + 1)))
980 return i;
981 return -1;
984 /* optimized version of mul/div/mod for powers of two */
985 static int mul_2(int op)
987 struct tmp *t1 = TMP(0);
988 struct tmp *t2 = TMP(1);
989 long n;
990 int r2;
991 int p;
992 if ((op & 0xff) == O_MUL && t2->loc == LOC_NUM && !t2->bt)
993 o_tmpswap();
994 if (t1->loc != LOC_NUM || t1->bt)
995 return 1;
996 n = t1->addr;
997 p = log2a(n);
998 if (n && p == -1)
999 return 1;
1000 if ((op & 0xff) == O_MUL) {
1001 tmp_drop(1);
1002 if (n == 1)
1003 return 0;
1004 if (n == 0) {
1005 tmp_drop(1);
1006 o_num(0);
1007 return 0;
1009 r2 = reg_fortmp(t2, 0);
1010 tmp_to(t2, r2);
1011 i_shl_imm(SM_LSL, r2, p);
1012 return 0;
1014 if (op == O_DIV) {
1015 tmp_drop(1);
1016 if (n == 1)
1017 return 0;
1018 r2 = reg_fortmp(t2, 0);
1019 tmp_to(t2, r2);
1020 i_shl_imm(op & O_SIGNED ? SM_ASR : SM_LSR, r2, p);
1021 return 0;
1023 if (op == O_MOD) {
1024 tmp_drop(1);
1025 if (n == 1) {
1026 tmp_drop(1);
1027 o_num(0);
1028 return 0;
1030 r2 = reg_fortmp(t2, 0);
1031 tmp_to(t2, r2);
1032 i_zx(r2, p);
1033 return 0;
1035 return 1;
1038 static void bin_div(int op)
1040 struct tmp *t2 = TMP(0);
1041 struct tmp *t1 = TMP(1);
1042 char *func;
1043 int i;
1044 putdiv = 1;
1045 if ((op & 0xff) == O_DIV)
1046 func = op & O_SIGNED ? "__divdi3" : "__udivdi3";
1047 else
1048 func = op & O_SIGNED ? "__moddi3" : "__umoddi3";
1049 for (i = 0; i < ARRAY_SIZE(argregs); i++)
1050 if (regs[argregs[i]] && regs[argregs[i]] - tmps < ntmp - 2)
1051 tmp_mem(regs[argregs[i]]);
1052 tmp_to(t1, argregs[0]);
1053 tmp_to(t2, argregs[1]);
1054 tmp_drop(2);
1055 i_call(func);
1056 tmp_push(REG_RET);
1059 static void bin_mul(int op)
1061 int r1, r2;
1062 if (!mul_2(op))
1063 return;
1064 if ((op & 0xff) == O_DIV || (op & 0xff) == O_MOD) {
1065 bin_div(op);
1066 } else {
1067 bin_regs(&r1, &r2);
1068 i_mul(r1, r1, r2);
1069 tmp_push(r1);
1073 static void bin_cmp(int op)
1075 /* lt, gt, le, ge, eq, neq */
1076 static int ucond[] = {3, 8, 9, 2, 0, 1};
1077 static int scond[] = {11, 12, 13, 10, 0, 1};
1078 int r1, r2;
1079 bin_regs(&r1, &r2);
1080 i_cmp(I_CMP, r1, r2);
1081 i_set(op & O_SIGNED ? scond[op & 0x0f] : ucond[op & 0x0f], r1);
1082 tmp_push(r1);
1085 void o_bop(int op)
1087 if (!c_bop(op))
1088 return;
1089 if ((op & 0xf0) == 0x00)
1090 bin_add(op);
1091 if ((op & 0xf0) == 0x10)
1092 bin_shx(op);
1093 if ((op & 0xf0) == 0x20)
1094 bin_mul(op);
1095 if ((op & 0xf0) == 0x30)
1096 bin_cmp(op);
1099 static void load_regs2(int *r0, int *r1, int *r2)
1101 struct tmp *t0 = TMP(0);
1102 struct tmp *t1 = TMP(1);
1103 struct tmp *t2 = TMP(2);
1104 *r0 = reg_fortmp(t0, 0);
1105 *r1 = reg_fortmp(t1, 1 << *r0);
1106 *r2 = reg_fortmp(t2, (1 << *r0) | (1 << *r1));
1107 tmp_to(t0, *r0);
1108 tmp_to(t1, *r1);
1109 tmp_to(t2, *r2);
1112 void o_memcpy(void)
1114 int rd, rs, rn;
1115 load_regs2(&rn, &rs, &rd);
1116 i_memcpy(rd, rs, rn);
1117 tmp_drop(2);
1120 void o_memset(void)
1122 int rd, rs, rn;
1123 load_regs2(&rn, &rs, &rd);
1124 i_memset(rd, rs, rn);
1125 tmp_drop(2);
1128 long o_mklabel(void)
1130 return cslen;
1133 static long jxz(long addr, int z)
1135 int r = reg_fortmp(TMP(0), 0);
1136 tmp_pop(r);
1137 i_b_if(addr, r, z);
1138 return cslen - 4;
1141 long o_jz(long addr)
1143 return jxz(addr, 1);
1146 long o_jnz(long addr)
1148 return jxz(addr, 0);
1151 long o_jmp(long addr)
1153 i_b(addr);
1154 return cslen - 4;
1157 void o_filljmp2(long addr, long jmpdst)
1159 i_b_fill((void *) cs + addr, jmpdst - addr);
1162 void o_filljmp(long addr)
1164 o_filljmp2(addr, cslen);
1167 void o_call(int argc, int rets)
1169 struct tmp *t;
1170 int i;
1171 int aregs = MIN(ARRAY_SIZE(argregs), argc);
1172 for (i = 0; i < ARRAY_SIZE(argregs); i++)
1173 if (regs[argregs[i]] && regs[argregs[i]] - tmps < ntmp - argc)
1174 tmp_mem(regs[argregs[i]]);
1175 if (argc > aregs) {
1176 sp_push(LONGSZ * (argc - aregs));
1177 for (i = argc - 1; i >= aregs; --i) {
1178 int reg = reg_fortmp(TMP(0), 0);
1179 tmp_pop(reg);
1180 i_ldr(0, reg, REG_SP, (i - aregs) * LONGSZ, LONGSZ);
1183 for (i = aregs - 1; i >= 0; --i)
1184 tmp_to(TMP(aregs - i - 1), argregs[i]);
1185 tmp_drop(aregs);
1186 t = TMP(0);
1187 if (t->loc == LOC_SYM && !t->bt) {
1188 i_call(t->sym);
1189 tmp_drop(1);
1190 } else {
1191 int reg = t->loc == LOC_REG ? t->addr : REG_TMP;
1192 tmp_pop(reg);
1193 i_call_reg(reg);
1195 if (rets)
1196 tmp_push(REG_RET);
1199 void o_nogen(void)
1201 nogen++;
1204 void o_dogen(void)
1206 nogen--;
1209 void dat_bss(char *name, int size, int global)
1211 out_sym(name, OUT_BSS | (global ? OUT_GLOB : 0), bsslen, size);
1212 bsslen += ALIGN(size, LONGSZ);
1215 #define MAXDATS (1 << 10)
1216 static char dat_names[MAXDATS][NAMELEN];
1217 static int dat_offs[MAXDATS];
1218 static int ndats;
1220 void err(char *msg);
1221 void *dat_dat(char *name, int size, int global)
1223 void *addr = ds + dslen;
1224 int idx = ndats++;
1225 if (idx >= MAXDATS)
1226 err("nomem: MAXDATS reached!\n");
1227 strcpy(dat_names[idx], name);
1228 dat_offs[idx] = dslen;
1229 out_sym(name, OUT_DS | (global ? OUT_GLOB : 0), dslen, size);
1230 dslen += ALIGN(size, LONGSZ);
1231 return addr;
1234 static int dat_off(char *name)
1236 int i;
1237 for (i = 0; i < ndats; i++)
1238 if (!strcmp(name, dat_names[i]))
1239 return dat_offs[i];
1240 return 0;
1243 void o_datset(char *name, int off, unsigned bt)
1245 struct tmp *t = TMP(0);
1246 int sym_off = dat_off(name) + off;
1247 if (t->loc == LOC_NUM && !t->bt) {
1248 num_cast(t, bt);
1249 memcpy(ds + sym_off, &t->addr, BT_SZ(bt));
1251 if (t->loc == LOC_SYM && !t->bt) {
1252 out_rel(t->sym, OUT_DS, sym_off);
1253 memcpy(ds + sym_off, &t->off, BT_SZ(bt));
1255 tmp_drop(1);
1258 /* compiled division functions; div.s contains the source */
1259 static int udivdi3[] = {
1260 0xe3a02000, 0xe3a03000, 0xe1110001, 0x0a00000a,
1261 0xe1b0c211, 0xe2822001, 0x5afffffc, 0xe3a0c001,
1262 0xe2522001, 0x4a000004, 0xe1500211, 0x3afffffb,
1263 0xe0400211, 0xe083321c, 0xeafffff8, 0xe1a01000,
1264 0xe1a00003, 0xe1a0f00e,
1266 static int umoddi3[] = {
1267 0xe92d4000, 0xebffffeb, 0xe1a00001, 0xe8bd8000,
1269 static int divdi3[] = {
1270 0xe92d4030, 0xe1a04000, 0xe1a05001, 0xe1100000,
1271 0x42600000, 0xe1110001, 0x42611000, 0xebffffe1,
1272 0xe1340005, 0x42600000, 0xe1140004, 0x42611000,
1273 0xe8bd8030,
1275 static int moddi3[] = {
1276 0xe92d4000, 0xebfffff0, 0xe1a00001, 0xe8bd8000,
1279 void o_write(int fd)
1281 if (putdiv) {
1282 out_sym("__udivdi3", OUT_CS, cslen, 0);
1283 os(udivdi3, sizeof(udivdi3));
1284 out_sym("__umoddi3", OUT_CS, cslen, 0);
1285 os(umoddi3, sizeof(umoddi3));
1286 out_sym("__divdi3", OUT_CS, cslen, 0);
1287 os(divdi3, sizeof(divdi3));
1288 out_sym("__moddi3", OUT_CS, cslen, 0);
1289 os(moddi3, sizeof(moddi3));
1291 out_write(fd, cs, cslen, ds, dslen);