6 #define TMP_ADDR 0x0001
10 #define LOC_SYM 0x0800
11 #define LOC_LOCAL 0x1000
12 #define LOC_MASK 0xff00
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
];
64 static long spsub_addr
;
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
];
87 static void putint(char *s
, long n
, int l
)
97 static void os(char *s
, int n
)
105 static void oi(long n
, int l
)
113 static long codeaddr(void)
118 static void o_op(int *op
, int nop
, int r1
, int r2
, unsigned bt
)
128 if (rex
|| (bt
& BT_SZMASK
) == 8)
130 if ((bt
& BT_SZMASK
) == 2)
132 if ((bt
& BT_SZMASK
) == 1)
134 for (i
= 0; i
< nop
; i
++)
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
);
145 oi((mod
<< 6) | ((src
& 0x07) << 3) | (base
& 0x07), 1);
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
)
174 #define LOC_NEW(f, l) (((f) & ~LOC_MASK) | (l))
176 static void tmp_mem(struct tmp
*tmp
)
179 if (!(tmp
->flags
& LOC_REG
))
183 tmp
->addr
= sp_push(8);
184 memop1(MOV_R2X
, src
, R_RBP
, -tmp
->addr
, BT_TMPBT(TMP_BT(tmp
)));
186 tmp
->flags
= LOC_NEW(tmp
->flags
, LOC_MEM
);
189 static int *movxx_x2r(int bt
)
191 static int movxx
[2] = {0x0f};
193 movxx
[1] = bt
& BT_SIGNED
? 0xbe : 0xb6;
195 movxx
[1] = bt
& BT_SIGNED
? 0xbf : 0xb7;
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);
211 if (sz1
== 4 && sz2
== 8) {
212 regop1(MOVSXD
, r1
, r2
, sz2
);
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
);
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
);
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
)
246 o_op(&op
, 1, 0, reg
, bt
);
250 static void tmp_reg(struct tmp
*tmp
, int dst
, unsigned bt
, int deref
)
252 if (!(tmp
->flags
& TMP_ADDR
))
255 tmp
->flags
&= ~TMP_ADDR
;
256 if (tmp
->flags
& LOC_NUM
) {
258 tmp
->bt
= BT_TMPBT(bt
);
259 num_reg(dst
, tmp
->bt
, tmp
->addr
);
262 tmp
->flags
= LOC_NEW(tmp
->flags
, LOC_REG
);
264 if (tmp
->flags
& LOC_SYM
) {
265 regop1(MOV_I2X
, 0, dst
, TMP_BT(tmp
));
267 out_rela(tmp
->addr
, codeaddr(), 0);
271 tmp
->flags
= LOC_NEW(tmp
->flags
, LOC_REG
);
273 if (tmp
->flags
& LOC_REG
) {
275 mov_m2r(dst
, tmp
->addr
, 0, tmp
->bt
, bt
);
277 mov_r2r(tmp
->addr
, dst
, TMP_BT(tmp
), bt
);
278 regs
[tmp
->addr
] = NULL
;
280 tmp
->bt
= BT_TMPBT(bt
);
284 if (tmp
->flags
& LOC_LOCAL
) {
286 mov_m2r(dst
, R_RBP
, -tmp
->addr
, tmp
->bt
, bt
);
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
);
294 mov_m2r(dst
, dst
, 0, tmp
->bt
, bt
);
297 tmp
->bt
= BT_TMPBT(bt
);
299 tmp
->flags
= LOC_NEW(tmp
->flags
, LOC_REG
);
302 static void reg_free(int reg
)
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);
315 static void reg_for(int reg
, struct tmp
*t
)
317 if (regs
[reg
] && regs
[reg
] != t
)
321 static void tmp_pop_bt(unsigned bt
, int reg
)
323 struct tmp
*t
= &tmp
[--ntmp
];
325 tmp_reg(t
, reg
, bt
, 1);
329 static unsigned tmp_pop(int deref
, int reg
)
331 struct tmp
*t
= &tmp
[--ntmp
];
333 tmp_reg(t
, reg
, deref
? t
->bt
: TMP_BT(t
), deref
);
338 static void tmp_push_reg(unsigned bt
, unsigned reg
)
340 struct tmp
*t
= &tmp
[ntmp
++];
347 void o_local(long addr
, unsigned bt
)
349 struct tmp
*t
= &tmp
[ntmp
++];
352 t
->flags
= LOC_LOCAL
| TMP_ADDR
;
355 void o_num(long num
, unsigned bt
)
357 struct tmp
*t
= &tmp
[ntmp
++];
363 void o_symaddr(long addr
, unsigned bt
)
365 struct tmp
*t
= &tmp
[ntmp
++];
368 t
->flags
= LOC_SYM
| TMP_ADDR
;
371 void o_tmpdrop(int n
)
374 if (n
== -1 || n
> ntmp
)
377 for (i
= ntmp
; i
< ntmp
+ n
; i
++)
378 if (tmp
[i
].flags
& LOC_REG
)
379 regs
[tmp
[i
].addr
] = NULL
;
387 #define FORK_REG R_RAX
391 struct tmp
*t
= &tmp
[ntmp
- 1];
392 reg_for(FORK_REG
, t
);
393 tmp_reg(t
, FORK_REG
, t
->bt
, 0);
399 struct tmp
*t
= &tmp
[ntmp
- 1];
400 reg_for(FORK_REG
, t
);
401 tmp_reg(t
, FORK_REG
, t
->bt
, 0);
406 struct tmp
*t1
= &tmp
[ntmp
- 1];
407 struct tmp
*t2
= &tmp
[ntmp
- 2];
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
)
417 for (i
= 0; i
< ARRAY_SIZE(tmpregs
); i
++)
418 if ((1 << tmpregs
[i
]) & mask
&& !regs
[tmpregs
[i
]])
420 for (i
= 0; i
< ARRAY_SIZE(tmpregs
); i
++)
421 if ((1 << tmpregs
[i
]) & mask
) {
422 reg_free(tmpregs
[i
]);
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
)))
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];
450 if (t
->flags
& LOC_NUM
) {
454 reg
= BT_SZ(bt
) == 1 ? TMP_BYTEREG(t
) : TMP_REG(t
);
456 tmp_push_reg(bt
, reg
);
459 long o_func_beg(char *name
, int global
)
461 long addr
= out_func_beg(name
, global
);
463 os("\x55", 1); /* push %rbp */
464 os("\x48\x89\xe5", 3); /* mov %rsp, %rbp */
471 memset(regs
, 0, sizeof(regs
));
472 os("\x48\x81\xec", 3); /* sub $xxx, %rsp */
473 spsub_addr
= codeaddr();
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);
484 t
->flags
|= TMP_ADDR
;
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
);
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];
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];
518 if (!TMP_CONST(t1
) || !TMP_CONST(t2
))
521 bt
= bt_op(t1
->bt
, t2
->bt
);
522 ret
= cop(t2
->addr
, t1
->addr
, bt
);
528 static int c_op(long (*cop
)(long a
, unsigned bt
), unsigned bt
)
530 struct tmp
*t1
= &tmp
[ntmp
- 1];
536 ret
= cop(t1
->addr
, bt
);
542 static void shx(int uop
, int sop
)
544 struct tmp
*t
= &tmp
[ntmp
- 2];
546 unsigned reg
= TMP_REG2(t
, 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
)
560 if (!c_binop(c_shl
, 0))
565 static long c_shr(long a
, long b
, unsigned bt
)
570 return (unsigned long) a
>> b
;
575 if (!c_binop(c_shr
, 0))
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
)
590 tmp_reg(t1
, reg
, bt
, 1);
592 tmp_reg(t2
, R_RAX
, bt
, 1);
596 regop1(MUL_A2X
, bt
& BT_SIGNED
? sop
: uop
, reg
, BT_TMPBT(bt2
));
600 static long c_mul(long a
, long b
, unsigned bt
)
608 if (!c_binop(c_mul
, 0))
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
)
622 if (!c_binop(c_div
, 0))
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
)
636 if (!c_binop(c_mod
, 0))
638 bt
= mulop(6, 7, R_RCX
);
639 tmp_push_reg(bt
, R_RDX
);
644 tmp
[ntmp
- 1].flags
&= ~TMP_ADDR
;
645 tmp
[ntmp
- 1].bt
= 8;
648 void o_ret(unsigned bt
)
651 tmp_pop_bt(bt
, R_RAX
);
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];
664 *reg
= TMP_REG2(t2
, r1
);
665 bt
= bt_op(t1
->bt
, t2
->bt
);
667 tmp_pop_bt(bt
, *reg
);
668 regop1(op
, *reg
, r1
, bt
);
672 static long c_add(long a
, long b
, unsigned bt
)
681 if (!c_binop(c_add
, 0))
683 bt
= binop(ADD_R2X
, ®
);
684 tmp_push_reg(bt
, reg
);
687 static long c_xor(long a
, long b
, unsigned bt
)
696 if (!c_binop(c_xor
, 0))
698 bt
= binop(XOR_R2X
, ®
);
699 tmp_push_reg(bt
, reg
);
702 static long c_and(long a
, long b
, unsigned bt
)
711 if (!c_binop(c_and
, 0))
713 bt
= binop(AND_R2X
, ®
);
714 tmp_push_reg(bt
, reg
);
717 static long c_or(long a
, long b
, unsigned bt
)
726 if (!c_binop(c_or
, 0))
728 bt
= binop(OR_R2X
, ®
);
729 tmp_push_reg(bt
, reg
);
732 static long c_sub(long a
, long b
, unsigned bt
)
741 if (!c_binop(c_sub
, 0))
743 bt
= binop(SUB_R2X
, ®
);
744 tmp_push_reg(bt
, reg
);
747 static void o_cmp(int uop
, int sop
)
749 char set
[] = "\x0f\x00\xc0";
751 int bt
= binop(CMP_R2X
, ®
);
752 set
[1] = bt
& BT_SIGNED
? sop
: uop
;
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
)
768 if (!c_binop(c_lt
, 4))
773 static long c_gt(long a
, long b
, unsigned bt
)
780 if (!c_binop(c_gt
, 4))
785 static long c_le(long a
, long b
, unsigned bt
)
792 if (!c_binop(c_le
, 4))
797 static long c_ge(long a
, long b
, unsigned bt
)
804 if (!c_binop(c_ge
, 4))
809 static long c_eq(long a
, long b
, unsigned bt
)
816 if (!c_binop(c_eq
, 4))
821 static long c_neq(long a
, long b
, unsigned bt
)
828 if (!c_binop(c_neq
, 4))
833 static long c_lnot(long a
, unsigned bt
)
840 if (!c_op(c_lnot
, 4))
842 if (cmp_last
== codeaddr()) {
843 buf
[cmp_setl
+ 1] ^= 0x10;
845 o_num(0, 4 | BT_SIGNED
);
850 static long c_neg(long a
, unsigned bt
)
857 struct tmp
*t
= &tmp
[ntmp
- 1];
859 unsigned bt
= BT_TMPBT(t
->bt
);
860 if (!c_op(c_neg
, t
->bt
| BT_SIGNED
))
864 regop1(NEG_REG
, 3, reg
, bt
);
865 tmp_push_reg(bt
, reg
);
868 static long c_not(long a
, unsigned bt
)
875 struct tmp
*t
= &tmp
[ntmp
- 1];
877 unsigned bt
= BT_TMPBT(t
->bt
);
882 regop1(NOT_REG
, 2, reg
, bt
);
883 tmp_push_reg(t
->bt
, reg
);
886 void o_func_end(void)
889 for (i
= 0; i
< nret
; 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
)
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
);
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
);
922 tmp_pop_bt(BT_TMPBT(bt
), r1
);
923 if (t2
->flags
& LOC_LOCAL
) {
928 reg
= TMP_REG2(t2
, r1
);
932 memop1(MOV_R2X
, r1
, reg
, off
, bt
);
933 tmp_push_reg(bt
, r1
);
936 static void tmp_to(struct tmp
*t
, int reg
)
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];
951 os("\xf3\xa4", 2); /* rep movs */
960 static long jx(int x
, long addr
)
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
);
976 static long jxcmp(long addr
, int inv
)
979 if (codeaddr() != cmp_last
)
982 cur
= buf
+ cmp_setl
;
983 x
= (unsigned char) buf
[cmp_setl
+ 1];
984 return jx((inv
? x
: x
^ 0x01) & ~0x10, 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
)
1020 for (i
= 0; i
< argc
; i
++)
1021 tmp_pop_bt(bt
[argc
- i
- 1], arg_regs
[argc
- i
- 1]);
1023 if (t
->flags
& LOC_SYM
) {
1024 os("\x31\xc0", 2); /* xor %eax, %eax */
1025 os("\xe8", 1); /* call $x */
1027 out_rela(t
->addr
, codeaddr(), 1);
1032 regop1(CALL_REG
, 2, R_RAX
, 4);
1034 for (i
= 0; i
< ARRAY_SIZE(tmpregs
); i
++)
1038 tmp_push_reg(ret_bt
, R_RAX
);