aboutsummaryrefslogtreecommitdiff
path: root/bcode.c
blob: b4f42317b4966e4c427050430fb799245e655705 (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
#include <stdlib.h>
#include <assert.h>
#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>

#include "bcode.h"

enum bcode_insn {
	END,
#include "gen/enum.inc"
};

static void append(struct compile_state *cs, enum bcode_insn label, breg_t imm)
{
	assert(cs->labels);

	if (cs->pc == cs->size) {
		cs->size *= 2;
		/* better memory checks could be a good idea */
		void *p = realloc(cs->s.op, cs->size * sizeof(*cs->s.op));
		assert(p);

		p = realloc(cs->s.imm, cs->size * sizeof(*cs->s.imm));
		assert(p);
	}

	struct run_state *s = &cs->s;
	s->op[cs->pc] = cs->labels[label];
	s->imm[cs->pc] = imm;
	cs->pc++;
}

#define RELOC cs->pc
#define PUSH_OP(label) append(cs, label, (breg_t){ .g = 0 })
#define PUSH_IMM_OP(label, imm) append(cs, label, (breg_t){ .g = imm })
#define PUSH_DIMM_OP(label, dimm) append(cs, label, (breg_t){ .f = dimm })

#include "gen/select.inc"
#include "gen/macro.inc"

#define IMM s.imm[pc].g
#define DIMM s.imm[pc].f
#define NEXT_INSN goto *s.op[pc++]
#define JUMP(i) goto *s.op[pc = (i)]

static gbreg_t _run(struct compile_state *cs, bool init)
{
	static void *labels[] = {
		[END] = &&end,
#include "gen/static.inc"
	};

	if (init) {
		cs->labels = labels;
		return 0;
	}

#include "gen/head.inc"
#include "gen/regs.inc"

	const struct run_state s = cs->s;
	size_t pc = 0;
	JUMP(pc);
#include "gen/body.inc"

end: /* we assume there's always at least one general register */
	return r0;
}

gbreg_t run(struct compile_state *cs)
{
	return _run(cs, false);
}

void init(struct compile_state *cs)
{
	cs->labels = NULL;
	cs->s.imm = NULL;
	cs->s.op = NULL;
	cs->size = 0;
	cs->pc = 0;
	_run(cs, true);
}

void destroy(struct compile_state *cs)
{
	free(cs->s.op);
	free(cs->s.imm);
}