6 #define TMP_ADDR 0x0001
10 #define LOC_SYM 0x0800
11 #define LOC_LOCAL 0x1000
12 #define LOC_MASK 0xff00
41 #define TMP_BT(t) ((t)->flags & TMP_ADDR ? 8 : (t)->bt)
43 static char buf
[SECSIZE
];
46 static long spsub_addr
;
56 static char names
[MAXTMP
][NAMELEN
];
60 static struct tmp
*regs
[NREGS
];
61 static int tmpregs
[] = {R_RAX
, R_RDI
, R_RSI
, R_RDX
, R_RCX
, R_R8
, R_R9
};
63 #define MAXRET (1 << 8)
65 static long ret
[MAXRET
];
68 static void putint(char *s
, long n
, int l
)
76 static void os(char *s
, int n
)
82 static void oi(long n
, int l
)
90 static long codeaddr(void)
95 static void o_op(int op
, int r1
, int r2
, unsigned bt
)
102 if (rex
|| (bt
& BT_SZMASK
) == 8)
104 if ((bt
& BT_SZMASK
) == 2)
106 if ((bt
& BT_SZMASK
) == 1)
111 static void memop(int op
, int src
, int base
, int off
, unsigned bt
)
113 int dis
= off
== (char) off
? 1 : 4;
114 int mod
= dis
== 4 ? 2 : 1;
115 o_op(op
, src
, base
, bt
);
118 oi((mod
<< 6) | ((src
& 0x07) << 3) | (base
& 0x07), 1);
123 static void regop(int op
, int src
, int dst
, unsigned bt
)
125 o_op(op
, src
, dst
, bt
);
126 oi((3 << 6) | (src
<< 3) | (dst
& 0x07), 1);
129 static long sp_push(int size
)
137 #define LOC_NEW(f, l) (((f) & ~LOC_MASK) | (l))
139 static void tmp_mem(struct tmp
*tmp
)
142 if (!(tmp
->flags
& LOC_REG
))
146 tmp
->addr
= sp_push(8);
147 memop(MOV_R2X
, src
, R_RBP
, -tmp
->addr
, TMP_BT(tmp
));
149 tmp
->flags
= LOC_NEW(tmp
->flags
, LOC_MEM
);
152 static void tmp_reg(struct tmp
*tmp
, unsigned dst
, int deref
)
154 if (!(tmp
->flags
& TMP_ADDR
))
157 tmp
->flags
&= ~TMP_ADDR
;
158 if (tmp
->flags
& LOC_NUM
) {
159 regop(MOV_I2R
, 0, dst
, TMP_BT(tmp
));
160 oi(tmp
->addr
, BT_SZ(tmp
->bt
));
163 tmp
->flags
= LOC_NEW(tmp
->flags
, LOC_REG
);
165 if (tmp
->flags
& LOC_SYM
) {
166 regop(MOV_I2R
, 0, dst
, TMP_BT(tmp
));
167 out_rela(names
[tmp
->addr
], codeaddr(), 0);
171 tmp
->flags
= LOC_NEW(tmp
->flags
, LOC_REG
);
173 if (tmp
->flags
& LOC_REG
) {
175 memop(MOV_M2R
, dst
, tmp
->addr
, 0, tmp
->bt
);
177 if (dst
== tmp
->addr
)
179 regop(MOV_R2X
, tmp
->addr
, dst
, TMP_BT(tmp
));
181 regs
[tmp
->addr
] = NULL
;
186 if (tmp
->flags
& LOC_LOCAL
) {
188 memop(MOV_M2R
, dst
, R_RBP
, -tmp
->addr
, TMP_BT(tmp
));
190 memop(LEA_M2R
, dst
, R_RBP
, -tmp
->addr
, 8);
192 if (tmp
->flags
& LOC_MEM
) {
193 memop(MOV_M2R
, dst
, R_RBP
, -tmp
->addr
, TMP_BT(tmp
));
195 memop(MOV_M2R
, dst
, dst
, 0, TMP_BT(tmp
));
199 tmp
->flags
= LOC_NEW(tmp
->flags
, LOC_REG
);
202 static void reg_free(int reg
)
207 for (i
= 0; i
< ARRAY_SIZE(tmpregs
); i
++)
208 if (!regs
[tmpregs
[i
]]) {
209 tmp_reg(regs
[reg
], tmpregs
[i
], 0);
215 static void reg_for(int reg
, struct tmp
*t
)
217 if (regs
[reg
] && regs
[reg
] != t
)
221 static unsigned tmp_pop(int deref
, int reg
)
223 struct tmp
*t
= &tmp
[--ntmp
];
225 tmp_reg(t
, reg
, deref
);
230 static void tmp_push_reg(unsigned bt
, unsigned reg
)
232 struct tmp
*t
= &tmp
[ntmp
++];
239 void o_local(long addr
, unsigned bt
)
241 struct tmp
*t
= &tmp
[ntmp
++];
244 t
->flags
= LOC_LOCAL
| TMP_ADDR
;
247 void o_num(long num
, unsigned bt
)
249 struct tmp
*t
= &tmp
[ntmp
++];
255 void o_symaddr(char *name
, unsigned bt
)
258 struct tmp
*t
= &tmp
[ntmp
++];
261 t
->flags
= LOC_SYM
| TMP_ADDR
;
262 strcpy(names
[id
], name
);
265 void o_tmpdrop(int n
)
268 if (n
== -1 || n
> ntmp
)
271 for (i
= ntmp
; i
< ntmp
+ n
; i
++)
272 if (tmp
[i
].flags
& LOC_REG
)
273 regs
[tmp
[i
].addr
] = NULL
;
282 #define FORK_REG R_RAX
286 struct tmp
*t
= &tmp
[ntmp
- 1];
287 reg_for(FORK_REG
, t
);
288 tmp_reg(t
, FORK_REG
, 0);
294 struct tmp
*t
= &tmp
[ntmp
- 1];
295 reg_for(FORK_REG
, t
);
296 tmp_reg(t
, FORK_REG
, 0);
301 struct tmp
*t1
= &tmp
[ntmp
- 1];
302 struct tmp
*t2
= &tmp
[ntmp
- 2];
304 memcpy(&t
, t1
, sizeof(t
));
305 memcpy(t1
, t2
, sizeof(t
));
306 memcpy(t2
, &t
, sizeof(t
));
309 static int reg_other(int not)
312 for (i
= 0; i
< ARRAY_SIZE(tmpregs
); i
++)
313 if (tmpregs
[i
] != not && !regs
[tmpregs
[i
]])
315 for (i
= 0; i
< ARRAY_SIZE(tmpregs
); i
++)
316 if (tmpregs
[i
] != not) {
317 reg_free(tmpregs
[i
]);
323 static int reg_get(void)
325 return reg_other(-1);
330 struct tmp
*t1
= &tmp
[ntmp
- 1];
331 struct tmp
*t2
= &tmp
[ntmp
++];
332 if (!(t1
->flags
& (LOC_REG
| LOC_MEM
))) {
333 memcpy(t2
, t1
, sizeof(*t2
));
336 memcpy(t2
, t1
, sizeof(*t1
));
337 if (t1
->flags
& LOC_MEM
)
338 tmp_reg(t2
, reg_get(), 0);
339 else if (t1
->flags
& LOC_REG
) {
340 t2
->addr
= reg_get();
341 regop(MOV_R2X
, t1
->addr
, t2
->addr
, TMP_BT(tmp
));
343 t2
->flags
= t1
->flags
;
346 void o_func_beg(char *name
)
350 os("\x55", 1); /* push %rbp */
351 os("\x48\x89\xe5", 3); /* mov %rsp, %rbp */
358 memset(regs
, 0, sizeof(regs
));
359 os("\x48\x81\xec", 3); /* sub $xxx, %rsp */
360 spsub_addr
= codeaddr();
364 void o_deref(unsigned bt
)
366 struct tmp
*t
= &tmp
[ntmp
- 1];
367 if (t
->flags
& TMP_ADDR
) {
368 int reg
= t
->flags
& LOC_REG
? t
->addr
: reg_get();
371 t
->flags
|= TMP_ADDR
;
376 struct tmp
*t
= &tmp
[ntmp
- 1];
377 int reg
= t
->flags
& LOC_REG
? t
->addr
: reg_get();
383 struct tmp
*t
= &tmp
[ntmp
- 2];
387 reg
= (t
->flags
& LOC_REG
) ? t
->addr
: reg_get();
388 bt
= tmp_pop(1, reg
);
389 regop(SHX_REG
, 4, reg
, bt
);
390 tmp_push_reg(bt
, reg
);
395 struct tmp
*t
= &tmp
[ntmp
- 2];
399 reg
= (t
->flags
& LOC_REG
) ? t
->addr
: reg_get();
400 bt
= tmp_pop(1, reg
);
401 regop(SHX_REG
, bt
& BT_SIGNED
? 5 : 7, reg
, bt
);
402 tmp_push_reg(bt
, reg
);
407 static unsigned bt_op(unsigned bt1
, unsigned bt2
)
409 unsigned s1
= BT_SZ(bt1
);
410 unsigned s2
= BT_SZ(bt2
);
411 return (bt1
| bt2
) & BT_SIGNED
| (s1
> s2
? s1
: s2
);
414 void mulop(int uop
, int sop
, int reg
)
416 struct tmp
*t1
= &tmp
[ntmp
- 1];
417 struct tmp
*t2
= &tmp
[ntmp
- 2];
418 int bt1
= TMP_BT(t1
);
419 int bt2
= TMP_BT(t2
);
420 if (t1
->flags
& LOC_REG
&& t1
->addr
!= R_RAX
&& t1
->addr
!= R_RDX
)
425 tmp_reg(t2
, R_RAX
, 1);
429 regop(MUL_A2X
, bt2
& BT_SIGNED
? sop
: uop
, reg
, bt2
);
430 return bt_op(bt1
, bt2
);
435 int bt
= mulop(4, 5, R_RDX
);
436 tmp_push_reg(bt
, R_RAX
);
441 int bt
= mulop(6, 7, R_RCX
);
442 tmp_push_reg(bt
, R_RAX
);
447 int bt
= mulop(6, 7, R_RCX
);
448 tmp_push_reg(bt
, R_RDX
);
453 tmp
[ntmp
- 1].flags
&= ~TMP_ADDR
;
454 tmp
[ntmp
- 1].bt
= 8;
457 void o_ret(unsigned bt
)
462 os("\x31\xc0", 2); /* xor %eax, %eax */
463 ret
[nret
++] = o_jmp(0);
466 static int binop(int *r1
, int *r2
)
468 struct tmp
*t1
= &tmp
[ntmp
- 1];
469 struct tmp
*t2
= &tmp
[ntmp
- 2];
471 *r1
= t1
->flags
& LOC_REG
? t1
->addr
: reg_get();
472 *r2
= t2
->flags
& LOC_REG
? t2
->addr
: reg_other(*r1
);
473 bt1
= tmp_pop(1, *r1
);
474 bt2
= tmp_pop(1, *r2
);
475 return bt_op(bt1
, bt2
);
481 int bt
= binop(&r1
, &r2
);
482 regop(ADD_R2R
, r1
, r2
, bt
);
483 tmp_push_reg(bt
, r2
);
489 int bt
= binop(&r1
, &r2
);
490 regop(SUB_R2R
, r1
, r2
, bt
);
491 tmp_push_reg(bt
, r2
);
494 static void o_cmp(int uop
, int sop
)
496 char set
[] = "\x0f\x00\xc0";
498 int bt
= binop(&r1
, &r2
);
499 regop(CMP_R2R
, r1
, r2
, bt
);
500 set
[1] = bt
& BT_SIGNED
? sop
: uop
;
502 os(set
, 3); /* setl %al */
503 os("\x0f\xb6\xc0", 3); /* movzbl %al, %eax */
504 tmp_push_reg(4 | BT_SIGNED
, R_RAX
);
512 void o_func_end(void)
515 for (i
= 0; i
< nret
; i
++)
517 os("\xc9\xc3", 2); /* leave; ret; */
518 putint(buf
+ spsub_addr
, (maxsp
+ 7) & ~0x07, 4);
519 out_func_end(buf
, cur
- buf
);
522 long o_mklocal(int size
)
524 return sp_push((size
+ 7) & ~0x07);
527 static int arg_regs
[] = {R_RDI
, R_RSI
, R_RDX
, R_RCX
, R_R8
, R_R9
};
529 long o_arg(int i
, unsigned bt
)
531 long addr
= o_mklocal(BT_SZ(bt
));
532 memop(MOV_R2X
, arg_regs
[i
], R_RBP
, -addr
, bt
);
536 void o_assign(unsigned bt
)
538 struct tmp
*t1
= &tmp
[ntmp
- 1];
539 struct tmp
*t2
= &tmp
[ntmp
- 2];
540 int r1
= t1
->flags
& LOC_REG
? t1
->addr
: reg_get();
544 if (t2
->flags
& LOC_LOCAL
) {
549 reg
= t2
->flags
& LOC_REG
? t2
->addr
: reg_other(r1
);
553 memop(MOV_R2X
, r1
, reg
, off
, bt
);
554 tmp_push_reg(bt
, r1
);
565 os("\x48\x85\xc0", 3); /* test %rax, %rax */
566 os("\x0f\x84", 2); /* jz $addr */
567 oi(addr
- codeaddr() - 4, 4);
568 return codeaddr() - 4;
571 long o_jmp(long addr
)
573 os("\xe9", 1); /* jmp $addr */
574 oi(addr
- codeaddr() - 4, 4);
575 return codeaddr() - 4;
578 void o_filljmp(long addr
)
580 putint(buf
+ addr
, codeaddr() - addr
- 4, 4);
583 #define CALL_REG 0xff
585 void o_call(int argc
, unsigned *bt
, unsigned ret_bt
)
589 for (i
= 0; i
< argc
; i
++)
590 tmp_pop(1, arg_regs
[i
]);
592 if (t
->flags
& LOC_SYM
) {
593 os("\xe8", 1); /* call $x */
594 out_rela(names
[tmp
->addr
], codeaddr(), 1);
599 regop(CALL_REG
, 2, R_RAX
, 4);
601 for (i
= 0; i
< ARRAY_SIZE(tmpregs
); i
++)
605 tmp_push_reg(ret_bt
, R_RAX
);