gen: pass the number of arguments to o_func_beg()
[neatcc.git] / gen.c
blob545663a9362c373519c8cb886a245210bc12eb4e
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 static void os(void *s, int n)
76 memcpy(cs + cslen, s, n);
77 cslen += n;
80 static void oi(long n)
82 if (nogen)
83 return;
84 *(int *) (cs + cslen) = n;
85 cslen += 4;
88 #define MAXNUMS 1024
90 /* data pool */
91 static long num_offs[MAXNUMS]; /* data immediate value */
92 static char num_names[MAXNUMS][NAMELEN]; /* relocation data symbol name */
93 static int nums;
95 static int pool_find(char *name, int off)
97 int i;
98 for (i = 0; i < nums; i++)
99 if (!strcmp(name, num_names[i]) && off == num_offs[i])
100 return i;
101 return -1;
104 static int pool_num(long num)
106 int idx = pool_find("", num);
107 if (idx < 0) {
108 idx = nums++;
109 num_offs[idx] = num;
110 num_names[idx][0] = '\0';
112 return idx << 2;
115 static int pool_reloc(char *name, long off)
117 int idx = pool_find(name, off);
118 if (idx < 0) {
119 idx = nums++;
120 num_offs[idx] = off;
121 strcpy(num_names[idx], name);
123 return idx << 2;
126 static void pool_write(void)
128 int i;
129 for (i = 0; i < nums; i++) {
130 if (num_names[i])
131 out_rel(num_names[i], OUT_CS, cslen);
132 oi(num_offs[i]);
137 * data processing:
138 * +---------------------------------------+
139 * |COND|00|I| op |S| Rn | Rd | operand2 |
140 * +---------------------------------------+
142 * S: set condition code
143 * Rn: first operand
144 * Rd: destination operand
146 * I=0 operand2=| shift | Rm |
147 * I=1 operand2=|rota| imm |
149 #define ADD(op, rd, rn, s, i, cond) \
150 (((cond) << 28) | ((i) << 25) | ((s) << 20) | \
151 ((op) << 21) | ((rn) << 16) | ((rd) << 12))
153 static int add_encimm(unsigned n)
155 int i = 0;
156 while (i < 12 && (n >> ((4 + i) << 1)))
157 i++;
158 return (n >> (i << 1)) | (((16 - i) & 0x0f) << 8);
161 static unsigned add_decimm(int n)
163 int rot = (16 - ((n >> 8) & 0x0f)) & 0x0f;
164 return (n & 0xff) << (rot << 1);
167 static int add_rndimm(unsigned n)
169 int rot = (n >> 8) & 0x0f;
170 int num = n & 0xff;
171 if (rot == 0)
172 return n;
173 if (num == 0xff) {
174 num = 0;
175 rot = (rot + 12) & 0x0f;
177 return ((num + 1) & 0xff) | (rot << 8);
180 static void i_add(int op, int rd, int rn, int rm)
182 oi(ADD(op, rd, rn, 0, 0, 14) | rm);
185 static void i_add_imm(int op, int rd, int rn, long n)
187 oi(ADD(op, rd, rn, 0, 1, 14) | add_encimm(n));
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 enc = add_encimm(n);
195 if (n == add_decimm(enc)) {
196 oi(ADD(I_MOV, rd, 0, 0, 1, 14) | enc);
197 return;
199 enc = add_encimm(-n - 1);
200 if (~n == add_decimm(enc)) {
201 oi(ADD(I_MVN, rd, 0, 0, 1, 14) | enc);
202 return;
204 if (!nogen) {
205 int off = pool_num(n);
206 i_ldr(1, rd, REG_DP, off, LONGSZ);
210 static void i_add_anyimm(int rd, int rn, long n)
212 int neg = n < 0;
213 int imm = add_encimm(neg ? -n : n);
214 if (imm == add_decimm(neg ? -n : n)) {
215 oi(ADD(neg ? I_SUB : I_ADD, rd, rn, 0, 1, 14) | imm);
216 } else {
217 i_num(rd, n);
218 i_add(I_ADD, rd, rd, rn);
223 * multiply
224 * +----------------------------------------+
225 * |COND|000000|A|S| Rd | Rn | Rs |1001| Rm |
226 * +----------------------------------------+
228 * Rd: destination
229 * A: accumulate
230 * C: set condition codes
232 * I=0 operand2=| shift | Rm |
233 * I=1 operand2=|rota| imm |
235 #define MUL(rd, rn, rs) \
236 ((14 << 28) | ((rd) << 16) | ((0) << 12) | ((rn) << 8) | ((9) << 4) | (rm))
238 static void i_mul(int rd, int rn, int rm)
240 oi(MUL(rd, rn, rm));
243 static void i_cmp(int op, int rn, int rm)
245 oi(ADD(op, 0, rn, 1, 0, 14) | rm);
248 static void i_cmp_imm(int op, int rn, long n)
250 oi(ADD(op, 0, rn, 1, 1, 14) | add_encimm(n));
253 static void i_set(int cond, int rd)
255 oi(ADD(I_MOV, rd, 0, 0, 1, 14));
256 oi(ADD(I_MOV, rd, 0, 0, 1, cond) | 1);
259 #define SM_LSL 0
260 #define SM_LSR 1
261 #define SM_ASR 2
263 static void i_shl(int sm, int rd, int rm, int rs)
265 oi(ADD(I_MOV, rd, 0, 0, 0, 14) | (rs << 8) | (sm << 5) | (1 << 4) | rm);
268 static void i_shl_imm(int sm, int rd, int rn, long n)
270 oi(ADD(I_MOV, rd, 0, 0, 0, 14) | (n << 7) | (sm << 5) | rn);
273 static void i_mov(int op, int rd, int rn)
275 oi(ADD(op, rd, 0, 0, 0, 14) | rn);
279 * single data transfer:
280 * +------------------------------------------+
281 * |COND|01|I|P|U|B|W|L| Rn | Rd | offset |
282 * +------------------------------------------+
284 * I: immediate/offset
285 * P: post/pre indexing
286 * U: down/up
287 * B: byte/word
288 * W: writeback
289 * L: store/load
290 * Rn: base register
291 * Rd: source/destination register
293 * I=0 offset=| immediate |
294 * I=1 offset=| shift | Rm |
296 * halfword and signed data transfer
297 * +----------------------------------------------+
298 * |COND|000|P|U|0|W|L| Rn | Rd |0000|1|S|H|1| Rm |
299 * +----------------------------------------------+
301 * +----------------------------------------------+
302 * |COND|000|P|U|1|W|L| Rn | Rd |off1|1|S|H|1|off2|
303 * +----------------------------------------------+
305 * S: singed
306 * H: halfword
308 #define LDR(l, rd, rn, b, u, p, w) \
309 ((14 << 28) | (1 << 26) | ((p) << 24) | ((b) << 22) | ((u) << 23) | \
310 ((w) << 21) | ((l) << 20) | ((rn) << 16) | ((rd) << 12))
311 #define LDRH(l, rd, rn, s, h, u, i) \
312 ((14 << 28) | (1 << 24) | ((u) << 23) | ((i) << 22) | ((l) << 20) | \
313 ((rn) << 16) | ((rd) << 12) | ((s) << 6) | ((h) << 5) | (9 << 4))
315 static void i_ldr(int l, int rd, int rn, int off, int bt)
317 int b = BT_SZ(bt) == 1;
318 int h = BT_SZ(bt) == 2;
319 int s = l && (bt & BT_SIGNED);
320 int half = h || (b && s);
321 int maximm = half ? 0x100 : 0x1000;
322 int neg = off < 0;
323 if (neg)
324 off = -off;
325 while (off >= maximm) {
326 int imm = add_encimm(off);
327 oi(ADD(neg ? I_SUB : I_ADD, REG_TMP, rn, 0, 1, 14) | imm);
328 rn = REG_TMP;
329 off -= add_decimm(imm);
331 if (!half)
332 oi(LDR(l, rd, rn, b, !neg, 1, 0) | off);
333 else
334 oi(LDRH(l, rd, rn, s, h, !neg, 1) |
335 ((off & 0xf0) << 4) | (off & 0x0f));
338 static void i_sym(int rd, char *sym, int off)
340 if (!nogen) {
341 int doff = pool_reloc(sym, off);
342 i_ldr(1, rd, REG_DP, doff, LONGSZ);
346 static void i_neg(int rd)
348 oi(ADD(I_RSB, rd, rd, 0, 1, 14));
351 static void i_not(int rd)
353 oi(ADD(I_MVN, rd, 0, 0, 0, 14) | rd);
356 static void i_lnot(int rd)
358 i_cmp(I_TST, rd, rd);
359 oi(ADD(I_MOV, rd, 0, 0, 1, 14));
360 oi(ADD(I_MOV, rd, 0, 0, 1, 0) | 1);
363 /* rd = rd & ((1 << bits) - 1) */
364 static void i_zx(int rd, int bits)
366 if (bits <= 8) {
367 oi(ADD(I_AND, rd, rd, 0, 1, 14) | add_encimm((1 << bits) - 1));
368 } else {
369 i_shl_imm(SM_LSL, rd, rd, 32 - bits);
370 i_shl_imm(SM_LSR, rd, rd, 32 - bits);
374 static void i_sx(int rd, int bits)
376 i_shl_imm(SM_LSL, rd, rd, 32 - bits);
377 i_shl_imm(SM_ASR, rd, rd, 32 - bits);
381 * branch:
382 * +-----------------------------------+
383 * |COND|101|L| offset |
384 * +-----------------------------------+
386 * L: link
388 #define BL(cond, l, o) (((cond) << 28) | (5 << 25) | ((l) << 24) | \
389 ((((o) - 8) >> 2) & 0x00ffffff))
391 static void i_b(long addr)
393 oi(BL(14, 0, addr - cslen));
396 static void i_b_if(long addr, int rn, int z)
398 i_cmp(I_TST, rn, rn);
399 oi(BL(z ? 0 : 1, 0, addr - cslen));
402 static void i_b_fill(long *dst, int diff)
404 *dst = (*dst & 0xff000000) | (((diff - 8) >> 2) & 0x00ffffff);
407 static void i_memcpy(int rd, int rs, int rn)
409 oi(ADD(I_SUB, rn, rn, 1, 1, 14) | 1);
410 oi(BL(4, 0, 16));
411 oi(LDR(1, REG_TMP, rs, 1, 1, 0, 0) | 1);
412 oi(LDR(0, REG_TMP, rd, 1, 1, 0, 0) | 1);
413 oi(BL(14, 0, -16));
416 static void i_memset(int rd, int rs, int rn)
418 oi(ADD(I_SUB, rn, rn, 1, 1, 14) | 1);
419 oi(BL(4, 0, 12));
420 oi(LDR(0, rs, rd, 1, 1, 0, 0) | 1);
421 oi(BL(14, 0, -12));
424 static void i_call_reg(int rd)
426 i_mov(I_MOV, REG_LR, REG_PC);
427 i_mov(I_MOV, REG_PC, rd);
430 static void i_call(char *sym)
432 if (!nogen)
433 out_rel(sym, OUT_CS | OUT_REL24, cslen);
434 oi(BL(14, 1, 0));
437 static void i_prolog(void)
439 func_beg = cslen;
440 nums = 0;
441 oi(0xe1a0c00d); /* mov r12, sp */
442 oi(0xe92d000f); /* stmfd sp!, {r0-r3} */
443 oi(0xe92d5ff0); /* stmfd sp!, {r0-r11, r12, lr} */
444 oi(0xe1a0b00d); /* mov fp, sp */
445 oi(0xe24dd000); /* sub sp, sp, xx */
446 oi(0xe28fa000); /* add dp, pc, xx */
449 static void i_epilog(void)
451 int dpoff;
452 oi(0xe89baff0); /* ldmfd fp, {r4-r11, sp, pc} */
453 dpoff = add_decimm(add_rndimm(add_encimm(cslen - func_beg - 28)));
454 cslen = func_beg + dpoff + 28;
455 maxsp = ALIGN(maxsp, 8);
456 maxsp = add_decimm(add_rndimm(add_encimm(maxsp)));
457 /* fill stack sub: sp = sp - xx */
458 *(long *) (cs + func_beg + 16) |= add_encimm(maxsp);
459 /* fill data ptr addition: dp = pc + xx */
460 *(long *) (cs + func_beg + 20) |= add_encimm(dpoff);
461 pool_write();
464 static long sp_push(int size)
466 sp += size;
467 if (sp > maxsp)
468 maxsp = sp;
469 return sp;
472 static void tmp_mem(struct tmp *tmp)
474 int src = tmp->addr;
475 if (!(tmp->loc == LOC_REG))
476 return;
477 if (tmpsp == -1)
478 tmpsp = sp;
479 tmp->addr = -sp_push(LONGSZ);
480 i_ldr(0, src, REG_FP, tmp->addr, LONGSZ);
481 regs[src] = NULL;
482 tmp->loc = LOC_MEM;
485 static void num_cast(struct tmp *t, unsigned bt)
487 if (!(bt & BT_SIGNED) && BT_SZ(bt) != LONGSZ)
488 t->addr &= ((1l << (long) (BT_SZ(bt) * 8)) - 1);
489 if (bt & BT_SIGNED && BT_SZ(bt) != LONGSZ &&
490 t->addr > (1l << (BT_SZ(bt) * 8 - 1)))
491 t->addr = -((1l << (BT_SZ(bt) * 8)) - t->addr);
494 static void tmp_reg(struct tmp *tmp, int dst, int deref)
496 int bt = tmp->bt;
497 if (!tmp->bt)
498 deref = 0;
499 if (deref)
500 tmp->bt = 0;
501 if (tmp->loc == LOC_NUM) {
502 i_num(dst, tmp->addr);
503 tmp->addr = dst;
504 regs[dst] = tmp;
505 tmp->loc = LOC_REG;
507 if (tmp->loc == LOC_SYM) {
508 i_sym(dst, tmp->sym, tmp->off);
509 tmp->addr = dst;
510 regs[dst] = tmp;
511 tmp->loc = LOC_REG;
513 if (tmp->loc == LOC_REG) {
514 if (deref)
515 i_ldr(1, dst, tmp->addr, 0, bt);
516 else if (dst != tmp->addr)
517 i_mov(I_MOV, dst, tmp->addr);
518 regs[tmp->addr] = NULL;
520 if (tmp->loc == LOC_LOCAL) {
521 if (deref)
522 i_ldr(1, dst, REG_FP, tmp->addr + tmp->off, bt);
523 else
524 i_add_anyimm(dst, REG_FP, tmp->addr + tmp->off);
526 if (tmp->loc == LOC_MEM) {
527 i_ldr(1, dst, REG_FP, tmp->addr, LONGSZ);
528 if (deref)
529 i_ldr(1, dst, dst, 0, bt);
531 tmp->addr = dst;
532 regs[dst] = tmp;
533 tmp->loc = LOC_REG;
536 static void reg_free(int reg)
538 int i;
539 if (!regs[reg])
540 return;
541 for (i = 0; i < ARRAY_SIZE(tmpregs); i++)
542 if (!regs[tmpregs[i]]) {
543 tmp_reg(regs[reg], tmpregs[i], 0);
544 return;
546 tmp_mem(regs[reg]);
549 static void reg_for(int reg, struct tmp *t)
551 if (regs[reg] && regs[reg] != t)
552 reg_free(reg);
555 static void tmp_mv(struct tmp *t, int reg)
557 reg_for(reg, t);
558 tmp_reg(t, reg, 0);
561 static void tmp_to(struct tmp *t, int reg)
563 reg_for(reg, t);
564 tmp_reg(t, reg, 1);
567 static void tmp_drop(int n)
569 int i;
570 for (i = ntmp - n; i < ntmp; i++)
571 if (tmps[i].loc == LOC_REG)
572 regs[tmps[i].addr] = NULL;
573 ntmp -= n;
576 static void tmp_pop(int reg)
578 struct tmp *t = TMP(0);
579 tmp_to(t, reg);
580 tmp_drop(1);
583 static struct tmp *tmp_new(void)
585 return &tmps[ntmp++];
588 static void tmp_push(int reg)
590 struct tmp *t = tmp_new();
591 t->addr = reg;
592 t->bt = 0;
593 t->loc = LOC_REG;
594 regs[reg] = t;
597 void o_local(long addr)
599 struct tmp *t = tmp_new();
600 t->addr = -addr;
601 t->loc = LOC_LOCAL;
602 t->bt = 0;
603 t->off = 0;
606 void o_num(long num)
608 struct tmp *t = tmp_new();
609 t->addr = num;
610 t->bt = 0;
611 t->loc = LOC_NUM;
614 void o_sym(char *name)
616 struct tmp *t = tmp_new();
617 strcpy(t->sym, name);
618 t->loc = LOC_SYM;
619 t->bt = 0;
620 t->off = 0;
623 void o_tmpdrop(int n)
625 if (n == -1 || n > ntmp)
626 n = ntmp;
627 tmp_drop(n);
628 if (!ntmp) {
629 if (tmpsp != -1)
630 sp = tmpsp;
631 tmpsp = -1;
635 #define FORK_REG 0x00
637 /* make sure tmps remain intact after a conditional expression */
638 void o_fork(void)
640 int i;
641 for (i = 0; i < ntmp - 1; i++)
642 tmp_mem(&tmps[i]);
645 void o_forkpush(void)
647 tmp_pop(FORK_REG);
650 void o_forkjoin(void)
652 tmp_push(FORK_REG);
655 void o_tmpswap(void)
657 struct tmp *t1 = TMP(0);
658 struct tmp *t2 = TMP(1);
659 struct tmp t;
660 memcpy(&t, t1, sizeof(t));
661 memcpy(t1, t2, sizeof(t));
662 memcpy(t2, &t, sizeof(t));
663 if (t1->loc == LOC_REG)
664 regs[t1->addr] = t1;
665 if (t2->loc == LOC_REG)
666 regs[t2->addr] = t2;
669 static int reg_get(int mask)
671 int i;
672 for (i = 0; i < ARRAY_SIZE(tmpregs); i++)
673 if ((1 << tmpregs[i]) & mask && !regs[tmpregs[i]])
674 return tmpregs[i];
675 for (i = 0; i < ARRAY_SIZE(tmpregs); i++)
676 if ((1 << tmpregs[i]) & mask) {
677 reg_free(tmpregs[i]);
678 return tmpregs[i];
680 return 0;
683 static int reg_fortmp(struct tmp *t, int notmask)
685 if (t->loc == LOC_REG && !(notmask & (1 << t->addr)))
686 return t->addr;
687 return reg_get(~notmask);
690 static void tmp_copy(struct tmp *t1)
692 struct tmp *t2 = tmp_new();
693 memcpy(t2, t1, sizeof(*t1));
694 if (!(t1->loc & (LOC_REG | LOC_MEM)))
695 return;
696 if (t1->loc == LOC_MEM) {
697 tmp_mv(t2, reg_get(~0));
698 } else if (t1->loc == LOC_REG) {
699 t2->addr = reg_fortmp(t2, 1 << t1->addr);
700 i_mov(I_MOV, t2->addr, t1->addr);
701 regs[t2->addr] = t2;
705 void o_tmpcopy(void)
707 tmp_copy(TMP(0));
710 void o_cast(unsigned bt)
712 struct tmp *t = TMP(0);
713 if (!t->bt && t->loc == LOC_NUM) {
714 num_cast(t, bt);
715 return;
717 if (BT_SZ(bt) != LONGSZ) {
718 int reg = reg_fortmp(t, 0);
719 tmp_to(t, reg);
720 if (bt & BT_SIGNED)
721 i_sx(reg, BT_SZ(bt) * 8);
722 else
723 i_zx(reg, BT_SZ(bt) * 8);
727 void o_func_beg(char *name, int argc, int global, int vararg)
729 out_sym(name, (global ? OUT_GLOB : 0) | OUT_CS, cslen, 0);
730 i_prolog();
731 sp = 0;
732 maxsp = sp;
733 ntmp = 0;
734 tmpsp = -1;
735 nret = 0;
736 memset(regs, 0, sizeof(regs));
739 void o_deref(unsigned bt)
741 struct tmp *t = TMP(0);
742 if (t->bt)
743 tmp_to(t, reg_fortmp(t, 0));
744 t->bt = bt;
747 void o_load(void)
749 struct tmp *t = TMP(0);
750 tmp_to(t, reg_fortmp(t, 0));
753 #define TMP_NUM(t) ((t)->loc == LOC_NUM && !(t)->bt)
754 #define LOCAL_PTR(t) ((t)->loc == LOC_LOCAL && !(t)->bt)
755 #define SYM_PTR(t) ((t)->loc == LOC_SYM && !(t)->bt)
757 int o_popnum(long *c)
759 struct tmp *t = TMP(0);
760 if (!TMP_NUM(t))
761 return 1;
762 *c = t->addr;
763 tmp_drop(1);
764 return 0;
767 void o_ret(int rets)
769 if (rets)
770 tmp_pop(REG_RET);
771 else
772 i_num(REG_RET, 0);
773 ret[nret++] = o_jmp(0);
776 void o_func_end(void)
778 int i;
779 for (i = 0; i < nret; i++)
780 o_filljmp(ret[i]);
781 i_epilog();
784 long o_mklocal(int size)
786 return sp_push(ALIGN(size, LONGSZ));
789 void o_rmlocal(long addr, int sz)
791 sp = addr - sz;
794 long o_arg2loc(int i)
796 return -(10 + i) << 2;
799 void o_assign(unsigned bt)
801 struct tmp *t1 = TMP(0);
802 struct tmp *t2 = TMP(1);
803 int r1 = reg_fortmp(t1, 0);
804 int r2 = reg_fortmp(t2, 1 << r1);
805 int off = 0;
806 tmp_to(t1, r1);
807 if (t2->bt)
808 tmp_to(t2, r2);
809 if (t2->loc == LOC_LOCAL) {
810 r2 = REG_FP;
811 off = t2->addr + t2->off;
812 } else {
813 tmp_to(t2, r2);
815 tmp_drop(2);
816 i_ldr(0, r1, r2, off, bt);
817 tmp_push(r1);
820 static long cu(int op, long i)
822 switch (op & 0xff) {
823 case O_NEG:
824 return -i;
825 case O_NOT:
826 return ~i;
827 case O_LNOT:
828 return !i;
830 return 0;
833 static int c_uop(int op)
835 struct tmp *t1 = TMP(0);
836 if (!TMP_NUM(t1))
837 return 1;
838 tmp_drop(1);
839 o_num(cu(op, t1->addr));
840 return 0;
843 static long cb(int op, long a, long b)
845 switch (op & 0xff) {
846 case O_ADD:
847 return a + b;
848 case O_SUB:
849 return a - b;
850 case O_AND:
851 return a & b;
852 case O_OR:
853 return a | b;
854 case O_XOR:
855 return a ^ b;
856 case O_MUL:
857 return a * b;
858 case O_DIV:
859 return a / b;
860 case O_MOD:
861 return a % b;
862 case O_SHL:
863 return a << b;
864 case O_SHR:
865 if (op & O_SIGNED)
866 return a >> b;
867 else
868 return (unsigned long) a >> b;
869 case O_LT:
870 return a < b;
871 case O_GT:
872 return a > b;
873 case O_LE:
874 return a <= b;
875 case O_GE:
876 return a >= b;
877 case O_EQ:
878 return a == b;
879 case O_NEQ:
880 return a != b;
882 return 0;
885 static int c_bop(int op)
887 struct tmp *t1 = TMP(0);
888 struct tmp *t2 = TMP(1);
889 int locals = LOCAL_PTR(t1) + LOCAL_PTR(t2);
890 int syms = SYM_PTR(t1) + SYM_PTR(t2);
891 int nums = TMP_NUM(t1) + TMP_NUM(t2);
892 if (syms + locals == 2 || syms + nums + locals != 2)
893 return 1;
894 if (nums == 1)
895 if ((op & 0xff) != O_ADD && ((op & 0xff) != O_SUB || TMP_NUM(t2)))
896 return 1;
897 if (nums == 1) {
898 long o1 = TMP_NUM(t1) ? t1->addr : t1->off;
899 long o2 = TMP_NUM(t2) ? t2->addr : t2->off;
900 long ret = cb(op, o2, o1);
901 if (!TMP_NUM(t1))
902 o_tmpswap();
903 t2->off = ret;
904 tmp_drop(1);
905 } else {
906 long ret = cb(op, t2->addr, t1->addr);
907 tmp_drop(2);
908 o_num(ret);
910 return 0;
913 void o_uop(int op)
915 int r1 = reg_fortmp(TMP(0), 0);
916 if (!c_uop(op))
917 return;
918 tmp_to(TMP(0), r1);
919 switch (op & 0xff) {
920 case O_NEG:
921 i_neg(r1);
922 break;
923 case O_NOT:
924 i_not(r1);
925 break;
926 case O_LNOT:
927 i_lnot(r1);
928 break;
932 static void bin_regs(int *r1, int *r2)
934 struct tmp *t2 = TMP(0);
935 struct tmp *t1 = TMP(1);
936 *r2 = reg_fortmp(t2, 0);
937 tmp_to(t2, *r2);
938 *r1 = reg_fortmp(t1, 1 << *r2);
939 tmp_pop(*r2);
940 tmp_pop(*r1);
943 static int bop_imm(int *r1, long *n, int swap)
945 struct tmp *t1 = TMP(0);
946 struct tmp *t2 = TMP(1);
947 if (!TMP_NUM(t1) && (!swap || !TMP_NUM(t2)))
948 return 1;
949 *n = TMP_NUM(t1) ? t1->addr : t2->addr;
950 if (add_decimm(add_encimm(*n)) != *n)
951 return 1;
952 if (!TMP_NUM(t1))
953 o_tmpswap();
954 *r1 = reg_fortmp(t2, 0);
955 tmp_drop(1);
956 tmp_pop(*r1);
957 return 0;
960 static void bin_add(int op)
962 /* opcode for O_ADD, O_SUB, O_AND, O_OR, O_XOR */
963 static int rx[] = {I_ADD, I_SUB, I_AND, I_ORR, I_EOR};
964 int r1, r2;
965 long n;
966 if (!bop_imm(&r1, &n, (op & 0xff) != O_SUB)) {
967 i_add_imm(rx[op & 0x0f], r1, r1, n);
968 } else {
969 bin_regs(&r1, &r2);
970 i_add(rx[op & 0x0f], r1, r1, r2);
972 tmp_push(r1);
975 static void bin_shx(int op)
977 int sm = SM_LSL;
978 int r1, r2;
979 long n;
980 if ((op & 0x0f) == 1)
981 sm = op & O_SIGNED ? SM_ASR : SM_LSR;
982 if (!bop_imm(&r1, &n, 0)) {
983 i_shl_imm(sm, r1, r1, n);
984 } else {
985 bin_regs(&r1, &r2);
986 i_shl(sm, r1, r1, r2);
988 tmp_push(r1);
991 static int log2a(unsigned long n)
993 int i = 0;
994 for (i = 0; i < LONGSZ * 8; i++)
995 if (n & (1u << i))
996 break;
997 if (i == LONGSZ * 8 || !(n >> (i + 1)))
998 return i;
999 return -1;
1002 /* optimized version of mul/div/mod for powers of two */
1003 static int mul_2(int op)
1005 struct tmp *t1 = TMP(0);
1006 struct tmp *t2 = TMP(1);
1007 long n;
1008 int r2;
1009 int p;
1010 if ((op & 0xff) == O_MUL && t2->loc == LOC_NUM && !t2->bt)
1011 o_tmpswap();
1012 if (t1->loc != LOC_NUM || t1->bt)
1013 return 1;
1014 n = t1->addr;
1015 p = log2a(n);
1016 if (n && p == -1)
1017 return 1;
1018 if ((op & 0xff) == O_MUL) {
1019 tmp_drop(1);
1020 if (n == 1)
1021 return 0;
1022 if (n == 0) {
1023 tmp_drop(1);
1024 o_num(0);
1025 return 0;
1027 r2 = reg_fortmp(t2, 0);
1028 tmp_to(t2, r2);
1029 i_shl_imm(SM_LSL, r2, r2, p);
1030 return 0;
1032 if (op == O_DIV) {
1033 tmp_drop(1);
1034 if (n == 1)
1035 return 0;
1036 r2 = reg_fortmp(t2, 0);
1037 tmp_to(t2, r2);
1038 i_shl_imm(op & O_SIGNED ? SM_ASR : SM_LSR, r2, r2, p);
1039 return 0;
1041 if (op == O_MOD) {
1042 tmp_drop(1);
1043 if (n == 1) {
1044 tmp_drop(1);
1045 o_num(0);
1046 return 0;
1048 r2 = reg_fortmp(t2, 0);
1049 tmp_to(t2, r2);
1050 i_zx(r2, p);
1051 return 0;
1053 return 1;
1056 static void bin_div(int op)
1058 struct tmp *t2 = TMP(0);
1059 struct tmp *t1 = TMP(1);
1060 char *func;
1061 int i;
1062 putdiv = 1;
1063 if ((op & 0xff) == O_DIV)
1064 func = op & O_SIGNED ? "__divdi3" : "__udivdi3";
1065 else
1066 func = op & O_SIGNED ? "__moddi3" : "__umoddi3";
1067 for (i = 0; i < ARRAY_SIZE(argregs); i++)
1068 if (regs[argregs[i]] && regs[argregs[i]] - tmps < ntmp - 2)
1069 tmp_mem(regs[argregs[i]]);
1070 tmp_to(t1, argregs[0]);
1071 tmp_to(t2, argregs[1]);
1072 tmp_drop(2);
1073 i_call(func);
1074 tmp_push(REG_RET);
1077 static void bin_mul(int op)
1079 int r1, r2;
1080 if (!mul_2(op))
1081 return;
1082 if ((op & 0xff) == O_DIV || (op & 0xff) == O_MOD) {
1083 bin_div(op);
1084 } else {
1085 bin_regs(&r1, &r2);
1086 i_mul(r1, r1, r2);
1087 tmp_push(r1);
1091 static void bin_cmp(int op)
1093 /* lt, gt, le, ge, eq, neq */
1094 static int ucond[] = {3, 8, 9, 2, 0, 1};
1095 static int scond[] = {11, 12, 13, 10, 0, 1};
1096 int r1, r2;
1097 long n;
1098 if (!bop_imm(&r1, &n, (op & 0xff) == O_EQ || (op & 0xff) == O_NEQ)) {
1099 i_cmp_imm(I_CMP, r1, n);
1100 } else {
1101 bin_regs(&r1, &r2);
1102 i_cmp(I_CMP, r1, r2);
1104 i_set(op & O_SIGNED ? scond[op & 0x0f] : ucond[op & 0x0f], r1);
1105 tmp_push(r1);
1108 void o_bop(int op)
1110 if (!c_bop(op))
1111 return;
1112 if ((op & 0xf0) == 0x00)
1113 bin_add(op);
1114 if ((op & 0xf0) == 0x10)
1115 bin_shx(op);
1116 if ((op & 0xf0) == 0x20)
1117 bin_mul(op);
1118 if ((op & 0xf0) == 0x30)
1119 bin_cmp(op);
1122 static void load_regs2(int *r0, int *r1, int *r2)
1124 struct tmp *t0 = TMP(0);
1125 struct tmp *t1 = TMP(1);
1126 struct tmp *t2 = TMP(2);
1127 *r0 = reg_fortmp(t0, 0);
1128 *r1 = reg_fortmp(t1, 1 << *r0);
1129 *r2 = reg_fortmp(t2, (1 << *r0) | (1 << *r1));
1130 tmp_to(t0, *r0);
1131 tmp_to(t1, *r1);
1132 tmp_to(t2, *r2);
1135 void o_memcpy(void)
1137 int rd, rs, rn;
1138 load_regs2(&rn, &rs, &rd);
1139 i_memcpy(rd, rs, rn);
1140 tmp_drop(2);
1143 void o_memset(void)
1145 int rd, rs, rn;
1146 load_regs2(&rn, &rs, &rd);
1147 i_memset(rd, rs, rn);
1148 tmp_drop(2);
1151 long o_mklabel(void)
1153 return cslen;
1156 static long jxz(long addr, int z)
1158 int r = reg_fortmp(TMP(0), 0);
1159 tmp_pop(r);
1160 i_b_if(addr, r, z);
1161 return cslen - 4;
1164 long o_jz(long addr)
1166 return jxz(addr, 1);
1169 long o_jnz(long addr)
1171 return jxz(addr, 0);
1174 long o_jmp(long addr)
1176 i_b(addr);
1177 return cslen - 4;
1180 void o_filljmp2(long addr, long jmpdst)
1182 i_b_fill((void *) cs + addr, jmpdst - addr);
1185 void o_filljmp(long addr)
1187 o_filljmp2(addr, cslen);
1190 void o_call(int argc, int rets)
1192 struct tmp *t;
1193 int i;
1194 int aregs = MIN(ARRAY_SIZE(argregs), argc);
1195 for (i = 0; i < ARRAY_SIZE(argregs); i++)
1196 if (regs[argregs[i]] && regs[argregs[i]] - tmps < ntmp - argc)
1197 tmp_mem(regs[argregs[i]]);
1198 if (argc > aregs) {
1199 sp_push(LONGSZ * (argc - aregs));
1200 for (i = argc - 1; i >= aregs; --i) {
1201 int reg = reg_fortmp(TMP(0), 0);
1202 tmp_pop(reg);
1203 i_ldr(0, reg, REG_SP, (i - aregs) * LONGSZ, LONGSZ);
1206 for (i = aregs - 1; i >= 0; --i)
1207 tmp_to(TMP(aregs - i - 1), argregs[i]);
1208 tmp_drop(aregs);
1209 t = TMP(0);
1210 if (t->loc == LOC_SYM && !t->bt) {
1211 i_call(t->sym);
1212 tmp_drop(1);
1213 } else {
1214 int reg = t->loc == LOC_REG ? t->addr : REG_TMP;
1215 tmp_pop(reg);
1216 i_call_reg(reg);
1218 if (rets)
1219 tmp_push(REG_RET);
1222 void o_nogen(void)
1224 nogen++;
1227 void o_dogen(void)
1229 nogen--;
1232 void o_mkbss(char *name, int size, int global)
1234 out_sym(name, OUT_BSS | (global ? OUT_GLOB : 0), bsslen, size);
1235 bsslen += ALIGN(size, LONGSZ);
1238 #define MAXDATS (1 << 10)
1239 static char dat_names[MAXDATS][NAMELEN];
1240 static int dat_offs[MAXDATS];
1241 static int ndats;
1243 void err(char *msg);
1244 void *o_mkdat(char *name, int size, int global)
1246 void *addr = ds + dslen;
1247 int idx = ndats++;
1248 if (idx >= MAXDATS)
1249 err("nomem: MAXDATS reached!\n");
1250 strcpy(dat_names[idx], name);
1251 dat_offs[idx] = dslen;
1252 out_sym(name, OUT_DS | (global ? OUT_GLOB : 0), dslen, size);
1253 dslen += ALIGN(size, LONGSZ);
1254 return addr;
1257 static int dat_off(char *name)
1259 int i;
1260 for (i = 0; i < ndats; i++)
1261 if (!strcmp(name, dat_names[i]))
1262 return dat_offs[i];
1263 return 0;
1266 void o_datset(char *name, int off, unsigned bt)
1268 struct tmp *t = TMP(0);
1269 int sym_off = dat_off(name) + off;
1270 if (t->loc == LOC_NUM && !t->bt) {
1271 num_cast(t, bt);
1272 memcpy(ds + sym_off, &t->addr, BT_SZ(bt));
1274 if (t->loc == LOC_SYM && !t->bt) {
1275 out_rel(t->sym, OUT_DS, sym_off);
1276 memcpy(ds + sym_off, &t->off, BT_SZ(bt));
1278 tmp_drop(1);
1281 /* compiled division functions; div.s contains the source */
1282 static int udivdi3[] = {
1283 0xe3a02000, 0xe3a03000, 0xe1110001, 0x0a00000a,
1284 0xe1b0c211, 0xe2822001, 0x5afffffc, 0xe3a0c001,
1285 0xe2522001, 0x4a000004, 0xe1500211, 0x3afffffb,
1286 0xe0400211, 0xe083321c, 0xeafffff8, 0xe1a01000,
1287 0xe1a00003, 0xe1a0f00e,
1289 static int umoddi3[] = {
1290 0xe92d4000, 0xebffffeb, 0xe1a00001, 0xe8bd8000,
1292 static int divdi3[] = {
1293 0xe92d4030, 0xe1a04000, 0xe1a05001, 0xe1100000,
1294 0x42600000, 0xe1110001, 0x42611000, 0xebffffe1,
1295 0xe1340005, 0x42600000, 0xe1140004, 0x42611000,
1296 0xe8bd8030,
1298 static int moddi3[] = {
1299 0xe92d4000, 0xebfffff0, 0xe1a00001, 0xe8bd8000,
1302 void o_write(int fd)
1304 if (putdiv) {
1305 out_sym("__udivdi3", OUT_CS, cslen, 0);
1306 os(udivdi3, sizeof(udivdi3));
1307 out_sym("__umoddi3", OUT_CS, cslen, 0);
1308 os(umoddi3, sizeof(umoddi3));
1309 out_sym("__divdi3", OUT_CS, cslen, 0);
1310 os(divdi3, sizeof(divdi3));
1311 out_sym("__moddi3", OUT_CS, cslen, 0);
1312 os(moddi3, sizeof(moddi3));
1314 out_write(fd, cs, cslen, ds, dslen);