9 /* variable location */
14 #define LOC_LOCAL 0x10
16 #define MIN(a, b) ((a) < (b) ? (a) : (b))
17 #define ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1))
19 char cs
[SECSIZE
]; /* code segment */
21 static char ds
[SECSIZE
]; /* data segment */
23 static long bsslen
; /* bss segment size */
25 static long sp
; /* stack pointer offset from R_RBP */
26 static long sp_max
; /* maximum stack pointer offset */
27 static long sp_tmp
; /* sp for the first tmp on the stack */
28 static int localoff
[NLOCALS
]; /* the offset of locals on the stack */
29 static int nlocals
; /* number of locals */
36 /* function statistics */
37 int pass1
; /* collect statistics; 1st pass */
38 static int stat_calls
; /* # of function calls */
39 static int stat_tmps
; /* # of stack temporaries */
40 static int stat_regs
; /* mask of used registers */
42 /* optimization info */
43 static int pass2
; /* use the collected statistics in the 1st pass */
44 static int tmp_mask
; /* registers that can be used for tmps */
46 /* register allocation for locals */
47 #define TMP_ISLREG(t) (!(t)->bt && (t)->loc == LOC_LOCAL && r_regmap((t)->id) >= 0)
48 #define TMP_LREG(t) (r_regmap((t)->id))
50 #define TMP(i) (((i) < ntmp) ? &tmps[ntmp - 1 - (i)] : NULL)
55 long off
; /* offset from a symbol or a local */
56 unsigned loc
; /* variable location */
57 unsigned bt
; /* type of address; zero when not a pointer */
58 int id
; /* local variable id */
62 static struct tmp
*regs
[N_REGS
];
65 #define MAXJMPS (1 << 14)
67 static long labels
[MAXJMPS
];
69 static long jmp_loc
[MAXJMPS
];
70 static int jmp_goal
[MAXJMPS
];
71 static int jmp_len
[MAXJMPS
];
82 /* the number of bytes needed for holding jmp displacement */
83 static int jmp_sz(int id
)
85 long n
= jmp_len
[id
] > 0 ? jmp_len
[id
] : -jmp_len
[id
];
89 return n
== 0 ? 0 : 1;
90 return n
< 0x7000 ? 2 : 4;
93 static void jmp_add(int id
, int rn
, int z
)
97 err("nomem: MAXJMPS reached!\n");
98 i_jmp(rn
, z
, jmp_sz(njmps
));
99 jmp_loc
[njmps
] = cslen
;
100 jmp_goal
[njmps
] = id
;
104 static void jmp_fill(void)
107 for (i
= 0; i
< njmps
; i
++)
108 jmp_len
[i
] = i_fill(jmp_loc
[i
], labels
[jmp_goal
[i
]], jmp_sz(i
));
111 /* generating code */
113 void os(void *s
, int n
)
116 cs
[cslen
++] = *(char *) (s
++);
119 void oi(long n
, int l
)
127 static long sp_push(int sz
)
129 sp
-= ALIGN(sz
, LONGSZ
);
135 static void tmp_mem(struct tmp
*tmp
)
138 if (tmp
->loc
!= LOC_REG
|| (1 << src
) & r_lregs())
142 tmp
->addr
= sp_push(LONGSZ
);
143 i_save(src
, REG_FP
, tmp
->addr
, LONGSZ
);
149 static void num_cast(struct tmp
*t
, unsigned bt
)
151 if (!(bt
& BT_SIGNED
) && BT_SZ(bt
) != LONGSZ
)
152 t
->addr
&= ((1l << (long) (BT_SZ(bt
) * 8)) - 1);
153 if (bt
& BT_SIGNED
&& BT_SZ(bt
) != LONGSZ
&&
154 t
->addr
> (1l << (BT_SZ(bt
) * 8 - 1)))
155 t
->addr
= -((1l << (BT_SZ(bt
) * 8)) - t
->addr
);
158 static void tmp_reg(struct tmp
*tmp
, int dst
, int deref
)
165 if (tmp
->loc
== LOC_NUM
) {
166 i_num(dst
, tmp
->addr
);
171 if (tmp
->loc
== LOC_SYM
) {
172 i_sym(dst
, tmp
->sym
, tmp
->off
);
177 if (tmp
->loc
== LOC_REG
) {
179 i_load(dst
, tmp
->addr
, 0, bt
);
180 else if (dst
!= tmp
->addr
)
181 i_mov(dst
, tmp
->addr
);
182 regs
[tmp
->addr
] = NULL
;
184 if (tmp
->loc
== LOC_LOCAL
) {
190 i_load(dst
, REG_FP
, tmp
->addr
+ tmp
->off
, bt
);
192 i_op_imm(O_ADD
, dst
, REG_FP
, tmp
->addr
+ tmp
->off
);
194 if (tmp
->loc
== LOC_MEM
) {
195 i_load(dst
, REG_FP
, tmp
->addr
, LONGSZ
);
197 i_load(dst
, dst
, 0, bt
);
200 stat_regs
|= 1 << dst
;
205 /* empty the given register, but never touch the registers in rsrvd mask */
206 static void reg_free(int reg
, int rsrvd
)
212 for (i
= 0; i
< N_TMPS
; i
++)
213 if (!regs
[tmpregs
[i
]] && ~rsrvd
& (1 << tmpregs
[i
])) {
214 tmp_reg(regs
[reg
], tmpregs
[i
], 0);
220 static void reg_for(int reg
, struct tmp
*t
)
222 if (regs
[reg
] && regs
[reg
] != t
)
226 static void tmp_mv(struct tmp
*t
, int reg
)
232 static void tmp_to(struct tmp
*t
, int reg
)
235 if (t
->loc
== LOC_LOCAL
&& TMP_ISLREG(t
)) {
237 t
->addr
= TMP_LREG(t
);
243 static void tmp_drop(int n
)
246 for (i
= ntmp
- n
; i
< ntmp
; i
++)
247 if (tmps
[i
].loc
== LOC_REG
)
248 regs
[tmps
[i
].addr
] = NULL
;
252 static void tmp_pop(int reg
)
254 struct tmp
*t
= TMP(0);
259 static struct tmp
*tmp_new(void)
261 return &tmps
[ntmp
++];
264 static void tmp_push(int reg
)
266 struct tmp
*t
= tmp_new();
269 stat_regs
|= 1 << reg
;
274 void o_local(long addr
)
276 struct tmp
*t
= tmp_new();
277 t
->addr
= localoff
[addr
];
286 struct tmp
*t
= tmp_new();
292 void o_sym(char *name
)
294 struct tmp
*t
= tmp_new();
295 strcpy(t
->sym
, name
);
301 void o_tmpdrop(int n
)
303 if (n
== -1 || n
> ntmp
)
313 /* make sure tmps remain intact after a conditional expression */
317 for (i
= 0; i
< ntmp
- 1; i
++)
321 void o_forkpush(void)
326 void o_forkjoin(void)
333 struct tmp
*t1
= TMP(0);
334 struct tmp
*t2
= TMP(1);
336 memcpy(&t
, t1
, sizeof(t
));
337 memcpy(t1
, t2
, sizeof(t
));
338 memcpy(t2
, &t
, sizeof(t
));
339 if (t1
->loc
== LOC_REG
)
341 if (t2
->loc
== LOC_REG
)
345 static int reg_get(int mask
)
349 for (i
= 0; i
< N_TMPS
; i
++)
350 if ((1 << tmpregs
[i
]) & mask
&& !regs
[tmpregs
[i
]]) {
351 stat_regs
|= 1 << tmpregs
[i
];
354 for (i
= 0; i
< N_TMPS
; i
++)
355 if ((1 << tmpregs
[i
]) & mask
) {
356 reg_free(tmpregs
[i
], 0);
357 stat_regs
|= 1 << tmpregs
[i
];
360 die("reg_get: out of registers!\n");
364 static int reg_tmp(struct tmp
*t
, int mask
, int readonly
)
366 if (t
->loc
== LOC_REG
&& (mask
& (1 << t
->addr
)))
367 if (!(r_lregs() & (1 << t
->addr
)) || (readonly
&& !t
->bt
))
369 return reg_get(mask
);
372 static int reg_tmpn(struct tmp
*t
, int notmask
, int readonly
)
374 if (t
->loc
== LOC_REG
&& !(notmask
& (1 << t
->addr
)))
375 if (!(r_lregs() & (1 << t
->addr
)) || (readonly
&& !t
->bt
))
377 return reg_get(~notmask
);
380 static void tmp_copy(struct tmp
*t1
)
382 struct tmp
*t2
= tmp_new();
383 memcpy(t2
, t1
, sizeof(*t1
));
384 if (!(t1
->loc
& (LOC_REG
| LOC_MEM
)))
386 if (t1
->loc
== LOC_MEM
) {
387 tmp_mv(t2
, reg_get(R_TMPS
));
388 } else if (t1
->loc
== LOC_REG
) {
389 t2
->addr
= reg_tmpn(t2
, 1 << t1
->addr
, 0);
390 i_mov(t2
->addr
, t1
->addr
);
392 stat_regs
|= 1 << t2
->addr
;
401 void o_deref(unsigned bt
)
403 struct tmp
*t
= TMP(0);
406 t
->addr
= TMP_LREG(t
);
409 tmp_to(t
, reg_tmp(t
, R_TMPS
, 0));
416 struct tmp
*t
= TMP(0);
417 tmp_to(t
, reg_tmp(t
, R_TMPS
, 0));
420 #define TMP_NUM(t) ((t)->loc == LOC_NUM && !(t)->bt)
421 #define LOCAL_PTR(t) ((t)->loc == LOC_LOCAL && !(t)->bt)
422 #define SYM_PTR(t) ((t)->loc == LOC_SYM && !(t)->bt)
424 int o_popnum(long *c
)
426 struct tmp
*t
= TMP(0);
443 long o_mklocal(int sz
)
446 localoff
[nlocals
] = sp_push(ALIGN(sz
, LONGSZ
));
450 void o_rmlocal(long addr
, int sz
)
455 long o_arg2loc(int i
)
460 #define MOVXX(bt) ((BT_SZ(bt) == LONGSZ ? O_MOV : ((bt) & BT_SIGNED ? O_SX : O_ZX)))
462 void o_assign(unsigned bt
)
464 struct tmp
*t1
= TMP(0);
465 struct tmp
*t2
= TMP(1);
466 int r1
= reg_tmp(t1
, BT_SZ(bt
) > 1 ? R_TMPS
: R_BYTE
, 1);
467 int r2
= reg_tmpn(t2
, 1 << r1
, 1);
470 if (TMP_ISLREG(t2
)) {
471 i_op_imm(MOVXX(bt
), TMP_LREG(t2
), r1
, BT_SZ(bt
) * 8);
476 if (t2
->loc
== LOC_LOCAL
) {
478 off
= t2
->addr
+ t2
->off
;
483 i_save(r1
, r2
, off
, bt
);
489 static long cu(int op
, long i
)
502 static int c_uop(int op
)
504 struct tmp
*t1
= TMP(0);
508 o_num(cu(op
, t1
->addr
));
512 static long cb(int op
, long a
, long b
)
537 return (unsigned long) a
>> b
;
554 static int c_bop(int op
)
556 struct tmp
*t1
= TMP(0);
557 struct tmp
*t2
= TMP(1);
558 int locs
= LOCAL_PTR(t1
) + LOCAL_PTR(t2
);
559 int syms
= SYM_PTR(t1
) + SYM_PTR(t2
);
560 int nums
= TMP_NUM(t1
) + TMP_NUM(t2
);
561 if (syms
+ locs
== 2 || syms
+ nums
+ locs
!= 2)
564 if ((op
& 0xff) != O_ADD
&& ((op
& 0xff) != O_SUB
|| TMP_NUM(t2
)))
567 long o1
= TMP_NUM(t1
) ? t1
->addr
: t1
->off
;
568 long o2
= TMP_NUM(t2
) ? t2
->addr
: t2
->off
;
569 long ret
= cb(op
, o2
, o1
);
572 if (t2
->loc
== LOC_LOCAL
)
577 long ret
= cb(op
, t2
->addr
, t1
->addr
);
584 /* allocate registers for the given binary or unary instruction */
585 static void regs2(int op
, int *rd
, int *r1
, int *r2
)
590 i_reg(op
, &md
, &m1
, &m2
, &mt
);
592 struct tmp
*t2
= TMP(0);
593 *r2
= reg_tmp(t2
, m2
, 1);
598 struct tmp
*t1
= TMP(m2
? 1 : 0);
599 *r1
= reg_tmp(t1
, m1
& ~all
, md
? 1 : 0);
604 if (m2
&& md
& tmp_mask
& (1 << *r2
))
606 else if (m1
&& md
& tmp_mask
& (1 << *r1
))
609 *rd
= reg_get(md
& ~all
);
615 for (i
= 0; i
< N_TMPS
; i
++)
616 if (mt
& ~all
& (1 << tmpregs
[i
]))
617 reg_free(tmpregs
[i
], all
| mt
);
620 tmp_drop(m2
? 2 : 1);
623 /* allocate registers for a 3 operand instruction */
624 static void regs3(int op
, int *r0
, int *r1
, int *r2
)
627 struct tmp
*t0
= TMP(2);
628 struct tmp
*t1
= TMP(1);
629 struct tmp
*t2
= TMP(0);
632 i_reg(op
, &m0
, &m1
, &m2
, &mt
);
634 *r2
= reg_tmp(t2
, m2
, 1);
639 *r1
= reg_tmp(t1
, m1
& ~(1 << *r2
), 1);
644 *r0
= reg_tmp(t0
, m0
& ~((1 << *r2
) | (1 << *r1
)), 1);
649 for (i
= 0; i
< N_TMPS
; i
++)
650 if (mt
& ~all
& (1 << tmpregs
[i
]))
651 reg_free(tmpregs
[i
], all
| mt
);
657 static void op_imm(int op
, long n
)
660 regs2(op
| O_IMM
, &rd
, &r1
, &r2
);
661 i_op_imm(op
| O_IMM
, rd
, r1
, n
);
670 regs2(op
, &rd
, &r1
, &r2
);
671 i_op(op
, rd
, r1
, r2
);
675 static int bop_imm(int op
, long *n
, int swap
)
677 struct tmp
*t1
= TMP(0);
678 struct tmp
*t2
= TMP(1);
679 if (!TMP_NUM(t1
) && (!swap
|| !TMP_NUM(t2
)))
681 *n
= TMP_NUM(t1
) ? t1
->addr
: t2
->addr
;
690 static void bin_op(int op
, int swap
)
694 if (!bop_imm(op
, &n
, swap
)) {
695 regs2(op
| O_IMM
, &rd
, &r1
, &r2
);
696 i_op_imm(op
, rd
, r1
, n
);
698 regs2(op
, &rd
, &r1
, &r2
);
699 i_op(op
, rd
, r1
, r2
);
704 static int log2a(unsigned long n
)
707 for (i
= 0; i
< LONGSZ
* 8; i
++)
710 if (i
== LONGSZ
* 8 || !(n
>> (i
+ 1)))
715 /* optimized version of mul/div/mod for powers of two */
716 static int mul_2(int op
)
718 struct tmp
*t1
= TMP(0);
719 struct tmp
*t2
= TMP(1);
722 if ((op
& 0xff) == O_MUL
&& t2
->loc
== LOC_NUM
&& !t2
->bt
)
724 if (t1
->loc
!= LOC_NUM
|| t1
->bt
)
730 if ((op
& 0xff) == O_MUL
) {
746 op_imm((op
& O_SIGNED
) | O_SHR
, p
);
766 if ((op
& 0xf0) == 0x00) /* add */
767 bin_op(op
, (op
& 0xff) != O_SUB
);
768 if ((op
& 0xf0) == 0x10) /* shx */
770 if ((op
& 0xf0) == 0x20) { /* mul */
773 bin_op(op
, (op
& 0xff) == O_MUL
);
775 if ((op
& 0xf0) == 0x30)
776 bin_op(op
, (op
& 0xff) == O_EQ
|| (op
& 0xff) == O_NEQ
);
782 regs3(O_MCPY
, &r0
, &r1
, &r2
);
783 i_memcpy(r0
, r1
, r2
);
789 regs3(O_MSET
, &r0
, &r1
, &r2
);
790 i_memset(r0
, r1
, r2
);
793 void o_cast(unsigned bt
)
795 struct tmp
*t
= TMP(0);
796 if (!t
->bt
&& t
->loc
== LOC_NUM
) {
800 if (BT_SZ(bt
) != LONGSZ
)
801 op_imm(MOVXX(bt
), BT_SZ(bt
) * 8);
804 static void jxz(int id
, int z
)
806 int r
= reg_tmp(TMP(0), R_TMPS
, 1);
826 void o_call(int argc
, int rets
)
830 int aregs
= MIN(N_ARGS
, argc
);
831 for (i
= 0; i
< N_TMPS
; i
++)
832 if (regs
[tmpregs
[i
]] && regs
[tmpregs
[i
]] - tmps
< ntmp
- argc
)
833 tmp_mem(regs
[tmpregs
[i
]]);
835 sp_push(LONGSZ
* (argc
- aregs
));
836 for (i
= argc
- 1; i
>= aregs
; --i
) {
837 int reg
= reg_tmp(TMP(0), R_TMPS
, 1);
839 i_save(reg
, REG_SP
, (i
- aregs
) * LONGSZ
, LONGSZ
);
842 for (i
= aregs
- 1; i
>= 0; --i
)
843 tmp_to(TMP(aregs
- i
- 1), argregs
[i
]);
846 if (t
->loc
== LOC_SYM
&& !t
->bt
) {
847 i_call(t
->sym
, t
->off
);
850 int reg
= reg_tmp(t
, R_TMPS
, 1);
859 void o_mkbss(char *name
, int size
, int global
)
863 out_sym(name
, OUT_BSS
| (global
? OUT_GLOB
: 0), bsslen
, size
);
864 bsslen
+= ALIGN(size
, OUT_ALIGNMENT
);
867 #define MAXDATS (1 << 10)
868 static char dat_names
[MAXDATS
][NAMELEN
];
869 static int dat_offs
[MAXDATS
];
872 void *o_mkdat(char *name
, int size
, int global
)
874 void *addr
= ds
+ dslen
;
880 err("nomem: MAXDATS reached!\n");
881 strcpy(dat_names
[idx
], name
);
882 dat_offs
[idx
] = dslen
;
883 out_sym(name
, OUT_DS
| (global
? OUT_GLOB
: 0), dslen
, size
);
884 dslen
+= ALIGN(size
, OUT_ALIGNMENT
);
888 static int dat_off(char *name
)
891 for (i
= 0; i
< ndats
; i
++)
892 if (!strcmp(name
, dat_names
[i
]))
897 void o_datset(char *name
, int off
, unsigned bt
)
899 struct tmp
*t
= TMP(0);
900 int sym_off
= dat_off(name
) + off
;
905 if (t
->loc
== LOC_NUM
&& !t
->bt
) {
907 memcpy(ds
+ sym_off
, &t
->addr
, BT_SZ(bt
));
909 if (t
->loc
== LOC_SYM
&& !t
->bt
) {
910 out_rel(t
->sym
, OUT_DS
, sym_off
);
911 memcpy(ds
+ sym_off
, &t
->off
, BT_SZ(bt
));
919 out_write(fd
, cs
, cslen
, ds
, dslen
);
922 static void func_reset(void)
926 memset(regs
, 0, sizeof(regs
));
936 stat_regs
= 1 << REG_RET
;
937 for (i
= 0; i
< func_argc
; i
++) {
938 localoff
[nlocals
++] = i_args() + argaddr
;
939 if (i
>= N_ARGS
|| r_sargs() & (1 << argregs
[i
]))
944 void o_func_beg(char *name
, int argc
, int global
, int varg
)
951 tmp_mask
= N_TMPS
> 6 ? R_TMPS
& ~R_SAVED
: R_TMPS
;
953 out_sym(name
, (global
? OUT_GLOB
: 0) | OUT_CS
, cslen
, 0);
954 i_prolog(argc
, varg
, r_sargs(), tmp_mask
& R_SAVED
, 1, 1);
966 int initfp
, subsp
, sregs
;
972 locregs
= r_alloc(leaf
, stat_regs
);
973 subsp
= nlocals
> locregs
|| !leaf
;
974 initfp
= subsp
|| stat_tmps
|| func_argc
> N_ARGS
;
975 sregs
= (r_lregs() | stat_regs
) & R_SAVED
;
976 tmp_mask
= stat_regs
;
979 i_prolog(func_argc
, func_varg
, r_sargs(), sregs
, initfp
, subsp
);
981 for (i
= 0; i
< MIN(func_argc
, N_ARGS
); i
++)
982 if (r_regmap(i
) >= 0 && r_regmap(i
) != argregs
[i
])
983 i_mov(r_regmap(i
), argregs
[i
]);
984 for (i
= N_ARGS
; i
< func_argc
; i
++)
985 if (r_regmap(i
) >= 0)
986 i_load(r_regmap(i
), REG_FP
, localoff
[i
], LONGSZ
);
989 void o_func_end(void)