10 /* variable location */
15 #define LOC_LOCAL 0x10
17 #define MIN(a, b) ((a) < (b) ? (a) : (b))
18 #define ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1))
20 char cs
[SECLEN
]; /* code segment */
22 static char ds
[SECLEN
]; /* data segment */
24 static long bsslen
; /* bss segment size */
26 static long sp
; /* stack pointer offset from R_RBP */
27 static long sp_max
; /* maximum stack pointer offset */
28 static long sp_tmp
; /* sp for the first tmp on the stack */
29 static int localoff
[NLOCALS
]; /* the offset of locals on the stack */
30 static int nlocals
; /* number of locals */
37 /* function statistics */
38 int pass1
; /* collect statistics; 1st pass */
39 static int stat_calls
; /* # of function calls */
40 static int stat_tmps
; /* # of stack temporaries */
41 static int stat_regs
; /* mask of used registers */
43 /* optimization info */
44 static int pass2
; /* use the collected statistics in the 1st pass */
45 static int tmp_mask
; /* registers that can be used for tmps */
47 /* register allocation for locals */
48 #define TMP_ISLREG(t) (!(t)->bt && (t)->loc == LOC_LOCAL && r_regmap((t)->id) >= 0)
49 #define TMP_LREG(t) (r_regmap((t)->id))
51 #define TMP(i) (((i) < ntmp) ? &tmps[ntmp - 1 - (i)] : NULL)
56 long off
; /* offset from a symbol or a local */
57 unsigned loc
; /* variable location */
58 unsigned bt
; /* type of address; zero when not a pointer */
59 int id
; /* local variable id */
63 static struct tmp
*regs
[N_REGS
];
66 static long labels
[NJMPS
];
68 static long jmp_loc
[NJMPS
];
69 static int jmp_goal
[NJMPS
];
70 static int jmp_len
[NJMPS
];
81 /* the number of bytes needed for holding jmp displacement */
82 static int jmp_sz(int id
)
84 long n
= jmp_len
[id
] > 0 ? jmp_len
[id
] : -jmp_len
[id
];
88 return n
== 0 ? 0 : 1;
89 return n
< 0x7000 ? 2 : 4;
92 static void jmp_add(int id
, int rn
, int z
)
96 err("nomem: NJMPS reached!\n");
97 i_jmp(rn
, z
, jmp_sz(njmps
));
98 jmp_loc
[njmps
] = cslen
;
103 static void jmp_fill(void)
106 for (i
= 0; i
< njmps
; i
++)
107 jmp_len
[i
] = i_fill(jmp_loc
[i
], labels
[jmp_goal
[i
]], jmp_sz(i
));
110 /* generating code */
112 void os(void *s
, int n
)
115 cs
[cslen
++] = *(char *) (s
++);
118 void oi(long n
, int l
)
126 static long sp_push(int sz
)
128 sp
-= ALIGN(sz
, LONGSZ
);
134 static void tmp_mem(struct tmp
*tmp
)
137 if (tmp
->loc
!= LOC_REG
|| (1 << src
) & r_lregs())
141 tmp
->addr
= sp_push(LONGSZ
);
142 i_save(src
, REG_FP
, tmp
->addr
, LONGSZ
);
148 static void num_cast(struct tmp
*t
, unsigned bt
)
150 if (!(bt
& BT_SIGNED
) && BT_SZ(bt
) != LONGSZ
)
151 t
->addr
&= ((1l << (long) (BT_SZ(bt
) * 8)) - 1);
152 if (bt
& BT_SIGNED
&& BT_SZ(bt
) != LONGSZ
&&
153 t
->addr
> (1l << (BT_SZ(bt
) * 8 - 1)))
154 t
->addr
= -((1l << (BT_SZ(bt
) * 8)) - t
->addr
);
157 static void tmp_reg(struct tmp
*tmp
, int dst
, int deref
)
164 if (tmp
->loc
== LOC_NUM
) {
165 i_num(dst
, tmp
->addr
);
170 if (tmp
->loc
== LOC_SYM
) {
171 i_sym(dst
, tmp
->sym
, tmp
->off
);
176 if (tmp
->loc
== LOC_REG
) {
178 i_load(dst
, tmp
->addr
, 0, bt
);
179 else if (dst
!= tmp
->addr
)
180 i_mov(dst
, tmp
->addr
);
181 regs
[tmp
->addr
] = NULL
;
183 if (tmp
->loc
== LOC_LOCAL
) {
189 i_load(dst
, REG_FP
, tmp
->addr
+ tmp
->off
, bt
);
191 i_op_imm(O_ADD
, dst
, REG_FP
, tmp
->addr
+ tmp
->off
);
193 if (tmp
->loc
== LOC_MEM
) {
194 i_load(dst
, REG_FP
, tmp
->addr
, LONGSZ
);
196 i_load(dst
, dst
, 0, bt
);
199 stat_regs
|= 1 << dst
;
204 /* empty the given register, but never touch the registers in rsrvd mask */
205 static void reg_free(int reg
, int rsrvd
)
211 for (i
= 0; i
< N_TMPS
; i
++)
212 if (!regs
[tmpregs
[i
]] && ~rsrvd
& (1 << tmpregs
[i
])) {
213 tmp_reg(regs
[reg
], tmpregs
[i
], 0);
219 static void reg_for(int reg
, struct tmp
*t
)
221 if (regs
[reg
] && regs
[reg
] != t
)
225 static void tmp_mv(struct tmp
*t
, int reg
)
231 static void tmp_to(struct tmp
*t
, int reg
)
234 if (t
->loc
== LOC_LOCAL
&& TMP_ISLREG(t
)) {
236 t
->addr
= TMP_LREG(t
);
242 static void tmp_drop(int n
)
245 for (i
= ntmp
- n
; i
< ntmp
; i
++)
246 if (tmps
[i
].loc
== LOC_REG
)
247 regs
[tmps
[i
].addr
] = NULL
;
251 static void tmp_pop(int reg
)
253 struct tmp
*t
= TMP(0);
258 static struct tmp
*tmp_new(void)
260 return &tmps
[ntmp
++];
263 static void tmp_push(int reg
)
265 struct tmp
*t
= tmp_new();
268 stat_regs
|= 1 << reg
;
273 void o_local(long addr
)
275 struct tmp
*t
= tmp_new();
276 t
->addr
= localoff
[addr
];
285 struct tmp
*t
= tmp_new();
291 void o_sym(char *name
)
293 struct tmp
*t
= tmp_new();
294 strcpy(t
->sym
, name
);
300 void o_tmpdrop(int n
)
302 if (n
== -1 || n
> ntmp
)
312 /* make sure tmps remain intact after a conditional expression */
316 for (i
= 0; i
< ntmp
- 1; i
++)
320 void o_forkpush(void)
325 void o_forkjoin(void)
332 struct tmp
*t1
= TMP(0);
333 struct tmp
*t2
= TMP(1);
335 memcpy(&t
, t1
, sizeof(t
));
336 memcpy(t1
, t2
, sizeof(t
));
337 memcpy(t2
, &t
, sizeof(t
));
338 if (t1
->loc
== LOC_REG
)
340 if (t2
->loc
== LOC_REG
)
344 static int reg_get(int mask
)
348 for (i
= 0; i
< N_TMPS
; i
++)
349 if ((1 << tmpregs
[i
]) & mask
&& !regs
[tmpregs
[i
]]) {
350 stat_regs
|= 1 << tmpregs
[i
];
353 for (i
= 0; i
< N_TMPS
; i
++)
354 if ((1 << tmpregs
[i
]) & mask
) {
355 reg_free(tmpregs
[i
], 0);
356 stat_regs
|= 1 << tmpregs
[i
];
359 die("reg_get: out of registers!\n");
363 static int reg_tmp(struct tmp
*t
, int mask
, int readonly
)
365 if (t
->loc
== LOC_REG
&& (mask
& (1 << t
->addr
)))
366 if (!(r_lregs() & (1 << t
->addr
)) || (readonly
&& !t
->bt
))
368 return reg_get(mask
);
371 static int reg_tmpn(struct tmp
*t
, int notmask
, int readonly
)
373 if (t
->loc
== LOC_REG
&& !(notmask
& (1 << t
->addr
)))
374 if (!(r_lregs() & (1 << t
->addr
)) || (readonly
&& !t
->bt
))
376 return reg_get(~notmask
);
379 static void tmp_copy(struct tmp
*t1
)
381 struct tmp
*t2
= tmp_new();
382 memcpy(t2
, t1
, sizeof(*t1
));
383 if (!(t1
->loc
& (LOC_REG
| LOC_MEM
)))
385 if (t1
->loc
== LOC_MEM
) {
386 tmp_mv(t2
, reg_get(R_TMPS
));
387 } else if (t1
->loc
== LOC_REG
) {
388 t2
->addr
= reg_tmpn(t2
, 1 << t1
->addr
, 0);
389 i_mov(t2
->addr
, t1
->addr
);
391 stat_regs
|= 1 << t2
->addr
;
400 void o_deref(unsigned bt
)
402 struct tmp
*t
= TMP(0);
405 t
->addr
= TMP_LREG(t
);
408 tmp_to(t
, reg_tmp(t
, R_TMPS
, 0));
415 struct tmp
*t
= TMP(0);
416 tmp_to(t
, reg_tmp(t
, R_TMPS
, 0));
419 #define TMP_NUM(t) ((t)->loc == LOC_NUM && !(t)->bt)
420 #define LOCAL_PTR(t) ((t)->loc == LOC_LOCAL && !(t)->bt)
421 #define SYM_PTR(t) ((t)->loc == LOC_SYM && !(t)->bt)
423 int o_popnum(long *c
)
425 struct tmp
*t
= TMP(0);
442 long o_mklocal(int sz
)
445 localoff
[nlocals
] = sp_push(ALIGN(sz
, LONGSZ
));
449 void o_rmlocal(long addr
, int sz
)
454 long o_arg2loc(int i
)
459 #define MOVXX(bt) ((BT_SZ(bt) == LONGSZ ? O_MOV : ((bt) & BT_SIGNED ? O_SX : O_ZX)))
461 void o_assign(unsigned bt
)
463 struct tmp
*t1
= TMP(0);
464 struct tmp
*t2
= TMP(1);
465 int r1
= reg_tmp(t1
, BT_SZ(bt
) > 1 ? R_TMPS
: R_BYTE
, 1);
466 int r2
= reg_tmpn(t2
, 1 << r1
, 1);
469 if (TMP_ISLREG(t2
)) {
470 i_op_imm(MOVXX(bt
), TMP_LREG(t2
), r1
, BT_SZ(bt
) * 8);
475 if (t2
->loc
== LOC_LOCAL
) {
477 off
= t2
->addr
+ t2
->off
;
482 i_save(r1
, r2
, off
, bt
);
488 static long cu(int op
, long i
)
501 static int c_uop(int op
)
503 struct tmp
*t1
= TMP(0);
507 o_num(cu(op
, t1
->addr
));
511 static long cb(int op
, long a
, long b
)
536 return (unsigned long) a
>> b
;
553 static int c_bop(int op
)
555 struct tmp
*t1
= TMP(0);
556 struct tmp
*t2
= TMP(1);
557 int locs
= LOCAL_PTR(t1
) + LOCAL_PTR(t2
);
558 int syms
= SYM_PTR(t1
) + SYM_PTR(t2
);
559 int nums
= TMP_NUM(t1
) + TMP_NUM(t2
);
560 if (syms
+ locs
== 2 || syms
+ nums
+ locs
!= 2)
563 if ((op
& 0xff) != O_ADD
&& ((op
& 0xff) != O_SUB
|| TMP_NUM(t2
)))
566 long o1
= TMP_NUM(t1
) ? t1
->addr
: t1
->off
;
567 long o2
= TMP_NUM(t2
) ? t2
->addr
: t2
->off
;
568 long ret
= cb(op
, o2
, o1
);
571 if (t2
->loc
== LOC_LOCAL
)
576 long ret
= cb(op
, t2
->addr
, t1
->addr
);
583 /* allocate registers for the given binary or unary instruction */
584 static void regs2(int op
, int *rd
, int *r1
, int *r2
)
589 i_reg(op
, &md
, &m1
, &m2
, &mt
);
591 struct tmp
*t2
= TMP(0);
592 *r2
= reg_tmp(t2
, m2
, 1);
597 struct tmp
*t1
= TMP(m2
? 1 : 0);
598 *r1
= reg_tmp(t1
, m1
& ~all
, md
? 1 : 0);
603 if (m2
&& md
& tmp_mask
& (1 << *r2
))
605 else if (m1
&& md
& tmp_mask
& (1 << *r1
))
608 *rd
= reg_get(md
& ~all
);
614 for (i
= 0; i
< N_TMPS
; i
++)
615 if (mt
& ~all
& (1 << tmpregs
[i
]))
616 reg_free(tmpregs
[i
], all
| mt
);
619 tmp_drop(m2
? 2 : 1);
622 /* allocate registers for a 3 operand instruction */
623 static void regs3(int op
, int *r0
, int *r1
, int *r2
)
626 struct tmp
*t0
= TMP(2);
627 struct tmp
*t1
= TMP(1);
628 struct tmp
*t2
= TMP(0);
631 i_reg(op
, &m0
, &m1
, &m2
, &mt
);
633 *r2
= reg_tmp(t2
, m2
, 1);
638 *r1
= reg_tmp(t1
, m1
& ~(1 << *r2
), 1);
643 *r0
= reg_tmp(t0
, m0
& ~((1 << *r2
) | (1 << *r1
)), 1);
648 for (i
= 0; i
< N_TMPS
; i
++)
649 if (mt
& ~all
& (1 << tmpregs
[i
]))
650 reg_free(tmpregs
[i
], all
| mt
);
656 static void op_imm(int op
, long n
)
659 regs2(op
| O_IMM
, &rd
, &r1
, &r2
);
660 i_op_imm(op
| O_IMM
, rd
, r1
, n
);
669 regs2(op
, &rd
, &r1
, &r2
);
670 i_op(op
, rd
, r1
, r2
);
674 static int bop_imm(int op
, long *n
, int swap
)
676 struct tmp
*t1
= TMP(0);
677 struct tmp
*t2
= TMP(1);
678 if (!TMP_NUM(t1
) && (!swap
|| !TMP_NUM(t2
)))
680 *n
= TMP_NUM(t1
) ? t1
->addr
: t2
->addr
;
689 static void bin_op(int op
, int swap
)
693 if (!bop_imm(op
, &n
, swap
)) {
694 regs2(op
| O_IMM
, &rd
, &r1
, &r2
);
695 i_op_imm(op
, rd
, r1
, n
);
697 regs2(op
, &rd
, &r1
, &r2
);
698 i_op(op
, rd
, r1
, r2
);
703 static int log2a(unsigned long n
)
706 for (i
= 0; i
< LONGSZ
* 8; i
++)
709 if (i
== LONGSZ
* 8 || !(n
>> (i
+ 1)))
714 /* optimized version of mul/div/mod for powers of two */
715 static int mul_2(int op
)
717 struct tmp
*t1
= TMP(0);
718 struct tmp
*t2
= TMP(1);
721 if ((op
& 0xff) == O_MUL
&& t2
->loc
== LOC_NUM
&& !t2
->bt
)
723 if (t1
->loc
!= LOC_NUM
|| t1
->bt
)
729 if ((op
& 0xff) == O_MUL
) {
745 op_imm((op
& O_SIGNED
) | O_SHR
, p
);
765 if ((op
& 0xf0) == 0x00) /* add */
766 bin_op(op
, (op
& 0xff) != O_SUB
);
767 if ((op
& 0xf0) == 0x10) /* shx */
769 if ((op
& 0xf0) == 0x20) { /* mul */
772 bin_op(op
, (op
& 0xff) == O_MUL
);
774 if ((op
& 0xf0) == 0x30)
775 bin_op(op
, (op
& 0xff) == O_EQ
|| (op
& 0xff) == O_NEQ
);
781 regs3(O_MCPY
, &r0
, &r1
, &r2
);
782 i_memcpy(r0
, r1
, r2
);
788 regs3(O_MSET
, &r0
, &r1
, &r2
);
789 i_memset(r0
, r1
, r2
);
792 void o_cast(unsigned bt
)
794 struct tmp
*t
= TMP(0);
795 if (!t
->bt
&& t
->loc
== LOC_NUM
) {
799 if (BT_SZ(bt
) != LONGSZ
)
800 op_imm(MOVXX(bt
), BT_SZ(bt
) * 8);
803 static void jxz(int id
, int z
)
805 int r
= reg_tmp(TMP(0), R_TMPS
, 1);
825 void o_call(int argc
, int rets
)
829 int aregs
= MIN(N_ARGS
, argc
);
830 for (i
= 0; i
< N_TMPS
; i
++)
831 if (regs
[tmpregs
[i
]] && regs
[tmpregs
[i
]] - tmps
< ntmp
- argc
)
832 tmp_mem(regs
[tmpregs
[i
]]);
834 sp_push(LONGSZ
* (argc
- aregs
));
835 for (i
= argc
- 1; i
>= aregs
; --i
) {
836 int reg
= reg_tmp(TMP(0), R_TMPS
, 1);
838 i_save(reg
, REG_SP
, (i
- aregs
) * LONGSZ
, LONGSZ
);
841 for (i
= aregs
- 1; i
>= 0; --i
)
842 tmp_to(TMP(aregs
- i
- 1), argregs
[i
]);
845 if (t
->loc
== LOC_SYM
&& !t
->bt
) {
846 i_call(t
->sym
, t
->off
);
849 int reg
= reg_tmp(t
, R_TMPS
, 1);
858 void o_bsnew(char *name
, int size
, int global
)
862 out_sym(name
, OUT_BSS
| (global
? OUT_GLOB
: 0), bsslen
, size
);
863 bsslen
+= ALIGN(size
, OUT_ALIGNMENT
);
866 static char dat_names
[NDATS
][NAMELEN
];
867 static int dat_offs
[NDATS
];
870 long o_dsnew(char *name
, int size
, int global
)
877 err("nomem: NDATS reached!\n");
878 strcpy(dat_names
[idx
], name
);
879 dat_offs
[idx
] = dslen
;
880 out_sym(name
, OUT_DS
| (global
? OUT_GLOB
: 0), dslen
, size
);
881 dslen
+= ALIGN(size
, OUT_ALIGNMENT
);
882 return dat_offs
[idx
];
885 void o_dscpy(long addr
, void *buf
, int len
)
887 memcpy(ds
+ addr
, buf
, len
);
890 static int dat_off(char *name
)
893 for (i
= 0; i
< ndats
; i
++)
894 if (!strcmp(name
, dat_names
[i
]))
899 void o_dsset(char *name
, int off
, unsigned bt
)
901 struct tmp
*t
= TMP(0);
902 int sym_off
= dat_off(name
) + off
;
907 if (t
->loc
== LOC_NUM
&& !t
->bt
) {
909 memcpy(ds
+ sym_off
, &t
->addr
, BT_SZ(bt
));
911 if (t
->loc
== LOC_SYM
&& !t
->bt
) {
912 out_rel(t
->sym
, OUT_DS
, sym_off
);
913 memcpy(ds
+ sym_off
, &t
->off
, BT_SZ(bt
));
921 out_write(fd
, cs
, cslen
, ds
, dslen
);
924 static void func_reset(void)
928 memset(regs
, 0, sizeof(regs
));
938 stat_regs
= 1 << REG_RET
;
939 for (i
= 0; i
< func_argc
; i
++) {
940 localoff
[nlocals
++] = i_args() + argaddr
;
941 if (i
>= N_ARGS
|| r_sargs() & (1 << argregs
[i
]))
946 void o_func_beg(char *name
, int argc
, int global
, int varg
)
953 tmp_mask
= N_TMPS
> 6 ? R_TMPS
& ~R_SAVED
: R_TMPS
;
955 out_sym(name
, (global
? OUT_GLOB
: 0) | OUT_CS
, cslen
, 0);
956 i_prolog(argc
, varg
, r_sargs(), tmp_mask
& R_SAVED
, 1, 1);
968 int initfp
, subsp
, sregs
;
974 locregs
= r_alloc(leaf
, stat_regs
);
975 subsp
= nlocals
> locregs
|| !leaf
;
976 initfp
= subsp
|| stat_tmps
|| func_argc
> N_ARGS
;
977 sregs
= (r_lregs() | stat_regs
) & R_SAVED
;
978 tmp_mask
= stat_regs
;
981 i_prolog(func_argc
, func_varg
, r_sargs(), sregs
, initfp
, subsp
);
983 for (i
= 0; i
< MIN(func_argc
, N_ARGS
); i
++)
984 if (r_regmap(i
) >= 0 && r_regmap(i
) != argregs
[i
])
985 i_mov(r_regmap(i
), argregs
[i
]);
986 for (i
= N_ARGS
; i
< func_argc
; i
++)
987 if (r_regmap(i
) >= 0)
988 i_load(r_regmap(i
), REG_FP
, localoff
[i
], LONGSZ
);
991 void o_func_end(void)