summary refs log tree commit diff
path: root/lisc/isel.c
blob: 8585703c0190ee1fa212a40f5cf83e97c11034fe (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
#include "lisc.h"

/* For x86_64, we have to:
 *
 * - check that constants are used only in
 *   places allowed by the machine
 *
 * - explicit machine register contraints
 *   on instructions like division.
 *
 * - lower calls (future, I have to think
 *   about their representation and the
 *   way I deal with structs/unions in the
 *   ABI)
 */

extern Ins insb[NIns], *curi; /* shared work buffer */

static void
emit(short op, Ref to, Ref arg0, Ref arg1)
{
	if (curi == insb)
		diag("isel: too many instructions");
	*--curi = (Ins){op, to, {arg0, arg1}};
}

static void
sel(Ins *i, Fn *fn)
{
	int t;
	Ref r0, r1;

	switch (i->op) {
	case ODiv:
		r0 = SYM(RAX);
		r1 = SYM(RDX);
	if (0) {
	case ORem:
		r0 = SYM(RDX);
		r1 = SYM(RAX);
	}
		emit(OCopy, i->to, r0, R);
		emit(OCopy, R, r1, R);
		if (rtype(i->arg[1]) == RCons) {
			/* immediates not allowed for
			 * divisions in x86
			 */
			t = fn->ntmp++;
			r0 = SYM(t);
		} else
			r0 = i->arg[1];
		emit(OXDiv, R, r0, R);
		emit(OSign, SYM(RDX), SYM(RAX), R);
		emit(OCopy, SYM(RAX), i->arg[0], R);
		if (rtype(i->arg[1]) == RCons)
			emit(OCopy, r0, i->arg[1], R);
		break;
	case OAdd:
	case OSub:
	case OCopy:
		emit(i->op, i->to, i->arg[0], i->arg[1]);
		break;
	default:
		diag("isel: non-exhaustive implementation");
	}
}

/* instruction selection
 */
void
isel(Fn *fn)
{
	Blk *b;
	Ins *i;
	int t0, t;
	uint nins;

	t0 = fn->ntmp;
	for (b=fn->start; b; b=b->link) {
		curi = &insb[NIns];
		for (i=&b->ins[b->nins]; i!=b->ins;) {
			sel(--i, fn);
		}
		nins = &insb[NIns] - curi;
		free(b->ins);
		b->ins = alloc(nins * sizeof b->ins[0]);
		memcpy(b->ins, curi, nins * sizeof b->ins[0]);
		b->nins = nins;
	}
	if (fn->ntmp == t0)
		return;
	fn->sym = realloc(fn->sym, fn->ntmp * sizeof(Sym));
	if (!fn->sym)
		diag("isel: out of memory");
	for (t=t0; t<fn->ntmp; t++) {
		fn->sym[t].type = STmp;
		sprintf(fn->sym[t].name, "isel%d", t-t0);
	}
}