ncc: handle forward struct ptr usage
[neatcc/cc.git] / gen.c
blob85963d25126466dd60eb6e6daabda5f96709d10d
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 static struct tmp {
70 long addr;
71 unsigned flags;
72 unsigned bt;
73 } tmp[MAXTMP];
74 static int ntmp;
76 static int tmpsp;
78 static struct tmp *regs[NREGS];
79 static int tmpregs[] = {R_RAX, R_RDI, R_RSI, R_RDX, R_RCX, R_R8, R_R9};
81 #define MAXRET (1 << 8)
83 static long ret[MAXRET];
84 static int nret;
86 static long cmp_last;
87 static long cmp_setl;
89 static void putint(char *s, long n, int l)
91 if (nogen)
92 return;
93 while (l--) {
94 *s++ = n;
95 n >>= 8;
99 static void os(char *s, int n)
101 if (nogen)
102 return;
103 while (n--)
104 *cur++ = *s++;
107 static void oi(long n, int l)
109 while (l--) {
110 *cur++ = n;
111 n >>= 8;
115 static long codeaddr(void)
117 return cur - buf;
120 static void o_op(int *op, int nop, int r1, int r2, unsigned bt)
122 int rex = 0;
123 int i;
124 if (r1 & 0x8)
125 rex |= 4;
126 if (r2 & 0x8)
127 rex |= 1;
128 if (BT_SZ(bt) == 8)
129 rex |= 8;
130 if (rex || (bt & BT_SZMASK) == 8)
131 oi(0x40 | rex, 1);
132 if ((bt & BT_SZMASK) == 2)
133 oi(0x66, 1);
134 if ((bt & BT_SZMASK) == 1)
135 op[nop - 1] &= ~0x1;
136 for (i = 0; i < nop; i++)
137 oi(op[i], 1);
140 static void memop(int *op, int nop, int src, int base, int off, unsigned bt)
142 int dis = off == (char) off ? 1 : 4;
143 int mod = dis == 4 ? 2 : 1;
144 o_op(op, nop, src, base, bt);
145 if (!off)
146 mod = 0;
147 oi((mod << 6) | ((src & 0x07) << 3) | (base & 0x07), 1);
148 if (off)
149 oi(off, dis);
152 static void memop1(int op, int src, int base, int off, unsigned bt)
154 memop(&op, 1, src, base, off, bt);
157 static void regop(int *op, int nop, int src, int dst, unsigned bt)
159 o_op(op, nop, src, dst, bt);
160 oi((3 << 6) | (src << 3) | (dst & 0x07), 1);
163 static void regop1(int op, int src, int dst, unsigned bt)
165 regop(&op, 1, src, dst, bt);
168 static long sp_push(int size)
170 sp += size;
171 if (sp > maxsp)
172 maxsp = sp;
173 return sp;
176 #define LOC_NEW(f, l) (((f) & ~LOC_MASK) | (l))
178 static void tmp_mem(struct tmp *tmp)
180 int src = tmp->addr;
181 if (!(tmp->flags & LOC_REG))
182 return;
183 if (tmpsp == -1)
184 tmpsp = sp;
185 tmp->addr = -sp_push(8);
186 memop1(MOV_R2X, src, R_RBP, tmp->addr, BT_TMPBT(TMP_BT(tmp)));
187 regs[src] = NULL;
188 tmp->flags = LOC_NEW(tmp->flags, LOC_MEM);
191 static int *movxx_x2r(int bt)
193 static int movxx[2] = {0x0f};
194 if (BT_SZ(bt) == 1)
195 movxx[1] = bt & BT_SIGNED ? 0xbe : 0xb6;
196 else
197 movxx[1] = bt & BT_SIGNED ? 0xbf : 0xb7;
198 return movxx;
201 #define MOVSXD 0x63
203 static void mov_r2r(int r1, int r2, unsigned bt1, unsigned bt2)
205 int s1 = bt1 & BT_SIGNED;
206 int s2 = bt2 & BT_SIGNED;
207 int sz1 = BT_SZ(bt1);
208 int sz2 = BT_SZ(bt2);
209 if (sz2 < 4 && (sz1 >= sz2 && s1 != s2)) {
210 regop(movxx_x2r(bt2), 2, r1, r2, 4);
211 return;
213 if (sz1 == 4 && sz2 == 8) {
214 regop1(MOVSXD, r1, r2, sz2);
215 return;
217 if (r1 != r2 || sz1 > sz2)
218 regop1(MOV_R2X, r1, r2, BT_TMPBT(bt2));
221 static void mov_m2r(int dst, int base, int off, int bt1, int bt2)
223 if (BT_SZ(bt1) < 4) {
224 memop(movxx_x2r(bt1), 2, dst, base, off,
225 bt1 & BT_SIGNED && BT_SZ(bt2) == 8 ? 8 : 4);
226 mov_r2r(dst, dst, bt1, bt2);
227 } else {
228 memop1(MOV_M2R, dst, base, off, bt1);
229 mov_r2r(dst, dst, bt1, bt2);
233 static void num_cast(struct tmp *t, unsigned bt)
235 if (!(bt & BT_SIGNED) && BT_SZ(bt) != 8)
236 t->addr &= ((1l << (long) (BT_SZ(bt) * 8)) - 1);
237 if (bt & BT_SIGNED && BT_SZ(bt) != 8 &&
238 t->addr > (1l << (BT_SZ(bt) * 8 - 1)))
239 t->addr = -((1l << (BT_SZ(bt) * 8)) - t->addr);
240 t->bt = bt;
243 static void num_reg(int reg, unsigned bt, long num)
245 int op = MOV_I2R + (reg & 7);
246 if (BT_SZ(bt) == 8 && num >= 0 && num == (unsigned) num)
247 bt = 4;
248 o_op(&op, 1, 0, reg, bt);
249 oi(num, BT_SZ(bt));
252 static void tmp_reg(struct tmp *tmp, int dst, unsigned bt, int deref)
254 if (!(tmp->flags & TMP_ADDR))
255 deref = 0;
256 if (deref)
257 tmp->flags &= ~TMP_ADDR;
258 if (tmp->flags & LOC_NUM) {
259 num_cast(tmp, bt);
260 tmp->bt = BT_TMPBT(bt);
261 num_reg(dst, tmp->bt, tmp->addr);
262 tmp->addr = dst;
263 regs[dst] = tmp;
264 tmp->flags = LOC_NEW(tmp->flags, LOC_REG);
266 if (tmp->flags & LOC_SYM) {
267 regop1(MOV_I2X, 0, dst, TMP_BT(tmp));
268 if (!nogen)
269 out_rela(tmp->addr, codeaddr(), 0);
270 oi(0, 4);
271 tmp->addr = dst;
272 regs[dst] = tmp;
273 tmp->flags = LOC_NEW(tmp->flags, LOC_REG);
275 if (tmp->flags & LOC_REG) {
276 if (deref)
277 mov_m2r(dst, tmp->addr, 0, tmp->bt, bt);
278 else
279 mov_r2r(tmp->addr, dst, TMP_BT(tmp), bt);
280 regs[tmp->addr] = NULL;
281 tmp->addr = dst;
282 tmp->bt = BT_TMPBT(bt);
283 regs[dst] = tmp;
284 return;
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 mov_m2r(dst, R_RBP, tmp->addr,
294 deref ? 8 : TMP_BT(tmp), deref ? 8 : bt);
295 if (deref)
296 mov_m2r(dst, dst, 0, tmp->bt, bt);
298 tmp->addr = dst;
299 tmp->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_pop_bt(unsigned bt, int reg)
325 struct tmp *t = &tmp[--ntmp];
326 reg_for(reg, t);
327 tmp_reg(t, reg, bt, 1);
328 regs[reg] = NULL;
331 static unsigned tmp_pop(int deref, int reg)
333 struct tmp *t = &tmp[--ntmp];
334 reg_for(reg, t);
335 tmp_reg(t, reg, deref ? t->bt : TMP_BT(t), deref);
336 regs[reg] = NULL;
337 return t->bt;
340 static void tmp_push_reg(unsigned bt, unsigned reg)
342 struct tmp *t = &tmp[ntmp++];
343 t->addr = reg;
344 t->bt = bt;
345 t->flags = LOC_REG;
346 regs[reg] = t;
349 void o_local(long addr, unsigned bt)
351 struct tmp *t = &tmp[ntmp++];
352 t->addr = -addr;
353 t->bt = bt;
354 t->flags = LOC_LOCAL | TMP_ADDR;
357 void o_num(long num, unsigned bt)
359 struct tmp *t = &tmp[ntmp++];
360 t->addr = num;
361 t->bt = bt;
362 t->flags = LOC_NUM;
365 void o_symaddr(long addr, unsigned bt)
367 struct tmp *t = &tmp[ntmp++];
368 t->bt = bt;
369 t->addr = addr;
370 t->flags = LOC_SYM | TMP_ADDR;
373 void o_tmpdrop(int n)
375 int i;
376 if (n == -1 || n > ntmp)
377 n = ntmp;
378 ntmp -= n;
379 for (i = ntmp; i < ntmp + n; i++)
380 if (tmp[i].flags & LOC_REG)
381 regs[tmp[i].addr] = NULL;
382 if (!ntmp) {
383 if (tmpsp != -1)
384 sp = tmpsp;
385 tmpsp = -1;
389 #define FORK_REG R_RAX
391 void o_tmpfork(void)
393 struct tmp *t = &tmp[ntmp - 1];
394 reg_for(FORK_REG, t);
395 tmp_reg(t, FORK_REG, t->bt, 0);
396 o_tmpdrop(1);
399 void o_tmpjoin(void)
401 struct tmp *t = &tmp[ntmp - 1];
402 reg_for(FORK_REG, t);
403 tmp_reg(t, FORK_REG, t->bt, 0);
406 void o_tmpswap(void)
408 struct tmp *t1 = &tmp[ntmp - 1];
409 struct tmp *t2 = &tmp[ntmp - 2];
410 struct tmp t;
411 memcpy(&t, t1, sizeof(t));
412 memcpy(t1, t2, sizeof(t));
413 memcpy(t2, &t, sizeof(t));
416 static int reg_get(int mask)
418 int i;
419 for (i = 0; i < ARRAY_SIZE(tmpregs); i++)
420 if ((1 << tmpregs[i]) & mask && !regs[tmpregs[i]])
421 return tmpregs[i];
422 for (i = 0; i < ARRAY_SIZE(tmpregs); i++)
423 if ((1 << tmpregs[i]) & mask) {
424 reg_free(tmpregs[i]);
425 return tmpregs[i];
427 return 0;
430 void o_tmpcopy(void)
432 struct tmp *t1 = &tmp[ntmp - 1];
433 struct tmp *t2 = &tmp[ntmp++];
434 memcpy(t2, t1, sizeof(*t1));
435 if (!(t1->flags & (LOC_REG | LOC_MEM)))
436 return;
437 if (t1->flags & LOC_MEM) {
438 tmp_reg(t2, reg_get(~0), t2->bt, 0);
439 } else if (t1->flags & LOC_REG) {
440 t2->addr = reg_get(~t1->addr);
441 regop1(MOV_R2X, t1->addr, t2->addr, BT_TMPBT(TMP_BT(tmp)));
443 t2->flags = t1->flags;
446 void o_cast(unsigned bt)
448 struct tmp *t = &tmp[ntmp - 1];
449 int reg;
450 if (t->bt == bt)
451 return;
452 if (t->flags & LOC_NUM) {
453 num_cast(t, bt);
454 return;
456 reg = BT_SZ(bt) == 1 ? TMP_BYTEREG(t) : TMP_REG(t);
457 tmp_pop_bt(bt, reg);
458 tmp_push_reg(bt, reg);
461 long o_func_beg(char *name, int global)
463 long addr = out_func_beg(name, global);
464 cur = buf;
465 os("\x55", 1); /* push %rbp */
466 os("\x48\x89\xe5", 3); /* mov %rsp, %rbp */
467 sp = 0;
468 maxsp = 0;
469 ntmp = 0;
470 tmpsp = -1;
471 nret = 0;
472 cmp_last = -1;
473 memset(regs, 0, sizeof(regs));
474 os("\x48\x81\xec", 3); /* sub $xxx, %rsp */
475 spsub_addr = codeaddr();
476 oi(0, 4);
477 return addr;
480 void o_deref(unsigned bt)
482 struct tmp *t = &tmp[ntmp - 1];
483 if (t->flags & TMP_ADDR)
484 tmp_reg(t, TMP_REG(t), 8, 1);
485 t->bt = bt;
486 t->flags |= TMP_ADDR;
489 void o_load(void)
491 struct tmp *t = &tmp[ntmp - 1];
492 tmp_reg(t, TMP_REG(t), t->bt, 1);
495 static unsigned bt_op(unsigned bt1, unsigned bt2)
497 unsigned s1 = BT_SZ(bt1);
498 unsigned s2 = BT_SZ(bt2);
499 unsigned bt = (bt1 | bt2) & BT_SIGNED | (s1 > s2 ? s1 : s2);
500 return BT_TMPBT(bt);
503 #define TMP_CONST(t) ((t)->flags & LOC_NUM && !((t)->flags & TMP_ADDR))
505 int o_popnum(long *c)
507 struct tmp *t = &tmp[ntmp - 1];
508 if (!TMP_CONST(t))
509 return 1;
510 *c = t->addr;
511 o_tmpdrop(1);
512 return 0;
515 #define LOCAL_PTR(t) ((t)->flags & LOC_LOCAL && !((t)->flags & TMP_ADDR))
517 static int c_binop(long (*cop)(long a, long b, unsigned bt), unsigned bt)
519 struct tmp *t1 = &tmp[ntmp - 1];
520 struct tmp *t2 = &tmp[ntmp - 2];
521 int locals = LOCAL_PTR(t1) + LOCAL_PTR(t2);
522 long ret;
523 if (!TMP_CONST(t1) && !LOCAL_PTR(t1) || !TMP_CONST(t2) && !LOCAL_PTR(t2))
524 return 1;
525 if (!bt) {
526 if (!locals)
527 bt = bt_op(t1->bt, t2->bt);
528 if (locals == 1)
529 bt = 8;
530 if (locals == 2)
531 bt = 4 | BT_SIGNED;
533 ret = cop(t2->addr, t1->addr, locals ? 4 | BT_SIGNED : bt);
534 o_tmpdrop(2);
535 if (locals == 1) {
536 o_local(-ret, bt);
537 o_addr();
538 } else {
539 o_num(ret, bt);
541 return 0;
544 static int c_op(long (*cop)(long a, unsigned bt), unsigned bt)
546 struct tmp *t1 = &tmp[ntmp - 1];
547 long ret;
548 if (!TMP_CONST(t1))
549 return 1;
550 if (!bt)
551 bt = t1->bt;
552 ret = cop(t1->addr, bt);
553 o_tmpdrop(1);
554 o_num(ret, bt);
555 return 0;
558 static void shx(int uop, int sop)
560 struct tmp *t = &tmp[ntmp - 2];
561 unsigned bt;
562 unsigned reg = TMP_REG2(t, R_RCX);
563 tmp_pop(1, R_RCX);
564 bt = tmp_pop(1, reg);
565 regop1(SHX_REG, bt & BT_SIGNED ? sop : uop, reg, BT_TMPBT(bt));
566 tmp_push_reg(bt, reg);
569 static long c_shl(long a, long b, unsigned bt)
571 return a << b;
574 void o_shl(void)
576 if (!c_binop(c_shl, 0))
577 return;
578 shx(4, 4);
581 static long c_shr(long a, long b, unsigned bt)
583 if (bt & BT_SIGNED)
584 return a >> b;
585 else
586 return (unsigned long) a >> b;
589 void o_shr(void)
591 if (!c_binop(c_shr, 0))
592 return;
593 shx(5, 7);
596 static int mulop(int uop, int sop, int reg)
598 struct tmp *t1 = &tmp[ntmp - 1];
599 struct tmp *t2 = &tmp[ntmp - 2];
600 int bt1 = TMP_BT(t1);
601 int bt2 = TMP_BT(t2);
602 int bt = bt_op(bt1, bt2);
603 if (t1->flags & LOC_REG && t1->addr != R_RAX && t1->addr != R_RDX)
604 reg = t1->addr;
605 reg_for(reg, t1);
606 tmp_reg(t1, reg, bt, 1);
607 reg_for(R_RAX, t2);
608 tmp_reg(t2, R_RAX, bt, 1);
609 if (reg != R_RDX)
610 reg_free(R_RDX);
611 o_tmpdrop(2);
612 regop1(MUL_A2X, bt & BT_SIGNED ? sop : uop, reg, BT_TMPBT(bt2));
613 return bt;
616 static long c_mul(long a, long b, unsigned bt)
618 return a * b;
621 void o_mul(void)
623 int bt;
624 if (!c_binop(c_mul, 0))
625 return;
626 bt = mulop(4, 5, R_RDX);
627 tmp_push_reg(bt, R_RAX);
630 static long c_div(long a, long b, unsigned bt)
632 return a / b;
635 void o_div(void)
637 int bt;
638 if (!c_binop(c_div, 0))
639 return;
640 bt = mulop(6, 7, R_RCX);
641 tmp_push_reg(bt, R_RAX);
644 static long c_mod(long a, long b, unsigned bt)
646 return a % b;
649 void o_mod(void)
651 int bt;
652 if (!c_binop(c_mod, 0))
653 return;
654 bt = mulop(6, 7, R_RCX);
655 tmp_push_reg(bt, R_RDX);
658 void o_addr(void)
660 tmp[ntmp - 1].flags &= ~TMP_ADDR;
661 tmp[ntmp - 1].bt = 8;
664 void o_ret(unsigned bt)
666 if (bt)
667 tmp_pop_bt(bt, R_RAX);
668 else
669 os("\x31\xc0", 2); /* xor %eax, %eax */
670 ret[nret++] = o_jmp(0);
673 static int binop(int op, int *reg)
675 struct tmp *t1 = &tmp[ntmp - 1];
676 struct tmp *t2 = &tmp[ntmp - 2];
677 int r1;
678 unsigned bt;
679 r1 = TMP_REG(t1);
680 *reg = TMP_REG2(t2, r1);
681 bt = bt_op(t1->bt, t2->bt);
682 tmp_pop_bt(bt, r1);
683 tmp_pop_bt(bt, *reg);
684 regop1(op, *reg, r1, bt);
685 return bt;
688 static long c_add(long a, long b, unsigned bt)
690 return a + b;
693 void o_add(void)
695 int reg;
696 int bt;
697 if (!c_binop(c_add, 0))
698 return;
699 bt = binop(ADD_R2X, &reg);
700 tmp_push_reg(bt, reg);
703 static long c_xor(long a, long b, unsigned bt)
705 return a ^ b;
708 void o_xor(void)
710 int reg;
711 int bt;
712 if (!c_binop(c_xor, 0))
713 return;
714 bt = binop(XOR_R2X, &reg);
715 tmp_push_reg(bt, reg);
718 static long c_and(long a, long b, unsigned bt)
720 return a & b;
723 void o_and(void)
725 int reg;
726 int bt;
727 if (!c_binop(c_and, 0))
728 return;
729 bt = binop(AND_R2X, &reg);
730 tmp_push_reg(bt, reg);
733 static long c_or(long a, long b, unsigned bt)
735 return a | b;
738 void o_or(void)
740 int reg;
741 int bt;
742 if (!c_binop(c_or, 0))
743 return;
744 bt = binop(OR_R2X, &reg);
745 tmp_push_reg(bt, reg);
748 static long c_sub(long a, long b, unsigned bt)
750 return a - b;
753 void o_sub(void)
755 int reg;
756 int bt;
757 if (!c_binop(c_sub, 0))
758 return;
759 bt = binop(SUB_R2X, &reg);
760 tmp_push_reg(bt, reg);
763 static void o_cmp(int uop, int sop)
765 char set[] = "\x0f\x00\xc0";
766 int reg;
767 int bt = binop(CMP_R2X, &reg);
768 set[1] = bt & BT_SIGNED ? sop : uop;
769 reg_free(R_RAX);
770 cmp_setl = codeaddr();
771 os(set, 3); /* setl %al */
772 os("\x0f\xb6\xc0", 3); /* movzbl %al, %eax */
773 tmp_push_reg(4 | BT_SIGNED, R_RAX);
774 cmp_last = codeaddr();
777 static long c_lt(long a, long b, unsigned bt)
779 return a < b;
782 void o_lt(void)
784 if (!c_binop(c_lt, 4))
785 return;
786 o_cmp(0x92, 0x9c);
789 static long c_gt(long a, long b, unsigned bt)
791 return a > b;
794 void o_gt(void)
796 if (!c_binop(c_gt, 4))
797 return;
798 o_cmp(0x97, 0x9f);
801 static long c_le(long a, long b, unsigned bt)
803 return a <= b;
806 void o_le(void)
808 if (!c_binop(c_le, 4))
809 return;
810 o_cmp(0x96, 0x9e);
813 static long c_ge(long a, long b, unsigned bt)
815 return a >= b;
818 void o_ge(void)
820 if (!c_binop(c_ge, 4))
821 return;
822 o_cmp(0x93, 0x9d);
825 static long c_eq(long a, long b, unsigned bt)
827 return a == b;
830 void o_eq(void)
832 if (!c_binop(c_eq, 4))
833 return;
834 o_cmp(0x94, 0x94);
837 static long c_neq(long a, long b, unsigned bt)
839 return a != b;
842 void o_neq(void)
844 if (!c_binop(c_neq, 4))
845 return;
846 o_cmp(0x95, 0x95);
849 static long c_lnot(long a, unsigned bt)
851 return !a;
854 void o_lnot(void)
856 if (!c_op(c_lnot, 4))
857 return;
858 if (cmp_last == codeaddr()) {
859 buf[cmp_setl + 1] ^= 0x10;
860 } else {
861 o_num(0, 4 | BT_SIGNED);
862 o_eq();
866 static long c_neg(long a, unsigned bt)
868 return -a;
871 void o_neg(void)
873 struct tmp *t = &tmp[ntmp - 1];
874 int reg;
875 unsigned bt = BT_TMPBT(t->bt);
876 if (!c_op(c_neg, t->bt | BT_SIGNED))
877 return;
878 reg = TMP_REG(t);
879 tmp_pop_bt(bt, reg);
880 regop1(NEG_REG, 3, reg, bt);
881 tmp_push_reg(bt, reg);
884 static long c_not(long a, unsigned bt)
886 return ~a;
889 void o_not(void)
891 struct tmp *t = &tmp[ntmp - 1];
892 int reg;
893 unsigned bt = BT_TMPBT(t->bt);
894 if (!c_op(c_not, 0))
895 return;
896 reg = TMP_REG(t);
897 tmp_pop_bt(bt, reg);
898 regop1(NOT_REG, 2, reg, bt);
899 tmp_push_reg(t->bt, reg);
902 void o_func_end(void)
904 int i;
905 for (i = 0; i < nret; i++)
906 o_filljmp(ret[i]);
907 os("\xc9\xc3", 2); /* leave; ret; */
908 putint(buf + spsub_addr, (maxsp + 7) & ~0x07, 4);
909 out_func_end(buf, cur - buf);
912 long o_mklocal(int size)
914 return sp_push((size + 7) & ~0x07);
917 void o_rmlocal(long addr, int sz)
919 sp = addr - sz;
922 static int arg_regs[] = {R_RDI, R_RSI, R_RDX, R_RCX, R_R8, R_R9};
924 #define R_NARGS ARRAY_SIZE(arg_regs)
926 long o_arg(int i, unsigned bt)
928 long addr;
929 if (i < R_NARGS) {
930 addr = o_mklocal(BT_SZ(bt));
931 memop1(MOV_R2X, arg_regs[i], R_RBP, -addr, bt);
932 } else {
933 addr = -8 * (i - R_NARGS + 2);
935 return addr;
938 void o_assign(unsigned bt)
940 struct tmp *t1 = &tmp[ntmp - 1];
941 struct tmp *t2 = &tmp[ntmp - 2];
942 int r1 = BT_SZ(bt) > 1 ? TMP_REG(t1) : TMP_BYTEREG(t1);
943 int reg;
944 int off;
945 tmp_pop_bt(BT_TMPBT(bt), r1);
946 if (t2->flags & LOC_LOCAL) {
947 reg = R_RBP;
948 off = t2->addr;
949 o_tmpdrop(1);
950 } else {
951 reg = TMP_REG2(t2, r1);
952 off = 0;
953 tmp_pop(0, reg);
955 memop1(MOV_R2X, r1, reg, off, bt);
956 tmp_push_reg(bt, r1);
959 static void tmp_to(struct tmp *t, int reg)
961 reg_for(reg, t);
962 tmp_reg(t, reg, t->bt, 0);
965 void o_memcpy(int sz)
967 struct tmp *t0 = &tmp[ntmp];
968 struct tmp *t1 = &tmp[ntmp - 1];
969 struct tmp *t2 = &tmp[ntmp - 2];
970 o_num(sz, 4);
971 tmp_to(t0, R_RCX);
972 tmp_to(t1, R_RSI);
973 tmp_to(t2, R_RDI);
974 os("\xf3\xa4", 2); /* rep movs */
975 o_tmpdrop(2);
978 void o_memset(int x, int sz)
980 struct tmp *t0 = &tmp[ntmp + 1];
981 struct tmp *t1 = &tmp[ntmp];
982 struct tmp *t2 = &tmp[ntmp - 1];
983 o_num(sz, 4);
984 o_num(x, 4);
985 tmp_to(t0, R_RAX);
986 tmp_to(t1, R_RCX);
987 tmp_to(t2, R_RDI);
988 os("\xf3\xaa", 2); /* rep stosb */
989 o_tmpdrop(2);
992 long o_mklabel(void)
994 return codeaddr();
997 static long jx(int x, long addr)
999 char op[2] = {0x0f};
1000 op[1] = x;
1001 os(op, 2); /* jx $addr */
1002 oi(addr - codeaddr() - 4, 4);
1003 return codeaddr() - 4;
1006 static long jxtest(int x, long addr)
1008 int bt = tmp_pop(1, R_RAX);
1009 regop1(TEST_R2R, R_RAX, R_RAX, bt);
1010 return jx(x, addr);
1013 static long jxcmp(long addr, int inv)
1015 int x;
1016 if (codeaddr() != cmp_last)
1017 return -1;
1018 o_tmpdrop(1);
1019 cur = buf + cmp_setl;
1020 x = (unsigned char) buf[cmp_setl + 1];
1021 return jx((inv ? x : x ^ 0x01) & ~0x10, addr);
1024 long o_jz(long addr)
1026 long ret = jxcmp(addr, 0);
1027 return ret != -1 ? ret : jxtest(0x84, addr);
1030 long o_jnz(long addr)
1032 long ret = jxcmp(addr, 1);
1033 return ret != -1 ? ret : jxtest(0x85, addr);
1036 long o_jmp(long addr)
1038 os("\xe9", 1); /* jmp $addr */
1039 oi(addr - codeaddr() - 4, 4);
1040 return codeaddr() - 4;
1043 void o_filljmp2(long addr, long jmpdst)
1045 putint(buf + addr, jmpdst - addr - 4, 4);
1048 void o_filljmp(long addr)
1050 o_filljmp2(addr, codeaddr());
1053 void o_call(int argc, unsigned *bt, unsigned ret_bt)
1055 int i;
1056 struct tmp *t;
1057 for (i = 0; i < ARRAY_SIZE(tmpregs); i++)
1058 if (regs[i] && (tmp - regs[i]) < ntmp - argc)
1059 tmp_mem(regs[i]);
1060 if (argc > R_NARGS) {
1061 long addr = sp_push(8 * (argc - R_NARGS));
1062 for (i = argc - 1; i >= R_NARGS; --i) {
1063 int reg = TMP_REG(&tmp[ntmp - 1]);
1064 tmp_pop_bt(bt[i], reg);
1065 memop1(MOV_R2X, reg, R_RBP,
1066 -(addr - (i - R_NARGS) * 8), BT_TMPBT(bt[i]));
1069 for (i = MIN(argc, R_NARGS) - 1; i >= 0; i--)
1070 tmp_pop_bt(bt[i], arg_regs[i]);
1071 t = &tmp[ntmp - 1];
1072 if (t->flags & LOC_SYM) {
1073 os("\x31\xc0", 2); /* xor %eax, %eax */
1074 os("\xe8", 1); /* call $x */
1075 if (!nogen)
1076 out_rela(t->addr, codeaddr(), 1);
1077 oi(-4, 4);
1078 o_tmpdrop(1);
1079 } else {
1080 tmp_pop(0, R_RAX);
1081 regop1(CALL_REG, 2, R_RAX, 4);
1083 if (ret_bt)
1084 tmp_push_reg(ret_bt, R_RAX);
1087 int o_nogen(void)
1089 return nogen++;
1092 void o_dogen(void)
1094 nogen = 0;