handle struct assignment
[neatcc.git] / gen.c
bloba62907846edd5ab33c67c0b7508c391378a4b387
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 R_BYTEMASK (1 << R_RAX | 1 << R_RDX | 1 << R_RCX)
51 #define TMP_BT(t) ((t)->flags & TMP_ADDR ? 8 : (t)->bt)
52 #define TMP_REG(t) ((t)->flags & LOC_REG ? (t)->addr : reg_get(~0))
53 #define TMP_REG2(t, r) ((t)->flags & LOC_REG && (t)->addr != r ? \
54 (t)->addr : reg_get(~(1 << r)))
55 #define TMP_BYTEREG(t) ((t)->flags & LOC_REG && \
56 (1 << (t)->addr) & R_BYTEMASK ? \
57 (t)->addr : reg_get(R_BYTEMASK))
58 #define BT_TMPBT(bt) (BT_SZ(bt) >= 4 ? (bt) : (bt) & BT_SIGNED | 4)
60 static char buf[SECSIZE];
61 static char *cur;
62 static int nogen;
63 static long sp;
64 static long spsub_addr;
65 static long maxsp;
67 static struct tmp {
68 long addr;
69 unsigned flags;
70 unsigned bt;
71 } tmp[MAXTMP];
72 static int ntmp;
74 static int tmpsp;
76 static struct tmp *regs[NREGS];
77 static int tmpregs[] = {R_RAX, R_RDI, R_RSI, R_RDX, R_RCX, R_R8, R_R9};
79 #define MAXRET (1 << 8)
81 static long ret[MAXRET];
82 static int nret;
84 static long cmp_last;
85 static long cmp_setl;
87 static void putint(char *s, long n, int l)
89 if (nogen)
90 return;
91 while (l--) {
92 *s++ = n;
93 n >>= 8;
97 static void os(char *s, int n)
99 if (nogen)
100 return;
101 while (n--)
102 *cur++ = *s++;
105 static void oi(long n, int l)
107 while (l--) {
108 *cur++ = n;
109 n >>= 8;
113 static long codeaddr(void)
115 return cur - buf;
118 static void o_op(int *op, int nop, int r1, int r2, unsigned bt)
120 int rex = 0;
121 int i;
122 if (r1 & 0x8)
123 rex |= 4;
124 if (r2 & 0x8)
125 rex |= 1;
126 if (BT_SZ(bt) == 8)
127 rex |= 8;
128 if (rex || (bt & BT_SZMASK) == 8)
129 oi(0x40 | rex, 1);
130 if ((bt & BT_SZMASK) == 2)
131 oi(0x66, 1);
132 if ((bt & BT_SZMASK) == 1)
133 op[nop - 1] &= ~0x1;
134 for (i = 0; i < nop; i++)
135 oi(op[i], 1);
138 static void memop(int *op, int nop, int src, int base, int off, unsigned bt)
140 int dis = off == (char) off ? 1 : 4;
141 int mod = dis == 4 ? 2 : 1;
142 o_op(op, nop, src, base, bt);
143 if (!off)
144 mod = 0;
145 oi((mod << 6) | ((src & 0x07) << 3) | (base & 0x07), 1);
146 if (off)
147 oi(off, dis);
150 static void memop1(int op, int src, int base, int off, unsigned bt)
152 memop(&op, 1, src, base, off, bt);
155 static void regop(int *op, int nop, int src, int dst, unsigned bt)
157 o_op(op, nop, src, dst, bt);
158 oi((3 << 6) | (src << 3) | (dst & 0x07), 1);
161 static void regop1(int op, int src, int dst, unsigned bt)
163 regop(&op, 1, src, dst, bt);
166 static long sp_push(int size)
168 sp += size;
169 if (sp > maxsp)
170 maxsp = sp;
171 return sp;
174 #define LOC_NEW(f, l) (((f) & ~LOC_MASK) | (l))
176 static void tmp_mem(struct tmp *tmp)
178 int src = tmp->addr;
179 if (!(tmp->flags & LOC_REG))
180 return;
181 if (tmpsp == -1)
182 tmpsp = sp;
183 tmp->addr = sp_push(8);
184 memop1(MOV_R2X, src, R_RBP, -tmp->addr, BT_TMPBT(TMP_BT(tmp)));
185 regs[src] = NULL;
186 tmp->flags = LOC_NEW(tmp->flags, LOC_MEM);
189 static int *movxx_x2r(int bt)
191 static int movxx[2] = {0x0f};
192 if (BT_SZ(bt) == 1)
193 movxx[1] = bt & BT_SIGNED ? 0xbe : 0xb6;
194 else
195 movxx[1] = bt & BT_SIGNED ? 0xbf : 0xb7;
196 return movxx;
199 #define MOVSXD 0x63
201 static void mov_r2r(int r1, int r2, unsigned bt1, unsigned bt2)
203 int s1 = bt1 & BT_SIGNED;
204 int s2 = bt2 & BT_SIGNED;
205 int sz1 = BT_SZ(bt1);
206 int sz2 = BT_SZ(bt2);
207 if (sz2 < 4 && (sz1 >= sz2 && s1 != s2)) {
208 regop(movxx_x2r(bt2), 2, r1, r2, 4);
209 return;
211 if (sz1 == 4 && sz2 == 8) {
212 regop1(MOVSXD, r1, r2, sz2);
213 return;
215 if (r1 != r2 || sz1 > sz2)
216 regop1(MOV_R2X, r1, r2, BT_TMPBT(bt2));
219 static void mov_m2r(int dst, int base, int off, int bt1, int bt2)
221 if (BT_SZ(bt1) < 4) {
222 memop(movxx_x2r(bt1), 2, dst, base, off,
223 bt1 & BT_SIGNED && BT_SZ(bt2) == 8 ? 8 : 4);
224 mov_r2r(dst, dst, bt1, bt2);
225 } else {
226 memop1(MOV_M2R, dst, base, off, bt1);
227 mov_r2r(dst, dst, bt1, bt2);
231 static void num_cast(struct tmp *t, unsigned bt)
233 if (!(bt & BT_SIGNED) && BT_SZ(bt) != 8)
234 t->addr &= ((1l << (long) (BT_SZ(bt) * 8)) - 1);
235 if (bt & BT_SIGNED && BT_SZ(bt) != 8 &&
236 t->addr > (1l << (BT_SZ(bt) * 8 - 1)))
237 t->addr = -((1l << (BT_SZ(bt) * 8)) - t->addr);
238 t->bt = bt;
241 static void num_reg(int reg, unsigned bt, long num)
243 int op = MOV_I2R + (reg & 7);
244 if (BT_SZ(bt) == 8 && num >= 0 && num == (unsigned) num)
245 bt = 4;
246 o_op(&op, 1, 0, reg, bt);
247 oi(num, BT_SZ(bt));
250 static void tmp_reg(struct tmp *tmp, int dst, unsigned bt, int deref)
252 if (!(tmp->flags & TMP_ADDR))
253 deref = 0;
254 if (deref)
255 tmp->flags &= ~TMP_ADDR;
256 if (tmp->flags & LOC_NUM) {
257 num_cast(tmp, bt);
258 tmp->bt = BT_TMPBT(bt);
259 num_reg(dst, tmp->bt, tmp->addr);
260 tmp->addr = dst;
261 regs[dst] = tmp;
262 tmp->flags = LOC_NEW(tmp->flags, LOC_REG);
264 if (tmp->flags & LOC_SYM) {
265 regop1(MOV_I2X, 0, dst, TMP_BT(tmp));
266 if (!nogen)
267 out_rela(tmp->addr, codeaddr(), 0);
268 oi(0, 4);
269 tmp->addr = dst;
270 regs[dst] = tmp;
271 tmp->flags = LOC_NEW(tmp->flags, LOC_REG);
273 if (tmp->flags & LOC_REG) {
274 if (deref)
275 mov_m2r(dst, tmp->addr, 0, tmp->bt, bt);
276 else
277 mov_r2r(tmp->addr, dst, TMP_BT(tmp), bt);
278 regs[tmp->addr] = NULL;
279 tmp->addr = dst;
280 tmp->bt = BT_TMPBT(bt);
281 regs[dst] = tmp;
282 return;
284 if (tmp->flags & LOC_LOCAL) {
285 if (deref)
286 mov_m2r(dst, R_RBP, -tmp->addr, tmp->bt, bt);
287 else
288 memop1(LEA_M2R, dst, R_RBP, -tmp->addr, 8);
290 if (tmp->flags & LOC_MEM) {
291 mov_m2r(dst, R_RBP, -tmp->addr,
292 deref ? 8 : TMP_BT(tmp), deref ? 8 : bt);
293 if (deref)
294 mov_m2r(dst, dst, 0, tmp->bt, bt);
296 tmp->addr = dst;
297 tmp->bt = BT_TMPBT(bt);
298 regs[dst] = tmp;
299 tmp->flags = LOC_NEW(tmp->flags, LOC_REG);
302 static void reg_free(int reg)
304 int i;
305 if (!regs[reg])
306 return;
307 for (i = 0; i < ARRAY_SIZE(tmpregs); i++)
308 if (!regs[tmpregs[i]]) {
309 tmp_reg(regs[reg], tmpregs[i], regs[reg]->bt, 0);
310 return;
312 tmp_mem(regs[reg]);
315 static void reg_for(int reg, struct tmp *t)
317 if (regs[reg] && regs[reg] != t)
318 reg_free(reg);
321 static void tmp_pop_bt(unsigned bt, int reg)
323 struct tmp *t = &tmp[--ntmp];
324 reg_for(reg, t);
325 tmp_reg(t, reg, bt, 1);
326 regs[reg] = NULL;
329 static unsigned tmp_pop(int deref, int reg)
331 struct tmp *t = &tmp[--ntmp];
332 reg_for(reg, t);
333 tmp_reg(t, reg, deref ? t->bt : TMP_BT(t), deref);
334 regs[reg] = NULL;
335 return t->bt;
338 static void tmp_push_reg(unsigned bt, unsigned reg)
340 struct tmp *t = &tmp[ntmp++];
341 t->addr = reg;
342 t->bt = bt;
343 t->flags = LOC_REG;
344 regs[reg] = t;
347 void o_local(long addr, unsigned bt)
349 struct tmp *t = &tmp[ntmp++];
350 t->addr = addr;
351 t->bt = bt;
352 t->flags = LOC_LOCAL | TMP_ADDR;
355 void o_num(long num, unsigned bt)
357 struct tmp *t = &tmp[ntmp++];
358 t->addr = num;
359 t->bt = bt;
360 t->flags = LOC_NUM;
363 void o_symaddr(long addr, unsigned bt)
365 struct tmp *t = &tmp[ntmp++];
366 t->bt = bt;
367 t->addr = addr;
368 t->flags = LOC_SYM | TMP_ADDR;
371 void o_tmpdrop(int n)
373 int i;
374 if (n == -1 || n > ntmp)
375 n = ntmp;
376 ntmp -= n;
377 for (i = ntmp; i < ntmp + n; i++)
378 if (tmp[i].flags & LOC_REG)
379 regs[tmp[i].addr] = NULL;
380 if (!ntmp) {
381 if (tmpsp != -1)
382 sp = tmpsp;
383 tmpsp = -1;
387 #define FORK_REG R_RAX
389 void o_tmpfork(void)
391 struct tmp *t = &tmp[ntmp - 1];
392 reg_for(FORK_REG, t);
393 tmp_reg(t, FORK_REG, t->bt, 0);
394 o_tmpdrop(1);
397 void o_tmpjoin(void)
399 struct tmp *t = &tmp[ntmp - 1];
400 reg_for(FORK_REG, t);
401 tmp_reg(t, FORK_REG, t->bt, 0);
404 void o_tmpswap(void)
406 struct tmp *t1 = &tmp[ntmp - 1];
407 struct tmp *t2 = &tmp[ntmp - 2];
408 struct tmp t;
409 memcpy(&t, t1, sizeof(t));
410 memcpy(t1, t2, sizeof(t));
411 memcpy(t2, &t, sizeof(t));
414 static int reg_get(int mask)
416 int i;
417 for (i = 0; i < ARRAY_SIZE(tmpregs); i++)
418 if ((1 << tmpregs[i]) & mask && !regs[tmpregs[i]])
419 return tmpregs[i];
420 for (i = 0; i < ARRAY_SIZE(tmpregs); i++)
421 if ((1 << tmpregs[i]) & mask) {
422 reg_free(tmpregs[i]);
423 return tmpregs[i];
425 return 0;
428 void o_tmpcopy(void)
430 struct tmp *t1 = &tmp[ntmp - 1];
431 struct tmp *t2 = &tmp[ntmp++];
432 memcpy(t2, t1, sizeof(*t1));
433 if (!(t1->flags & (LOC_REG | LOC_MEM)))
434 return;
435 if (t1->flags & LOC_MEM) {
436 tmp_reg(t2, reg_get(~0), t2->bt, 0);
437 } else if (t1->flags & LOC_REG) {
438 t2->addr = reg_get(~t1->addr);
439 regop1(MOV_R2X, t1->addr, t2->addr, BT_TMPBT(TMP_BT(tmp)));
441 t2->flags = t1->flags;
444 void o_cast(unsigned bt)
446 struct tmp *t = &tmp[ntmp - 1];
447 int reg;
448 if (t->bt == bt)
449 return;
450 if (t->flags & LOC_NUM) {
451 num_cast(t, bt);
452 return;
454 reg = BT_SZ(bt) == 1 ? TMP_BYTEREG(t) : TMP_REG(t);
455 tmp_pop_bt(bt, reg);
456 tmp_push_reg(bt, reg);
459 long o_func_beg(char *name, int global)
461 long addr = out_func_beg(name, global);
462 cur = buf;
463 os("\x55", 1); /* push %rbp */
464 os("\x48\x89\xe5", 3); /* mov %rsp, %rbp */
465 sp = 0;
466 maxsp = 0;
467 ntmp = 0;
468 tmpsp = -1;
469 nret = 0;
470 cmp_last = -1;
471 memset(regs, 0, sizeof(regs));
472 os("\x48\x81\xec", 3); /* sub $xxx, %rsp */
473 spsub_addr = codeaddr();
474 oi(0, 4);
475 return addr;
478 void o_deref(unsigned bt)
480 struct tmp *t = &tmp[ntmp - 1];
481 if (t->flags & TMP_ADDR)
482 tmp_reg(t, TMP_REG(t), 8, 1);
483 t->bt = bt;
484 t->flags |= TMP_ADDR;
487 void o_load(void)
489 struct tmp *t = &tmp[ntmp - 1];
490 tmp_reg(t, TMP_REG(t), t->bt, 1);
493 static unsigned bt_op(unsigned bt1, unsigned bt2)
495 unsigned s1 = BT_SZ(bt1);
496 unsigned s2 = BT_SZ(bt2);
497 unsigned bt = (bt1 | bt2) & BT_SIGNED | (s1 > s2 ? s1 : s2);
498 return BT_TMPBT(bt);
501 #define TMP_CONST(t) ((t)->flags & LOC_NUM && !((t)->flags & TMP_ADDR))
503 int o_popnum(long *c)
505 struct tmp *t = &tmp[ntmp - 1];
506 if (!TMP_CONST(t))
507 return 1;
508 *c = t->addr;
509 o_tmpdrop(1);
510 return 0;
513 static int c_binop(long (*cop)(long a, long b, unsigned bt), unsigned bt)
515 struct tmp *t1 = &tmp[ntmp - 1];
516 struct tmp *t2 = &tmp[ntmp - 2];
517 long ret;
518 if (!TMP_CONST(t1) || !TMP_CONST(t2))
519 return 1;
520 if (!bt)
521 bt = bt_op(t1->bt, t2->bt);
522 ret = cop(t2->addr, t1->addr, bt);
523 o_tmpdrop(2);
524 o_num(ret, bt);
525 return 0;
528 static int c_op(long (*cop)(long a, unsigned bt), unsigned bt)
530 struct tmp *t1 = &tmp[ntmp - 1];
531 long ret;
532 if (!TMP_CONST(t1))
533 return 1;
534 if (!bt)
535 bt = t1->bt;
536 ret = cop(t1->addr, bt);
537 o_tmpdrop(1);
538 o_num(ret, bt);
539 return 0;
542 static void shx(int uop, int sop)
544 struct tmp *t = &tmp[ntmp - 2];
545 unsigned bt;
546 unsigned reg = TMP_REG2(t, R_RCX);
547 tmp_pop(1, R_RCX);
548 bt = tmp_pop(1, reg);
549 regop1(SHX_REG, bt & BT_SIGNED ? sop : uop, reg, BT_TMPBT(bt));
550 tmp_push_reg(bt, reg);
553 static long c_shl(long a, long b, unsigned bt)
555 return a << b;
558 void o_shl(void)
560 if (!c_binop(c_shl, 0))
561 return;
562 shx(4, 4);
565 static long c_shr(long a, long b, unsigned bt)
567 if (bt & BT_SIGNED)
568 return a >> b;
569 else
570 return (unsigned long) a >> b;
573 void o_shr(void)
575 if (!c_binop(c_shr, 0))
576 return;
577 shx(5, 7);
580 static int mulop(int uop, int sop, int reg)
582 struct tmp *t1 = &tmp[ntmp - 1];
583 struct tmp *t2 = &tmp[ntmp - 2];
584 int bt1 = TMP_BT(t1);
585 int bt2 = TMP_BT(t2);
586 int bt = bt_op(bt1, bt2);
587 if (t1->flags & LOC_REG && t1->addr != R_RAX && t1->addr != R_RDX)
588 reg = t1->addr;
589 reg_for(reg, t1);
590 tmp_reg(t1, reg, bt, 1);
591 reg_for(R_RAX, t2);
592 tmp_reg(t2, R_RAX, bt, 1);
593 if (reg != R_RDX)
594 reg_free(R_RDX);
595 o_tmpdrop(2);
596 regop1(MUL_A2X, bt & BT_SIGNED ? sop : uop, reg, BT_TMPBT(bt2));
597 return bt;
600 static long c_mul(long a, long b, unsigned bt)
602 return a * b;
605 void o_mul(void)
607 int bt;
608 if (!c_binop(c_mul, 0))
609 return;
610 bt = mulop(4, 5, R_RDX);
611 tmp_push_reg(bt, R_RAX);
614 static long c_div(long a, long b, unsigned bt)
616 return a / b;
619 void o_div(void)
621 int bt;
622 if (!c_binop(c_div, 0))
623 return;
624 bt = mulop(6, 7, R_RCX);
625 tmp_push_reg(bt, R_RAX);
628 static long c_mod(long a, long b, unsigned bt)
630 return a % b;
633 void o_mod(void)
635 int bt;
636 if (!c_binop(c_mod, 0))
637 return;
638 bt = mulop(6, 7, R_RCX);
639 tmp_push_reg(bt, R_RDX);
642 void o_addr(void)
644 tmp[ntmp - 1].flags &= ~TMP_ADDR;
645 tmp[ntmp - 1].bt = 8;
648 void o_ret(unsigned bt)
650 if (bt)
651 tmp_pop_bt(bt, R_RAX);
652 else
653 os("\x31\xc0", 2); /* xor %eax, %eax */
654 ret[nret++] = o_jmp(0);
657 static int binop(int op, int *reg)
659 struct tmp *t1 = &tmp[ntmp - 1];
660 struct tmp *t2 = &tmp[ntmp - 2];
661 int r1;
662 unsigned bt;
663 r1 = TMP_REG(t1);
664 *reg = TMP_REG2(t2, r1);
665 bt = bt_op(t1->bt, t2->bt);
666 tmp_pop_bt(bt, r1);
667 tmp_pop_bt(bt, *reg);
668 regop1(op, *reg, r1, bt);
669 return bt;
672 static long c_add(long a, long b, unsigned bt)
674 return a + b;
677 void o_add(void)
679 int reg;
680 int bt;
681 if (!c_binop(c_add, 0))
682 return;
683 bt = binop(ADD_R2X, &reg);
684 tmp_push_reg(bt, reg);
687 static long c_xor(long a, long b, unsigned bt)
689 return a ^ b;
692 void o_xor(void)
694 int reg;
695 int bt;
696 if (!c_binop(c_xor, 0))
697 return;
698 bt = binop(XOR_R2X, &reg);
699 tmp_push_reg(bt, reg);
702 static long c_and(long a, long b, unsigned bt)
704 return a & b;
707 void o_and(void)
709 int reg;
710 int bt;
711 if (!c_binop(c_and, 0))
712 return;
713 bt = binop(AND_R2X, &reg);
714 tmp_push_reg(bt, reg);
717 static long c_or(long a, long b, unsigned bt)
719 return a | b;
722 void o_or(void)
724 int reg;
725 int bt;
726 if (!c_binop(c_or, 0))
727 return;
728 bt = binop(OR_R2X, &reg);
729 tmp_push_reg(bt, reg);
732 static long c_sub(long a, long b, unsigned bt)
734 return a - b;
737 void o_sub(void)
739 int reg;
740 int bt;
741 if (!c_binop(c_sub, 0))
742 return;
743 bt = binop(SUB_R2X, &reg);
744 tmp_push_reg(bt, reg);
747 static void o_cmp(int uop, int sop)
749 char set[] = "\x0f\x00\xc0";
750 int reg;
751 int bt = binop(CMP_R2X, &reg);
752 set[1] = bt & BT_SIGNED ? sop : uop;
753 reg_free(R_RAX);
754 cmp_setl = codeaddr();
755 os(set, 3); /* setl %al */
756 os("\x0f\xb6\xc0", 3); /* movzbl %al, %eax */
757 tmp_push_reg(4 | BT_SIGNED, R_RAX);
758 cmp_last = codeaddr();
761 static long c_lt(long a, long b, unsigned bt)
763 return a < b;
766 void o_lt(void)
768 if (!c_binop(c_lt, 4))
769 return;
770 o_cmp(0x92, 0x9c);
773 static long c_gt(long a, long b, unsigned bt)
775 return a > b;
778 void o_gt(void)
780 if (!c_binop(c_gt, 4))
781 return;
782 o_cmp(0x97, 0x9f);
785 static long c_le(long a, long b, unsigned bt)
787 return a <= b;
790 void o_le(void)
792 if (!c_binop(c_le, 4))
793 return;
794 o_cmp(0x96, 0x9e);
797 static long c_ge(long a, long b, unsigned bt)
799 return a >= b;
802 void o_ge(void)
804 if (!c_binop(c_ge, 4))
805 return;
806 o_cmp(0x93, 0x9d);
809 static long c_eq(long a, long b, unsigned bt)
811 return a == b;
814 void o_eq(void)
816 if (!c_binop(c_eq, 4))
817 return;
818 o_cmp(0x94, 0x94);
821 static long c_neq(long a, long b, unsigned bt)
823 return a != b;
826 void o_neq(void)
828 if (!c_binop(c_neq, 4))
829 return;
830 o_cmp(0x95, 0x95);
833 static long c_lnot(long a, unsigned bt)
835 return !a;
838 void o_lnot(void)
840 if (!c_op(c_lnot, 4))
841 return;
842 if (cmp_last == codeaddr()) {
843 buf[cmp_setl + 1] ^= 0x10;
844 } else {
845 o_num(0, 4 | BT_SIGNED);
846 o_eq();
850 static long c_neg(long a, unsigned bt)
852 return -a;
855 void o_neg(void)
857 struct tmp *t = &tmp[ntmp - 1];
858 int reg;
859 unsigned bt = BT_TMPBT(t->bt);
860 if (!c_op(c_neg, t->bt | BT_SIGNED))
861 return;
862 reg = TMP_REG(t);
863 tmp_pop_bt(bt, reg);
864 regop1(NEG_REG, 3, reg, bt);
865 tmp_push_reg(bt, reg);
868 static long c_not(long a, unsigned bt)
870 return ~a;
873 void o_not(void)
875 struct tmp *t = &tmp[ntmp - 1];
876 int reg;
877 unsigned bt = BT_TMPBT(t->bt);
878 if (!c_op(c_not, 0))
879 return;
880 reg = TMP_REG(t);
881 tmp_pop_bt(bt, reg);
882 regop1(NOT_REG, 2, reg, bt);
883 tmp_push_reg(t->bt, reg);
886 void o_func_end(void)
888 int i;
889 for (i = 0; i < nret; i++)
890 o_filljmp(ret[i]);
891 os("\xc9\xc3", 2); /* leave; ret; */
892 putint(buf + spsub_addr, (maxsp + 7) & ~0x07, 4);
893 out_func_end(buf, cur - buf);
896 long o_mklocal(int size)
898 return sp_push((size + 7) & ~0x07);
901 void o_rmlocal(long addr, int sz)
903 sp = addr - sz;
906 static int arg_regs[] = {R_RDI, R_RSI, R_RDX, R_RCX, R_R8, R_R9};
908 long o_arg(int i, unsigned bt)
910 long addr = o_mklocal(BT_SZ(bt));
911 memop1(MOV_R2X, arg_regs[i], R_RBP, -addr, bt);
912 return addr;
915 void o_assign(unsigned bt)
917 struct tmp *t1 = &tmp[ntmp - 1];
918 struct tmp *t2 = &tmp[ntmp - 2];
919 int r1 = BT_SZ(bt) > 1 ? TMP_REG(t1) : TMP_BYTEREG(t1);
920 int reg;
921 int off;
922 tmp_pop_bt(BT_TMPBT(bt), r1);
923 if (t2->flags & LOC_LOCAL) {
924 reg = R_RBP;
925 off = -t2->addr;
926 o_tmpdrop(1);
927 } else {
928 reg = TMP_REG2(t2, r1);
929 off = 0;
930 tmp_pop(0, reg);
932 memop1(MOV_R2X, r1, reg, off, bt);
933 tmp_push_reg(bt, r1);
936 static void tmp_to(struct tmp *t, int reg)
938 reg_for(reg, t);
939 tmp_reg(t, reg, t->bt, 0);
942 void o_memcpy(int sz)
944 struct tmp *t0 = &tmp[ntmp];
945 struct tmp *t1 = &tmp[ntmp - 1];
946 struct tmp *t2 = &tmp[ntmp - 2];
947 o_num(sz, 4);
948 tmp_to(t0, R_RCX);
949 tmp_to(t1, R_RSI);
950 tmp_to(t2, R_RDI);
951 os("\xf3\xa4", 2); /* rep movs */
952 o_tmpdrop(2);
955 long o_mklabel(void)
957 return codeaddr();
960 static long jx(int x, long addr)
962 char op[2] = {0x0f};
963 op[1] = x;
964 os(op, 2); /* jx $addr */
965 oi(addr - codeaddr() - 4, 4);
966 return codeaddr() - 4;
969 static long jxtest(int x, long addr)
971 int bt = tmp_pop(1, R_RAX);
972 regop1(TEST_R2R, R_RAX, R_RAX, bt);
973 return jx(x, addr);
976 static long jxcmp(long addr, int inv)
978 int x;
979 if (codeaddr() != cmp_last)
980 return -1;
981 o_tmpdrop(1);
982 cur = buf + cmp_setl;
983 x = (unsigned char) buf[cmp_setl + 1];
984 return jx((inv ? x : x ^ 0x01) & ~0x10, addr);
987 long o_jz(long addr)
989 long ret = jxcmp(addr, 0);
990 return ret != -1 ? ret : jxtest(0x84, addr);
993 long o_jnz(long addr)
995 long ret = jxcmp(addr, 1);
996 return ret != -1 ? ret : jxtest(0x85, addr);
999 long o_jmp(long addr)
1001 os("\xe9", 1); /* jmp $addr */
1002 oi(addr - codeaddr() - 4, 4);
1003 return codeaddr() - 4;
1006 void o_filljmp2(long addr, long jmpdst)
1008 putint(buf + addr, jmpdst - addr - 4, 4);
1011 void o_filljmp(long addr)
1013 o_filljmp2(addr, codeaddr());
1016 void o_call(int argc, unsigned *bt, unsigned ret_bt)
1018 int i;
1019 struct tmp *t;
1020 for (i = 0; i < argc; i++)
1021 tmp_pop_bt(bt[argc - i - 1], arg_regs[argc - i - 1]);
1022 t = &tmp[ntmp - 1];
1023 if (t->flags & LOC_SYM) {
1024 os("\x31\xc0", 2); /* xor %eax, %eax */
1025 os("\xe8", 1); /* call $x */
1026 if (!nogen)
1027 out_rela(t->addr, codeaddr(), 1);
1028 oi(-4, 4);
1029 o_tmpdrop(1);
1030 } else {
1031 tmp_pop(0, R_RAX);
1032 regop1(CALL_REG, 2, R_RAX, 4);
1034 for (i = 0; i < ARRAY_SIZE(tmpregs); i++)
1035 if (regs[i])
1036 tmp_mem(regs[i]);
1037 if (ret_bt)
1038 tmp_push_reg(ret_bt, R_RAX);
1041 int o_nogen(void)
1043 return nogen++;
1046 void o_dogen(void)
1048 nogen = 0;