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