summary refs log tree commit diff
path: root/lisc/emit.c
blob: 9841c141200b262d8303dd9a4181896f1d9202d6 (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
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
#include "lisc.h"


static void
eref(Ref r, Fn *fn, FILE *f)
{
	switch (rtype(r)) {
	case RSym:
		assert(fn->sym[r.val].type == SReg);
		fprintf(f, "%%%s", fn->sym[r.val].name);
		break;
	case RSlot:
		fprintf(f, "-%d(%%rbp)", 8 * r.val);
		break;
	case RConst:
		fprintf(f, "$%d", (int)r.val);
		break;
	default:
		diag("emitref: invalid reference");
	}
}

static void
eop(char *op, Ref a, Ref b, Fn *fn, FILE *f)
{
	fprintf(f, "\t%s ", op);
	eref(a, fn, f);
	if (!req(b, R)) {
		fprintf(f, ", ");
		eref(b, fn, f);
	}
	fprintf(f, "\n");
}

static void
eins(Ins i, Fn *fn, FILE *f)
{
	static char *opi[] = {
		[OAdd] = "add",
		[OSub] = "sub",
	};

	switch (i.op) {
	case OAdd:
	case OSub:
		if (!req(i.to, i.arg[0]))
			eop("mov", i.arg[0], i.to, fn, f);
		eop(opi[i.op], i.arg[1], i.to, fn, f);
		break;
	case OStore:
		i.to = i.arg[1];
		/* fall through */
	case OCopy:
	case OLoad:
		if (!req(i.arg[0], i.to))
			eop("mov", i.arg[0], i.to, fn, f);
		break;
	case OSwap:
		eop("xchg", i.arg[0], i.arg[1], fn, f);
		break;
	case ONop:
		break;
	default:
		diag("emit: unhandled instruction");
	}
}

void
emitfn(Fn *fn, FILE *f)
{
	char *js;
	Blk *b, *s;
	Ins *i;

	fprintf(f,
		".text\n"
		".globl liscf\n"
		".type liscf, @function\n"
		"liscf:\n"
		"\tpush %%rbp\n"
		"\tmov %%rsp, %%rbp\n"
		"\tsub $%u, %%rsp\n",
		fn->nspill * 8
	);
	for (b=fn->start; b; b=b->link) {
		fprintf(f, ".L%s:\n", b->name);
		for (i=b->ins; i-b->ins < b->nins; i++)
			eins(*i, fn, f);
		switch (b->jmp.type) {
		case JRet:
			fprintf(f,
				"\tleave\n"
				"\tret\n"
			);
			break;
		case JJmp:
			if (b->s1 != b->link)
				fprintf(f, "\tjmp .L%s\n", b->s1->name);
			break;
		case JJez:
			if (b->s1 == b->link) {
				js = "jnz";
				s = b->s2;
			} else if (b->s2 == b->link) {
				js = "jz";
				s = b->s1;
			} else
				diag("emit: unhandled jump (1)");
			eop("test", b->jmp.arg, b->jmp.arg, fn, f);
			fprintf(f, "\t%s .L%s\n", js, s->name);
			break;
		default:
			diag("emit: unhandled jump (2)");
		}
	}

}