gen: move the register allocation to reg.c
[neatcc.git] / gen.h
blob4beaab49b6d2f710aa64402f4a77e6089eb090c4
1 #define SECSIZE (1 << 18)
2 #define MAXTMP (1 << 12)
3 #define NLOCALS (1 << 10)
5 /* basic types */
6 #define BT_SZMASK 0x00ff
7 #define BT_SIGNED 0x0100
8 #define BT_SZ(bt) ((bt) & BT_SZMASK)
10 #define O_SIGNED 0x100
11 /* binary instructions for o_bop() */
12 #define O_ADD 0x00
13 #define O_SUB 0x01
14 #define O_AND 0x02
15 #define O_OR 0x03
16 #define O_XOR 0x04
17 #define O_SHL 0x10
18 #define O_SHR 0x11
19 #define O_MUL 0x20
20 #define O_DIV 0x21
21 #define O_MOD 0x22
22 #define O_LT 0x30
23 #define O_GT 0x31
24 #define O_LE 0x32
25 #define O_GE 0x33
26 #define O_EQ 0x34
27 #define O_NEQ 0x35
28 /* unary instructions for o_uop() */
29 #define O_NEG 0x40
30 #define O_NOT 0x41
31 #define O_LNOT 0x42
33 /* operations */
34 void o_bop(int op);
35 void o_uop(int op);
36 void o_cast(unsigned bt);
37 void o_memcpy(void);
38 void o_memset(void);
39 void o_call(int argc, int ret);
40 void o_ret(int ret);
41 void o_assign(unsigned bt);
42 void o_deref(unsigned bt);
43 void o_load(void);
44 int o_popnum(long *c);
45 /* pushing values */
46 void o_num(long n);
47 void o_local(long addr);
48 void o_sym(char *sym);
49 void o_tmpdrop(int n);
50 void o_tmpswap(void);
51 void o_tmpcopy(void);
52 /* handling locals */
53 long o_mklocal(int size);
54 void o_rmlocal(long addr, int sz);
55 long o_arg2loc(int i);
56 /* branches */
57 void o_label(int id);
58 void o_jmp(int id);
59 void o_jz(int id);
60 void o_jnz(int id);
61 /* conditional instructions */
62 void o_fork(void);
63 void o_forkpush(void);
64 void o_forkjoin(void);
65 /* data/bss sections */
66 void o_mkbss(char *name, int size, int global);
67 void *o_mkdat(char *name, int size, int global);
68 void o_datset(char *name, int off, unsigned bt);
69 /* functions */
70 void o_func_beg(char *name, int argc, int global, int vararg);
71 void o_func_end(void);
72 /* output */
73 void o_write(int fd);
74 /* passes */
75 void o_pass1(void);
76 void o_pass2(void);
79 * neatcc architecture-dependent code-generation interface
81 * To make maintaining three different architectures easier and unifying the
82 * optimization patch, I've extracted gen.c from x86.c and arm.c. The i_*()
83 * functions are now the low level architecture-specific code generation
84 * entry points. The differences between RISC and CISC architectures,
85 * actually the annoying asymmetry in CISC architecture, made this interface
86 * a bit more complex than it could have ideally been. Nevertheless, the
87 * benefits of extracting gen.c and the cleaner design, especially with the
88 * presence of the optimization patch, is worth the added complexity.
90 * I tried to make the interface as small as possible. I'll describe the
91 * key functions and macros here. Overall, there were many challenges for
92 * extracting gen.c including:
93 * + Different register sets; caller/callee saved and argument registers
94 * + CISC-style instructions that work on limited registers and parameters
95 * + Different instruction formats and immediate value limitations
96 * + Producing epilog, prolog, and local variable addresses when optimizing
98 * Instructions:
99 * + i_reg(): The mask of allowed registers for each operand of an instruction.
100 * If md is zero, we assume the destination register should be equal to the
101 * first register, as in CISC architectures. m2 can be zero which means
102 * the instruction doesn't have three operands. mt denotes the mask of
103 * registers that may lose their contents after the instruction.
104 * + i_load(), i_save(), i_mov(), i_num(), i_sym(): The name is clear.
105 * + i_imm(): Specifies if the given immediate can be encoded for the given
106 * instruction.
107 * + i_jmp(), i_fill(): Branching instructions. If rn >= 0, the branch is
108 * a conditional branch: jump only the register rn is zero (or nonzero if
109 * jc is nonzero). nbytes specifies the number of bytes necessary for
110 * holding the jump distance; useful if the architecture supports short
111 * branching instructions. i_fill() actually fills the jump at src in
112 * code segment. It returns the amount of bytes jumped.
113 * + i_args(): The offset of the first argument from the frame pointer.
114 * It is probably positive.
115 * + i_args(): The offset of the first local from the frame pointer.
116 * It is probably negative
117 * + tmpregs: Register that can be used for holding temporaries.
118 * + argregs: Register for holding the first N_ARGS arguments.
120 * There are a few other macros defined in arch headers. See x64.h as
121 * an example.
124 #ifdef NEATCC_ARM
125 #include "arm.h"
126 #endif
127 #ifdef NEATCC_X64
128 #include "x64.h"
129 #endif
130 #ifdef NEATCC_X86
131 #include "x86.h"
132 #endif
134 /* intermediate instructions */
135 #define O_IMM 0x200 /* mask for immediate instructions */
136 #define O_MSET 0x51 /* memset() */
137 #define O_MCPY 0x52 /* memcpy() */
138 #define O_MOV 0x53 /* mov */
139 #define O_SX 0x54 /* sign extend */
140 #define O_ZX 0x55 /* zero extend */
142 void i_load(int rd, int rn, int off, int bt);
143 void i_save(int rd, int rn, int off, int bt);
144 void i_mov(int rd, int rn);
145 void i_reg(int op, int *md, int *m1, int *m2, int *mt);
146 void i_op(int op, int rd, int r1, int r2);
147 int i_imm(int op, long imm);
148 void i_op_imm(int op, int rd, int r1, long n);
150 void i_num(int rd, long n);
151 void i_sym(int rd, char *sym, int off);
153 void i_jmp(int rn, int jc, int nbytes);
154 long i_fill(long src, long dst, int nbytes);
156 void i_call(char *sym, int off);
157 void i_call_reg(int rd);
158 void i_memset(int r0, int r1, int r2);
159 void i_memcpy(int r0, int r1, int r2);
161 int i_args(void); /* the address of the first arg relative to fp */
162 int i_sp(void); /* the address of the first local relative to fp */
164 void i_prolog(int argc, int varg, int sargs, int sregs, int initfp, int subsp);
165 void i_epilog(int sp_max);
166 void i_done(void);
168 extern int tmpregs[];
169 extern int argregs[];
171 /* code segment text */
172 extern char cs[]; /* code segment */
173 extern int cslen; /* code segment length */
174 extern int pass1; /* first pass */
176 void os(void *s, int n);
177 void oi(long n, int l);