ncc: handle ptr operations on structs ptrs
[neatcc.git] / gen.c
blobd3edd8a0f0e1a0fab8151082bd8bf29f2bdd235c
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_I2X 0xc7
35 #define MOV_I2R 0xb8
36 #define ADD_R2X 0x03
37 #define SUB_R2X 0x2b
38 #define SHX_REG 0xd3
39 #define CMP_R2X 0x3b
40 #define LEA_M2R 0x8d
41 #define NEG_REG 0xf7
42 #define NOT_REG 0xf7
43 #define CALL_REG 0xff
44 #define MUL_A2X 0xf7
45 #define XOR_R2X 0x33
46 #define AND_R2X 0x23
47 #define OR_R2X 0x0b
48 #define TEST_R2R 0x85
50 #define MIN(a, b) ((a) < (b) ? (a) : (b))
52 #define R_BYTEMASK (1 << R_RAX | 1 << R_RDX | 1 << R_RCX)
53 #define TMP_BT(t) ((t)->flags & TMP_ADDR ? 8 : (t)->bt)
54 #define TMP_REG(t) ((t)->flags & LOC_REG ? (t)->addr : reg_get(~0))
55 #define TMP_REG2(t, r) ((t)->flags & LOC_REG && (t)->addr != r ? \
56 (t)->addr : reg_get(~(1 << r)))
57 #define TMP_BYTEREG(t) ((t)->flags & LOC_REG && \
58 (1 << (t)->addr) & R_BYTEMASK ? \
59 (t)->addr : reg_get(R_BYTEMASK))
60 #define BT_TMPBT(bt) (BT_SZ(bt) >= 4 ? (bt) : (bt) & BT_SIGNED | 4)
62 static char buf[SECSIZE];
63 static char *cur;
64 static int nogen;
65 static long sp;
66 static long spsub_addr;
67 static long maxsp;
69 #define TMP(i) (&tmps[ntmp - 1 - (i)])
71 static struct tmp {
72 long addr;
73 long off; /* used for LOC_SYM; offset from a symbol address */
74 unsigned flags;
75 unsigned bt;
76 } tmps[MAXTMP];
77 static int ntmp;
79 static int tmpsp;
81 static struct tmp *regs[NREGS];
82 static int tmpregs[] = {R_RAX, R_RDI, R_RSI, R_RDX, R_RCX, R_R8, R_R9};
84 #define MAXRET (1 << 8)
86 static long ret[MAXRET];
87 static int nret;
89 static long cmp_last;
90 static long cmp_setl;
92 static void putint(char *s, long n, int l)
94 while (l--) {
95 *s++ = n;
96 n >>= 8;
100 static void os(char *s, int n)
102 if (nogen)
103 return;
104 while (n--)
105 *cur++ = *s++;
108 static void oi(long n, int l)
110 if (nogen)
111 return;
112 while (l--) {
113 *cur++ = n;
114 n >>= 8;
118 static long codeaddr(void)
120 return cur - buf;
123 static void o_op(int *op, int nop, int r1, int r2, unsigned bt)
125 int rex = 0;
126 int i;
127 if (r1 & 0x8)
128 rex |= 4;
129 if (r2 & 0x8)
130 rex |= 1;
131 if (BT_SZ(bt) == 8)
132 rex |= 8;
133 if (rex || (bt & BT_SZMASK) == 8)
134 oi(0x40 | rex, 1);
135 if ((bt & BT_SZMASK) == 2)
136 oi(0x66, 1);
137 if ((bt & BT_SZMASK) == 1)
138 op[nop - 1] &= ~0x1;
139 for (i = 0; i < nop; i++)
140 oi(op[i], 1);
143 static void memop(int *op, int nop, int src, int base, int off, unsigned bt)
145 int dis = off == (char) off ? 1 : 4;
146 int mod = dis == 4 ? 2 : 1;
147 o_op(op, nop, src, base, bt);
148 if (!off)
149 mod = 0;
150 oi((mod << 6) | ((src & 0x07) << 3) | (base & 0x07), 1);
151 if (off)
152 oi(off, dis);
155 static void memop1(int op, int src, int base, int off, unsigned bt)
157 memop(&op, 1, src, base, off, bt);
160 static void regop(int *op, int nop, int src, int dst, unsigned bt)
162 o_op(op, nop, src, dst, bt);
163 oi((3 << 6) | (src << 3) | (dst & 0x07), 1);
166 static void regop1(int op, int src, int dst, unsigned bt)
168 regop(&op, 1, src, dst, bt);
171 static long sp_push(int size)
173 sp += size;
174 if (sp > maxsp)
175 maxsp = sp;
176 return sp;
179 #define LOC_NEW(f, l) (((f) & ~LOC_MASK) | (l))
181 static void tmp_mem(struct tmp *tmp)
183 int src = tmp->addr;
184 if (!(tmp->flags & LOC_REG))
185 return;
186 if (tmpsp == -1)
187 tmpsp = sp;
188 tmp->addr = -sp_push(8);
189 memop1(MOV_R2X, src, R_RBP, tmp->addr, BT_TMPBT(TMP_BT(tmp)));
190 regs[src] = NULL;
191 tmp->flags = LOC_NEW(tmp->flags, LOC_MEM);
194 static int *movxx_x2r(int bt)
196 static int movxx[2] = {0x0f};
197 if (BT_SZ(bt) == 1)
198 movxx[1] = bt & BT_SIGNED ? 0xbe : 0xb6;
199 else
200 movxx[1] = bt & BT_SIGNED ? 0xbf : 0xb7;
201 return movxx;
204 #define MOVSXD 0x63
206 static void mov_r2r(int r1, int r2, unsigned bt1, unsigned bt2)
208 int s1 = bt1 & BT_SIGNED;
209 int s2 = bt2 & BT_SIGNED;
210 int sz1 = BT_SZ(bt1);
211 int sz2 = BT_SZ(bt2);
212 if (sz2 < 4 && (sz1 >= sz2 && s1 != s2)) {
213 regop(movxx_x2r(bt2), 2, r1, r2, 4);
214 return;
216 if (sz1 == 4 && sz2 == 8) {
217 regop1(MOVSXD, r2, r1, sz2);
218 return;
220 if (r1 != r2 || sz1 > sz2)
221 regop1(MOV_R2X, r1, r2, BT_TMPBT(bt2));
224 static void mov_m2r(int dst, int base, int off, int bt1, int bt2)
226 if (BT_SZ(bt1) < 4) {
227 memop(movxx_x2r(bt1), 2, dst, base, off,
228 bt1 & BT_SIGNED && BT_SZ(bt2) == 8 ? 8 : 4);
229 mov_r2r(dst, dst, bt1, bt2);
230 } else {
231 memop1(MOV_M2R, dst, base, off, bt1);
232 mov_r2r(dst, dst, bt1, bt2);
236 static void num_cast(struct tmp *t, unsigned bt)
238 if (!(bt & BT_SIGNED) && BT_SZ(bt) != 8)
239 t->addr &= ((1l << (long) (BT_SZ(bt) * 8)) - 1);
240 if (bt & BT_SIGNED && BT_SZ(bt) != 8 &&
241 t->addr > (1l << (BT_SZ(bt) * 8 - 1)))
242 t->addr = -((1l << (BT_SZ(bt) * 8)) - t->addr);
243 t->bt = bt;
246 static void num_reg(int reg, unsigned bt, long num)
248 int op = MOV_I2R + (reg & 7);
249 if (BT_SZ(bt) == 8 && num >= 0 && num == (unsigned) num)
250 bt = 4;
251 o_op(&op, 1, 0, reg, bt);
252 oi(num, BT_SZ(bt));
255 static void tmp_reg(struct tmp *tmp, int dst, unsigned bt, int deref)
257 if (deref && tmp->flags & TMP_ADDR)
258 tmp->flags &= ~TMP_ADDR;
259 else
260 deref = 0;
261 if (tmp->flags & LOC_NUM) {
262 num_cast(tmp, bt);
263 tmp->bt = BT_TMPBT(bt);
264 num_reg(dst, tmp->bt, tmp->addr);
265 tmp->addr = dst;
266 regs[dst] = tmp;
267 tmp->flags = LOC_NEW(tmp->flags, LOC_REG);
269 if (tmp->flags & LOC_SYM) {
270 regop1(MOV_I2X, 0, dst, 4);
271 if (!nogen)
272 out_rela(tmp->addr, codeaddr(), 0);
273 oi(tmp->off, 4);
274 tmp->addr = dst;
275 regs[dst] = tmp;
276 tmp->flags = LOC_NEW(tmp->flags, LOC_REG);
278 if (tmp->flags & LOC_REG) {
279 if (deref)
280 mov_m2r(dst, tmp->addr, 0, tmp->bt, bt);
281 else
282 mov_r2r(tmp->addr, dst, TMP_BT(tmp),
283 tmp->flags & TMP_ADDR ? 8 : bt);
284 regs[tmp->addr] = NULL;
286 if (tmp->flags & LOC_LOCAL) {
287 if (deref)
288 mov_m2r(dst, R_RBP, tmp->addr, tmp->bt, bt);
289 else
290 memop1(LEA_M2R, dst, R_RBP, tmp->addr, 8);
292 if (tmp->flags & LOC_MEM) {
293 int nbt = deref ? 8 : TMP_BT(tmp);
294 mov_m2r(dst, R_RBP, tmp->addr, nbt, nbt);
295 if (deref)
296 mov_m2r(dst, dst, 0, tmp->bt, bt);
298 tmp->addr = dst;
299 tmp->bt = tmp->flags & TMP_ADDR ? bt : BT_TMPBT(bt);
300 regs[dst] = tmp;
301 tmp->flags = LOC_NEW(tmp->flags, LOC_REG);
304 static void reg_free(int reg)
306 int i;
307 if (!regs[reg])
308 return;
309 for (i = 0; i < ARRAY_SIZE(tmpregs); i++)
310 if (!regs[tmpregs[i]]) {
311 tmp_reg(regs[reg], tmpregs[i], regs[reg]->bt, 0);
312 return;
314 tmp_mem(regs[reg]);
317 static void reg_for(int reg, struct tmp *t)
319 if (regs[reg] && regs[reg] != t)
320 reg_free(reg);
323 static void tmp_mv(struct tmp *t, int reg)
325 reg_for(reg, t);
326 tmp_reg(t, reg, t->bt, 0);
329 static void tmp_to(struct tmp *t, int reg, int bt)
331 reg_for(reg, t);
332 tmp_reg(t, reg, bt ? bt : t->bt, 1);
335 static void tmp_drop(int n)
337 int i;
338 for (i = ntmp - n; i < ntmp; i++)
339 if (tmps[i].flags & LOC_REG)
340 regs[tmps[i].addr] = NULL;
341 cmp_last = -1;
342 ntmp -= n;
345 static int tmp_pop(int reg, int bt)
347 struct tmp *t = TMP(0);
348 tmp_to(t, reg, bt);
349 tmp_drop(1);
350 return t->bt;
353 static struct tmp *tmp_new(void)
355 cmp_last = -1;
356 return &tmps[ntmp++];
359 static void tmp_push(int reg, unsigned bt)
361 struct tmp *t = tmp_new();
362 t->addr = reg;
363 t->bt = bt;
364 t->flags = LOC_REG;
365 regs[reg] = t;
368 void o_local(long addr, unsigned bt)
370 struct tmp *t = tmp_new();
371 t->addr = -addr;
372 t->bt = bt;
373 t->flags = LOC_LOCAL | TMP_ADDR;
376 void o_num(long num, unsigned bt)
378 struct tmp *t = tmp_new();
379 t->addr = num;
380 t->bt = bt;
381 t->flags = LOC_NUM;
384 void o_symaddr(long addr, unsigned bt)
386 struct tmp *t = tmp_new();
387 t->bt = bt;
388 t->addr = addr;
389 t->flags = LOC_SYM | TMP_ADDR;
390 t->off = 0;
393 void o_tmpdrop(int n)
395 int i;
396 if (n == -1 || n > ntmp)
397 n = ntmp;
398 tmp_drop(n);
399 if (!ntmp) {
400 if (tmpsp != -1)
401 sp = tmpsp;
402 tmpsp = -1;
406 #define FORK_REG R_RAX
408 /* make sure tmps remain intact after a conditional expression */
409 void o_fork(void)
411 int i;
412 for (i = 0; i < ntmp - 1; i++)
413 tmp_mem(&tmps[i]);
416 void o_forkpush(void)
418 tmp_pop(R_RAX, 0);
421 void o_forkjoin(void)
423 tmp_push(FORK_REG, 0);
426 void o_tmpswap(void)
428 struct tmp *t1 = TMP(0);
429 struct tmp *t2 = TMP(1);
430 struct tmp t;
431 memcpy(&t, t1, sizeof(t));
432 memcpy(t1, t2, sizeof(t));
433 memcpy(t2, &t, sizeof(t));
434 if (t1->flags & LOC_REG)
435 regs[t1->addr] = t1;
436 if (t2->flags & LOC_REG)
437 regs[t2->addr] = t2;
440 static int reg_get(int mask)
442 int i;
443 for (i = 0; i < ARRAY_SIZE(tmpregs); i++)
444 if ((1 << tmpregs[i]) & mask && !regs[tmpregs[i]])
445 return tmpregs[i];
446 for (i = 0; i < ARRAY_SIZE(tmpregs); i++)
447 if ((1 << tmpregs[i]) & mask) {
448 reg_free(tmpregs[i]);
449 return tmpregs[i];
451 return 0;
454 void o_tmpcopy(void)
456 struct tmp *t1 = TMP(0);
457 struct tmp *t2 = tmp_new();
458 memcpy(t2, t1, sizeof(*t1));
459 if (!(t1->flags & (LOC_REG | LOC_MEM)))
460 return;
461 if (t1->flags & LOC_MEM) {
462 tmp_reg(t2, reg_get(~0), t2->bt, 0);
463 } else if (t1->flags & LOC_REG) {
464 t2->addr = reg_get(~(1 << t1->addr));
465 regop1(MOV_R2X, t1->addr, t2->addr, BT_TMPBT(TMP_BT(t1)));
466 regs[t2->addr] = t2;
468 t2->flags = t1->flags;
471 void o_cast(unsigned bt)
473 struct tmp *t = TMP(0);
474 int reg;
475 if (t->bt == bt)
476 return;
477 if (t->flags & LOC_NUM) {
478 num_cast(t, bt);
479 return;
481 reg = BT_SZ(bt) == 1 ? TMP_BYTEREG(t) : TMP_REG(t);
482 tmp_to(t, reg, bt);
485 long o_func_beg(char *name, int global)
487 long addr = out_func_beg(name, global);
488 cur = buf;
489 os("\x55", 1); /* push %rbp */
490 os("\x48\x89\xe5", 3); /* mov %rsp, %rbp */
491 sp = 0;
492 maxsp = 0;
493 ntmp = 0;
494 tmpsp = -1;
495 nret = 0;
496 cmp_last = -1;
497 memset(regs, 0, sizeof(regs));
498 os("\x48\x81\xec", 3); /* sub $xxx, %rsp */
499 spsub_addr = codeaddr();
500 oi(0, 4);
501 return addr;
504 void o_deref(unsigned bt)
506 struct tmp *t = TMP(0);
507 if (t->flags & TMP_ADDR)
508 tmp_to(t, TMP_REG(t), t->bt);
509 t->bt = bt;
510 t->flags |= TMP_ADDR;
513 void o_load(void)
515 struct tmp *t = TMP(0);
516 tmp_to(t, TMP_REG(t), t->bt);
519 static unsigned bt_op(unsigned bt1, unsigned bt2)
521 unsigned s1 = BT_SZ(bt1);
522 unsigned s2 = BT_SZ(bt2);
523 unsigned bt = (bt1 | bt2) & BT_SIGNED | (s1 > s2 ? s1 : s2);
524 return BT_TMPBT(bt);
527 #define TMP_CONST(t) ((t)->flags & LOC_NUM && !((t)->flags & TMP_ADDR))
528 #define LOCAL_PTR(t) ((t)->flags & LOC_LOCAL && !((t)->flags & TMP_ADDR))
529 #define SYM_PTR(t) ((t)->flags & LOC_SYM && !((t)->flags & TMP_ADDR))
531 int o_popnum(long *c)
533 struct tmp *t = TMP(0);
534 if (!TMP_CONST(t))
535 return 1;
536 *c = t->addr;
537 tmp_drop(1);
538 return 0;
541 static int c_binop(long (*cop)(long a, long b, unsigned bt), unsigned bt)
543 struct tmp *t1 = TMP(0);
544 struct tmp *t2 = TMP(1);
545 int locals = LOCAL_PTR(t1) + LOCAL_PTR(t2);
546 int syms = SYM_PTR(t1) + SYM_PTR(t2);
547 int nums = TMP_CONST(t1) + TMP_CONST(t2);
548 if (syms == 2 || syms && locals || syms + nums + locals != 2)
549 return 1;
550 if (!bt) {
551 if (!locals)
552 bt = syms ? 8 : bt_op(t1->bt, t2->bt);
553 if (locals == 1)
554 bt = 8;
555 if (locals == 2)
556 bt = 4 | BT_SIGNED;
558 if (syms) {
559 long o1 = SYM_PTR(t1) ? t1->off : t1->addr;
560 long o2 = SYM_PTR(t2) ? t2->off : t2->addr;
561 long ret = cop(o2, o1, bt);
562 if (!SYM_PTR(t2))
563 o_tmpswap();
564 t2->off = ret;
565 tmp_drop(1);
566 } else {
567 long ret = cop(t2->addr, t1->addr, locals ? 4 | BT_SIGNED : bt);
568 tmp_drop(2);
569 if (locals == 1) {
570 o_local(-ret, bt);
571 o_addr();
572 } else {
573 o_num(ret, bt);
576 return 0;
579 static int c_op(long (*cop)(long a, unsigned bt), unsigned bt)
581 struct tmp *t1 = TMP(0);
582 long ret;
583 if (!TMP_CONST(t1))
584 return 1;
585 if (!bt)
586 bt = t1->bt;
587 ret = cop(t1->addr, bt);
588 tmp_drop(1);
589 o_num(ret, bt);
590 return 0;
593 static void shx(int uop, int sop)
595 struct tmp *t2 = TMP(1);
596 int r2 = TMP_REG2(t2, R_RCX);
597 int bt;
598 tmp_pop(R_RCX, 0);
599 bt = tmp_pop(r2, 0);
600 regop1(SHX_REG, bt & BT_SIGNED ? sop : uop, r2, BT_TMPBT(bt));
601 tmp_push(r2, bt);
604 static long c_shl(long a, long b, unsigned bt)
606 return a << b;
609 void o_shl(void)
611 if (!c_binop(c_shl, 0))
612 return;
613 shx(4, 4);
616 static long c_shr(long a, long b, unsigned bt)
618 if (bt & BT_SIGNED)
619 return a >> b;
620 else
621 return (unsigned long) a >> b;
624 void o_shr(void)
626 if (!c_binop(c_shr, 0))
627 return;
628 shx(5, 7);
631 static int mulop(int uop, int sop, int reg)
633 struct tmp *t1 = TMP(0);
634 struct tmp *t2 = TMP(1);
635 int bt1 = TMP_BT(t1);
636 int bt2 = TMP_BT(t2);
637 int bt = bt_op(bt1, bt2);
638 if (t1->flags & LOC_REG && t1->addr != R_RAX && t1->addr != R_RDX)
639 reg = t1->addr;
640 tmp_to(t1, reg, bt);
641 tmp_to(t2, R_RAX, bt);
642 if (reg != R_RDX) {
643 int cqo = 0x99;
644 reg_free(R_RDX);
645 if (bt & BT_SIGNED)
646 o_op(&cqo, 1, R_RAX, R_RDX, bt);
647 else
648 regop1(XOR_R2X, R_RDX, R_RDX, bt);
650 tmp_drop(2);
651 regop1(MUL_A2X, bt & BT_SIGNED ? sop : uop, reg, BT_TMPBT(bt2));
652 return bt;
655 static long c_mul(long a, long b, unsigned bt)
657 return a * b;
660 void o_mul(void)
662 int bt;
663 if (!c_binop(c_mul, 0))
664 return;
665 bt = mulop(4, 5, R_RDX);
666 tmp_push(R_RAX, bt);
669 static long c_div(long a, long b, unsigned bt)
671 return a / b;
674 void o_div(void)
676 int bt;
677 if (!c_binop(c_div, 0))
678 return;
679 bt = mulop(6, 7, R_RCX);
680 tmp_push(R_RAX, bt);
683 static long c_mod(long a, long b, unsigned bt)
685 return a % b;
688 void o_mod(void)
690 int bt;
691 if (!c_binop(c_mod, 0))
692 return;
693 bt = mulop(6, 7, R_RCX);
694 tmp_push(R_RDX, bt);
697 void o_addr(void)
699 tmps[ntmp - 1].flags &= ~TMP_ADDR;
700 tmps[ntmp - 1].bt = 8;
703 void o_ret(unsigned bt)
705 if (bt)
706 tmp_pop(R_RAX, bt);
707 else
708 os("\x31\xc0", 2); /* xor %eax, %eax */
709 ret[nret++] = o_jmp(0);
712 static int binop(int op, int *reg)
714 struct tmp *t1 = TMP(0);
715 struct tmp *t2 = TMP(1);
716 int r1, r2;
717 unsigned bt = bt_op(t1->bt, t2->bt);
718 r1 = TMP_REG(t1);
719 r2 = TMP_REG2(t2, r1);
720 tmp_pop(r1, bt);
721 tmp_pop(r2, bt);
722 regop1(op, r2, r1, bt);
723 *reg = r2;
724 return bt;
727 static long c_add(long a, long b, unsigned bt)
729 return a + b;
732 void o_add(void)
734 int reg;
735 int bt;
736 if (!c_binop(c_add, 0))
737 return;
738 bt = binop(ADD_R2X, &reg);
739 tmp_push(reg, bt);
742 static long c_xor(long a, long b, unsigned bt)
744 return a ^ b;
747 void o_xor(void)
749 int reg;
750 int bt;
751 if (!c_binop(c_xor, 0))
752 return;
753 bt = binop(XOR_R2X, &reg);
754 tmp_push(reg, bt);
757 static long c_and(long a, long b, unsigned bt)
759 return a & b;
762 void o_and(void)
764 int reg;
765 int bt;
766 if (!c_binop(c_and, 0))
767 return;
768 bt = binop(AND_R2X, &reg);
769 tmp_push(reg, bt);
772 static long c_or(long a, long b, unsigned bt)
774 return a | b;
777 void o_or(void)
779 int reg;
780 int bt;
781 if (!c_binop(c_or, 0))
782 return;
783 bt = binop(OR_R2X, &reg);
784 tmp_push(reg, bt);
787 static long c_sub(long a, long b, unsigned bt)
789 return a - b;
792 void o_sub(void)
794 int reg;
795 int bt;
796 if (!c_binop(c_sub, 0))
797 return;
798 bt = binop(SUB_R2X, &reg);
799 tmp_push(reg, bt);
802 static void o_cmp(int uop, int sop)
804 struct tmp *t1 = TMP(0);
805 struct tmp *t2 = TMP(1);
806 char set[] = "\x0f\x00\xc0";
807 int reg;
808 int bt;
809 if (regs[R_RAX] && regs[R_RAX] != t1 && regs[R_RAX] != t2)
810 reg_free(R_RAX);
811 bt = binop(CMP_R2X, &reg);
812 set[1] = bt & BT_SIGNED ? sop : uop;
813 cmp_setl = codeaddr();
814 os(set, 3); /* setl %al */
815 os("\x0f\xb6\xc0", 3); /* movzbl %al, %eax */
816 tmp_push(R_RAX, 4 | BT_SIGNED);
817 cmp_last = codeaddr();
820 static long c_lt(long a, long b, unsigned bt)
822 return a < b;
825 void o_lt(void)
827 if (!c_binop(c_lt, 4))
828 return;
829 o_cmp(0x92, 0x9c);
832 static long c_gt(long a, long b, unsigned bt)
834 return a > b;
837 void o_gt(void)
839 if (!c_binop(c_gt, 4))
840 return;
841 o_cmp(0x97, 0x9f);
844 static long c_le(long a, long b, unsigned bt)
846 return a <= b;
849 void o_le(void)
851 if (!c_binop(c_le, 4))
852 return;
853 o_cmp(0x96, 0x9e);
856 static long c_ge(long a, long b, unsigned bt)
858 return a >= b;
861 void o_ge(void)
863 if (!c_binop(c_ge, 4))
864 return;
865 o_cmp(0x93, 0x9d);
868 static long c_eq(long a, long b, unsigned bt)
870 return a == b;
873 void o_eq(void)
875 if (!c_binop(c_eq, 4))
876 return;
877 o_cmp(0x94, 0x94);
880 static long c_neq(long a, long b, unsigned bt)
882 return a != b;
885 void o_neq(void)
887 if (!c_binop(c_neq, 4))
888 return;
889 o_cmp(0x95, 0x95);
892 static long c_lnot(long a, unsigned bt)
894 return !a;
897 void o_lnot(void)
899 if (!c_op(c_lnot, 4))
900 return;
901 if (cmp_last == codeaddr()) {
902 buf[cmp_setl + 1] ^= 0x01;
903 } else {
904 o_num(0, 4 | BT_SIGNED);
905 o_eq();
909 static long c_neg(long a, unsigned bt)
911 return -a;
914 void o_neg(void)
916 struct tmp *t = TMP(0);
917 int reg;
918 unsigned bt = BT_TMPBT(t->bt);
919 if (!c_op(c_neg, t->bt | BT_SIGNED))
920 return;
921 reg = TMP_REG(t);
922 tmp_to(t, reg, bt);
923 regop1(NEG_REG, 3, reg, bt);
926 static long c_not(long a, unsigned bt)
928 return ~a;
931 void o_not(void)
933 struct tmp *t = TMP(0);
934 int reg;
935 unsigned bt = BT_TMPBT(t->bt);
936 if (!c_op(c_not, 0))
937 return;
938 reg = TMP_REG(t);
939 tmp_to(t, reg, bt);
940 regop1(NOT_REG, 2, reg, bt);
943 void o_func_end(void)
945 int i;
946 for (i = 0; i < nret; i++)
947 o_filljmp(ret[i]);
948 os("\xc9\xc3", 2); /* leave; ret; */
949 putint(buf + spsub_addr, (maxsp + 7) & ~0x07, 4);
950 out_func_end(buf, cur - buf);
953 long o_mklocal(int size)
955 return sp_push((size + 7) & ~0x07);
958 void o_rmlocal(long addr, int sz)
960 sp = addr - sz;
963 static int arg_regs[] = {R_RDI, R_RSI, R_RDX, R_RCX, R_R8, R_R9};
965 #define R_NARGS ARRAY_SIZE(arg_regs)
967 long o_arg(int i, unsigned bt)
969 long addr;
970 if (i < R_NARGS) {
971 addr = o_mklocal(BT_SZ(bt));
972 memop1(MOV_R2X, arg_regs[i], R_RBP, -addr, bt);
973 } else {
974 addr = -8 * (i - R_NARGS + 2);
976 return addr;
979 void o_assign(unsigned bt)
981 struct tmp *t1 = TMP(0);
982 struct tmp *t2 = TMP(1);
983 int r1 = BT_SZ(bt) > 1 ? TMP_REG(t1) : TMP_BYTEREG(t1);
984 int reg;
985 int off;
986 tmp_to(t1, r1, BT_TMPBT(bt));
987 if (t2->flags & LOC_LOCAL) {
988 reg = R_RBP;
989 off = t2->addr;
990 } else {
991 reg = TMP_REG2(t2, r1);
992 off = 0;
993 tmp_mv(t2, reg);
995 tmp_drop(2);
996 memop1(MOV_R2X, r1, reg, off, bt);
997 tmp_push(r1, bt);
1000 void o_memcpy(int sz)
1002 struct tmp *t0 = TMP(-1);
1003 struct tmp *t1 = TMP(0);
1004 struct tmp *t2 = TMP(1);
1005 o_num(sz, 4);
1006 tmp_to(t0, R_RCX, 0);
1007 tmp_mv(t1, R_RSI);
1008 tmp_mv(t2, R_RDI);
1009 os("\xf3\xa4", 2); /* rep movs */
1010 tmp_drop(2);
1013 void o_memset(int x, int sz)
1015 struct tmp *t0 = TMP(-2);
1016 struct tmp *t1 = TMP(-1);
1017 struct tmp *t2 = TMP(0);
1018 o_num(sz, 4);
1019 o_num(x, 4);
1020 tmp_to(t0, R_RAX, 0);
1021 tmp_to(t1, R_RCX, 0);
1022 tmp_mv(t2, R_RDI);
1023 os("\xf3\xaa", 2); /* rep stosb */
1024 tmp_drop(2);
1027 long o_mklabel(void)
1029 return codeaddr();
1032 static long jx(int x, long addr)
1034 char op[2] = {0x0f};
1035 op[1] = x;
1036 os(op, 2); /* jx $addr */
1037 oi(addr - codeaddr() - 4, 4);
1038 return codeaddr() - 4;
1041 static long jxtest(int x, long addr)
1043 int bt = tmp_pop(R_RAX, 0);
1044 regop1(TEST_R2R, R_RAX, R_RAX, bt);
1045 return jx(x, addr);
1048 static long jxcmp(long addr, int inv)
1050 int x;
1051 if (codeaddr() != cmp_last)
1052 return -1;
1053 tmp_drop(1);
1054 cur = buf + cmp_setl;
1055 x = (unsigned char) buf[cmp_setl + 1];
1056 return jx((inv ? x : x ^ 0x01) & ~0x10, addr);
1059 long o_jz(long addr)
1061 long ret = jxcmp(addr, 0);
1062 return ret != -1 ? ret : jxtest(0x84, addr);
1065 long o_jnz(long addr)
1067 long ret = jxcmp(addr, 1);
1068 return ret != -1 ? ret : jxtest(0x85, addr);
1071 long o_jmp(long addr)
1073 os("\xe9", 1); /* jmp $addr */
1074 oi(addr - codeaddr() - 4, 4);
1075 return codeaddr() - 4;
1078 void o_filljmp2(long addr, long jmpdst)
1080 putint(buf + addr, jmpdst - addr - 4, 4);
1083 void o_filljmp(long addr)
1085 o_filljmp2(addr, codeaddr());
1088 void o_call(int argc, unsigned *bt, unsigned ret_bt)
1090 int i;
1091 struct tmp *t;
1092 for (i = 0; i < ARRAY_SIZE(tmpregs); i++)
1093 if (regs[tmpregs[i]] && regs[tmpregs[i]] - tmps < ntmp - argc)
1094 tmp_mem(regs[tmpregs[i]]);
1095 if (argc > R_NARGS) {
1096 long addr = sp_push(8 * (argc - R_NARGS));
1097 for (i = argc - 1; i >= R_NARGS; --i) {
1098 int reg = TMP_REG(TMP(0));
1099 tmp_pop(reg, bt[i]);
1100 memop1(MOV_R2X, reg, R_RBP,
1101 -(addr - (i - R_NARGS) * 8), BT_TMPBT(bt[i]));
1104 for (i = MIN(argc, R_NARGS) - 1; i >= 0; i--)
1105 tmp_pop(arg_regs[i], bt[i]);
1106 t = TMP(0);
1107 if (t->flags & LOC_SYM) {
1108 os("\x31\xc0", 2); /* xor %eax, %eax */
1109 os("\xe8", 1); /* call $x */
1110 if (!nogen)
1111 out_rela(t->addr, codeaddr(), 1);
1112 oi(-4 + t->off, 4);
1113 tmp_drop(1);
1114 } else {
1115 tmp_mv(TMP(0), R_RAX);
1116 tmp_drop(1);
1117 regop1(CALL_REG, 2, R_RAX, 4);
1119 if (ret_bt)
1120 tmp_push(R_RAX, ret_bt);
1123 int o_nogen(void)
1125 return nogen++;
1128 void o_dogen(void)
1130 nogen = 0;
1133 void o_datset(long addr, int off, unsigned bt)
1135 struct tmp *t = TMP(0);
1136 if (t->flags & LOC_NUM && !(t->flags & TMP_ADDR)) {
1137 num_cast(t, bt);
1138 out_datcpy(addr, off, (void *) &t->addr, BT_SZ(bt));
1140 if (t->flags & LOC_SYM && !(t->flags & TMP_ADDR)) {
1141 out_datrela(t->addr, addr, off);
1142 out_datcpy(addr, off, (void *) &t->off, BT_SZ(bt));
1144 tmp_drop(1);