1 /* neatcc code generation interface */
3 #define BT_SZMASK 0x00ff
4 #define BT_SIGNED 0x0100
5 #define BT_SZ(bt) ((bt) & BT_SZMASK)
8 /* binary instructions for o_bop() */
25 /* unary instructions for o_uop() */
30 /* operations on the stack */
31 void o_bop(int op
); /* binary operation */
32 void o_uop(int op
); /* unary operation */
33 void o_cast(unsigned bt
);
36 void o_call(int argc
, int ret
);
38 void o_assign(unsigned bt
);
39 void o_deref(unsigned bt
);
41 int o_popnum(long *c
);
42 /* pushing values to the stack */
44 void o_local(long addr
);
45 void o_sym(char *sym
);
46 void o_tmpdrop(int n
);
50 long o_mklocal(int size
);
51 void o_rmlocal(long addr
, int sz
);
52 long o_arg2loc(int i
);
58 /* conditional instructions */
60 void o_forkpush(void);
61 void o_forkjoin(void);
62 /* data/bss sections */
63 long o_dsnew(char *name
, int size
, int global
);
64 void o_dscpy(long addr
, void *buf
, int len
);
65 void o_dsset(char *name
, int off
, unsigned bt
);
66 void o_bsnew(char *name
, int size
, int global
);
68 void o_func_beg(char *name
, int argc
, int global
, int vararg
);
69 void o_func_end(void);
77 * neatcc architecture-dependent code-generation interface
79 * To make maintaining three different architectures easier and unifying the
80 * optimization patch, I've extracted gen.c from x86.c and arm.c. The i_*()
81 * functions are now the low level architecture-specific code generation
82 * entry points. The differences between RISC and CISC architectures,
83 * actually the annoying asymmetry in CISC architecture, made this interface
84 * a bit more complex than it could have ideally been. Nevertheless, the
85 * benefits of extracting gen.c and the cleaner design, especially with the
86 * presence of the optimization patch, is worth the added complexity.
88 * I tried to make the interface as small as possible. I'll describe the
89 * key functions and macros here. Overall, there were many challenges for
90 * extracting gen.c including:
91 * + Different register sets; caller/callee saved and argument registers
92 * + CISC-style instructions that work on limited registers and parameters
93 * + Different instruction formats and immediate value limitations
94 * + Producing epilog, prolog, and local variable addresses when optimizing
97 * + i_reg(): The mask of allowed registers for each operand of an instruction.
98 * If md is zero, we assume the destination register should be equal to the
99 * first register, as in CISC architectures. m2 can be zero which means
100 * the instruction doesn't have three operands. mt denotes the mask of
101 * registers that may lose their contents after the instruction.
102 * + i_load(), i_save(), i_mov(), i_num(), i_sym(): The name is clear.
103 * + i_imm(): Specifies if the given immediate can be encoded for the given
105 * + i_jmp(), i_fill(): Branching instructions. If rn >= 0, the branch is
106 * a conditional branch: jump only the register rn is zero (or nonzero if
107 * jc is nonzero). nbytes specifies the number of bytes necessary for
108 * holding the jump distance; useful if the architecture supports short
109 * branching instructions. i_fill() actually fills the jump at src in
110 * code segment. It returns the amount of bytes jumped.
111 * + i_args(): The offset of the first argument from the frame pointer.
112 * It is probably positive.
113 * + i_args(): The offset of the first local from the frame pointer.
114 * It is probably negative
115 * + tmpregs: Register that can be used for holding temporaries.
116 * + argregs: Register for holding the first N_ARGS arguments.
118 * There are a few other macros defined in arch headers. See x64.h as
132 /* intermediate instructions */
133 #define O_IMM 0x200 /* mask for immediate instructions */
134 #define O_MSET 0x51 /* memset() */
135 #define O_MCPY 0x52 /* memcpy() */
136 #define O_MOV 0x53 /* mov */
137 #define O_SX 0x54 /* sign extend */
138 #define O_ZX 0x55 /* zero extend */
140 void i_load(int rd
, int rn
, int off
, int bt
);
141 void i_save(int rd
, int rn
, int off
, int bt
);
142 void i_mov(int rd
, int rn
);
143 void i_reg(int op
, int *md
, int *m1
, int *m2
, int *mt
);
144 void i_op(int op
, int rd
, int r1
, int r2
);
145 int i_imm(int op
, long imm
);
146 void i_op_imm(int op
, int rd
, int r1
, long n
);
148 void i_num(int rd
, long n
);
149 void i_sym(int rd
, char *sym
, int off
);
151 void i_jmp(int rn
, int jc
, int nbytes
);
152 long i_fill(long src
, long dst
, int nbytes
);
154 void i_call(char *sym
, int off
);
155 void i_call_reg(int rd
);
156 void i_memset(int r0
, int r1
, int r2
);
157 void i_memcpy(int r0
, int r1
, int r2
);
159 int i_args(void); /* the address of the first arg relative to fp */
160 int i_sp(void); /* the address of the first local relative to fp */
162 void i_prolog(int argc
, int varg
, int sargs
, int sregs
, int initfp
, int subsp
);
163 void i_epilog(int sp_max
);
166 extern int tmpregs
[];
167 extern int argregs
[];
169 /* code segment text */
170 extern char cs
[]; /* code segment */
171 extern int cslen
; /* code segment length */
172 extern int pass1
; /* first pass */
174 void os(void *s
, int n
);
175 void oi(long n
, int l
);