arm: O_MSET does not modify its second argument
[neatcc.git] / gen.c
blob1fd3255bd183c53f8a7eaa96304f11ca68083073
1 /* neatcc code generation */
2 #include <stdlib.h>
3 #include <stdio.h>
4 #include <string.h>
5 #include "ncc.h"
7 static struct mem ds; /* data segment */
8 static struct mem cs; /* code segment */
9 static long bsslen; /* bss segment size */
11 static long *loc_off; /* offset of locals on the stack */
12 static long loc_n, loc_sz; /* number of locals */
13 static long loc_pos; /* current stack position */
14 static int *loc_mem; /* local memory was accessed */
15 static int *loc_ptr; /* the address of this local is fetched */
16 static int *loc_dat; /* the number of data accesses of this local */
18 static char (*ds_name)[NAMELEN];/* data section symbols */
19 static long *ds_off; /* data section offsets */
20 static long ds_n, ds_sz; /* number of data section symbols */
22 static int func_argc; /* number of arguments */
23 static int func_varg; /* varargs */
24 static int func_regs; /* used registers */
25 static int func_maxargs; /* the maximum number of arguments on the stack */
26 static int func_leaf; /* a leaf function */
27 static long *ic_luse; /* the last use of values generated by instructions */
28 static long *ic_bbeg; /* whether each instruction begins a basic block */
30 static long ra_vmap[N_REGS]; /* register to intermediate value assignments */
31 static long ra_lmap[N_REGS]; /* register to local assignments */
32 static long ra_lmapglob[N_REGS]; /* global register to local assignments */
33 static long *ra_gmask; /* the mask of good registers for each value */
34 static long ra_live[NTMPS]; /* live values */
35 static int ra_vmax; /* the number of values stored on the stack */
37 static long loc_add(long pos)
39 if (loc_n >= loc_sz) {
40 loc_sz = MAX(128, loc_sz * 2);
41 loc_off = mextend(loc_off, loc_n, loc_sz, sizeof(loc_off[0]));
43 loc_off[loc_n] = pos;
44 return loc_n++;
47 long o_mklocal(long sz)
49 loc_pos += ALIGN(sz, ULNG);
50 return loc_add(loc_pos);
53 void o_rmlocal(long addr, long sz)
57 long o_arg2loc(int i)
59 return i;
62 void o_bsnew(char *name, long size, int global)
64 out_def(name, OUT_BSS | (global ? OUT_GLOB : 0), bsslen, size);
65 bsslen += ALIGN(size, OUT_ALIGNMENT);
68 long o_dsnew(char *name, long size, int global)
70 int idx;
71 if (ds_n >= ds_sz) {
72 ds_sz = MAX(128, ds_sz * 2);
73 ds_name = mextend(ds_name, ds_n, ds_sz, sizeof(ds_name[0]));
74 ds_off = mextend(ds_off, ds_n, ds_sz, sizeof(ds_off[0]));
76 idx = ds_n++;
77 strcpy(ds_name[idx], name);
78 ds_off[idx] = mem_len(&ds);
79 out_def(name, OUT_DS | (global ? OUT_GLOB : 0), mem_len(&ds), size);
80 mem_putz(&ds, ALIGN(size, OUT_ALIGNMENT));
81 return ds_off[idx];
84 void o_dscpy(long addr, void *buf, long len)
86 mem_cpy(&ds, addr, buf, len);
89 static int dat_off(char *name)
91 int i;
92 for (i = 0; i < ds_n; i++)
93 if (!strcmp(name, ds_name[i]))
94 return ds_off[i];
95 return 0;
98 void o_dsset(char *name, long off, long bt)
100 long sym_off = dat_off(name) + off;
101 long num, roff, rsym;
102 if (!o_popnum(&num)) {
103 mem_cpy(&ds, sym_off, &num, T_SZ(bt));
104 return;
106 if (!o_popsym(&rsym, &roff)) {
107 out_rel(rsym, OUT_DS, sym_off);
108 mem_cpy(&ds, sym_off, &roff, T_SZ(bt));
112 /* number of register arguments */
113 static int ic_regcnt(struct ic *ic)
115 long o = ic->op;
116 if (o & O_BOP)
117 return o & (O_NUM | O_SYM | O_LOC) ? 2 : 3;
118 if (o & O_UOP)
119 return o & (O_NUM | O_SYM | O_LOC) ? 1 : 2;
120 if (o & O_CALL)
121 return o & (O_NUM | O_SYM | O_LOC) ? 1 : 2;
122 if (o & O_MOV)
123 return o & (O_NUM | O_SYM | O_LOC) ? 1 : 2;
124 if (o & O_MEM)
125 return 3;
126 if (o & O_JMP)
127 return 0;
128 if (o & O_JZ)
129 return 1;
130 if (o & O_JCC)
131 return o & (O_NUM | O_SYM | O_LOC) ? 1 : 2;
132 if (o & O_RET)
133 return 1;
134 if (o & (O_LD | O_ST) && o & (O_SYM | O_LOC))
135 return 1;
136 if (o & (O_LD | O_ST))
137 return o & O_NUM ? 2 : 3;
138 return 0;
141 static int ra_vreg(int val)
143 int i;
144 for (i = 0; i < LEN(ra_vmap); i++)
145 if (ra_vmap[i] == val)
146 return i;
147 return -1;
150 static int ra_lreg(int loc)
152 int i;
153 for (i = 0; i < LEN(ra_lmap); i++)
154 if (ra_lmap[i] == loc)
155 return i;
156 return -1;
159 /* find a register, with the given good, acceptable, and bad register masks */
160 static long ra_regget(long iv, long gmask, long amask, long bmask)
162 int i;
163 gmask &= ~bmask & amask;
164 amask &= ~bmask;
165 if (ra_vreg(iv) >= 0 && (1 << ra_vreg(iv)) & (gmask | amask))
166 return ra_vreg(iv);
167 for (i = 0; i < N_TMPS; i++)
168 if ((1 << tmpregs[i]) & gmask && ra_vmap[tmpregs[i]] < 0 &&
169 ra_lmap[tmpregs[i]] < 0)
170 return tmpregs[i];
171 for (i = 0; i < N_TMPS; i++)
172 if ((1 << tmpregs[i]) & amask && ra_vmap[tmpregs[i]] < 0 &&
173 ra_lmap[tmpregs[i]] < 0)
174 return tmpregs[i];
175 for (i = 0; i < N_TMPS; i++)
176 if ((1 << tmpregs[i]) & gmask)
177 return tmpregs[i];
178 for (i = 0; i < N_TMPS; i++)
179 if ((1 << tmpregs[i]) & amask)
180 return tmpregs[i];
181 die("neatcc: cannot allocate an acceptable register\n");
182 return 0;
185 /* allocate registers for a 3-operand instruction */
186 static void ra_map(struct ic *ic, int *r0, int *r1, int *r2, long *mt)
188 long m0, m1, m2;
189 long all = 0;
190 int n = ic_regcnt(ic);
191 int oc = O_C(ic->op);
192 int i;
193 *r0 = -1;
194 *r1 = -1;
195 *r2 = -1;
196 *mt = 0;
197 /* optimizing loading locals: point to local's register */
198 if (oc == (O_LD | O_LOC) && ra_lreg(ic->arg1) >= 0 &&
199 ra_vmap[ra_lreg(ic->arg1)] < 0) {
200 *r0 = ra_lreg(ic->arg1);
201 func_regs |= 1 << *r0;
202 return;
204 /* do not use argument registers to hold call destination */
205 if (oc & O_CALL)
206 for (i = 0; i < MIN(ic->arg2, N_ARGS); i++)
207 all |= (1 << argregs[i]);
208 /* instructions on locals can be simplified */
209 if (oc & O_LOC) {
210 if (oc & O_MOV)
211 oc = O_ADD | O_NUM;
212 if (oc & (O_ST | O_LD))
213 oc = (oc & ~O_LOC) & O_NUM;
215 if (i_reg(ic->op, &m0, &m1, &m2, mt))
216 die("neatcc: instruction %08lx not supported\n", ic->op);
218 * the registers used in global register allocation should not
219 * be used in the last instruction of a basic block.
221 if (ic->op & (O_JZ | O_JCC))
222 for (i = 0; i < LEN(ra_lmap); i++)
223 if (ra_lmapglob[i] >= 0 && ra_lmap[i] != ra_lmapglob[i])
224 all |= (1 << i);
225 /* allocating registers for the operands */
226 if (n >= 3) {
227 *r2 = ra_regget(ic->arg2, m2, m2, all);
228 all |= (1 << *r2);
230 if (n >= 2) {
231 *r1 = ra_regget(ic->arg1, m1, m1, all);
232 all |= (1 << *r1);
234 if (n >= 1 && m0) {
235 int wop = ic->op & O_OUT;
236 if (wop && n >= 3 && m0 & (1 << *r2))
237 *r0 = *r2;
238 else if (wop && n >= 2 && m0 & (1 << *r1))
239 *r0 = *r1;
240 else
241 *r0 = ra_regget(ic->arg0, ra_gmask[ic->arg0],
242 m0, wop ? 0 : all);
244 if (n >= 1 && !m0)
245 *r0 = *r1;
246 /* if r0 is overwritten and it is a local; use another register */
247 if (n >= 1 && oc & O_OUT && ra_lmap[*r0] >= 0) {
248 long m3 = (m0 ? m0 : m1) & ~(all | (1 << *r0));
249 long arg3 = m0 ? ic->arg0 : ic->arg1;
250 if (m3 != 0) {
251 int r3 = ra_regget(arg3, ra_gmask[ic->arg0], m3, 0);
252 if (n >= 2 && *r0 == *r1)
253 *r1 = r3;
254 if (n >= 3 && *r0 == *r2)
255 *r2 = r3;
256 *r0 = r3;
259 if (n)
260 all |= (1 << *r0);
261 func_regs |= all | *mt;
264 static long iv_rank(long iv)
266 int i;
267 for (i = 0; i < LEN(ra_live); i++)
268 if (ra_live[i] == iv)
269 return i;
270 die("neatcc: the specified value is not live\n");
271 return 0;
274 static long iv_addr(long rank)
276 return loc_pos + rank * ULNG + ULNG;
279 static void loc_toreg(long loc, long off, int reg, int bt)
281 loc_mem[loc]++;
282 i_ins(O_MK(O_LD | O_NUM, bt), reg, REG_FP, -loc_off[loc] + off);
285 static void loc_tomem(long loc, long off, int reg, int bt)
287 loc_mem[loc]++;
288 i_ins(O_MK(O_ST | O_NUM, bt), reg, REG_FP, -loc_off[loc] + off);
291 static void loc_toadd(long loc, long off, int reg)
293 loc_mem[loc]++;
294 i_ins(O_ADD | O_NUM, reg, REG_FP, -loc_off[loc] + off);
297 static void val_toreg(long val, int reg)
299 i_ins(O_MK(O_LD | O_NUM, ULNG), reg, REG_FP, -iv_addr(iv_rank(val)));
302 static void val_tomem(long val, int reg)
304 long rank = iv_rank(val);
305 ra_vmax = MAX(ra_vmax, rank + 1);
306 i_ins(O_MK(O_ST | O_NUM, ULNG), reg, REG_FP, -iv_addr(rank));
309 /* move the value to the stack */
310 static void ra_spill(int reg)
312 if (ra_vmap[reg] >= 0) {
313 val_tomem(ra_vmap[reg], reg);
314 ra_vmap[reg] = -1;
316 if (ra_lmap[reg] >= 0) {
317 if (ra_lmap[reg] == ra_lmapglob[reg])
318 loc_tomem(ra_lmap[reg], 0, reg, ULNG);
319 ra_lmap[reg] = -1;
323 /* set the value to the given register */
324 static void ra_vsave(long iv, int reg)
326 int i;
327 ra_vmap[reg] = iv;
328 for (i = 0; i < LEN(ra_live); i++)
329 if (ra_live[i] < 0)
330 break;
331 if (i == LEN(ra_live))
332 die("neatcc: too many live values\n");
333 ra_live[i] = iv;
336 /* load the value into a register */
337 static void ra_vload(long iv, int reg)
339 if (ra_vmap[reg] == iv)
340 return;
341 if (ra_vmap[reg] >= 0 || ra_lmap[reg] >= 0)
342 ra_spill(reg);
343 if (ra_vreg(iv) >= 0) {
344 i_ins(O_MK(O_MOV, ULNG), reg, ra_vreg(iv), 0);
345 ra_vmap[ra_vreg(iv)] = -1;
346 } else {
347 val_toreg(iv, reg);
349 ra_vmap[reg] = iv;
352 /* the value is no longer needed */
353 static void ra_vdrop(long iv)
355 int i;
356 for (i = 0; i < LEN(ra_live); i++)
357 if (ra_live[i] == iv)
358 ra_live[i] = -1;
359 if (ra_vreg(iv) >= 0)
360 ra_vmap[ra_vreg(iv)] = -1;
363 /* load the value of local loc into register reg */
364 static void ra_lload(long loc, long off, int reg, int bt)
366 if (ra_lreg(loc) < 0 && !loc_ptr[loc] && loc_dat[loc] > 2) {
367 ra_lmap[reg] = loc;
368 loc_toreg(loc, off, reg, bt);
370 if (ra_lreg(loc) >= 0) {
371 if (ra_lreg(loc) != reg)
372 i_ins(O_MK(O_MOV, bt), reg, ra_lreg(loc), 0);
373 } else {
374 loc_toreg(loc, off, reg, bt);
378 /* register reg contains the value of local loc */
379 static void ra_lsave(long loc, long off, int reg, int bt)
381 int lreg = ra_lreg(loc);
382 if (lreg >= 0 && ra_lmapglob[lreg] == ra_lmap[lreg]) {
383 if (ra_vmap[lreg] >= 0) { /* values using the same register */
384 val_tomem(ra_vmap[lreg], lreg);
385 ra_vmap[lreg] = -1;
387 i_ins(O_MK(O_MOV, bt), lreg, reg, 0);
388 } else {
389 if (lreg >= 0)
390 ra_lmap[lreg] = -1;
391 loc_tomem(loc, off, reg, bt);
392 if (!loc_ptr[loc] && loc_dat[loc] > 2)
393 ra_lmap[reg] = loc;
397 /* end of a basic block */
398 static void ra_bbend(void)
400 int i;
401 /* save values to memory */
402 for (i = 0; i < LEN(ra_vmap); i++)
403 if (ra_vmap[i] >= 0)
404 ra_spill(i);
405 /* dropping local caches */
406 for (i = 0; i < LEN(ra_lmap); i++)
407 if (ra_lmap[i] != ra_lmapglob[i] && ra_lmap[i] >= 0)
408 ra_spill(i);
409 /* load global register allocations from memory */
410 for (i = 0; i < LEN(ra_lmap); i++) {
411 if (ra_lmap[i] != ra_lmapglob[i]) {
412 ra_lmap[i] = ra_lmapglob[i];
413 loc_toreg(ra_lmap[i], 0, i, ULNG);
418 /* perform global register allocation */
419 static void ra_glob(struct ic *ic, int ic_n)
421 int *srt;
422 long mask;
423 int nregs;
424 int i, j;
425 mask = func_leaf ? R_TMPS : R_PERM;
426 nregs = MIN(N_TMPS >> 1, 4);
427 srt = malloc(loc_n * sizeof(srt[0]));
428 /* sorting locals */
429 for (i = 0; i < loc_n; i++) {
430 for (j = i - 1; j >= 0 && loc_dat[i] > loc_dat[srt[j]]; j--)
431 srt[j + 1] = srt[j];
432 srt[j + 1] = i;
434 /* allocating registers */
435 for (i = 0; i < loc_n && nregs > 0; i++) {
436 int l = srt[i];
437 if (loc_ptr[l])
438 continue;
439 if (func_leaf && l < N_ARGS && l < func_argc &&
440 ra_lmapglob[argregs[l]] < 0) {
441 ra_lmapglob[argregs[l]] = l;
442 nregs--;
443 continue;
445 if (loc_dat[l] < 2)
446 continue;
447 for (j = func_leaf ? 1 : 3; j < N_TMPS; j++) {
448 int r = tmpregs[j];
449 if (ra_lmapglob[r] < 0 && (1 << r) & mask) {
450 ra_lmapglob[r] = l;
451 nregs--;
452 break;
456 free(srt);
459 /* return the values written to and read from in the given instruction */
460 static void ic_info(struct ic *ic, long **w, long **r1, long **r2, long **r3)
462 long n = ic_regcnt(ic);
463 long o = ic->op & O_OUT;
464 *r1 = NULL;
465 *r2 = NULL;
466 *r3 = NULL;
467 *w = NULL;
468 if (o) {
469 *w = &ic->arg0;
470 *r1 = n >= 2 ? &ic->arg1 : NULL;
471 *r2 = n >= 3 ? &ic->arg2 : NULL;
472 } else {
473 *r1 = n >= 1 ? &ic->arg0 : NULL;
474 *r2 = n >= 2 ? &ic->arg1 : NULL;
475 *r3 = n >= 3 ? &ic->arg2 : NULL;
479 static void ra_init(struct ic *ic, int ic_n)
481 long m0, m1, m2, mt;
482 int *loc_sz;
483 int i, j;
484 ic_luse = calloc(ic_n, sizeof(ic_luse[0]));
485 ic_bbeg = calloc(ic_n, sizeof(ic_bbeg[0]));
486 ra_gmask = calloc(ic_n, sizeof(ra_gmask[0]));
487 loc_mem = calloc(loc_n, sizeof(loc_mem[0]));
488 /* ic_luse */
489 for (i = ic_n - 1; i >= 0; --i) {
490 long *w, *r1, *r2, *r3;
491 ic_info(ic + i, &w, &r1, &r2, &r3);
492 if (!ic_luse[i])
493 if (!w || ic[i].op & O_CALL)
494 ic_luse[i] = -1;
495 if (!ic_luse[i])
496 continue;
497 if (r1 && !ic_luse[*r1])
498 ic_luse[*r1] = i;
499 if (r2 && !ic_luse[*r2])
500 ic_luse[*r2] = i;
501 if (r3 && !ic_luse[*r3])
502 ic_luse[*r3] = i;
503 if (ic[i].op & O_CALL)
504 for (j = 0; j < ic[i].arg2; j++)
505 if (!ic_luse[ic[i].args[j]])
506 ic_luse[ic[i].args[j]] = i;
508 /* ic_bbeg */
509 for (i = 0; i < ic_n; i++) {
510 if (!ic_luse[i])
511 continue;
512 if (i + 1 < ic_n && ic[i].op & (O_JXX | O_RET))
513 ic_bbeg[i + 1] = 1;
514 if (ic[i].op & O_JXX && ic[i].arg2 < ic_n)
515 ic_bbeg[ic[i].arg2] = 1;
517 /* ra_gmask */
518 for (i = 0; i < ic_n; i++) {
519 int n = ic_regcnt(ic + i);
520 int op = ic[i].op;
521 if (!ic_luse[i])
522 continue;
523 i_reg(op, &m0, &m1, &m2, &mt);
524 if (n >= 1 && !(op & O_OUT))
525 ra_gmask[ic[i].arg0] = m0;
526 if (n >= 2)
527 ra_gmask[ic[i].arg1] = m1;
528 if (n >= 3)
529 ra_gmask[ic[i].arg2] = m2;
530 if (op & O_CALL)
531 for (j = 0; j < MIN(N_ARGS, ic[i].arg2); j++)
532 ra_gmask[ic[i].args[j]] = 1 << argregs[j];
534 /* loc_ptr and loc_dat */
535 loc_ptr = calloc(loc_n, sizeof(loc_ptr[0]));
536 loc_dat = calloc(loc_n, sizeof(loc_dat[0]));
537 loc_sz = calloc(loc_n, sizeof(loc_sz[0]));
538 for (i = 0; i < ic_n; i++) {
539 long oc = O_C(ic[i].op);
540 if (!ic_luse[i])
541 continue;
542 if (oc == (O_LD | O_LOC) || oc == (O_ST | O_LOC)) {
543 int loc = ic[i].arg1;
544 int sz = T_SZ(O_T(ic[i].op));
545 if (!loc_sz[loc])
546 loc_sz[loc] = sz;
547 if (ic[i].arg2 || sz < 2 || sz != loc_sz[loc])
548 loc_ptr[loc]++;
549 else
550 loc_dat[loc]++;
552 if (oc == (O_MOV | O_LOC))
553 loc_ptr[ic[i].arg1]++;
555 free(loc_sz);
556 /* func_leaf */
557 func_leaf = 1;
558 for (i = 0; i < ic_n; i++)
559 if (ic_luse[i] && ic[i].op & O_CALL)
560 func_leaf = 0;
561 /* ra_vmap */
562 for (i = 0; i < LEN(ra_vmap); i++)
563 ra_vmap[i] = -1;
564 /* ra_lmap */
565 for (i = 0; i < N_REGS; i++)
566 ra_lmapglob[i] = -1;
567 ra_glob(ic, ic_n);
568 memcpy(ra_lmap, ra_lmapglob, sizeof(ra_lmap));
569 /* ra_lmask */
570 for (i = 0; i < LEN(ra_lmapglob); i++)
571 if (ra_lmapglob[i] >= 0)
572 func_regs |= (1 << i);
573 /* ra_live */
574 for (i = 0; i < LEN(ra_live); i++)
575 ra_live[i] = -1;
576 ra_vmax = 0;
577 func_maxargs = 0;
580 static void ra_done(void)
582 free(ic_luse);
583 free(ic_bbeg);
584 free(ra_gmask);
585 free(loc_mem);
586 free(loc_ptr);
587 free(loc_dat);
590 static void ic_gencode(struct ic *ic, int ic_n)
592 int r0, r1, r2;
593 long mt;
594 int i, j;
595 /* loading arguments in their allocated registers */
596 for (i = 0; i < LEN(ra_lmap); i++) {
597 int loc = ra_lmap[i];
598 if (loc >= 0 && loc < func_argc)
599 if (loc >= N_ARGS || i != argregs[loc])
600 loc_toreg(loc, 0, i, ULNG);
602 /* generating code */
603 for (i = 0; i < ic_n; i++) {
604 long op = ic[i].op;
605 long oc = O_C(op);
606 int n = ic_regcnt(ic + i);
607 i_label(i);
608 if (!ic_luse[i])
609 continue;
610 ra_map(ic + i, &r0, &r1, &r2, &mt);
611 if (oc & O_CALL) {
612 int argc = ic[i].arg2;
613 int aregs = MIN(N_ARGS, argc);
614 /* arguments passed via stack */
615 for (j = argc - 1; j >= aregs; --j) {
616 int v = ic[i].args[j];
617 int rx = ra_vreg(v) >= 0 ? ra_vreg(v) : r0;
618 ra_vload(v, rx);
619 i_ins(O_MK(O_ST | O_NUM, ULNG), rx, REG_SP,
620 (j - aregs) * ULNG);
621 ra_vdrop(v);
623 func_maxargs = MAX(func_maxargs, argc - aregs);
624 /* arguments passed via registers */
625 for (j = aregs - 1; j >= 0; --j)
626 ra_vload(ic[i].args[j], argregs[j]);
628 /* loading the operands */
629 if (n >= 1 && !(oc & O_OUT))
630 ra_vload(ic[i].arg0, r0);
631 if (n >= 2 && !(oc & O_LOC))
632 ra_vload(ic[i].arg1, r1);
633 if (n >= 3)
634 ra_vload(ic[i].arg2, r2);
635 /* dropping values that are no longer used */
636 for (j = 0; j < LEN(ra_live); j++)
637 if (ra_live[j] >= 0 && ic_luse[ra_live[j]] <= i)
638 ra_vdrop(ra_live[j]);
639 /* saving values stored in registers that may change */
640 for (j = 0; j < N_REGS; j++)
641 if (mt & (1 << j))
642 ra_spill(j);
643 /* overwriting a value that is needed later (unless loading a local to its register) */
644 if (n >= 1 && oc & O_OUT)
645 if (oc != (O_LD | O_LOC) || ra_lmap[r0] != ic[i].arg1 ||
646 ra_vmap[r0] >= 0)
647 ra_spill(r0);
648 /* before the last instruction of a basic block; for jumps */
649 if (i + 1 < ic_n && ic_bbeg[i + 1] && oc & O_JXX)
650 ra_bbend();
651 /* performing the instruction */
652 if (oc & O_BOP)
653 i_ins(op, r0, r1, oc & O_NUM ? ic[i].arg2 : r2);
654 if (oc & O_UOP)
655 i_ins(op, r0, r1, r2);
656 if (oc == (O_LD | O_NUM))
657 i_ins(op, r0, r1, ic[i].arg2);
658 if (oc == (O_LD | O_LOC))
659 ra_lload(ic[i].arg1, ic[i].arg2, r0, O_T(op));
660 if (oc == (O_ST | O_NUM))
661 i_ins(op, r0, r1, ic[i].arg2);
662 if (oc == (O_ST | O_LOC))
663 ra_lsave(ic[i].arg1, ic[i].arg2, r0, O_T(op));
664 if (oc == O_RET)
665 i_ins(op, r0, 0, 0);
666 if (oc == O_MOV)
667 i_ins(op, r0, r0, 0);
668 if (oc == (O_MOV | O_NUM))
669 i_ins(op, r0, ic[i].arg1, 0);
670 if (oc == (O_MOV | O_LOC))
671 loc_toadd(ic[i].arg1, ic[i].arg2, r0);
672 if (oc == (O_MOV | O_SYM))
673 i_ins(op, r0, ic[i].arg1, ic[i].arg2);
674 if (oc == O_CALL)
675 i_ins(op, r0, r1, 0);
676 if (oc == (O_CALL | O_SYM))
677 i_ins(op, r0, ic[i].arg1, 0);
678 if (oc == O_JMP)
679 i_ins(op, 0, 0, ic[i].arg2);
680 if (oc & O_JZ)
681 i_ins(op, r0, 0, ic[i].arg2);
682 if (oc & O_JCC)
683 i_ins(op, r0, oc & O_NUM ? ic[i].arg1 : r1, ic[i].arg2);
684 if (oc == O_MSET)
685 i_ins(op, r0, r1, r2);
686 if (oc == O_MCPY)
687 i_ins(op, r0, r1, r2);
688 /* saving back the output register */
689 if (oc & O_OUT)
690 ra_vsave(ic[i].arg0, r0);
691 /* after the last instruction of a basic block */
692 if (i + 1 < ic_n && ic_bbeg[i + 1] && !(oc & O_JXX))
693 ra_bbend();
695 i_label(ic_n);
698 static void ic_reset(void)
700 o_tmpdrop(-1);
701 o_back(0);
702 free(loc_off);
703 loc_off = NULL;
704 loc_n = 0;
705 loc_sz = 0;
706 loc_pos = I_LOC0;
709 void o_func_beg(char *name, int argc, int global, int varg)
711 int i;
712 func_argc = argc;
713 func_varg = varg;
714 func_regs = 0;
715 ic_reset();
716 for (i = 0; i < argc; i++)
717 loc_add(I_ARG0 + -i * ULNG);
718 out_def(name, (global ? OUT_GLOB : 0) | OUT_CS, mem_len(&cs), 0);
721 void o_code(char *name, char *c, long c_len)
723 out_def(name, OUT_CS, mem_len(&cs), 0);
724 mem_put(&cs, c, c_len);
727 void o_func_end(void)
729 struct ic *ic;
730 long ic_n, spsub;
731 long sargs = 0;
732 long sargs_last = -1;
733 long sregs_pos;
734 char *c;
735 long c_len, *rsym, *rflg, *roff, rcnt;
736 int locs = 0; /* accessing locals on the stack */
737 int i;
738 ic_get(&ic, &ic_n); /* the intermediate code */
739 ra_init(ic, ic_n); /* initialize register allocation */
740 ic_gencode(ic, ic_n); /* generating machine code */
741 /* deciding which arguments to save */
742 for (i = 0; i < func_argc; i++)
743 if (loc_mem[i])
744 sargs_last = i + 1;
745 for (i = 0; i < N_ARGS && (func_varg || i < sargs_last); i++)
746 sargs |= 1 << argregs[i];
747 /* computing the amount of stack subtraction */
748 for (i = 0; i < loc_n; i++)
749 if (loc_mem[i])
750 locs = 1;
751 spsub = (locs || ra_vmax) ? loc_pos + ra_vmax * ULNG : 0;
752 for (i = 0; i < N_TMPS; i++)
753 if (((1 << tmpregs[i]) & func_regs & R_PERM) != 0)
754 spsub += ULNG;
755 sregs_pos = spsub;
756 spsub += func_maxargs * ULNG;
757 /* adding function prologue and epilogue */
758 i_wrap(func_argc, sargs, spsub, spsub || locs || !func_leaf,
759 func_regs & R_PERM, -sregs_pos);
760 ra_done();
761 i_code(&c, &c_len, &rsym, &rflg, &roff, &rcnt);
762 for (i = 0; i < rcnt; i++) /* adding the relocations */
763 out_rel(rsym[i], rflg[i], roff[i] + mem_len(&cs));
764 mem_put(&cs, c, c_len); /* appending function code */
765 free(c);
766 free(rsym);
767 free(rflg);
768 free(roff);
769 for (i = 0; i < ic_n; i++)
770 if (ic[i].op & O_CALL)
771 free(ic[i].args);
772 free(ic);
773 ic_reset();
776 void o_write(int fd)
778 i_done();
779 out_write(fd, mem_buf(&cs), mem_len(&cs), mem_buf(&ds), mem_len(&ds));
780 free(loc_off);
781 free(ds_name);
782 free(ds_off);
783 mem_done(&cs);
784 mem_done(&ds);