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 static void putint(char *s
, long n
, int l
)
71 static void os(char *s
, int n
)
77 static void oi(long n
, int l
)
85 static long codeaddr(void)
90 static void o_op(int op
, int r1
, int r2
, unsigned bt
)
97 if (rex
|| (bt
& BT_SZMASK
) == 8)
99 if ((bt
& BT_SZMASK
) == 2)
101 if ((bt
& BT_SZMASK
) == 1)
106 static void memop(int op
, int src
, int base
, int off
, unsigned bt
)
108 int dis
= off
== (char) off
? 1 : 4;
109 int mod
= dis
== 4 ? 2 : 1;
110 o_op(op
, src
, base
, bt
);
113 oi((mod
<< 6) | ((src
& 0x07) << 3) | (base
& 0x07), 1);
118 static void regop(int op
, int src
, int dst
, unsigned bt
)
120 o_op(op
, src
, dst
, bt
);
121 oi((3 << 6) | (src
<< 3) | (dst
& 0x07), 1);
124 static long sp_push(int size
)
132 #define LOC_NEW(f, l) (((f) & ~LOC_MASK) | (l))
134 static void tmp_mem(struct tmp
*tmp
)
137 if (!(tmp
->flags
& LOC_REG
))
141 tmp
->addr
= sp_push(8);
142 memop(MOV_R2X
, src
, R_RBP
, -tmp
->addr
, TMP_BT(tmp
));
144 tmp
->flags
= LOC_NEW(tmp
->flags
, LOC_MEM
);
147 static void tmp_reg(struct tmp
*tmp
, unsigned dst
, int deref
)
149 if (!(tmp
->flags
& TMP_ADDR
))
152 tmp
->flags
&= ~TMP_ADDR
;
153 if (tmp
->flags
& LOC_NUM
) {
154 regop(MOV_I2R
, 0, dst
, TMP_BT(tmp
));
155 oi(tmp
->addr
, BT_SZ(tmp
->bt
));
158 tmp
->flags
= LOC_NEW(tmp
->flags
, LOC_REG
);
160 if (tmp
->flags
& LOC_SYM
) {
161 regop(MOV_I2R
, 0, dst
, TMP_BT(tmp
));
162 out_rela(names
[tmp
->addr
], codeaddr(), 0);
166 tmp
->flags
= LOC_NEW(tmp
->flags
, LOC_REG
);
168 if (tmp
->flags
& LOC_REG
) {
170 memop(MOV_M2R
, dst
, tmp
->addr
, 0, tmp
->bt
);
172 if (dst
== tmp
->addr
)
174 regop(MOV_R2X
, tmp
->addr
, dst
, TMP_BT(tmp
));
176 regs
[tmp
->addr
] = NULL
;
181 if (tmp
->flags
& LOC_LOCAL
) {
183 memop(MOV_M2R
, dst
, R_RBP
, -tmp
->addr
, TMP_BT(tmp
));
185 memop(LEA_M2R
, dst
, R_RBP
, -tmp
->addr
, 8);
187 if (tmp
->flags
& LOC_MEM
) {
188 memop(MOV_M2R
, dst
, R_RBP
, -tmp
->addr
, TMP_BT(tmp
));
190 memop(MOV_M2R
, dst
, dst
, 0, TMP_BT(tmp
));
194 tmp
->flags
= LOC_NEW(tmp
->flags
, LOC_REG
);
197 static void reg_free(int reg
)
202 for (i
= 0; i
< ARRAY_SIZE(tmpregs
); i
++)
203 if (!regs
[tmpregs
[i
]]) {
204 tmp_reg(regs
[reg
], tmpregs
[i
], 0);
210 static void reg_for(int reg
, struct tmp
*t
)
212 if (regs
[reg
] && regs
[reg
] != t
)
216 static unsigned tmp_pop(int deref
, int reg
)
218 struct tmp
*t
= &tmp
[--ntmp
];
220 tmp_reg(t
, reg
, deref
);
225 static void tmp_push_reg(unsigned bt
, unsigned reg
)
227 struct tmp
*t
= &tmp
[ntmp
++];
234 void o_local(long addr
, unsigned bt
)
236 struct tmp
*t
= &tmp
[ntmp
++];
239 t
->flags
= LOC_LOCAL
| TMP_ADDR
;
242 void o_num(long num
, unsigned bt
)
244 struct tmp
*t
= &tmp
[ntmp
++];
250 void o_symaddr(char *name
, unsigned bt
)
253 struct tmp
*t
= &tmp
[ntmp
++];
256 t
->flags
= LOC_SYM
| TMP_ADDR
;
257 strcpy(names
[id
], name
);
260 void o_tmpdrop(int n
)
263 if (n
== -1 || n
> ntmp
)
266 for (i
= ntmp
; i
< ntmp
+ n
; i
++)
267 if (tmp
[i
].flags
& LOC_REG
)
268 regs
[tmp
[i
].addr
] = NULL
;
277 #define FORK_REG R_RAX
281 struct tmp
*t
= &tmp
[ntmp
- 1];
282 reg_for(FORK_REG
, t
);
283 tmp_reg(t
, FORK_REG
, 0);
289 struct tmp
*t
= &tmp
[ntmp
- 1];
290 reg_for(FORK_REG
, t
);
291 tmp_reg(t
, FORK_REG
, 0);
296 struct tmp
*t1
= &tmp
[ntmp
- 1];
297 struct tmp
*t2
= &tmp
[ntmp
- 2];
299 memcpy(&t
, t1
, sizeof(t
));
300 memcpy(t1
, t2
, sizeof(t
));
301 memcpy(t2
, &t
, sizeof(t
));
304 static int reg_other(int not)
307 for (i
= 0; i
< ARRAY_SIZE(tmpregs
); i
++)
308 if (tmpregs
[i
] != not && !regs
[tmpregs
[i
]])
310 for (i
= 0; i
< ARRAY_SIZE(tmpregs
); i
++)
311 if (tmpregs
[i
] != not) {
312 reg_free(tmpregs
[i
]);
318 static int reg_get(void)
320 return reg_other(-1);
325 struct tmp
*t1
= &tmp
[ntmp
- 1];
326 struct tmp
*t2
= &tmp
[ntmp
++];
327 if (!(t1
->flags
& (LOC_REG
| LOC_MEM
))) {
328 memcpy(t2
, t1
, sizeof(*t2
));
331 memcpy(t2
, t1
, sizeof(*t1
));
332 if (t1
->flags
& LOC_MEM
)
333 tmp_reg(t2
, reg_get(), 0);
334 else if (t1
->flags
& LOC_REG
) {
335 t2
->addr
= reg_get();
336 regop(MOV_R2X
, t1
->addr
, t2
->addr
, TMP_BT(tmp
));
338 t2
->flags
= t1
->flags
;
341 void o_func_beg(char *name
)
345 os("\x55", 1); /* push %rbp */
346 os("\x48\x89\xe5", 3); /* mov %rsp, %rbp */
352 memset(regs
, 0, sizeof(regs
));
353 os("\x48\x81\xec", 3); /* sub $xxx, %rsp */
354 spsub_addr
= codeaddr();
358 void o_deref(unsigned bt
)
360 struct tmp
*t
= &tmp
[ntmp
- 1];
361 if (t
->flags
& TMP_ADDR
) {
362 int reg
= t
->flags
& LOC_REG
? t
->addr
: reg_get();
365 t
->flags
|= TMP_ADDR
;
370 struct tmp
*t
= &tmp
[ntmp
- 1];
371 int reg
= t
->flags
& LOC_REG
? t
->addr
: reg_get();
377 struct tmp
*t
= &tmp
[ntmp
- 2];
381 reg
= (t
->flags
& LOC_REG
) ? t
->addr
: reg_get();
382 bt
= tmp_pop(1, reg
);
383 regop(SHX_REG
, 4, reg
, bt
);
384 tmp_push_reg(bt
, reg
);
389 struct tmp
*t
= &tmp
[ntmp
- 2];
393 reg
= (t
->flags
& LOC_REG
) ? t
->addr
: reg_get();
394 bt
= tmp_pop(1, reg
);
395 regop(SHX_REG
, bt
& BT_SIGNED
? 5 : 7, reg
, bt
);
396 tmp_push_reg(bt
, reg
);
403 struct tmp
*t1
= &tmp
[ntmp
- 1];
406 if (t1
->flags
& LOC_REG
&& t1
->addr
!= R_RAX
)
409 reg
= reg_other(R_RAX
);
410 bt1
= tmp_pop(1, reg
);
411 bt2
= tmp_pop(1, R_RAX
);
412 regop(MUL_A2X
, bt2
& BT_SIGNED
? 5 : 4, reg
, bt2
);
413 tmp_push_reg(bt2
, R_RAX
);
418 tmp
[ntmp
- 1].flags
&= ~TMP_ADDR
;
419 tmp
[ntmp
- 1].bt
= 8;
422 void o_ret(unsigned bt
)
427 os("\x31\xc0", 2); /* xor %eax, %eax */
428 os("\xc9\xc3", 2); /* leave; ret; */
431 static int binop(int *r1
, int *r2
)
433 struct tmp
*t1
= &tmp
[ntmp
- 1];
434 struct tmp
*t2
= &tmp
[ntmp
- 2];
436 *r1
= t1
->flags
& LOC_REG
? t1
->addr
: reg_get();
437 *r2
= t2
->flags
& LOC_REG
? t2
->addr
: reg_other(*r1
);
438 bt1
= tmp_pop(1, *r1
);
439 bt2
= tmp_pop(1, *r2
);
440 return BT_SZ(bt1
) > BT_SZ(bt2
) ? bt1
: bt2
;
446 int bt
= binop(&r1
, &r2
);
447 regop(ADD_R2R
, r1
, r2
, bt
);
448 tmp_push_reg(bt
, r2
);
454 int bt
= binop(&r1
, &r2
);
455 regop(SUB_R2R
, r1
, r2
, bt
);
456 tmp_push_reg(bt
, r2
);
459 static void o_cmp(int uop
, int sop
)
461 char set
[] = "\x0f\x00\xc0";
463 int bt
= binop(&r1
, &r2
);
464 regop(CMP_R2R
, r1
, r2
, bt
);
465 set
[1] = bt
& BT_SIGNED
? sop
: uop
;
467 os(set
, 3); /* setl %al */
468 os("\x0f\xb6\xc0", 3); /* movzbl %al, %eax */
469 tmp_push_reg(4 | BT_SIGNED
, R_RAX
);
477 void o_func_end(void)
479 os("\xc9\xc3", 2); /* leave; ret; */
480 putint(buf
+ spsub_addr
, (maxsp
+ 7) & ~0x07, 4);
481 out_func_end(buf
, cur
- buf
);
484 long o_mklocal(int size
)
486 return sp_push((size
+ 7) & ~0x07);
489 static int arg_regs
[] = {R_RDI
, R_RSI
, R_RDX
, R_RCX
, R_R8
, R_R9
};
491 long o_arg(int i
, unsigned bt
)
493 long addr
= o_mklocal(BT_SZ(bt
));
494 memop(MOV_R2X
, arg_regs
[i
], R_RBP
, -addr
, bt
);
498 void o_assign(unsigned bt
)
500 struct tmp
*t1
= &tmp
[ntmp
- 1];
501 struct tmp
*t2
= &tmp
[ntmp
- 2];
502 int r1
= t1
->flags
& LOC_REG
? t1
->addr
: reg_get();
506 if (t2
->flags
& LOC_LOCAL
) {
511 reg
= t2
->flags
& LOC_REG
? t2
->addr
: reg_other(r1
);
515 memop(MOV_R2X
, r1
, reg
, off
, bt
);
516 tmp_push_reg(bt
, r1
);
527 os("\x48\x85\xc0", 3); /* test %rax, %rax */
528 os("\x0f\x84", 2); /* jz $addr */
529 oi(addr
- codeaddr() - 4, 4);
530 return codeaddr() - 4;
533 long o_jmp(long addr
)
535 os("\xe9", 1); /* jmp $addr */
536 oi(addr
- codeaddr() - 4, 4);
537 return codeaddr() - 4;
540 void o_filljmp(long addr
)
542 putint(buf
+ addr
, codeaddr() - addr
- 4, 4);
545 #define CALL_REG 0xff
547 void o_call(int argc
, unsigned *bt
, unsigned ret_bt
)
551 for (i
= 0; i
< argc
; i
++)
552 tmp_pop(1, arg_regs
[i
]);
554 if (t
->flags
& LOC_SYM
) {
555 os("\xe8", 1); /* call $x */
556 out_rela(names
[tmp
->addr
], codeaddr(), 1);
561 regop(CALL_REG
, 2, R_RAX
, 4);
563 for (i
= 0; i
< ARRAY_SIZE(tmpregs
); i
++)
567 tmp_push_reg(ret_bt
, R_RAX
);