port neatcc to x86
[neatcc/cc.git] / gen.c
blob1c2bf59a86200b608dea6cc6f6a9aea10c55e78b
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_EAX 0x00
15 #define R_ECX 0x01
16 #define R_EDX 0x02
17 #define R_EBX 0x03
18 #define R_ESP 0x04
19 #define R_EBP 0x05
20 #define R_ESI 0x06
21 #define R_EDI 0x07
22 #define NREGS 0x08
24 #define MOV_M2R 0x8b
25 #define MOV_R2X 0x89
26 #define MOV_I2X 0xc7
27 #define MOV_I2R 0xb8
28 #define ADD_R2X 0x03
29 #define SUB_R2X 0x2b
30 #define SHX_REG 0xd3
31 #define CMP_R2X 0x3b
32 #define LEA_M2R 0x8d
33 #define NEG_REG 0xf7
34 #define NOT_REG 0xf7
35 #define CALL_REG 0xff
36 #define MUL_A2X 0xf7
37 #define XOR_R2X 0x33
38 #define AND_R2X 0x23
39 #define OR_R2X 0x0b
40 #define TEST_R2R 0x85
41 #define INC_X 0xff
43 #define MIN(a, b) ((a) < (b) ? (a) : (b))
45 #define TMP_BT(t) ((t)->flags & TMP_ADDR ? LONGSZ : (t)->bt)
46 #define TMP_REG(t) ((t)->flags & LOC_REG ? (t)->addr : reg_get(~0))
47 #define TMP_REG2(t, r) ((t)->flags & LOC_REG && (t)->addr != r ? \
48 (t)->addr : reg_get(~(1 << r)))
49 #define TMPBT(bt) (BT_SZ(bt) >= 4 ? (bt) : (bt) & BT_SIGNED | 4)
51 #define R_BYTEREGS (1 << R_EAX | 1 << R_EDX | 1 << R_ECX)
52 #define TMP_BYTEREG(t) ((t)->flags & LOC_REG && \
53 (1 << (t)->addr) & R_BYTEREGS ? \
54 (t)->addr : reg_get(R_BYTEREGS))
56 static char buf[SECSIZE];
57 static char *cur;
58 static int nogen;
59 static long sp;
60 static long spsub_addr;
61 static long maxsp;
63 #define TMP(i) (&tmps[ntmp - 1 - (i)])
65 static struct tmp {
66 long addr;
67 long off; /* used for LOC_SYM; offset from a symbol address */
68 unsigned flags;
69 unsigned bt;
70 } tmps[MAXTMP];
71 static int ntmp;
73 static int tmpsp;
75 static struct tmp *regs[NREGS];
76 static int tmpregs[] = {R_EAX, R_ESI, R_EDI, R_EBX, R_EDX, R_ECX};
78 #define MAXRET (1 << 8)
80 static long ret[MAXRET];
81 static int nret;
83 static long cmp_last;
84 static long cmp_setl;
86 static void putint(char *s, long n, int l)
88 while (l--) {
89 *s++ = n;
90 n >>= 8;
94 static void os(char *s, int n)
96 if (nogen)
97 return;
98 while (n--)
99 *cur++ = *s++;
102 static void oi(long n, int l)
104 if (nogen)
105 return;
106 while (l--) {
107 *cur++ = n;
108 n >>= 8;
112 static long codeaddr(void)
114 return cur - buf;
117 #define OP2(o2, o1) (0x010000 | ((o2) << 8) | (o1))
118 #define O2(op) (((op) >> 8) & 0xff)
119 #define O1(op) ((op) & 0xff)
120 #define MODRM(m, r1, r2) ((m) << 6 | (r1) << 3 | (r2))
122 static void op_x(int op, int r1, int r2, int bt)
124 int sz = BT_SZ(bt);
125 if (sz == 2)
126 oi(0x66, 1);
127 if (op & 0x10000)
128 oi(O2(op), 1);
129 oi(sz == 1 ? O1(op) & ~0x1 : O1(op), 1);
132 #define op_mr op_rm
134 /* op_*(): r=reg, m=mem, i=imm, s=sym */
135 static void op_rm(int op, int src, int base, int off, int bt)
137 int dis = off == (char) off ? 1 : 4;
138 int mod = dis == 4 ? 2 : 1;
139 if (!off)
140 mod = 0;
141 op_x(op, src, base, bt);
142 oi(MODRM(mod, src & 0x07, base & 0x07), 1);
143 if (base == R_ESP)
144 oi(0x24, 1);
145 if (off)
146 oi(off, dis);
149 static void op_rr(int op, int src, int dst, int bt)
151 op_x(op, src, dst, bt);
152 oi(MODRM(3, src & 0x07, dst & 0x07), 1);
155 static void op_rs(int op, int src, long addr, int off, int bt)
157 op_x(op, src, 0, bt);
158 oi(MODRM(0, src & 0x07, 5), 1);
159 if (!nogen)
160 out_rela(addr, codeaddr(), 1);
161 oi(off - 4, 4);
164 static void op_ri(int op, int o3, int src, long num, int bt)
166 op_x(op, src, 0, bt);
167 oi(MODRM(3, o3, src & 0x07), 1);
168 oi(num, MIN(4, BT_SZ(bt)));
171 static void op_sr(int op, int src, long addr, int off, int bt)
173 op_x(op, src, 0, bt);
174 oi(MODRM(0, src & 0x07, 5), 1);
175 if (!nogen)
176 out_rela(addr, codeaddr(), 1);
177 oi(off - 4, 4);
180 static void op_si(int op, int o3, long addr, int off, long num, int bt)
182 int sz = MIN(4, BT_SZ(bt));
183 op_x(op, 0, 0, bt);
184 oi(MODRM(0, o3, 5), 1);
185 if (!nogen)
186 out_rela(addr, codeaddr(), 1);
187 oi(off - 4 - sz, 4);
188 oi(num, sz);
191 static void op_mi(int op, int o3, int base, int off, long num, int bt)
193 int dis = off == (char) off ? 1 : 4;
194 int mod = dis == 4 ? 2 : 1;
195 if (!off)
196 mod = 0;
197 op_x(op, 0, base, bt);
198 oi(MODRM(mod, 0, base), 1);
199 if (off)
200 oi(off, dis);
201 oi(num, MIN(4, BT_SZ(bt)));
204 static long sp_push(int size)
206 sp += size;
207 if (sp > maxsp)
208 maxsp = sp;
209 return sp;
212 #define LOC_NEW(f, l) (((f) & ~LOC_MASK) | (l))
214 static void tmp_mem(struct tmp *tmp)
216 int src = tmp->addr;
217 if (!(tmp->flags & LOC_REG))
218 return;
219 if (tmpsp == -1)
220 tmpsp = sp;
221 tmp->addr = -sp_push(LONGSZ);
222 op_rm(MOV_R2X, src, R_EBP, tmp->addr, TMPBT(TMP_BT(tmp)));
223 regs[src] = NULL;
224 tmp->flags = LOC_NEW(tmp->flags, LOC_MEM);
227 static int movxx_x2r(int bt)
229 int o2;
230 if (BT_SZ(bt) == 1)
231 o2 = bt & BT_SIGNED ? 0xbe : 0xb6;
232 else
233 o2 = bt & BT_SIGNED ? 0xbf : 0xb7;
234 return OP2(0x0f, o2);
237 #define MOVSXD 0x63
239 static void mov_r2r(int r1, int r2, unsigned bt1, unsigned bt2)
241 int s1 = bt1 & BT_SIGNED;
242 int s2 = bt2 & BT_SIGNED;
243 int sz1 = BT_SZ(bt1);
244 int sz2 = BT_SZ(bt2);
245 if (sz2 < 4 && (sz1 > sz2 || s1 != s2)) {
246 op_rr(movxx_x2r(bt2), r1, r2, 4);
247 return;
249 if (sz1 == 4 && sz2 == 8 && s1) {
250 op_rr(MOVSXD, r2, r1, sz2);
251 return;
253 if (r1 != r2 || sz1 > sz2)
254 op_rr(MOV_R2X, r1, r2, TMPBT(bt2));
257 static void mov_m2r(int dst, int base, int off, int bt1, int bt2)
259 if (BT_SZ(bt1) < 4) {
260 op_rm(movxx_x2r(bt1), dst, base, off,
261 bt1 & BT_SIGNED && BT_SZ(bt2) == 8 ? 8 : 4);
262 mov_r2r(dst, dst, bt1, bt2);
263 } else {
264 op_rm(MOV_M2R, dst, base, off, bt1);
265 mov_r2r(dst, dst, bt1, bt2);
269 static void num_cast(struct tmp *t, unsigned bt)
271 if (!(bt & BT_SIGNED) && BT_SZ(bt) != LONGSZ)
272 t->addr &= ((1l << (long) (BT_SZ(bt) * 8)) - 1);
273 if (bt & BT_SIGNED && BT_SZ(bt) != LONGSZ &&
274 t->addr > (1l << (BT_SZ(bt) * 8 - 1)))
275 t->addr = -((1l << (BT_SZ(bt) * 8)) - t->addr);
276 t->bt = bt;
279 static void num_reg(int reg, unsigned bt, long num)
281 int op = MOV_I2R + (reg & 7);
282 op_x(op, 0, reg, bt);
283 oi(num, BT_SZ(bt));
286 static void tmp_reg(struct tmp *tmp, int dst, unsigned bt, int deref)
288 if (deref && tmp->flags & TMP_ADDR)
289 tmp->flags &= ~TMP_ADDR;
290 else
291 deref = 0;
292 if (tmp->flags & LOC_NUM) {
293 num_cast(tmp, bt);
294 tmp->bt = TMPBT(bt);
295 num_reg(dst, tmp->bt, tmp->addr);
296 tmp->addr = dst;
297 regs[dst] = tmp;
298 tmp->flags = LOC_NEW(tmp->flags, LOC_REG);
300 if (tmp->flags & LOC_SYM) {
301 op_rr(MOV_I2X, 0, dst, 4);
302 if (!nogen)
303 out_rela(tmp->addr, codeaddr(), 0);
304 oi(tmp->off, 4);
305 tmp->addr = dst;
306 regs[dst] = tmp;
307 tmp->flags = LOC_NEW(tmp->flags, LOC_REG);
309 if (tmp->flags & LOC_REG) {
310 if (deref)
311 mov_m2r(dst, tmp->addr, 0, tmp->bt, bt);
312 else
313 mov_r2r(tmp->addr, dst, TMP_BT(tmp),
314 tmp->flags & TMP_ADDR ? LONGSZ : bt);
315 regs[tmp->addr] = NULL;
317 if (tmp->flags & LOC_LOCAL) {
318 if (deref)
319 mov_m2r(dst, R_EBP, tmp->addr, tmp->bt, bt);
320 else
321 op_rm(LEA_M2R, dst, R_EBP, tmp->addr, LONGSZ);
323 if (tmp->flags & LOC_MEM) {
324 int nbt = deref ? LONGSZ : TMP_BT(tmp);
325 mov_m2r(dst, R_EBP, tmp->addr, nbt, nbt);
326 if (deref)
327 mov_m2r(dst, dst, 0, tmp->bt, bt);
329 tmp->addr = dst;
330 tmp->bt = tmp->flags & TMP_ADDR ? bt : TMPBT(bt);
331 regs[dst] = tmp;
332 tmp->flags = LOC_NEW(tmp->flags, LOC_REG);
335 static void reg_free(int reg)
337 int i;
338 if (!regs[reg])
339 return;
340 for (i = 0; i < ARRAY_SIZE(tmpregs); i++)
341 if (!regs[tmpregs[i]]) {
342 tmp_reg(regs[reg], tmpregs[i], regs[reg]->bt, 0);
343 return;
345 tmp_mem(regs[reg]);
348 static void reg_for(int reg, struct tmp *t)
350 if (regs[reg] && regs[reg] != t)
351 reg_free(reg);
354 static void tmp_mv(struct tmp *t, int reg)
356 reg_for(reg, t);
357 tmp_reg(t, reg, t->bt, 0);
360 static void tmp_to(struct tmp *t, int reg, int bt)
362 reg_for(reg, t);
363 tmp_reg(t, reg, bt ? bt : t->bt, 1);
366 static void tmp_drop(int n)
368 int i;
369 for (i = ntmp - n; i < ntmp; i++)
370 if (tmps[i].flags & LOC_REG)
371 regs[tmps[i].addr] = NULL;
372 cmp_last = -1;
373 ntmp -= n;
376 static int tmp_pop(int reg, int bt)
378 struct tmp *t = TMP(0);
379 tmp_to(t, reg, bt);
380 tmp_drop(1);
381 return t->bt;
384 static struct tmp *tmp_new(void)
386 cmp_last = -1;
387 return &tmps[ntmp++];
390 static void tmp_push(int reg, unsigned bt)
392 struct tmp *t = tmp_new();
393 t->addr = reg;
394 t->bt = bt;
395 t->flags = LOC_REG;
396 regs[reg] = t;
399 void o_local(long addr, unsigned bt)
401 struct tmp *t = tmp_new();
402 t->addr = -addr;
403 t->bt = bt;
404 t->flags = LOC_LOCAL | TMP_ADDR;
407 void o_num(long num, unsigned bt)
409 struct tmp *t = tmp_new();
410 t->addr = num;
411 t->bt = bt;
412 t->flags = LOC_NUM;
415 void o_symaddr(long addr, unsigned bt)
417 struct tmp *t = tmp_new();
418 t->bt = bt;
419 t->addr = addr;
420 t->flags = LOC_SYM | TMP_ADDR;
421 t->off = 0;
424 void o_tmpdrop(int n)
426 if (n == -1 || n > ntmp)
427 n = ntmp;
428 tmp_drop(n);
429 if (!ntmp) {
430 if (tmpsp != -1)
431 sp = tmpsp;
432 tmpsp = -1;
436 #define FORK_REG R_EAX
438 /* make sure tmps remain intact after a conditional expression */
439 void o_fork(void)
441 int i;
442 for (i = 0; i < ntmp - 1; i++)
443 tmp_mem(&tmps[i]);
446 void o_forkpush(void)
448 tmp_pop(R_EAX, 0);
451 void o_forkjoin(void)
453 tmp_push(FORK_REG, 0);
456 void o_tmpswap(void)
458 struct tmp *t1 = TMP(0);
459 struct tmp *t2 = TMP(1);
460 struct tmp t;
461 memcpy(&t, t1, sizeof(t));
462 memcpy(t1, t2, sizeof(t));
463 memcpy(t2, &t, sizeof(t));
464 if (t1->flags & LOC_REG)
465 regs[t1->addr] = t1;
466 if (t2->flags & LOC_REG)
467 regs[t2->addr] = t2;
470 static int reg_get(int mask)
472 int i;
473 for (i = 0; i < ARRAY_SIZE(tmpregs); i++)
474 if ((1 << tmpregs[i]) & mask && !regs[tmpregs[i]])
475 return tmpregs[i];
476 for (i = 0; i < ARRAY_SIZE(tmpregs); i++)
477 if ((1 << tmpregs[i]) & mask) {
478 reg_free(tmpregs[i]);
479 return tmpregs[i];
481 return 0;
484 void tmp_copy(struct tmp *t1)
486 struct tmp *t2 = tmp_new();
487 memcpy(t2, t1, sizeof(*t1));
488 if (!(t1->flags & (LOC_REG | LOC_MEM)))
489 return;
490 if (t1->flags & LOC_MEM) {
491 tmp_reg(t2, reg_get(~0), t2->bt, 0);
492 } else if (t1->flags & LOC_REG) {
493 t2->addr = reg_get(~(1 << t1->addr));
494 op_rr(MOV_R2X, t1->addr, t2->addr, TMPBT(TMP_BT(t1)));
495 regs[t2->addr] = t2;
499 void o_tmpcopy(void)
501 tmp_copy(TMP(0));
504 void o_cast(unsigned bt)
506 struct tmp *t = TMP(0);
507 int reg;
508 if (t->bt == bt)
509 return;
510 if (t->flags & LOC_NUM) {
511 num_cast(t, bt);
512 return;
514 reg = BT_SZ(bt) > 1 ? TMP_REG(t) : TMP_BYTEREG(t);
515 tmp_to(t, reg, bt);
518 long o_func_beg(char *name, int global)
520 long addr = out_func_beg(name, global);
521 cur = buf;
522 os("\x55", 1); /* push %rbp */
523 os("\x89\xe5", 2); /* mov %rsp, %rbp */
524 os("\x53\x56\x57", 3); /* push ebx; push esi; push edi */
525 sp = 0;
526 maxsp = 0;
527 ntmp = 0;
528 tmpsp = -1;
529 nret = 0;
530 cmp_last = -1;
531 memset(regs, 0, sizeof(regs));
532 os("\x81\xec", 2); /* sub $xxx, %rsp */
533 spsub_addr = codeaddr();
534 oi(0, 4);
535 return addr;
538 void o_deref(unsigned bt)
540 struct tmp *t = TMP(0);
541 if (t->flags & TMP_ADDR)
542 tmp_to(t, TMP_REG(t), t->bt);
543 t->bt = bt;
544 t->flags |= TMP_ADDR;
547 void o_load(void)
549 struct tmp *t = TMP(0);
550 tmp_to(t, TMP_REG(t), t->bt);
553 static unsigned bt_op(unsigned bt1, unsigned bt2)
555 unsigned s1 = BT_SZ(bt1);
556 unsigned s2 = BT_SZ(bt2);
557 unsigned bt = (bt1 | bt2) & BT_SIGNED | (s1 > s2 ? s1 : s2);
558 return TMPBT(bt);
561 #define TMP_NUM(t) ((t)->flags & LOC_NUM && !((t)->flags & TMP_ADDR))
562 #define TMP_SYM(t) ((t)->flags & LOC_SYM && (t)->flags & TMP_ADDR)
563 #define TMP_LOCAL(t) ((t)->flags & LOC_LOCAL && (t)->flags & TMP_ADDR)
564 #define LOCAL_PTR(t) ((t)->flags & LOC_LOCAL && !((t)->flags & TMP_ADDR))
565 #define SYM_PTR(t) ((t)->flags & LOC_SYM && !((t)->flags & TMP_ADDR))
567 int o_popnum(long *c)
569 struct tmp *t = TMP(0);
570 if (!TMP_NUM(t))
571 return 1;
572 *c = t->addr;
573 tmp_drop(1);
574 return 0;
577 static int c_op(long (*cop)(long a, unsigned bt), unsigned bt)
579 struct tmp *t1 = TMP(0);
580 long ret;
581 if (!TMP_NUM(t1))
582 return 1;
583 if (!bt)
584 bt = t1->bt;
585 ret = cop(t1->addr, bt);
586 tmp_drop(1);
587 o_num(ret, bt);
588 return 0;
591 static void shx(int uop, int sop)
593 struct tmp *t1 = TMP(0);
594 struct tmp *t2 = TMP(1);
595 int r2 = TMP_REG2(t2, R_ECX);
596 int bt = t2->bt;
597 tmp_to(t1, R_ECX, 0);
598 tmp_to(t2, r2, 0);
599 tmp_drop(1);
600 op_rr(SHX_REG, bt & BT_SIGNED ? sop : uop, r2, TMPBT(bt));
603 #define CQO_REG 0x99
605 static int mulop(int uop, int sop, int reg)
607 struct tmp *t1 = TMP(0);
608 struct tmp *t2 = TMP(1);
609 int bt = bt_op(t1->bt, t2->bt);
610 if (t1->flags & LOC_REG && t1->addr != R_EAX && t1->addr != R_EDX)
611 reg = t1->addr;
612 tmp_to(t1, reg, bt);
613 tmp_to(t2, R_EAX, bt);
614 if (reg != R_EDX) {
615 reg_free(R_EDX);
616 if (bt & BT_SIGNED)
617 op_x(CQO_REG, R_EAX, R_EDX, bt);
618 else
619 op_rr(XOR_R2X, R_EDX, R_EDX, bt);
621 tmp_drop(2);
622 op_rr(MUL_A2X, bt & BT_SIGNED ? sop : uop, reg, TMPBT(t2->bt));
623 return bt;
626 void o_addr(void)
628 tmps[ntmp - 1].flags &= ~TMP_ADDR;
629 tmps[ntmp - 1].bt = LONGSZ;
632 void o_ret(unsigned bt)
634 if (bt)
635 tmp_pop(R_EAX, bt);
636 else
637 os("\x31\xc0", 2); /* xor %eax, %eax */
638 ret[nret++] = o_jmp(0);
641 static void inc(int op)
643 struct tmp *t = TMP(0);
644 int reg;
645 int off;
646 if (t->flags & LOC_LOCAL) {
647 reg = R_EBP;
648 off = t->addr;
649 } else {
650 reg = TMP_REG(t);
651 off = 0;
652 tmp_mv(t, reg);
654 op_rm(INC_X, op, reg, off, t->bt);
657 void o_lnot(void)
659 if (cmp_last == codeaddr()) {
660 buf[cmp_setl + 1] ^= 0x01;
661 } else {
662 o_num(0, 4 | BT_SIGNED);
663 o_bop(O_EQ);
667 void o_neg(int id)
669 struct tmp *t = TMP(0);
670 int reg;
671 unsigned bt = TMPBT(t->bt);
672 reg = TMP_REG(t);
673 tmp_to(t, reg, bt);
674 op_rr(NOT_REG, id, reg, bt);
677 void o_func_end(void)
679 int i;
680 for (i = 0; i < nret; i++)
681 o_filljmp(ret[i]);
682 os("\x5f\x5e\x5b", 3); /* pop edi; pop esi; pop ebx */
683 os("\xc9\xc3", 2); /* leave; ret; */
684 putint(buf + spsub_addr, (maxsp + 7) & ~0x07, 4);
685 out_func_end(buf, cur - buf);
688 long o_mklocal(int size)
690 return sp_push((size + 7) & ~0x07);
693 void o_rmlocal(long addr, int sz)
695 sp = addr - sz;
698 long o_arg(int i, unsigned bt)
700 return -LONGSZ * (i + 2);
703 void o_assign(unsigned bt)
705 struct tmp *t1 = TMP(0);
706 struct tmp *t2 = TMP(1);
707 int r1 = BT_SZ(bt) > 1 ? TMP_REG(t1) : TMP_BYTEREG(t1);
708 int reg;
709 int off;
710 tmp_to(t1, r1, TMPBT(bt));
711 if (t2->flags & LOC_LOCAL) {
712 reg = R_EBP;
713 off = t2->addr;
714 } else {
715 reg = TMP_REG2(t2, r1);
716 off = 0;
717 tmp_mv(t2, reg);
719 tmp_drop(2);
720 op_rm(MOV_R2X, r1, reg, off, bt);
721 tmp_push(r1, bt);
724 static long cu(int op, long i)
726 switch (op) {
727 case O_NEG:
728 return -i;
729 case O_NOT:
730 return ~i;
731 case O_LNOT:
732 return !i;
736 static int c_uop(int op)
738 struct tmp *t1 = TMP(0);
739 if (!TMP_NUM(t1))
740 return 1;
741 tmp_drop(1);
742 o_num(cu(op, t1->addr), t1->bt);
743 return 0;
746 static long cb(int op, long a, long b, int *bt, int bt1, int bt2)
748 *bt = bt_op(bt1, bt2);
749 switch (op) {
750 case O_ADD:
751 return a + b;
752 case O_SUB:
753 return a - b;
754 case O_AND:
755 return a & b;
756 case O_OR:
757 return a | b;
758 case O_XOR:
759 return a ^ b;
760 case O_MUL:
761 return a * b;
762 case O_DIV:
763 return a / b;
764 case O_MOD:
765 return a % b;
766 case O_SHL:
767 *bt = bt1;
768 return a << b;
769 case O_SHR:
770 *bt = bt1;
771 if (bt1 & BT_SIGNED)
772 return a >> b;
773 else
774 return (unsigned long) a >> b;
775 case O_LT:
776 *bt = 4;
777 return a < b;
778 case O_GT:
779 *bt = 4;
780 return a > b;
781 case O_LE:
782 *bt = 4;
783 return a <= b;
784 case O_GE:
785 *bt = 4;
786 return a >= b;
787 case O_EQ:
788 *bt = 4;
789 return a == b;
790 case O_NEQ:
791 *bt = 4;
792 return a != b;
796 static int c_bop(int op)
798 struct tmp *t1 = TMP(0);
799 struct tmp *t2 = TMP(1);
800 int locals = LOCAL_PTR(t1) + LOCAL_PTR(t2);
801 int syms = SYM_PTR(t1) + SYM_PTR(t2);
802 int nums = TMP_NUM(t1) + TMP_NUM(t2);
803 int bt;
804 if (syms == 2 || syms && locals || syms + nums + locals != 2)
805 return 1;
806 if (!locals)
807 bt = syms ? LONGSZ : bt_op(t1->bt, t2->bt);
808 if (locals == 1)
809 bt = LONGSZ;
810 if (locals == 2)
811 bt = 4 | BT_SIGNED;
812 if (syms) {
813 long o1 = SYM_PTR(t1) ? t1->off : t1->addr;
814 long o2 = SYM_PTR(t2) ? t2->off : t2->addr;
815 long ret = cb(op, o2, o1, &bt, t2->bt, t1->bt);
816 if (!SYM_PTR(t2))
817 o_tmpswap();
818 t2->off = ret;
819 tmp_drop(1);
820 } else {
821 long ret = cb(op, t2->addr, t1->addr, &bt, t2->bt, t1->bt);
822 tmp_drop(2);
823 if (locals == 1) {
824 o_local(-ret, bt);
825 o_addr();
826 } else {
827 o_num(ret, bt);
830 return 0;
833 void o_uop(int op)
835 if (!c_uop(op))
836 return;
837 switch (op) {
838 case O_NEG:
839 case O_NOT:
840 o_neg(op == O_NEG ? 3 : 2);
841 break;
842 case O_LNOT:
843 o_lnot();
844 break;
845 case O_INC:
846 case O_DEC:
847 inc(op == O_DEC);
848 break;
852 static int binop(int op, int *reg)
854 struct tmp *t1 = TMP(0);
855 struct tmp *t2 = TMP(1);
856 int r1, r2;
857 unsigned bt = bt_op(t1->bt, t2->bt);
858 r1 = TMP_REG(t1);
859 r2 = TMP_REG2(t2, r1);
860 tmp_pop(r1, bt);
861 tmp_pop(r2, bt);
862 op_rr(op, r2, r1, bt);
863 *reg = r2;
864 return bt;
867 static void bin_add(int op)
869 /* opcode for O_ADD, O_SUB, O_AND, O_OR, O_XOR */
870 static int rx[] = {0x03, 0x2b, 0x23, 0x0b, 0x33};
871 int reg;
872 int bt = binop(rx[op & 0x0f], &reg);
873 tmp_push(reg, bt);
876 static void bin_shx(int op)
878 if ((op & 0xff) == O_SHL)
879 shx(4, 4);
880 else
881 shx(5, 7);
884 static void bin_mul(int op)
886 if ((op & 0xff) == O_MUL)
887 tmp_push(R_EAX, mulop(4, 5, R_EDX));
888 if ((op & 0xff) == O_DIV)
889 tmp_push(R_EAX, mulop(6, 7, R_ECX));
890 if ((op & 0xff) == O_MOD)
891 tmp_push(R_EDX, mulop(6, 7, R_ECX));
894 static void o_cmp(int uop, int sop)
896 struct tmp *t1 = TMP(0);
897 struct tmp *t2 = TMP(1);
898 char set[] = "\x0f\x00\xc0";
899 int reg;
900 int bt;
901 if (regs[R_EAX] && regs[R_EAX] != t1 && regs[R_EAX] != t2)
902 reg_free(R_EAX);
903 bt = binop(CMP_R2X, &reg);
904 set[1] = bt & BT_SIGNED ? sop : uop;
905 cmp_setl = codeaddr();
906 os(set, 3); /* setl %al */
907 os("\x0f\xb6\xc0", 3); /* movzbl %al, %eax */
908 tmp_push(R_EAX, 4 | BT_SIGNED);
909 cmp_last = codeaddr();
912 static void bin_cmp(int op)
914 switch (op & 0xff) {
915 case O_LT:
916 o_cmp(0x92, 0x9c);
917 break;
918 case O_GT:
919 o_cmp(0x97, 0x9f);
920 break;
921 case O_LE:
922 o_cmp(0x96, 0x9e);
923 break;
924 case O_GE:
925 o_cmp(0x93, 0x9d);
926 break;
927 case O_EQ:
928 o_cmp(0x94, 0x94);
929 break;
930 case O_NEQ:
931 o_cmp(0x95, 0x95);
932 break;
936 static void o_bopset(int op)
938 tmp_copy(TMP(1));
939 o_tmpswap();
940 o_bop(op & ~O_SET);
941 o_assign(TMP(1)->bt);
944 void o_bop(int op)
946 if (!(op & O_SET) && !c_bop(op))
947 return;
948 if (op & O_SET) {
949 o_bopset(op);
950 return;
952 if ((op & 0xf0) == 0x00)
953 bin_add(op);
954 if ((op & 0xf0) == 0x10)
955 bin_shx(op);
956 if ((op & 0xf0) == 0x20)
957 bin_mul(op);
958 if ((op & 0xf0) == 0x30)
959 bin_cmp(op);
962 void o_memcpy(int sz)
964 struct tmp *t0 = TMP(-1);
965 struct tmp *t1 = TMP(0);
966 struct tmp *t2 = TMP(1);
967 o_num(sz, 4);
968 tmp_to(t0, R_ECX, 0);
969 tmp_mv(t1, R_ESI);
970 tmp_mv(t2, R_EDI);
971 os("\xf3\xa4", 2); /* rep movs */
972 tmp_drop(2);
975 void o_memset(int x, int sz)
977 struct tmp *t0 = TMP(-2);
978 struct tmp *t1 = TMP(-1);
979 struct tmp *t2 = TMP(0);
980 o_num(sz, 4);
981 o_num(x, 4);
982 tmp_to(t0, R_EAX, 0);
983 tmp_to(t1, R_ECX, 0);
984 tmp_mv(t2, R_EDI);
985 os("\xf3\xaa", 2); /* rep stosb */
986 tmp_drop(2);
989 long o_mklabel(void)
991 return codeaddr();
994 static long jx(int x, long addr)
996 char op[2] = {0x0f};
997 op[1] = x;
998 os(op, 2); /* jx $addr */
999 oi(addr - codeaddr() - 4, 4);
1000 return codeaddr() - 4;
1003 static long jxtest(int x, long addr)
1005 int bt = tmp_pop(R_EAX, 0);
1006 op_rr(TEST_R2R, R_EAX, R_EAX, bt);
1007 return jx(x, addr);
1010 static long jxcmp(long addr, int inv)
1012 int x;
1013 if (codeaddr() != cmp_last)
1014 return -1;
1015 tmp_drop(1);
1016 cur = buf + cmp_setl;
1017 x = (unsigned char) buf[cmp_setl + 1];
1018 return jx((inv ? x : x ^ 0x01) & ~0x10, addr);
1021 long o_jz(long addr)
1023 long ret = jxcmp(addr, 0);
1024 return ret != -1 ? ret : jxtest(0x84, addr);
1027 long o_jnz(long addr)
1029 long ret = jxcmp(addr, 1);
1030 return ret != -1 ? ret : jxtest(0x85, addr);
1033 long o_jmp(long addr)
1035 os("\xe9", 1); /* jmp $addr */
1036 oi(addr - codeaddr() - 4, 4);
1037 return codeaddr() - 4;
1040 void o_filljmp2(long addr, long jmpdst)
1042 putint(buf + addr, jmpdst - addr - 4, 4);
1045 void o_filljmp(long addr)
1047 o_filljmp2(addr, codeaddr());
1050 void o_call(int argc, unsigned *bt, unsigned ret_bt)
1052 struct tmp *t;
1053 int i;
1054 for (i = 0; i < ARRAY_SIZE(tmpregs); i++)
1055 if (regs[tmpregs[i]] && regs[tmpregs[i]] - tmps < ntmp - argc)
1056 tmp_mem(regs[tmpregs[i]]);
1057 sp_push(LONGSZ * argc);
1058 for (i = argc - 1; i >= 0; --i) {
1059 int reg = TMP_REG(TMP(0));
1060 tmp_pop(reg, TMPBT(bt[i]));
1061 op_rm(MOV_R2X, reg, R_ESP, i * LONGSZ, TMPBT(bt[i]));
1063 t = TMP(0);
1064 if (t->flags & LOC_SYM) {
1065 os("\x31\xc0", 2); /* xor %eax, %eax */
1066 os("\xe8", 1); /* call $x */
1067 if (!nogen)
1068 out_rela(t->addr, codeaddr(), 1);
1069 oi(-4 + t->off, 4);
1070 tmp_drop(1);
1071 } else {
1072 tmp_mv(TMP(0), R_EAX);
1073 tmp_drop(1);
1074 op_rr(CALL_REG, 2, R_EAX, 4);
1076 if (ret_bt)
1077 tmp_push(R_EAX, ret_bt);
1080 int o_nogen(void)
1082 return nogen++;
1085 void o_dogen(void)
1087 nogen = 0;
1090 void o_datset(long addr, int off, unsigned bt)
1092 struct tmp *t = TMP(0);
1093 if (t->flags & LOC_NUM && !(t->flags & TMP_ADDR)) {
1094 num_cast(t, bt);
1095 out_datcpy(addr, off, (void *) &t->addr, BT_SZ(bt));
1097 if (t->flags & LOC_SYM && !(t->flags & TMP_ADDR)) {
1098 out_datrela(t->addr, addr, off);
1099 out_datcpy(addr, off, (void *) &t->off, BT_SZ(bt));
1101 tmp_drop(1);