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

#include "bcode.h"

#include "gen/head.inc"

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

static void append(struct compile_state *cs, enum bcode_insn label, bcval_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, (bcval_t){ .r = 0 })
#define PUSH_IMM_OP(label, imm) append(cs, label, (bcval_t){ .r = imm })
#define PUSH_DIMM_OP(label, dimm) append(cs, label, (bcval_t){ .d = dimm })

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

#define IMM s.imm[pc].r
#define SIMM s.imm[pc].s
#define FIMM s.imm[pc].f
#define DIMM s.imm[pc].d

#define NEXT_INSN goto *s.op[++pc]
#define JUMP(i) goto *s.op[pc = (i)]

static ubcval_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/regs.inc"
#include "gen/extra.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;
}

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

void init(struct compile_state *cs)
{
	cs->labels = NULL;
	cs->size = 16;

	cs->s.imm = malloc(cs->size * sizeof(*cs->s.imm));
	assert(cs->s.imm);

	cs->s.op = malloc(cs->size * sizeof(*cs->s.op));
	assert(cs->s.op);

	cs->pc = 0;
	_run(cs, true);
}

void end(struct compile_state *cs)
{
	PUSH_OP(END);
}

bcval_t label(struct compile_state *cs)
{
	return (bcval_t){.r = cs->pc};
}

void patch(struct compile_state *cs, bcreloc_t reloc, bcval_t imm)
{
	cs->s.imm[reloc] = imm;
}

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