gen: extend eax to edx for mul/div op
[neatcc.git] / gen.c
blob104164fc5328a070c39cf56df35161a4efe13396
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 long off; /* used for LOC_SYM; offset from a symbol address */
72 unsigned flags;
73 unsigned bt;
74 } tmp[MAXTMP];
75 static int ntmp;
77 static int tmpsp;
79 static struct tmp *regs[NREGS];
80 static int tmpregs[] = {R_RAX, R_RDI, R_RSI, R_RDX, R_RCX, R_R8, R_R9};
82 #define MAXRET (1 << 8)
84 static long ret[MAXRET];
85 static int nret;
87 static long cmp_last;
88 static long cmp_setl;
90 static void putint(char *s, long n, int l)
92 if (nogen)
93 return;
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 while (l--) {
111 *cur++ = n;
112 n >>= 8;
116 static long codeaddr(void)
118 return cur - buf;
121 static void o_op(int *op, int nop, int r1, int r2, unsigned bt)
123 int rex = 0;
124 int i;
125 if (r1 & 0x8)
126 rex |= 4;
127 if (r2 & 0x8)
128 rex |= 1;
129 if (BT_SZ(bt) == 8)
130 rex |= 8;
131 if (rex || (bt & BT_SZMASK) == 8)
132 oi(0x40 | rex, 1);
133 if ((bt & BT_SZMASK) == 2)
134 oi(0x66, 1);
135 if ((bt & BT_SZMASK) == 1)
136 op[nop - 1] &= ~0x1;
137 for (i = 0; i < nop; i++)
138 oi(op[i], 1);
141 static void memop(int *op, int nop, int src, int base, int off, unsigned bt)
143 int dis = off == (char) off ? 1 : 4;
144 int mod = dis == 4 ? 2 : 1;
145 o_op(op, nop, src, base, bt);
146 if (!off)
147 mod = 0;
148 oi((mod << 6) | ((src & 0x07) << 3) | (base & 0x07), 1);
149 if (off)
150 oi(off, dis);
153 static void memop1(int op, int src, int base, int off, unsigned bt)
155 memop(&op, 1, src, base, off, bt);
158 static void regop(int *op, int nop, int src, int dst, unsigned bt)
160 o_op(op, nop, src, dst, bt);
161 oi((3 << 6) | (src << 3) | (dst & 0x07), 1);
164 static void regop1(int op, int src, int dst, unsigned bt)
166 regop(&op, 1, src, dst, bt);
169 static long sp_push(int size)
171 sp += size;
172 if (sp > maxsp)
173 maxsp = sp;
174 return sp;
177 #define LOC_NEW(f, l) (((f) & ~LOC_MASK) | (l))
179 static void tmp_mem(struct tmp *tmp)
181 int src = tmp->addr;
182 if (!(tmp->flags & LOC_REG))
183 return;
184 if (tmpsp == -1)
185 tmpsp = sp;
186 tmp->addr = -sp_push(8);
187 memop1(MOV_R2X, src, R_RBP, tmp->addr, BT_TMPBT(TMP_BT(tmp)));
188 regs[src] = NULL;
189 tmp->flags = LOC_NEW(tmp->flags, LOC_MEM);
192 static int *movxx_x2r(int bt)
194 static int movxx[2] = {0x0f};
195 if (BT_SZ(bt) == 1)
196 movxx[1] = bt & BT_SIGNED ? 0xbe : 0xb6;
197 else
198 movxx[1] = bt & BT_SIGNED ? 0xbf : 0xb7;
199 return movxx;
202 #define MOVSXD 0x63
204 static void mov_r2r(int r1, int r2, unsigned bt1, unsigned bt2)
206 int s1 = bt1 & BT_SIGNED;
207 int s2 = bt2 & BT_SIGNED;
208 int sz1 = BT_SZ(bt1);
209 int sz2 = BT_SZ(bt2);
210 if (sz2 < 4 && (sz1 >= sz2 && s1 != s2)) {
211 regop(movxx_x2r(bt2), 2, r1, r2, 4);
212 return;
214 if (sz1 == 4 && sz2 == 8) {
215 regop1(MOVSXD, r2, r1, sz2);
216 return;
218 if (r1 != r2 || sz1 > sz2)
219 regop1(MOV_R2X, r1, r2, BT_TMPBT(bt2));
222 static void mov_m2r(int dst, int base, int off, int bt1, int bt2)
224 if (BT_SZ(bt1) < 4) {
225 memop(movxx_x2r(bt1), 2, dst, base, off,
226 bt1 & BT_SIGNED && BT_SZ(bt2) == 8 ? 8 : 4);
227 mov_r2r(dst, dst, bt1, bt2);
228 } else {
229 memop1(MOV_M2R, dst, base, off, bt1);
230 mov_r2r(dst, dst, bt1, bt2);
234 static void num_cast(struct tmp *t, unsigned bt)
236 if (!(bt & BT_SIGNED) && BT_SZ(bt) != 8)
237 t->addr &= ((1l << (long) (BT_SZ(bt) * 8)) - 1);
238 if (bt & BT_SIGNED && BT_SZ(bt) != 8 &&
239 t->addr > (1l << (BT_SZ(bt) * 8 - 1)))
240 t->addr = -((1l << (BT_SZ(bt) * 8)) - t->addr);
241 t->bt = bt;
244 static void num_reg(int reg, unsigned bt, long num)
246 int op = MOV_I2R + (reg & 7);
247 if (BT_SZ(bt) == 8 && num >= 0 && num == (unsigned) num)
248 bt = 4;
249 o_op(&op, 1, 0, reg, bt);
250 oi(num, BT_SZ(bt));
253 static void tmp_reg(struct tmp *tmp, int dst, unsigned bt, int deref)
255 if (!(tmp->flags & TMP_ADDR))
256 deref = 0;
257 if (deref)
258 tmp->flags &= ~TMP_ADDR;
259 if (tmp->flags & LOC_NUM) {
260 num_cast(tmp, bt);
261 tmp->bt = BT_TMPBT(bt);
262 num_reg(dst, tmp->bt, tmp->addr);
263 tmp->addr = dst;
264 regs[dst] = tmp;
265 tmp->flags = LOC_NEW(tmp->flags, LOC_REG);
267 if (tmp->flags & LOC_SYM) {
268 regop1(MOV_I2X, 0, dst, TMP_BT(tmp));
269 if (!nogen)
270 out_rela(tmp->addr, codeaddr(), 0);
271 oi(tmp->off, 4);
272 tmp->addr = dst;
273 regs[dst] = tmp;
274 tmp->flags = LOC_NEW(tmp->flags, LOC_REG);
276 if (tmp->flags & LOC_REG) {
277 if (deref)
278 mov_m2r(dst, tmp->addr, 0, tmp->bt, bt);
279 else
280 mov_r2r(tmp->addr, dst, TMP_BT(tmp), bt);
281 regs[tmp->addr] = NULL;
282 tmp->addr = dst;
283 tmp->bt = BT_TMPBT(bt);
284 regs[dst] = tmp;
285 return;
287 if (tmp->flags & LOC_LOCAL) {
288 if (deref)
289 mov_m2r(dst, R_RBP, tmp->addr, tmp->bt, bt);
290 else
291 memop1(LEA_M2R, dst, R_RBP, tmp->addr, 8);
293 if (tmp->flags & LOC_MEM) {
294 mov_m2r(dst, R_RBP, tmp->addr,
295 deref ? 8 : TMP_BT(tmp), deref ? 8 : bt);
296 if (deref)
297 mov_m2r(dst, dst, 0, tmp->bt, bt);
299 tmp->addr = dst;
300 tmp->bt = BT_TMPBT(bt);
301 regs[dst] = tmp;
302 tmp->flags = LOC_NEW(tmp->flags, LOC_REG);
305 static void reg_free(int reg)
307 int i;
308 if (!regs[reg])
309 return;
310 for (i = 0; i < ARRAY_SIZE(tmpregs); i++)
311 if (!regs[tmpregs[i]]) {
312 tmp_reg(regs[reg], tmpregs[i], regs[reg]->bt, 0);
313 return;
315 tmp_mem(regs[reg]);
318 static void reg_for(int reg, struct tmp *t)
320 if (regs[reg] && regs[reg] != t)
321 reg_free(reg);
324 static void tmp_pop_bt(unsigned bt, int reg)
326 struct tmp *t = &tmp[--ntmp];
327 reg_for(reg, t);
328 tmp_reg(t, reg, bt, 1);
329 regs[reg] = NULL;
332 static unsigned tmp_pop(int deref, int reg)
334 struct tmp *t = &tmp[--ntmp];
335 reg_for(reg, t);
336 tmp_reg(t, reg, deref ? t->bt : TMP_BT(t), deref);
337 regs[reg] = NULL;
338 return t->bt;
341 static struct tmp *tmp_new(void)
343 cmp_last = -1;
344 return &tmp[ntmp++];
347 static void tmp_push_reg(unsigned bt, unsigned reg)
349 struct tmp *t = tmp_new();
350 t->addr = reg;
351 t->bt = bt;
352 t->flags = LOC_REG;
353 regs[reg] = t;
356 void o_local(long addr, unsigned bt)
358 struct tmp *t = tmp_new();
359 t->addr = -addr;
360 t->bt = bt;
361 t->flags = LOC_LOCAL | TMP_ADDR;
364 void o_num(long num, unsigned bt)
366 struct tmp *t = tmp_new();
367 t->addr = num;
368 t->bt = bt;
369 t->flags = LOC_NUM;
372 void o_symaddr(long addr, unsigned bt)
374 struct tmp *t = tmp_new();
375 t->bt = bt;
376 t->addr = addr;
377 t->flags = LOC_SYM | TMP_ADDR;
378 t->off = 0;
381 void o_tmpdrop(int n)
383 int i;
384 cmp_last = -1;
385 if (n == -1 || n > ntmp)
386 n = ntmp;
387 ntmp -= n;
388 for (i = ntmp; i < ntmp + n; i++)
389 if (tmp[i].flags & LOC_REG)
390 regs[tmp[i].addr] = NULL;
391 if (!ntmp) {
392 if (tmpsp != -1)
393 sp = tmpsp;
394 tmpsp = -1;
398 #define FORK_REG R_RAX
400 void o_tmpfork(void)
402 struct tmp *t = &tmp[ntmp - 1];
403 reg_for(FORK_REG, t);
404 tmp_reg(t, FORK_REG, t->bt, 1);
405 o_tmpdrop(1);
408 void o_tmpjoin(void)
410 struct tmp *t = &tmp[ntmp - 1];
411 reg_for(FORK_REG, t);
412 tmp_reg(t, FORK_REG, t->bt, 1);
415 void o_tmpswap(void)
417 struct tmp *t1 = &tmp[ntmp - 1];
418 struct tmp *t2 = &tmp[ntmp - 2];
419 struct tmp t;
420 memcpy(&t, t1, sizeof(t));
421 memcpy(t1, t2, sizeof(t));
422 memcpy(t2, &t, sizeof(t));
425 static int reg_get(int mask)
427 int i;
428 for (i = 0; i < ARRAY_SIZE(tmpregs); i++)
429 if ((1 << tmpregs[i]) & mask && !regs[tmpregs[i]])
430 return tmpregs[i];
431 for (i = 0; i < ARRAY_SIZE(tmpregs); i++)
432 if ((1 << tmpregs[i]) & mask) {
433 reg_free(tmpregs[i]);
434 return tmpregs[i];
436 return 0;
439 void o_tmpcopy(void)
441 struct tmp *t1 = &tmp[ntmp - 1];
442 struct tmp *t2 = tmp_new();
443 memcpy(t2, t1, sizeof(*t1));
444 if (!(t1->flags & (LOC_REG | LOC_MEM)))
445 return;
446 if (t1->flags & LOC_MEM) {
447 tmp_reg(t2, reg_get(~0), t2->bt, 0);
448 } else if (t1->flags & LOC_REG) {
449 t2->addr = reg_get(~t1->addr);
450 regop1(MOV_R2X, t1->addr, t2->addr, BT_TMPBT(TMP_BT(t1)));
452 t2->flags = t1->flags;
455 void o_cast(unsigned bt)
457 struct tmp *t = &tmp[ntmp - 1];
458 int reg;
459 if (t->bt == bt)
460 return;
461 if (t->flags & LOC_NUM) {
462 num_cast(t, bt);
463 return;
465 reg = BT_SZ(bt) == 1 ? TMP_BYTEREG(t) : TMP_REG(t);
466 tmp_pop_bt(bt, reg);
467 tmp_push_reg(bt, reg);
470 long o_func_beg(char *name, int global)
472 long addr = out_func_beg(name, global);
473 cur = buf;
474 os("\x55", 1); /* push %rbp */
475 os("\x48\x89\xe5", 3); /* mov %rsp, %rbp */
476 sp = 0;
477 maxsp = 0;
478 ntmp = 0;
479 tmpsp = -1;
480 nret = 0;
481 cmp_last = -1;
482 memset(regs, 0, sizeof(regs));
483 os("\x48\x81\xec", 3); /* sub $xxx, %rsp */
484 spsub_addr = codeaddr();
485 oi(0, 4);
486 return addr;
489 void o_deref(unsigned bt)
491 struct tmp *t = &tmp[ntmp - 1];
492 if (t->flags & TMP_ADDR)
493 tmp_reg(t, TMP_REG(t), 8, 1);
494 t->bt = bt;
495 t->flags |= TMP_ADDR;
498 void o_load(void)
500 struct tmp *t = &tmp[ntmp - 1];
501 tmp_reg(t, TMP_REG(t), t->bt, 1);
504 static unsigned bt_op(unsigned bt1, unsigned bt2)
506 unsigned s1 = BT_SZ(bt1);
507 unsigned s2 = BT_SZ(bt2);
508 unsigned bt = (bt1 | bt2) & BT_SIGNED | (s1 > s2 ? s1 : s2);
509 return BT_TMPBT(bt);
512 #define TMP_CONST(t) ((t)->flags & LOC_NUM && !((t)->flags & TMP_ADDR))
513 #define LOCAL_PTR(t) ((t)->flags & LOC_LOCAL && !((t)->flags & TMP_ADDR))
514 #define SYM_PTR(t) ((t)->flags & LOC_LOCAL && !((t)->flags & TMP_ADDR))
516 int o_popnum(long *c)
518 struct tmp *t = &tmp[ntmp - 1];
519 if (!TMP_CONST(t))
520 return 1;
521 *c = t->addr;
522 o_tmpdrop(1);
523 return 0;
526 static int c_binop(long (*cop)(long a, long b, unsigned bt), unsigned bt)
528 struct tmp *t1 = &tmp[ntmp - 1];
529 struct tmp *t2 = &tmp[ntmp - 2];
530 int locals = LOCAL_PTR(t1) + LOCAL_PTR(t2);
531 int syms = SYM_PTR(t1) + SYM_PTR(t2);
532 int nums = TMP_CONST(t1) + TMP_CONST(t2);
533 if (syms == 2 || syms && locals || syms + nums + locals != 2)
534 return 1;
535 if (!bt) {
536 if (!locals)
537 bt = syms ? 8 : bt_op(t1->bt, t2->bt);
538 if (locals == 1)
539 bt = 8;
540 if (locals == 2)
541 bt = 4 | BT_SIGNED;
543 if (syms) {
544 long o1 = SYM_PTR(t1) ? t1->off : t1->addr;
545 long o2 = SYM_PTR(t2) ? t2->off : t2->addr;
546 long ret = cop(o2, o1, bt);
547 if (!SYM_PTR(t2))
548 o_tmpswap();
549 t2->off = ret;
550 o_tmpdrop(1);
551 } else {
552 long ret = cop(t2->addr, t1->addr, locals ? 4 | BT_SIGNED : bt);
553 o_tmpdrop(2);
554 if (locals == 1) {
555 o_local(-ret, bt);
556 o_addr();
557 } else {
558 o_num(ret, bt);
561 return 0;
564 static int c_op(long (*cop)(long a, unsigned bt), unsigned bt)
566 struct tmp *t1 = &tmp[ntmp - 1];
567 long ret;
568 if (!TMP_CONST(t1))
569 return 1;
570 if (!bt)
571 bt = t1->bt;
572 ret = cop(t1->addr, bt);
573 o_tmpdrop(1);
574 o_num(ret, bt);
575 return 0;
578 static void shx(int uop, int sop)
580 struct tmp *t = &tmp[ntmp - 2];
581 unsigned bt;
582 unsigned reg = TMP_REG2(t, R_RCX);
583 tmp_pop(1, R_RCX);
584 bt = tmp_pop(1, reg);
585 regop1(SHX_REG, bt & BT_SIGNED ? sop : uop, reg, BT_TMPBT(bt));
586 tmp_push_reg(bt, reg);
589 static long c_shl(long a, long b, unsigned bt)
591 return a << b;
594 void o_shl(void)
596 if (!c_binop(c_shl, 0))
597 return;
598 shx(4, 4);
601 static long c_shr(long a, long b, unsigned bt)
603 if (bt & BT_SIGNED)
604 return a >> b;
605 else
606 return (unsigned long) a >> b;
609 void o_shr(void)
611 if (!c_binop(c_shr, 0))
612 return;
613 shx(5, 7);
616 static int mulop(int uop, int sop, int reg)
618 struct tmp *t1 = &tmp[ntmp - 1];
619 struct tmp *t2 = &tmp[ntmp - 2];
620 int bt1 = TMP_BT(t1);
621 int bt2 = TMP_BT(t2);
622 int bt = bt_op(bt1, bt2);
623 if (t1->flags & LOC_REG && t1->addr != R_RAX && t1->addr != R_RDX)
624 reg = t1->addr;
625 reg_for(reg, t1);
626 tmp_reg(t1, reg, bt, 1);
627 reg_for(R_RAX, t2);
628 tmp_reg(t2, R_RAX, bt, 1);
629 if (reg != R_RDX) {
630 int cqo = 0x99;
631 reg_free(R_RDX);
632 if (bt & BT_SIGNED)
633 o_op(&cqo, 1, R_RAX, R_RDX, bt);
634 else
635 bt = regop1(XOR_R2X, R_RDX, R_RDX, bt);
637 o_tmpdrop(2);
638 regop1(MUL_A2X, bt & BT_SIGNED ? sop : uop, reg, BT_TMPBT(bt2));
639 return bt;
642 static long c_mul(long a, long b, unsigned bt)
644 return a * b;
647 void o_mul(void)
649 int bt;
650 if (!c_binop(c_mul, 0))
651 return;
652 bt = mulop(4, 5, R_RDX);
653 tmp_push_reg(bt, R_RAX);
656 static long c_div(long a, long b, unsigned bt)
658 return a / b;
661 void o_div(void)
663 int bt;
664 if (!c_binop(c_div, 0))
665 return;
666 bt = mulop(6, 7, R_RCX);
667 tmp_push_reg(bt, R_RAX);
670 static long c_mod(long a, long b, unsigned bt)
672 return a % b;
675 void o_mod(void)
677 int bt;
678 if (!c_binop(c_mod, 0))
679 return;
680 bt = mulop(6, 7, R_RCX);
681 tmp_push_reg(bt, R_RDX);
684 void o_addr(void)
686 tmp[ntmp - 1].flags &= ~TMP_ADDR;
687 tmp[ntmp - 1].bt = 8;
690 void o_ret(unsigned bt)
692 if (bt)
693 tmp_pop_bt(bt, R_RAX);
694 else
695 os("\x31\xc0", 2); /* xor %eax, %eax */
696 ret[nret++] = o_jmp(0);
699 static int binop(int op, int *reg)
701 struct tmp *t1 = &tmp[ntmp - 1];
702 struct tmp *t2 = &tmp[ntmp - 2];
703 int r1;
704 unsigned bt;
705 r1 = TMP_REG(t1);
706 *reg = TMP_REG2(t2, r1);
707 bt = bt_op(t1->bt, t2->bt);
708 tmp_pop_bt(bt, r1);
709 tmp_pop_bt(bt, *reg);
710 regop1(op, *reg, r1, bt);
711 return bt;
714 static long c_add(long a, long b, unsigned bt)
716 return a + b;
719 void o_add(void)
721 int reg;
722 int bt;
723 if (!c_binop(c_add, 0))
724 return;
725 bt = binop(ADD_R2X, &reg);
726 tmp_push_reg(bt, reg);
729 static long c_xor(long a, long b, unsigned bt)
731 return a ^ b;
734 void o_xor(void)
736 int reg;
737 int bt;
738 if (!c_binop(c_xor, 0))
739 return;
740 bt = binop(XOR_R2X, &reg);
741 tmp_push_reg(bt, reg);
744 static long c_and(long a, long b, unsigned bt)
746 return a & b;
749 void o_and(void)
751 int reg;
752 int bt;
753 if (!c_binop(c_and, 0))
754 return;
755 bt = binop(AND_R2X, &reg);
756 tmp_push_reg(bt, reg);
759 static long c_or(long a, long b, unsigned bt)
761 return a | b;
764 void o_or(void)
766 int reg;
767 int bt;
768 if (!c_binop(c_or, 0))
769 return;
770 bt = binop(OR_R2X, &reg);
771 tmp_push_reg(bt, reg);
774 static long c_sub(long a, long b, unsigned bt)
776 return a - b;
779 void o_sub(void)
781 int reg;
782 int bt;
783 if (!c_binop(c_sub, 0))
784 return;
785 bt = binop(SUB_R2X, &reg);
786 tmp_push_reg(bt, reg);
789 static void o_cmp(int uop, int sop)
791 char set[] = "\x0f\x00\xc0";
792 int reg;
793 int bt = binop(CMP_R2X, &reg);
794 set[1] = bt & BT_SIGNED ? sop : uop;
795 reg_free(R_RAX);
796 cmp_setl = codeaddr();
797 os(set, 3); /* setl %al */
798 os("\x0f\xb6\xc0", 3); /* movzbl %al, %eax */
799 tmp_push_reg(4 | BT_SIGNED, R_RAX);
800 cmp_last = codeaddr();
803 static long c_lt(long a, long b, unsigned bt)
805 return a < b;
808 void o_lt(void)
810 if (!c_binop(c_lt, 4))
811 return;
812 o_cmp(0x92, 0x9c);
815 static long c_gt(long a, long b, unsigned bt)
817 return a > b;
820 void o_gt(void)
822 if (!c_binop(c_gt, 4))
823 return;
824 o_cmp(0x97, 0x9f);
827 static long c_le(long a, long b, unsigned bt)
829 return a <= b;
832 void o_le(void)
834 if (!c_binop(c_le, 4))
835 return;
836 o_cmp(0x96, 0x9e);
839 static long c_ge(long a, long b, unsigned bt)
841 return a >= b;
844 void o_ge(void)
846 if (!c_binop(c_ge, 4))
847 return;
848 o_cmp(0x93, 0x9d);
851 static long c_eq(long a, long b, unsigned bt)
853 return a == b;
856 void o_eq(void)
858 if (!c_binop(c_eq, 4))
859 return;
860 o_cmp(0x94, 0x94);
863 static long c_neq(long a, long b, unsigned bt)
865 return a != b;
868 void o_neq(void)
870 if (!c_binop(c_neq, 4))
871 return;
872 o_cmp(0x95, 0x95);
875 static long c_lnot(long a, unsigned bt)
877 return !a;
880 void o_lnot(void)
882 if (!c_op(c_lnot, 4))
883 return;
884 if (cmp_last == codeaddr()) {
885 buf[cmp_setl + 1] ^= 0x10;
886 } else {
887 o_num(0, 4 | BT_SIGNED);
888 o_eq();
892 static long c_neg(long a, unsigned bt)
894 return -a;
897 void o_neg(void)
899 struct tmp *t = &tmp[ntmp - 1];
900 int reg;
901 unsigned bt = BT_TMPBT(t->bt);
902 if (!c_op(c_neg, t->bt | BT_SIGNED))
903 return;
904 reg = TMP_REG(t);
905 tmp_pop_bt(bt, reg);
906 regop1(NEG_REG, 3, reg, bt);
907 tmp_push_reg(bt, reg);
910 static long c_not(long a, unsigned bt)
912 return ~a;
915 void o_not(void)
917 struct tmp *t = &tmp[ntmp - 1];
918 int reg;
919 unsigned bt = BT_TMPBT(t->bt);
920 if (!c_op(c_not, 0))
921 return;
922 reg = TMP_REG(t);
923 tmp_pop_bt(bt, reg);
924 regop1(NOT_REG, 2, reg, bt);
925 tmp_push_reg(t->bt, reg);
928 void o_func_end(void)
930 int i;
931 for (i = 0; i < nret; i++)
932 o_filljmp(ret[i]);
933 os("\xc9\xc3", 2); /* leave; ret; */
934 putint(buf + spsub_addr, (maxsp + 7) & ~0x07, 4);
935 out_func_end(buf, cur - buf);
938 long o_mklocal(int size)
940 return sp_push((size + 7) & ~0x07);
943 void o_rmlocal(long addr, int sz)
945 sp = addr - sz;
948 static int arg_regs[] = {R_RDI, R_RSI, R_RDX, R_RCX, R_R8, R_R9};
950 #define R_NARGS ARRAY_SIZE(arg_regs)
952 long o_arg(int i, unsigned bt)
954 long addr;
955 if (i < R_NARGS) {
956 addr = o_mklocal(BT_SZ(bt));
957 memop1(MOV_R2X, arg_regs[i], R_RBP, -addr, bt);
958 } else {
959 addr = -8 * (i - R_NARGS + 2);
961 return addr;
964 void o_assign(unsigned bt)
966 struct tmp *t1 = &tmp[ntmp - 1];
967 struct tmp *t2 = &tmp[ntmp - 2];
968 int r1 = BT_SZ(bt) > 1 ? TMP_REG(t1) : TMP_BYTEREG(t1);
969 int reg;
970 int off;
971 tmp_pop_bt(BT_TMPBT(bt), r1);
972 if (t2->flags & LOC_LOCAL) {
973 reg = R_RBP;
974 off = t2->addr;
975 o_tmpdrop(1);
976 } else {
977 reg = TMP_REG2(t2, r1);
978 off = 0;
979 tmp_pop(0, reg);
981 memop1(MOV_R2X, r1, reg, off, bt);
982 tmp_push_reg(bt, r1);
985 static void tmp_to(struct tmp *t, int reg)
987 reg_for(reg, t);
988 tmp_reg(t, reg, t->bt, 0);
991 void o_memcpy(int sz)
993 struct tmp *t0 = &tmp[ntmp];
994 struct tmp *t1 = &tmp[ntmp - 1];
995 struct tmp *t2 = &tmp[ntmp - 2];
996 o_num(sz, 4);
997 tmp_to(t0, R_RCX);
998 tmp_to(t1, R_RSI);
999 tmp_to(t2, R_RDI);
1000 os("\xf3\xa4", 2); /* rep movs */
1001 o_tmpdrop(2);
1004 void o_memset(int x, int sz)
1006 struct tmp *t0 = &tmp[ntmp + 1];
1007 struct tmp *t1 = &tmp[ntmp];
1008 struct tmp *t2 = &tmp[ntmp - 1];
1009 o_num(sz, 4);
1010 o_num(x, 4);
1011 tmp_to(t0, R_RAX);
1012 tmp_to(t1, R_RCX);
1013 tmp_to(t2, R_RDI);
1014 os("\xf3\xaa", 2); /* rep stosb */
1015 o_tmpdrop(2);
1018 long o_mklabel(void)
1020 return codeaddr();
1023 static long jx(int x, long addr)
1025 char op[2] = {0x0f};
1026 op[1] = x;
1027 os(op, 2); /* jx $addr */
1028 oi(addr - codeaddr() - 4, 4);
1029 return codeaddr() - 4;
1032 static long jxtest(int x, long addr)
1034 int bt = tmp_pop(1, R_RAX);
1035 regop1(TEST_R2R, R_RAX, R_RAX, bt);
1036 return jx(x, addr);
1039 static long jxcmp(long addr, int inv)
1041 int x;
1042 if (codeaddr() != cmp_last)
1043 return -1;
1044 o_tmpdrop(1);
1045 cur = buf + cmp_setl;
1046 x = (unsigned char) buf[cmp_setl + 1];
1047 return jx((inv ? x : x ^ 0x01) & ~0x10, addr);
1050 long o_jz(long addr)
1052 long ret = jxcmp(addr, 0);
1053 return ret != -1 ? ret : jxtest(0x84, addr);
1056 long o_jnz(long addr)
1058 long ret = jxcmp(addr, 1);
1059 return ret != -1 ? ret : jxtest(0x85, addr);
1062 long o_jmp(long addr)
1064 os("\xe9", 1); /* jmp $addr */
1065 oi(addr - codeaddr() - 4, 4);
1066 return codeaddr() - 4;
1069 void o_filljmp2(long addr, long jmpdst)
1071 putint(buf + addr, jmpdst - addr - 4, 4);
1074 void o_filljmp(long addr)
1076 o_filljmp2(addr, codeaddr());
1079 void o_call(int argc, unsigned *bt, unsigned ret_bt)
1081 int i;
1082 struct tmp *t;
1083 for (i = 0; i < ARRAY_SIZE(tmpregs); i++)
1084 if (regs[tmpregs[i]] && regs[tmpregs[i]] - tmp < ntmp - argc)
1085 tmp_mem(regs[tmpregs[i]]);
1086 if (argc > R_NARGS) {
1087 long addr = sp_push(8 * (argc - R_NARGS));
1088 for (i = argc - 1; i >= R_NARGS; --i) {
1089 int reg = TMP_REG(&tmp[ntmp - 1]);
1090 tmp_pop_bt(bt[i], reg);
1091 memop1(MOV_R2X, reg, R_RBP,
1092 -(addr - (i - R_NARGS) * 8), BT_TMPBT(bt[i]));
1095 for (i = MIN(argc, R_NARGS) - 1; i >= 0; i--)
1096 tmp_pop_bt(bt[i], arg_regs[i]);
1097 t = &tmp[ntmp - 1];
1098 if (t->flags & LOC_SYM) {
1099 os("\x31\xc0", 2); /* xor %eax, %eax */
1100 os("\xe8", 1); /* call $x */
1101 if (!nogen)
1102 out_rela(t->addr, codeaddr(), 1);
1103 oi(-4 + t->off, 4);
1104 o_tmpdrop(1);
1105 } else {
1106 tmp_pop(0, R_RAX);
1107 regop1(CALL_REG, 2, R_RAX, 4);
1109 if (ret_bt)
1110 tmp_push_reg(ret_bt, R_RAX);
1113 int o_nogen(void)
1115 return nogen++;
1118 void o_dogen(void)
1120 nogen = 0;
1123 void o_datset(long addr, int off, unsigned bt)
1125 struct tmp *t = &tmp[ntmp - 1];
1126 if (t->flags & LOC_NUM && !(t->flags & TMP_ADDR)) {
1127 num_cast(t, bt);
1128 out_datcpy(addr, off, (void *) &t->addr, BT_SZ(bt));
1130 if (t->flags & LOC_SYM && !(t->flags & TMP_ADDR)) {
1131 out_datrela(tmp->addr, addr, off);
1132 out_datcpy(addr, off, (void *) &t->off, BT_SZ(bt));
1134 o_tmpdrop(1);