out: align bss variables
[neatcc.git] / gen.c
blobe89bef3a57ad2ac8f98f9d3d3d90965694e26d17
1 #include <stdlib.h>
2 #include <string.h>
3 #include "gen.h"
4 #include "tok.h"
6 #define TMP_ADDR 0x0001
7 #define LOC_REG 0x0100
8 #define LOC_MEM 0x0200
9 #define LOC_NUM 0x0400
10 #define LOC_SYM 0x0800
11 #define LOC_LOCAL 0x1000
12 #define LOC_MASK 0xff00
14 #define R_RAX 0x00
15 #define R_RCX 0x01
16 #define R_RDX 0x02
17 #define R_RBX 0x03
18 #define R_RSP 0x04
19 #define R_RBP 0x05
20 #define R_RSI 0x06
21 #define R_RDI 0x07
22 #define R_R8 0x08
23 #define R_R9 0x09
24 #define R_R10 0x0a
25 #define R_R11 0x0b
26 #define R_R12 0x0c
27 #define R_R13 0x0d
28 #define R_R14 0x0e
29 #define R_R15 0x0f
30 #define NREGS 0x10
32 #define MOV_M2R 0x8b
33 #define MOV_R2X 0x89
34 #define MOV_I2R 0xc7
35 #define ADD_R2X 0x03
36 #define SUB_R2X 0x2b
37 #define SHX_REG 0xd3
38 #define CMP_R2X 0x3b
39 #define LEA_M2R 0x8d
40 #define NEG_REG 0xf7
41 #define NOT_REG 0xf7
42 #define CALL_REG 0xff
43 #define MUL_A2X 0xf7
44 #define XOR_R2X 0x33
45 #define AND_R2X 0x23
46 #define OR_R2X 0x0b
47 #define TEST_R2R 0x85
49 #define R_BYTEMASK (1 << R_RAX | 1 << R_RDX | 1 << R_RCX)
50 #define TMP_BT(t) ((t)->flags & TMP_ADDR ? 8 : (t)->bt)
51 #define TMP_REG(t) ((t)->flags & LOC_REG ? (t)->addr : reg_get(~0))
52 #define TMP_REG2(t, r) ((t)->flags & LOC_REG && (t)->addr != r ? \
53 (t)->addr : reg_get(~(1 << r)))
54 #define TMP_BYTEREG(t) ((t)->flags & LOC_REG && \
55 (1 << (t)->addr) & R_BYTEMASK ? \
56 (t)->addr : reg_get(R_BYTEMASK))
57 #define BT_TMPBT(bt) (BT_SZ(bt) >= 4 ? (bt) : (bt) & BT_SIGNED | 4)
59 static char buf[SECSIZE];
60 static char *cur;
61 static long sp;
62 static long spsub_addr;
63 static long maxsp;
65 static struct tmp {
66 long addr;
67 unsigned flags;
68 unsigned bt;
69 } tmp[MAXTMP];
70 static int ntmp;
72 static int tmpsp;
74 static struct tmp *regs[NREGS];
75 static int tmpregs[] = {R_RAX, R_RDI, R_RSI, R_RDX, R_RCX, R_R8, R_R9};
77 #define MAXRET (1 << 8)
79 static long ret[MAXRET];
80 static int nret;
82 static long cmp_last;
83 static long cmp_setl;
85 static void putint(char *s, long n, int l)
87 while (l--) {
88 *s++ = n;
89 n >>= 8;
93 static void os(char *s, int n)
95 while (n--)
96 *cur++ = *s++;
99 static void oi(long n, int l)
101 while (l--) {
102 *cur++ = n;
103 n >>= 8;
107 static long codeaddr(void)
109 return cur - buf;
112 static void o_op(int *op, int nop, int r1, int r2, unsigned bt)
114 int rex = 0;
115 int i;
116 if (r1 & 0x8)
117 rex |= 4;
118 if (r2 & 0x8)
119 rex |= 1;
120 if (rex || (bt & BT_SZMASK) == 8)
121 oi(0x48 | rex, 1);
122 if ((bt & BT_SZMASK) == 2)
123 oi(0x66, 1);
124 if ((bt & BT_SZMASK) == 1)
125 op[nop - 1] &= ~0x1;
126 for (i = 0; i < nop; i++)
127 oi(op[i], 1);
130 static void memop(int *op, int nop, int src, int base, int off, unsigned bt)
132 int dis = off == (char) off ? 1 : 4;
133 int mod = dis == 4 ? 2 : 1;
134 o_op(op, nop, src, base, bt);
135 if (!off)
136 mod = 0;
137 oi((mod << 6) | ((src & 0x07) << 3) | (base & 0x07), 1);
138 if (off)
139 oi(off, dis);
142 static void memop1(int op, int src, int base, int off, unsigned bt)
144 memop(&op, 1, src, base, off, bt);
147 static void regop(int op, int src, int dst, unsigned bt)
149 o_op(&op, 1, src, dst, bt);
150 oi((3 << 6) | (src << 3) | (dst & 0x07), 1);
153 static long sp_push(int size)
155 sp += size;
156 if (sp > maxsp)
157 maxsp = sp;
158 return sp;
161 #define LOC_NEW(f, l) (((f) & ~LOC_MASK) | (l))
163 static void tmp_mem(struct tmp *tmp)
165 int src = tmp->addr;
166 if (!(tmp->flags & LOC_REG))
167 return;
168 if (tmpsp == -1)
169 tmpsp = sp;
170 tmp->addr = sp_push(8);
171 memop1(MOV_R2X, src, R_RBP, -tmp->addr, BT_TMPBT(TMP_BT(tmp)));
172 regs[src] = NULL;
173 tmp->flags = LOC_NEW(tmp->flags, LOC_MEM);
176 static void mov_m2r(int dst, int base, int off, int bt)
178 int movxx[2] = {0x0f};
179 if (BT_SZ(bt) < 4) {
180 if (BT_SZ(bt) == 1)
181 movxx[1] = bt & BT_SIGNED ? 0xbe : 0xb6;
182 else
183 movxx[1] = bt & BT_SIGNED ? 0xbf : 0xb7;
184 memop(movxx, 2, dst, base, off, BT_SIGNED ? 8 : 4);
185 return;
187 memop1(MOV_M2R, dst, base, off, bt);
190 static void tmp_reg(struct tmp *tmp, unsigned dst, int deref)
192 if (!(tmp->flags & TMP_ADDR))
193 deref = 0;
194 if (deref)
195 tmp->flags &= ~TMP_ADDR;
196 if (tmp->flags & LOC_NUM) {
197 regop(MOV_I2R, 0, dst, TMP_BT(tmp));
198 oi(tmp->addr, BT_SZ(tmp->bt));
199 tmp->addr = dst;
200 regs[dst] = tmp;
201 tmp->flags = LOC_NEW(tmp->flags, LOC_REG);
203 if (tmp->flags & LOC_SYM) {
204 regop(MOV_I2R, 0, dst, TMP_BT(tmp));
205 out_rela(tmp->addr, codeaddr(), 0);
206 oi(0, 4);
207 tmp->addr = dst;
208 regs[dst] = tmp;
209 tmp->flags = LOC_NEW(tmp->flags, LOC_REG);
211 if (tmp->flags & LOC_REG) {
212 if (deref) {
213 mov_m2r(dst, tmp->addr, 0, tmp->bt);
214 } else {
215 if (dst == tmp->addr)
216 return;
217 regop(MOV_R2X, tmp->addr, dst, BT_TMPBT(TMP_BT(tmp)));
219 regs[tmp->addr] = NULL;
220 tmp->addr = dst;
221 regs[dst] = tmp;
222 return;
224 if (tmp->flags & LOC_LOCAL) {
225 if (deref)
226 mov_m2r(dst, R_RBP, -tmp->addr, TMP_BT(tmp));
227 else
228 memop1(LEA_M2R, dst, R_RBP, -tmp->addr, 8);
230 if (tmp->flags & LOC_MEM) {
231 mov_m2r(dst, R_RBP, -tmp->addr, TMP_BT(tmp));
232 if (deref)
233 mov_m2r(dst, dst, 0, TMP_BT(tmp));
235 tmp->addr = dst;
236 regs[dst] = tmp;
237 tmp->flags = LOC_NEW(tmp->flags, LOC_REG);
240 static void reg_free(int reg)
242 int i;
243 if (!regs[reg])
244 return;
245 for (i = 0; i < ARRAY_SIZE(tmpregs); i++)
246 if (!regs[tmpregs[i]]) {
247 tmp_reg(regs[reg], tmpregs[i], 0);
248 return;
250 tmp_mem(regs[reg]);
253 static void reg_for(int reg, struct tmp *t)
255 if (regs[reg] && regs[reg] != t)
256 reg_free(reg);
259 static unsigned tmp_pop(int deref, int reg)
261 struct tmp *t = &tmp[--ntmp];
262 reg_for(reg, t);
263 tmp_reg(t, reg, deref);
264 regs[reg] = NULL;
265 return t->bt;
268 static void tmp_push_reg(unsigned bt, unsigned reg)
270 struct tmp *t = &tmp[ntmp++];
271 t->addr = reg;
272 t->bt = bt;
273 t->flags = LOC_REG;
274 regs[reg] = t;
277 void o_local(long addr, unsigned bt)
279 struct tmp *t = &tmp[ntmp++];
280 t->addr = addr;
281 t->bt = bt;
282 t->flags = LOC_LOCAL | TMP_ADDR;
285 void o_num(long num, unsigned bt)
287 struct tmp *t = &tmp[ntmp++];
288 t->addr = num;
289 t->bt = bt;
290 t->flags = LOC_NUM;
293 void o_symaddr(long addr, unsigned bt)
295 struct tmp *t = &tmp[ntmp++];
296 t->bt = bt;
297 t->addr = addr;
298 t->flags = LOC_SYM | TMP_ADDR;
301 void o_tmpdrop(int n)
303 int i;
304 if (n == -1 || n > ntmp)
305 n = ntmp;
306 ntmp -= n;
307 for (i = ntmp; i < ntmp + n; i++)
308 if (tmp[i].flags & LOC_REG)
309 regs[tmp[i].addr] = NULL;
310 if (!ntmp) {
311 if (tmpsp != -1)
312 sp = tmpsp;
313 tmpsp = -1;
317 #define FORK_REG R_RAX
319 void o_tmpfork(void)
321 struct tmp *t = &tmp[ntmp - 1];
322 reg_for(FORK_REG, t);
323 tmp_reg(t, FORK_REG, 0);
324 o_tmpdrop(1);
327 void o_tmpjoin(void)
329 struct tmp *t = &tmp[ntmp - 1];
330 reg_for(FORK_REG, t);
331 tmp_reg(t, FORK_REG, 0);
334 void o_tmpswap(void)
336 struct tmp *t1 = &tmp[ntmp - 1];
337 struct tmp *t2 = &tmp[ntmp - 2];
338 struct tmp t;
339 memcpy(&t, t1, sizeof(t));
340 memcpy(t1, t2, sizeof(t));
341 memcpy(t2, &t, sizeof(t));
344 static int reg_get(int mask)
346 int i;
347 for (i = 0; i < ARRAY_SIZE(tmpregs); i++)
348 if ((1 << tmpregs[i]) & mask && !regs[tmpregs[i]])
349 return tmpregs[i];
350 for (i = 0; i < ARRAY_SIZE(tmpregs); i++)
351 if ((1 << tmpregs[i]) & mask) {
352 reg_free(tmpregs[i]);
353 return tmpregs[i];
355 return 0;
358 void o_tmpcopy(void)
360 struct tmp *t1 = &tmp[ntmp - 1];
361 struct tmp *t2 = &tmp[ntmp++];
362 if (!(t1->flags & (LOC_REG | LOC_MEM))) {
363 memcpy(t2, t1, sizeof(*t2));
364 return;
366 memcpy(t2, t1, sizeof(*t1));
367 if (t1->flags & LOC_MEM) {
368 tmp_reg(t2, reg_get(~0), 0);
369 } else if (t1->flags & LOC_REG) {
370 t2->addr = reg_get(~t1->addr);
371 regop(MOV_R2X, t1->addr, t2->addr, BT_TMPBT(TMP_BT(tmp)));
373 t2->flags = t1->flags;
376 long o_func_beg(char *name)
378 long addr = out_func_beg(name);
379 cur = buf;
380 os("\x55", 1); /* push %rbp */
381 os("\x48\x89\xe5", 3); /* mov %rsp, %rbp */
382 sp = 0;
383 maxsp = 0;
384 ntmp = 0;
385 tmpsp = -1;
386 nret = 0;
387 cmp_last = -1;
388 memset(regs, 0, sizeof(regs));
389 os("\x48\x81\xec", 3); /* sub $xxx, %rsp */
390 spsub_addr = codeaddr();
391 oi(0, 4);
392 return addr;
395 void o_deref(unsigned bt)
397 struct tmp *t = &tmp[ntmp - 1];
398 if (t->flags & TMP_ADDR)
399 tmp_reg(t, TMP_REG(t), 1);
400 t->bt = bt;
401 t->flags |= TMP_ADDR;
404 void o_load(void)
406 struct tmp *t = &tmp[ntmp - 1];
407 tmp_reg(t, TMP_REG(t), 1);
410 static void shx(int uop, int sop)
412 struct tmp *t = &tmp[ntmp - 2];
413 unsigned bt;
414 unsigned reg = TMP_REG2(t, R_RCX);
415 tmp_pop(1, R_RCX);
416 bt = tmp_pop(1, reg);
417 regop(SHX_REG, bt & BT_SIGNED ? sop : uop, reg, BT_TMPBT(bt));
418 tmp_push_reg(bt, reg);
421 void o_shl(void)
423 shx(4, 4);
426 void o_shr(void)
428 shx(5, 7);
431 static unsigned bt_op(unsigned bt1, unsigned bt2)
433 unsigned s1 = BT_SZ(bt1);
434 unsigned s2 = BT_SZ(bt2);
435 return (bt1 | bt2) & BT_SIGNED | (s1 > s2 ? s1 : s2);
438 static int mulop(int uop, int sop, int reg)
440 struct tmp *t1 = &tmp[ntmp - 1];
441 struct tmp *t2 = &tmp[ntmp - 2];
442 int bt1 = TMP_BT(t1);
443 int bt2 = TMP_BT(t2);
444 if (t1->flags & LOC_REG && t1->addr != R_RAX && t1->addr != R_RDX)
445 reg = t1->addr;
446 reg_for(reg, t1);
447 tmp_reg(t1, reg, 1);
448 reg_for(R_RAX, t2);
449 tmp_reg(t2, R_RAX, 1);
450 if (reg != R_RDX)
451 reg_free(R_RDX);
452 o_tmpdrop(2);
453 regop(MUL_A2X, bt2 & BT_SIGNED ? sop : uop, reg, BT_TMPBT(bt2));
454 return bt_op(bt1, bt2);
457 void o_mul(void)
459 int bt = mulop(4, 5, R_RDX);
460 tmp_push_reg(bt, R_RAX);
463 void o_div(void)
465 int bt = mulop(6, 7, R_RCX);
466 tmp_push_reg(bt, R_RAX);
469 void o_mod(void)
471 int bt = mulop(6, 7, R_RCX);
472 tmp_push_reg(bt, R_RDX);
475 void o_addr(void)
477 tmp[ntmp - 1].flags &= ~TMP_ADDR;
478 tmp[ntmp - 1].bt = 8;
481 void o_ret(unsigned bt)
483 if (bt)
484 tmp_pop(1, R_RAX);
485 else
486 os("\x31\xc0", 2); /* xor %eax, %eax */
487 ret[nret++] = o_jmp(0);
490 static int binop(int op, int *reg)
492 struct tmp *t1 = &tmp[ntmp - 1];
493 struct tmp *t2 = &tmp[ntmp - 2];
494 int r1;
495 unsigned bt1, bt2, bt;
496 r1 = TMP_REG(t1);
497 *reg = TMP_REG2(t2, r1);
498 bt1 = tmp_pop(1, r1);
499 bt2 = tmp_pop(1, *reg);
500 bt = bt_op(bt1, bt2);
501 regop(op, *reg, r1, BT_TMPBT(bt));
502 return bt;
505 void o_add(void)
507 int reg;
508 int bt = binop(ADD_R2X, &reg);
509 tmp_push_reg(bt, reg);
512 void o_xor(void)
514 int reg;
515 int bt = binop(XOR_R2X, &reg);
516 tmp_push_reg(bt, reg);
519 void o_and(void)
521 int reg;
522 int bt = binop(AND_R2X, &reg);
523 tmp_push_reg(bt, reg);
526 void o_or(void)
528 int reg;
529 int bt = binop(OR_R2X, &reg);
530 tmp_push_reg(bt, reg);
533 void o_sub(void)
535 int reg;
536 int bt = binop(SUB_R2X, &reg);
537 tmp_push_reg(bt, reg);
540 static void o_cmp(int uop, int sop)
542 char set[] = "\x0f\x00\xc0";
543 int reg;
544 int bt = binop(CMP_R2X, &reg);
545 set[1] = bt & BT_SIGNED ? sop : uop;
546 reg_free(R_RAX);
547 cmp_setl = codeaddr();
548 os(set, 3); /* setl %al */
549 os("\x0f\xb6\xc0", 3); /* movzbl %al, %eax */
550 tmp_push_reg(4 | BT_SIGNED, R_RAX);
551 cmp_last = codeaddr();
554 void o_lt(void)
556 o_cmp(0x92, 0x9c);
559 void o_gt(void)
561 o_cmp(0x97, 0x9f);
564 void o_le(void)
566 o_cmp(0x96, 0x9e);
569 void o_ge(void)
571 o_cmp(0x93, 0x9d);
574 void o_eq(void)
576 o_cmp(0x94, 0x94);
579 void o_neq(void)
581 o_cmp(0x95, 0x95);
584 void o_lnot(void)
586 if (cmp_last == codeaddr()) {
587 buf[cmp_setl + 1] ^= 0x10;
588 } else {
589 o_num(0, 4 | BT_SIGNED);
590 o_eq();
594 void o_neg(void)
596 struct tmp *t = &tmp[ntmp - 1];
597 int reg = TMP_REG(t);
598 tmp_pop(1, reg);
599 regop(NEG_REG, 3, reg, BT_TMPBT(t->bt));
600 tmp_push_reg(t->bt, reg);
603 void o_not(void)
605 struct tmp *t = &tmp[ntmp - 1];
606 int reg = TMP_REG(t);
607 tmp_pop(1, reg);
608 regop(NOT_REG, 2, reg, BT_TMPBT(t->bt));
609 tmp_push_reg(t->bt, reg);
612 void o_func_end(void)
614 int i;
615 for (i = 0; i < nret; i++)
616 o_filljmp(ret[i]);
617 os("\xc9\xc3", 2); /* leave; ret; */
618 putint(buf + spsub_addr, (maxsp + 7) & ~0x07, 4);
619 out_func_end(buf, cur - buf);
622 long o_mklocal(int size)
624 return sp_push((size + 7) & ~0x07);
627 static int arg_regs[] = {R_RDI, R_RSI, R_RDX, R_RCX, R_R8, R_R9};
629 long o_arg(int i, unsigned bt)
631 long addr = o_mklocal(BT_SZ(bt));
632 memop1(MOV_R2X, arg_regs[i], R_RBP, -addr, bt);
633 return addr;
636 void o_assign(unsigned bt)
638 struct tmp *t1 = &tmp[ntmp - 1];
639 struct tmp *t2 = &tmp[ntmp - 2];
640 int r1 = BT_SZ(bt) > 1 ? TMP_REG(t1) : TMP_BYTEREG(t1);
641 int reg;
642 int off;
643 tmp_pop(1, r1);
644 if (t2->flags & LOC_LOCAL) {
645 reg = R_RBP;
646 off = -t2->addr;
647 o_tmpdrop(1);
648 } else {
649 reg = TMP_REG2(t2, r1);
650 off = 0;
651 tmp_pop(0, reg);
653 memop1(MOV_R2X, r1, reg, off, bt);
654 tmp_push_reg(bt, r1);
657 long o_mklabel(void)
659 return codeaddr();
662 static long jx(int x, long addr)
664 char op[2] = {0x0f};
665 op[1] = x;
666 os(op, 2); /* jx $addr */
667 oi(addr - codeaddr() - 4, 4);
668 return codeaddr() - 4;
671 static long jxtest(int x, long addr)
673 int bt = tmp_pop(1, R_RAX);
674 regop(TEST_R2R, R_RAX, R_RAX, BT_TMPBT(bt));
675 return jx(x, addr);
678 static long jxcmp(long addr, int inv)
680 int x;
681 if (codeaddr() != cmp_last)
682 return -1;
683 o_tmpdrop(1);
684 cur = buf + cmp_setl;
685 x = (unsigned char) buf[cmp_setl + 1];
686 return jx((inv ? x : x ^ 0x01) & ~0x10, addr);
689 long o_jz(long addr)
691 long ret = jxcmp(addr, 0);
692 return ret != -1 ? ret : jxtest(0x84, addr);
695 long o_jnz(long addr)
697 long ret = jxcmp(addr, 1);
698 return ret != -1 ? ret : jxtest(0x85, addr);
701 long o_jmp(long addr)
703 os("\xe9", 1); /* jmp $addr */
704 oi(addr - codeaddr() - 4, 4);
705 return codeaddr() - 4;
708 void o_filljmp(long addr)
710 putint(buf + addr, codeaddr() - addr - 4, 4);
713 void o_call(int argc, unsigned *bt, unsigned ret_bt)
715 int i;
716 struct tmp *t;
717 for (i = 0; i < argc; i++)
718 tmp_pop(1, arg_regs[i]);
719 t = &tmp[ntmp - 1];
720 if (t->flags & LOC_SYM) {
721 os("\xe8", 1); /* call $x */
722 out_rela(t->addr, codeaddr(), 1);
723 oi(-4, 4);
724 o_tmpdrop(1);
725 } else {
726 tmp_pop(0, R_RAX);
727 regop(CALL_REG, 2, R_RAX, 4);
729 for (i = 0; i < ARRAY_SIZE(tmpregs); i++)
730 if (regs[i])
731 tmp_mem(regs[i]);
732 if (ret_bt)
733 tmp_push_reg(ret_bt, R_RAX);