cpp: don't remove non-macro number signs
[neatcc/cc.git] / gen.c
blobff035f5e7af4d9b6711f4209a5a4c84a7f4c69f6
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 OP_XR(op) (op | 03)
25 #define OP_B(op) (op & ~01)
27 #define I_MOV 0x89
28 #define I_MOVI 0xc7
29 #define I_MOVIR 0xb8
30 #define I_MOVR 0x8b
31 #define I_SHX 0xd3
32 #define I_CMP 0x3b
33 #define I_LEA 0x8d
34 #define I_NOT 0xf7
35 #define I_CALL 0xff
36 #define I_MUL 0xf7
37 #define I_XOR 0x33
38 #define I_TEST 0x85
39 #define I_INC 0xff
41 #define MIN(a, b) ((a) < (b) ? (a) : (b))
43 #define TMP_BT(t) ((t)->flags & TMP_ADDR ? LONGSZ : (t)->bt)
44 #define TMP_REG(t) ((t)->flags & LOC_REG ? (t)->addr : reg_get(~0))
45 #define TMP_REG2(t, r) ((t)->flags & LOC_REG && (t)->addr != r ? \
46 (t)->addr : reg_get(~(1 << r)))
47 #define TMPBT(bt) (BT_SZ(bt) >= 4 ? (bt) : (bt) & BT_SIGNED | 4)
49 #define R_BYTEREGS (1 << R_EAX | 1 << R_EDX | 1 << R_ECX)
50 #define TMP_BYTEREG(t) ((t)->flags & LOC_REG && \
51 (1 << (t)->addr) & R_BYTEREGS ? \
52 (t)->addr : reg_get(R_BYTEREGS))
54 static char buf[SECSIZE];
55 static char *cur;
56 static int nogen;
57 static long sp;
58 static long spsub_addr;
59 static long maxsp;
61 #define TMP(i) (&tmps[ntmp - 1 - (i)])
63 static struct tmp {
64 long addr;
65 long off; /* offset from a symbol or a local */
66 unsigned flags;
67 unsigned bt;
68 } tmps[MAXTMP];
69 static int ntmp;
71 static int tmpsp;
73 static struct tmp *regs[NREGS];
74 static int tmpregs[] = {R_EAX, R_ESI, R_EDI, R_EBX, R_EDX, R_ECX};
76 #define MAXRET (1 << 8)
78 static long ret[MAXRET];
79 static int nret;
81 static long cmp_last;
82 static long cmp_setl;
84 static void putint(char *s, long n, int l)
86 while (l--) {
87 *s++ = n;
88 n >>= 8;
92 static void os(char *s, int n)
94 if (nogen)
95 return;
96 while (n--)
97 *cur++ = *s++;
100 static void oi(long n, int l)
102 if (nogen)
103 return;
104 while (l--) {
105 *cur++ = n;
106 n >>= 8;
110 static long codeaddr(void)
112 return cur - buf;
115 #define OP2(o2, o1) (0x010000 | ((o2) << 8) | (o1))
116 #define O2(op) (((op) >> 8) & 0xff)
117 #define O1(op) ((op) & 0xff)
118 #define MODRM(m, r1, r2) ((m) << 6 | (r1) << 3 | (r2))
120 static void op_x(int op, int r1, int r2, int bt)
122 int sz = BT_SZ(bt);
123 if (sz == 2)
124 oi(0x66, 1);
125 if (op & 0x10000)
126 oi(O2(op), 1);
127 oi(sz == 1 ? O1(op) & ~0x1 : O1(op), 1);
130 #define op_mr op_rm
132 /* op_*(): r=reg, m=mem, i=imm, s=sym */
133 static void op_rm(int op, int src, int base, int off, int bt)
135 int dis = off == (char) off ? 1 : 4;
136 int mod = dis == 4 ? 2 : 1;
137 if (!off && base != R_EBP)
138 mod = 0;
139 op_x(op, src, base, bt);
140 oi(MODRM(mod, src & 0x07, base & 0x07), 1);
141 if (base == R_ESP)
142 oi(0x24, 1);
143 if (mod)
144 oi(off, dis);
147 static void op_rr(int op, int src, int dst, int bt)
149 op_x(op, src, dst, bt);
150 oi(MODRM(3, src & 0x07, dst & 0x07), 1);
153 static void op_rs(int op, int src, long addr, int off, int bt)
155 op_x(op, src, 0, bt);
156 oi(MODRM(0, src & 0x07, 5), 1);
157 if (!nogen)
158 out_rela(addr, codeaddr(), 0);
159 oi(off, 4);
162 static void op_ri(int op, int o3, int src, long num, int bt)
164 op_x(op, src, 0, bt);
165 oi(MODRM(3, o3, src & 0x07), 1);
166 oi(num, MIN(4, BT_SZ(bt)));
169 static void op_sr(int op, int src, long addr, int off, int bt)
171 op_x(op, src, 0, bt);
172 oi(MODRM(0, src & 0x07, 5), 1);
173 if (!nogen)
174 out_rela(addr, codeaddr(), 1);
175 oi(off - 4, 4);
178 static void op_si(int op, int o3, long addr, int off, long num, int bt)
180 int sz = MIN(4, BT_SZ(bt));
181 op_x(op, 0, 0, bt);
182 oi(MODRM(0, o3, 5), 1);
183 if (!nogen)
184 out_rela(addr, codeaddr(), 1);
185 oi(off - 4 - sz, 4);
186 oi(num, sz);
189 static void op_mi(int op, int o3, int base, int off, long num, int bt)
191 int dis = off == (char) off ? 1 : 4;
192 int mod = dis == 4 ? 2 : 1;
193 if (!off && base != R_EBP)
194 mod = 0;
195 op_x(op, 0, base, bt);
196 oi(MODRM(mod, 0, base), 1);
197 if (mod)
198 oi(off, dis);
199 oi(num, MIN(4, BT_SZ(bt)));
202 static long sp_push(int size)
204 sp += size;
205 if (sp > maxsp)
206 maxsp = sp;
207 return sp;
210 #define LOC_NEW(f, l) (((f) & ~LOC_MASK) | (l))
212 static void tmp_mem(struct tmp *tmp)
214 int src = tmp->addr;
215 if (!(tmp->flags & LOC_REG))
216 return;
217 if (tmpsp == -1)
218 tmpsp = sp;
219 tmp->addr = -sp_push(LONGSZ);
220 op_rm(I_MOV, src, R_EBP, tmp->addr, TMPBT(TMP_BT(tmp)));
221 regs[src] = NULL;
222 tmp->flags = LOC_NEW(tmp->flags, LOC_MEM);
225 static int movxx_x2r(int bt)
227 int o2;
228 if (BT_SZ(bt) == 1)
229 o2 = bt & BT_SIGNED ? 0xbe : 0xb6;
230 else
231 o2 = bt & BT_SIGNED ? 0xbf : 0xb7;
232 return OP2(0x0f, o2);
235 #define MOVSXD 0x63
237 static void mov_r2r(int r1, int r2, unsigned bt1, unsigned bt2)
239 int s1 = bt1 & BT_SIGNED;
240 int s2 = bt2 & BT_SIGNED;
241 int sz1 = BT_SZ(bt1);
242 int sz2 = BT_SZ(bt2);
243 if (sz2 < 4 && (sz1 > sz2 || s1 != s2)) {
244 op_rr(movxx_x2r(bt2), r1, r2, 4);
245 return;
247 if (sz1 == 4 && sz2 == 8 && s1) {
248 op_rr(MOVSXD, r2, r1, sz2);
249 return;
251 if (r1 != r2 || sz1 > sz2)
252 op_rr(I_MOV, r1, r2, TMPBT(bt2));
255 static void mov_m2r(int dst, int base, int off, int bt1, int bt2)
257 if (BT_SZ(bt1) < 4) {
258 op_rm(movxx_x2r(bt1), dst, base, off,
259 bt1 & BT_SIGNED && BT_SZ(bt2) == 8 ? 8 : 4);
260 mov_r2r(dst, dst, bt1, bt2);
261 } else {
262 op_rm(I_MOVR, dst, base, off, bt1);
263 mov_r2r(dst, dst, bt1, bt2);
267 static void num_cast(struct tmp *t, unsigned bt)
269 if (!(bt & BT_SIGNED) && BT_SZ(bt) != LONGSZ)
270 t->addr &= ((1l << (long) (BT_SZ(bt) * 8)) - 1);
271 if (bt & BT_SIGNED && BT_SZ(bt) != LONGSZ &&
272 t->addr > (1l << (BT_SZ(bt) * 8 - 1)))
273 t->addr = -((1l << (BT_SZ(bt) * 8)) - t->addr);
274 t->bt = bt;
277 static void num_reg(int reg, unsigned bt, long num)
279 int op = I_MOVIR + (reg & 7);
280 op_x(op, 0, reg, bt);
281 oi(num, BT_SZ(bt));
284 static void tmp_reg(struct tmp *tmp, int dst, unsigned bt, int deref)
286 if (deref && tmp->flags & TMP_ADDR)
287 tmp->flags &= ~TMP_ADDR;
288 else
289 deref = 0;
290 if (tmp->flags & LOC_NUM) {
291 num_cast(tmp, bt);
292 tmp->bt = TMPBT(bt);
293 num_reg(dst, tmp->bt, tmp->addr);
294 tmp->addr = dst;
295 regs[dst] = tmp;
296 tmp->flags = LOC_NEW(tmp->flags, LOC_REG);
298 if (tmp->flags & LOC_SYM) {
299 op_rr(I_MOVI, 0, dst, 4);
300 if (!nogen)
301 out_rela(tmp->addr, codeaddr(), 0);
302 oi(tmp->off, 4);
303 tmp->addr = dst;
304 regs[dst] = tmp;
305 tmp->flags = LOC_NEW(tmp->flags, LOC_REG);
307 if (tmp->flags & LOC_REG) {
308 if (deref)
309 mov_m2r(dst, tmp->addr, 0, tmp->bt, bt);
310 else
311 mov_r2r(tmp->addr, dst, TMP_BT(tmp),
312 tmp->flags & TMP_ADDR ? LONGSZ : bt);
313 regs[tmp->addr] = NULL;
315 if (tmp->flags & LOC_LOCAL) {
316 if (deref)
317 mov_m2r(dst, R_EBP, tmp->addr + tmp->off, tmp->bt, bt);
318 else
319 op_rm(I_LEA, dst, R_EBP, tmp->addr + tmp->off, LONGSZ);
321 if (tmp->flags & LOC_MEM) {
322 int nbt = deref ? LONGSZ : TMP_BT(tmp);
323 mov_m2r(dst, R_EBP, tmp->addr, nbt, nbt);
324 if (deref)
325 mov_m2r(dst, dst, 0, tmp->bt, bt);
327 tmp->addr = dst;
328 tmp->bt = tmp->flags & TMP_ADDR ? bt : TMPBT(bt);
329 regs[dst] = tmp;
330 tmp->flags = LOC_NEW(tmp->flags, LOC_REG);
333 static void reg_free(int reg)
335 int i;
336 if (!regs[reg])
337 return;
338 for (i = 0; i < ARRAY_SIZE(tmpregs); i++)
339 if (!regs[tmpregs[i]]) {
340 tmp_reg(regs[reg], tmpregs[i], regs[reg]->bt, 0);
341 return;
343 tmp_mem(regs[reg]);
346 static void reg_for(int reg, struct tmp *t)
348 if (regs[reg] && regs[reg] != t)
349 reg_free(reg);
352 static void tmp_mv(struct tmp *t, int reg)
354 reg_for(reg, t);
355 tmp_reg(t, reg, t->bt, 0);
358 static void tmp_to(struct tmp *t, int reg, int bt)
360 reg_for(reg, t);
361 tmp_reg(t, reg, bt ? bt : t->bt, 1);
364 static void tmp_drop(int n)
366 int i;
367 for (i = ntmp - n; i < ntmp; i++)
368 if (tmps[i].flags & LOC_REG)
369 regs[tmps[i].addr] = NULL;
370 cmp_last = -1;
371 ntmp -= n;
374 static int tmp_pop(int reg, int bt)
376 struct tmp *t = TMP(0);
377 tmp_to(t, reg, bt);
378 tmp_drop(1);
379 return t->bt;
382 static struct tmp *tmp_new(void)
384 cmp_last = -1;
385 return &tmps[ntmp++];
388 static void tmp_push(int reg, unsigned bt)
390 struct tmp *t = tmp_new();
391 t->addr = reg;
392 t->bt = bt;
393 t->flags = LOC_REG;
394 regs[reg] = t;
397 void o_local(long addr, unsigned bt)
399 struct tmp *t = tmp_new();
400 t->addr = -addr;
401 t->bt = bt;
402 t->flags = LOC_LOCAL | TMP_ADDR;
403 t->off = 0;
406 void o_num(long num, unsigned bt)
408 struct tmp *t = tmp_new();
409 t->addr = num;
410 t->bt = bt;
411 t->flags = LOC_NUM;
414 void o_symaddr(long addr, unsigned bt)
416 struct tmp *t = tmp_new();
417 t->bt = bt;
418 t->addr = addr;
419 t->flags = LOC_SYM | TMP_ADDR;
420 t->off = 0;
423 void o_tmpdrop(int n)
425 if (n == -1 || n > ntmp)
426 n = ntmp;
427 tmp_drop(n);
428 if (!ntmp) {
429 if (tmpsp != -1)
430 sp = tmpsp;
431 tmpsp = -1;
435 #define FORK_REG R_EAX
437 /* make sure tmps remain intact after a conditional expression */
438 void o_fork(void)
440 int i;
441 for (i = 0; i < ntmp - 1; i++)
442 tmp_mem(&tmps[i]);
445 void o_forkpush(void)
447 tmp_pop(R_EAX, 0);
450 void o_forkjoin(void)
452 tmp_push(FORK_REG, 0);
455 void o_tmpswap(void)
457 struct tmp *t1 = TMP(0);
458 struct tmp *t2 = TMP(1);
459 struct tmp t;
460 memcpy(&t, t1, sizeof(t));
461 memcpy(t1, t2, sizeof(t));
462 memcpy(t2, &t, sizeof(t));
463 if (t1->flags & LOC_REG)
464 regs[t1->addr] = t1;
465 if (t2->flags & LOC_REG)
466 regs[t2->addr] = t2;
469 static int reg_get(int mask)
471 int i;
472 for (i = 0; i < ARRAY_SIZE(tmpregs); i++)
473 if ((1 << tmpregs[i]) & mask && !regs[tmpregs[i]])
474 return tmpregs[i];
475 for (i = 0; i < ARRAY_SIZE(tmpregs); i++)
476 if ((1 << tmpregs[i]) & mask) {
477 reg_free(tmpregs[i]);
478 return tmpregs[i];
480 return 0;
483 void tmp_copy(struct tmp *t1)
485 struct tmp *t2 = tmp_new();
486 memcpy(t2, t1, sizeof(*t1));
487 if (!(t1->flags & (LOC_REG | LOC_MEM)))
488 return;
489 if (t1->flags & LOC_MEM) {
490 tmp_reg(t2, reg_get(~0), t2->bt, 0);
491 } else if (t1->flags & LOC_REG) {
492 t2->addr = reg_get(~(1 << t1->addr));
493 op_rr(I_MOV, t1->addr, t2->addr, TMPBT(TMP_BT(t1)));
494 regs[t2->addr] = t2;
498 void o_tmpcopy(void)
500 tmp_copy(TMP(0));
503 void o_cast(unsigned bt)
505 struct tmp *t = TMP(0);
506 int reg;
507 if (t->bt == bt)
508 return;
509 if (t->flags & LOC_NUM) {
510 num_cast(t, bt);
511 return;
513 reg = BT_SZ(bt) > 1 ? TMP_REG(t) : TMP_BYTEREG(t);
514 tmp_to(t, reg, bt);
517 long o_func_beg(char *name, int global)
519 long addr = out_func_beg(name, global);
520 cur = buf;
521 os("\x55", 1); /* push %rbp */
522 os("\x89\xe5", 2); /* mov %rsp, %rbp */
523 os("\x53\x56\x57", 3); /* push ebx; push esi; push edi */
524 sp = 3 * LONGSZ;
525 maxsp = sp;
526 ntmp = 0;
527 tmpsp = -1;
528 nret = 0;
529 cmp_last = -1;
530 memset(regs, 0, sizeof(regs));
531 os("\x81\xec", 2); /* sub $xxx, %rsp */
532 spsub_addr = codeaddr();
533 oi(0, 4);
534 return addr;
537 void o_deref(unsigned bt)
539 struct tmp *t = TMP(0);
540 if (t->flags & TMP_ADDR)
541 tmp_to(t, TMP_REG(t), t->bt);
542 t->bt = bt;
543 t->flags |= TMP_ADDR;
546 void o_load(void)
548 struct tmp *t = TMP(0);
549 tmp_to(t, TMP_REG(t), t->bt);
552 static unsigned bt_op(unsigned bt1, unsigned bt2)
554 unsigned s1 = BT_SZ(bt1);
555 unsigned s2 = BT_SZ(bt2);
556 unsigned bt = (bt1 | bt2) & BT_SIGNED | (s1 > s2 ? s1 : s2);
557 return TMPBT(bt);
560 #define TMP_NUM(t) ((t)->flags & LOC_NUM && !((t)->flags & TMP_ADDR))
561 #define LOCAL_PTR(t) ((t)->flags & LOC_LOCAL && !((t)->flags & TMP_ADDR))
562 #define SYM_PTR(t) ((t)->flags & LOC_SYM && !((t)->flags & TMP_ADDR))
564 int o_popnum(long *c)
566 struct tmp *t = TMP(0);
567 if (!TMP_NUM(t))
568 return 1;
569 *c = t->addr;
570 tmp_drop(1);
571 return 0;
574 static void shx(int uop, int sop)
576 struct tmp *t1 = TMP(0);
577 struct tmp *t2 = TMP(1);
578 int r2;
579 int bt = t2->bt;
580 tmp_to(t1, R_ECX, 0);
581 r2 = TMP_REG2(t2, R_ECX);
582 tmp_to(t2, r2, 0);
583 tmp_drop(1);
584 op_rr(I_SHX, bt & BT_SIGNED ? sop : uop, r2, TMPBT(bt));
587 #define CQO_REG 0x99
589 static int mulop(int uop, int sop, int reg)
591 struct tmp *t1 = TMP(0);
592 struct tmp *t2 = TMP(1);
593 /* for div and mod, the sign of the second operand don't matter */
594 int bt = uop == 4 ? bt_op(t1->bt, t2->bt) : TMPBT(t2->bt);
595 if (t1->flags & LOC_REG && t1->addr != R_EAX && t1->addr != R_EDX)
596 reg = t1->addr;
597 tmp_to(t1, reg, bt);
598 tmp_to(t2, R_EAX, bt);
599 if (reg != R_EDX) {
600 reg_free(R_EDX);
601 if (bt & BT_SIGNED)
602 op_x(CQO_REG, R_EAX, R_EDX, bt);
603 else
604 op_rr(I_XOR, R_EDX, R_EDX, bt);
606 tmp_drop(2);
607 op_rr(I_MUL, bt & BT_SIGNED ? sop : uop, reg, TMPBT(t2->bt));
608 return bt;
611 void o_addr(void)
613 tmps[ntmp - 1].flags &= ~TMP_ADDR;
614 tmps[ntmp - 1].bt = LONGSZ;
617 void o_ret(unsigned bt)
619 if (bt)
620 tmp_pop(R_EAX, bt);
621 else
622 os("\x31\xc0", 2); /* xor %eax, %eax */
623 ret[nret++] = o_jmp(0);
626 static void inc(int op)
628 struct tmp *t = TMP(0);
629 int reg;
630 int off;
631 if (t->flags & LOC_LOCAL) {
632 reg = R_EBP;
633 off = t->addr + t->off;
634 } else {
635 reg = TMP_REG(t);
636 off = 0;
637 tmp_mv(t, reg);
639 op_rm(I_INC, op, reg, off, t->bt);
642 void o_lnot(void)
644 if (cmp_last == codeaddr()) {
645 buf[cmp_setl + 1] ^= 0x01;
646 } else {
647 o_num(0, 4 | BT_SIGNED);
648 o_bop(O_EQ);
652 void o_neg(int id)
654 struct tmp *t = TMP(0);
655 int reg;
656 unsigned bt = TMPBT(t->bt);
657 reg = TMP_REG(t);
658 tmp_to(t, reg, bt);
659 op_rr(I_NOT, id, reg, bt);
662 #define ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1))
664 void o_func_end(void)
666 int i;
667 for (i = 0; i < nret; i++)
668 o_filljmp(ret[i]);
669 os("\x5f\x5e\x5b", 3); /* pop edi; pop esi; pop ebx */
670 os("\xc9\xc3", 2); /* leave; ret; */
671 putint(buf + spsub_addr, ALIGN(maxsp - 3 * LONGSZ, LONGSZ), 4);
672 out_func_end(buf, cur - buf);
675 long o_mklocal(int size)
677 return sp_push(ALIGN(size, LONGSZ));
680 void o_rmlocal(long addr, int sz)
682 sp = addr - sz;
685 long o_arg(int i, unsigned bt)
687 return -LONGSZ * (i + 2);
690 void o_assign(unsigned bt)
692 struct tmp *t1 = TMP(0);
693 struct tmp *t2 = TMP(1);
694 int r1 = BT_SZ(bt) > 1 ? TMP_REG(t1) : TMP_BYTEREG(t1);
695 int reg;
696 int off;
697 tmp_to(t1, r1, TMPBT(bt));
698 if (t2->flags & LOC_LOCAL) {
699 reg = R_EBP;
700 off = t2->addr + t2->off;
701 } else {
702 reg = TMP_REG2(t2, r1);
703 off = 0;
704 tmp_mv(t2, reg);
706 tmp_drop(2);
707 op_rm(I_MOV, r1, reg, off, bt);
708 tmp_push(r1, bt);
711 static long cu(int op, long i)
713 switch (op) {
714 case O_NEG:
715 return -i;
716 case O_NOT:
717 return ~i;
718 case O_LNOT:
719 return !i;
723 static int c_uop(int op)
725 struct tmp *t1 = TMP(0);
726 if (!TMP_NUM(t1))
727 return 1;
728 tmp_drop(1);
729 o_num(cu(op, t1->addr), t1->bt);
730 return 0;
733 static long cb(int op, long a, long b, int *bt, int bt1, int bt2)
735 *bt = bt_op(bt1, bt2);
736 switch (op) {
737 case O_ADD:
738 return a + b;
739 case O_SUB:
740 return a - b;
741 case O_AND:
742 return a & b;
743 case O_OR:
744 return a | b;
745 case O_XOR:
746 return a ^ b;
747 case O_MUL:
748 return a * b;
749 case O_DIV:
750 return a / b;
751 case O_MOD:
752 return a % b;
753 case O_SHL:
754 *bt = bt1;
755 return a << b;
756 case O_SHR:
757 *bt = bt1;
758 if (bt1 & BT_SIGNED)
759 return a >> b;
760 else
761 return (unsigned long) a >> b;
762 case O_LT:
763 *bt = 4;
764 return a < b;
765 case O_GT:
766 *bt = 4;
767 return a > b;
768 case O_LE:
769 *bt = 4;
770 return a <= b;
771 case O_GE:
772 *bt = 4;
773 return a >= b;
774 case O_EQ:
775 *bt = 4;
776 return a == b;
777 case O_NEQ:
778 *bt = 4;
779 return a != b;
783 static int c_bop(int op)
785 struct tmp *t1 = TMP(0);
786 struct tmp *t2 = TMP(1);
787 int locals = LOCAL_PTR(t1) + LOCAL_PTR(t2);
788 int syms = SYM_PTR(t1) + SYM_PTR(t2);
789 int nums = TMP_NUM(t1) + TMP_NUM(t2);
790 int bt;
791 if (syms + locals == 2 || syms + nums + locals != 2)
792 return 1;
793 if (nums == 1)
794 if (op != O_ADD && op != O_SUB || op == O_SUB && TMP_NUM(t2))
795 return 1;
796 bt = BT_SIGNED | LONGSZ;
797 if (nums == 2)
798 bt = bt_op(t1->bt, t2->bt);
799 if (nums == 1) {
800 long o1 = TMP_NUM(t1) ? t1->addr : t1->off;
801 long o2 = TMP_NUM(t2) ? t2->addr : t2->off;
802 long ret = cb(op, o2, o1, &bt, t2->bt, t1->bt);
803 if (!TMP_NUM(t1))
804 o_tmpswap();
805 t2->off = ret;
806 tmp_drop(1);
807 } else {
808 long ret = cb(op, t2->addr, t1->addr, &bt, t2->bt, t1->bt);
809 tmp_drop(2);
810 o_num(ret, bt);
812 return 0;
815 void o_uop(int op)
817 if (!c_uop(op))
818 return;
819 switch (op) {
820 case O_NEG:
821 case O_NOT:
822 o_neg(op == O_NEG ? 3 : 2);
823 break;
824 case O_LNOT:
825 o_lnot();
826 break;
827 case O_INC:
828 case O_DEC:
829 inc(op == O_DEC);
830 break;
834 static int binop(int op, int *reg)
836 struct tmp *t1 = TMP(0);
837 struct tmp *t2 = TMP(1);
838 int r1, r2;
839 unsigned bt = bt_op(t1->bt, t2->bt);
840 r1 = TMP_REG(t1);
841 tmp_to(t1, r1, bt);
842 r2 = TMP_REG2(t2, r1);
843 tmp_pop(r1, bt);
844 tmp_pop(r2, bt);
845 op_rr(op, r2, r1, bt);
846 *reg = r2;
847 return bt;
850 static void bin_add(int op)
852 /* opcode for O_ADD, O_SUB, O_AND, O_OR, O_XOR */
853 static int rx[] = {0003, 0053, 0043, 0013, 0063};
854 int reg;
855 int bt = binop(rx[op & 0x0f], &reg);
856 tmp_push(reg, bt);
859 static void bin_shx(int op)
861 if ((op & 0xff) == O_SHL)
862 shx(4, 4);
863 else
864 shx(5, 7);
867 static void bin_mul(int op)
869 if ((op & 0xff) == O_MUL)
870 tmp_push(R_EAX, mulop(4, 5, R_EDX));
871 if ((op & 0xff) == O_DIV)
872 tmp_push(R_EAX, mulop(6, 7, R_ECX));
873 if ((op & 0xff) == O_MOD)
874 tmp_push(R_EDX, mulop(6, 7, R_ECX));
877 static void o_cmp(int uop, int sop)
879 struct tmp *t1 = TMP(0);
880 struct tmp *t2 = TMP(1);
881 char set[] = "\x0f\x00\xc0";
882 int reg;
883 int bt;
884 if (regs[R_EAX] && regs[R_EAX] != t1 && regs[R_EAX] != t2)
885 reg_free(R_EAX);
886 bt = binop(I_CMP, &reg);
887 set[1] = bt & BT_SIGNED ? sop : uop;
888 cmp_setl = codeaddr();
889 os(set, 3); /* setl %al */
890 os("\x0f\xb6\xc0", 3); /* movzbl %al, %eax */
891 tmp_push(R_EAX, 4 | BT_SIGNED);
892 cmp_last = codeaddr();
895 static void bin_cmp(int op)
897 switch (op & 0xff) {
898 case O_LT:
899 o_cmp(0x92, 0x9c);
900 break;
901 case O_GT:
902 o_cmp(0x97, 0x9f);
903 break;
904 case O_LE:
905 o_cmp(0x96, 0x9e);
906 break;
907 case O_GE:
908 o_cmp(0x93, 0x9d);
909 break;
910 case O_EQ:
911 o_cmp(0x94, 0x94);
912 break;
913 case O_NEQ:
914 o_cmp(0x95, 0x95);
915 break;
919 static void o_bopset(int op)
921 tmp_copy(TMP(1));
922 o_tmpswap();
923 o_bop(op & ~O_SET);
924 o_assign(TMP(1)->bt);
927 void o_bop(int op)
929 if (!(op & O_SET) && !c_bop(op))
930 return;
931 if (op & O_SET) {
932 o_bopset(op);
933 return;
935 if ((op & 0xf0) == 0x00)
936 bin_add(op);
937 if ((op & 0xf0) == 0x10)
938 bin_shx(op);
939 if ((op & 0xf0) == 0x20)
940 bin_mul(op);
941 if ((op & 0xf0) == 0x30)
942 bin_cmp(op);
945 void o_memcpy(int sz)
947 struct tmp *t0 = TMP(-1);
948 struct tmp *t1 = TMP(0);
949 struct tmp *t2 = TMP(1);
950 o_num(sz, 4);
951 tmp_to(t0, R_ECX, 0);
952 tmp_mv(t1, R_ESI);
953 tmp_mv(t2, R_EDI);
954 os("\xf3\xa4", 2); /* rep movs */
955 tmp_drop(2);
958 void o_memset(int x, int sz)
960 struct tmp *t0 = TMP(-2);
961 struct tmp *t1 = TMP(-1);
962 struct tmp *t2 = TMP(0);
963 o_num(sz, 4);
964 o_num(x, 4);
965 tmp_to(t0, R_EAX, 0);
966 tmp_to(t1, R_ECX, 0);
967 tmp_mv(t2, R_EDI);
968 os("\xf3\xaa", 2); /* rep stosb */
969 tmp_drop(2);
972 long o_mklabel(void)
974 return codeaddr();
977 static long jx(int x, long addr)
979 char op[2] = {0x0f};
980 op[1] = x;
981 os(op, 2); /* jx $addr */
982 oi(addr - codeaddr() - 4, 4);
983 return codeaddr() - 4;
986 static long jxtest(int x, long addr)
988 int bt = tmp_pop(R_EAX, 0);
989 op_rr(I_TEST, R_EAX, R_EAX, bt);
990 return jx(x, addr);
993 static long jxcmp(long addr, int inv)
995 int x;
996 if (codeaddr() != cmp_last)
997 return -1;
998 tmp_drop(1);
999 cur = buf + cmp_setl;
1000 x = (unsigned char) buf[cmp_setl + 1];
1001 return jx((inv ? x : x ^ 0x01) & ~0x10, addr);
1004 long o_jz(long addr)
1006 long ret = jxcmp(addr, 0);
1007 return ret != -1 ? ret : jxtest(0x84, addr);
1010 long o_jnz(long addr)
1012 long ret = jxcmp(addr, 1);
1013 return ret != -1 ? ret : jxtest(0x85, addr);
1016 long o_jmp(long addr)
1018 os("\xe9", 1); /* jmp $addr */
1019 oi(addr - codeaddr() - 4, 4);
1020 return codeaddr() - 4;
1023 void o_filljmp2(long addr, long jmpdst)
1025 putint(buf + addr, jmpdst - addr - 4, 4);
1028 void o_filljmp(long addr)
1030 o_filljmp2(addr, codeaddr());
1033 void o_call(int argc, unsigned *bt, unsigned ret_bt)
1035 struct tmp *t;
1036 int i;
1037 for (i = 0; i < ARRAY_SIZE(tmpregs); i++)
1038 if (regs[tmpregs[i]] && regs[tmpregs[i]] - tmps < ntmp - argc)
1039 tmp_mem(regs[tmpregs[i]]);
1040 sp_push(LONGSZ * argc);
1041 for (i = argc - 1; i >= 0; --i) {
1042 int reg = TMP_REG(TMP(0));
1043 tmp_pop(reg, TMPBT(bt[i]));
1044 op_rm(I_MOV, reg, R_ESP, i * LONGSZ, TMPBT(bt[i]));
1046 t = TMP(0);
1047 if (t->flags & LOC_SYM) {
1048 os("\xe8", 1); /* call $x */
1049 if (!nogen)
1050 out_rela(t->addr, codeaddr(), 1);
1051 oi(-4 + t->off, 4);
1052 tmp_drop(1);
1053 } else {
1054 tmp_mv(t, R_EAX);
1055 tmp_drop(1);
1056 op_rr(I_CALL, 2, R_EAX, 4);
1058 if (ret_bt)
1059 tmp_push(R_EAX, ret_bt);
1062 int o_nogen(void)
1064 return nogen++;
1067 void o_dogen(void)
1069 nogen = 0;
1072 void o_datset(long addr, int off, unsigned bt)
1074 struct tmp *t = TMP(0);
1075 if (t->flags & LOC_NUM && !(t->flags & TMP_ADDR)) {
1076 num_cast(t, bt);
1077 out_datcpy(addr, off, (void *) &t->addr, BT_SZ(bt));
1079 if (t->flags & LOC_SYM && !(t->flags & TMP_ADDR)) {
1080 out_datrela(t->addr, addr, off);
1081 out_datcpy(addr, off, (void *) &t->off, BT_SZ(bt));
1083 tmp_drop(1);