rename vs to bt for basic type
[neatcc.git] / gen.c
blob72bd67658bd4b434eb304160dafebedb886d75a5
1 #include "gen.h"
2 #include "tok.h"
4 #define MAXTEMP (1 << 12)
5 #define TMP_CONST 1
6 #define TMP_ADDR 2
8 #define R_RAX 0x00
9 #define R_RCX 0x01
10 #define R_RDX 0x02
11 #define R_RBX 0x03
12 #define R_RSP 0x04
13 #define R_RBP 0x05
14 #define R_RSI 0x06
15 #define R_RDI 0x07
16 #define R_R8 0x08
17 #define R_R9 0x09
18 #define R_R10 0x10
19 #define R_R11 0x11
21 #define MOV_M2R 0x8b
22 #define MOV_R2X 0x89
23 #define ADD_R2R 0x01
24 #define SUB_R2R 0x29
26 #define TMP_BT(t) ((t)->type == TMP_ADDR ? 8 : (t)->bt)
28 static char buf[SECSIZE];
29 static char *cur;
30 static long sp;
31 static long spsub_addr;
32 static long maxsp;
33 static struct tmp {
34 long addr;
35 int type;
36 unsigned bt;
37 } tmp[MAXTEMP];
38 static int ntmp;
40 static void putint(char *s, long n, int l)
42 while (l--) {
43 *s++ = n;
44 n >>= 8;
48 static void os(char *s, int n)
50 while (n--)
51 *cur++ = *s++;
54 static void oi(long n, int l)
56 while (l--) {
57 *cur++ = n;
58 n >>= 8;
62 static void o_op(int op, int r1, int r2, unsigned bt)
64 int rex = 0;
65 if (r1 & 0x8)
66 rex |= 4;
67 if (r2 & 0x8)
68 rex |= 1;
69 if (rex || (bt & BT_SZMASK) == 8)
70 oi(0x48 | rex, 1);
71 if ((bt & BT_SZMASK) == 2)
72 oi(0x66, 1);
73 if ((bt & BT_SZMASK) == 1)
74 op &= ~0x1;
75 oi(op, 1);
78 static void memop(int op, int src, int base, int off, unsigned bt)
80 int dis = off == (char) off ? 1 : 4;
81 int mod = off == 4 ? 2 : 1;
82 o_op(op, src, base, bt);
83 if (!off)
84 mod = 0;
85 oi((mod << 6) | ((src & 0x07) << 3) | (base & 0x07), 1);
86 if (off)
87 oi(off, dis);
90 static void regop(int op, int src, int dst, unsigned bt)
92 o_op(op, src, dst, bt);
93 oi((3 << 6) | (src << 3) | (dst & 0x07), 1);
96 static long sp_push(int size)
98 long osp = sp;
99 sp += size;
100 if (sp > maxsp)
101 maxsp = sp;
102 return osp;
105 static void deref(unsigned bt)
107 memop(MOV_M2R, R_RAX, R_RAX, 0, bt);
110 static unsigned tmp_pop(int rval)
112 struct tmp *t = &tmp[--ntmp];
113 memop(MOV_M2R, R_RAX, R_RBP, -t->addr, TMP_BT(t));
114 sp = t->addr;
115 if (!rval && t->type == TMP_ADDR)
116 deref(t->bt);
117 return t->bt;
120 static void tmp_push(int type, unsigned bt)
122 struct tmp *t = &tmp[ntmp++];
123 t->addr = sp_push(8);
124 t->bt = bt;
125 t->type = type;
126 memop(MOV_R2X, R_RAX, R_RBP, -t->addr, TMP_BT(t));
129 void o_droptmp(void)
131 if (ntmp)
132 sp = tmp[0].addr;
133 ntmp = 0;
136 static long codeaddr(void)
138 return cur - buf;
141 void o_func_beg(char *name)
143 out_func_beg(name);
144 cur = buf;
145 os("\x55", 1); /* push %rbp */
146 os("\x48\x89\xe5", 3); /* mov %rsp, %rbp */
147 sp = 8;
148 maxsp = 0;
149 ntmp = 0;
150 os("\x48\x81\xec", 3); /* sub $xxx, %rsp */
151 spsub_addr = codeaddr();
152 oi(0, 4);
155 void o_num(int n, unsigned bt)
157 os("\xb8", 1);
158 oi(n, 4);
159 tmp_push(TMP_CONST, bt);
162 void o_deref(unsigned bt)
164 tmp_pop(0);
165 tmp_push(TMP_ADDR, bt);
168 void o_ret(unsigned bt)
170 if (bt)
171 tmp_pop(0);
172 else
173 os("\x31\xc0", 3); /* xor %eax, %eax */
174 os("\xc9\xc3", 2); /* leave; ret; */
177 static int binop(void)
179 int vs1, vs2;
180 vs1 = tmp_pop(0);
181 regop(MOV_R2X, R_RAX, R_RBX, vs1);
182 vs2 = tmp_pop(0);
183 return vs1;
186 void o_add(void)
188 int bt = binop();
189 regop(ADD_R2R, R_RBX, R_RAX, bt);
190 tmp_push(TMP_CONST, bt);
193 void o_sub(void)
195 int bt = binop();
196 regop(SUB_R2R, R_RBX, R_RAX, bt);
197 tmp_push(TMP_CONST, bt);
200 void o_func_end(void)
202 os("\xc9\xc3", 2); /* leave; ret; */
203 out_func_end(buf, cur - buf);
204 putint(buf + spsub_addr, maxsp + 8, 4);
207 void o_local(long addr, unsigned bt)
209 os("\x48\x89\xe8", 3); /* mov %rbp, %rax */
210 os("\x48\x05", 2); /* add $addr, %rax */
211 oi(-addr, 4);
212 tmp_push(TMP_ADDR, bt);
215 long o_mklocal(unsigned bt)
217 return sp_push(8);
220 static int arg_regs[] = {R_RDI, R_RSI, R_RDX, R_RCX, R_R8, R_R9};
222 long o_arg(int i, unsigned bt)
224 long addr = o_mklocal(bt);
225 memop(MOV_R2X, arg_regs[i], R_RBP, -addr, bt);
226 return addr;
229 void o_assign(unsigned bt)
231 int vs2 = tmp_pop(0);
232 regop(MOV_R2X, R_RAX, R_RBX, vs2);
233 tmp_pop(1);
234 memop(MOV_R2X, R_RBX, R_RAX, 0, bt);
237 long o_mklabel(void)
239 return codeaddr();
242 void o_jz(long addr)
244 os("\x48\x85\xc0", 3); /* test %rax, %rax */
245 os("\x0f\x84", 2); /* jz $addr */
246 oi(codeaddr() - addr - 4, 4);
249 long o_stubjz(void)
251 o_jz(codeaddr());
252 return cur - buf - 4;
255 void o_filljz(long addr)
257 putint(buf + addr, codeaddr() - addr - 4, 4);
260 void o_symaddr(char *name, unsigned bt)
262 os("\x48\xc7\xc0", 3); /* mov $addr, %rax */
263 out_rela(name, codeaddr());
264 oi(0, 4);
265 tmp_push(TMP_ADDR, bt);
268 void o_call(int argc, unsigned *bt, unsigned ret_bt)
270 int i;
271 for (i = 0; i < argc; i++) {
272 tmp_pop(0);
273 regop(MOV_R2X, R_RAX, arg_regs[i], bt[i]);
275 tmp_pop(1);
276 os("\xff\xd0", 2); /* callq *%rax */
277 if (ret_bt)
278 tmp_push(TMP_CONST, ret_bt);