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
118
|
#pragma once
#include <stdio.h>
#include <stdbool.h>
// IR uses an unlimited number of registers. This will later be fixed by a regalloc.
enum instype {
INS_ADD, // r0 = r1 + r2
INS_SUB, // r0 = r1 - r2
INS_MUL, // r0 = r1 * r2
INS_DIV, // r0 = r1 / r2
INS_MOD, // r0 = r1 % r2
INS_NEG, // r0 = -r1
INS_NOT, // r0 = ~r1
INS_TEST, // r1 & r2 (flags)
INS_PUSH, // push r1
INS_POP, // r0 = pop
INS_CMP, // r1 - r2 (flags)
INS_LBL, // label name
INS_JMP, // jmp name
INS_JCC, // if condcode, jmp name
INS_CALL, // call name
INS_CALLV, // r0 = call name
INS_RET, // return
INS_RETV, // return r1
INS_MOV, // r0 = r1
INS_BRK, // halt
};
enum condcode {
CCZ, CCNZ, CCL, CCG, CCLE, CCGE
};
enum reftype {
REF_REG, // reg
REF_MEM, // [reg + offset + {0, .data, heap base}[rel]]
REF_IMM, // imm
};
enum refrel {
REFREL_ZERO,
REFREL_DATA,
REFREL_HEAP,
};
#define REG_UNUSED (-1)
#define REG_A (-10)
#define REG_B (-11)
#define REG_C (-12)
#define REG_D (-13)
#define REG_X (-14)
#define REG_Y (-15)
#define REG_SP (-16)
#define REG_BP (-17)
struct ref {
enum reftype type;
int reg; // >=0 for temporary or one of the REG_ constants
int offset;
enum refrel rel;
int imm;
};
struct irins {
enum instype type;
union {
struct ref three_refs[3];
struct {struct ref r0, r1, r2;};
};
const char *name; // should be a return value from ir_str()
enum condcode condcode;
};
struct ir {
int cap, len;
struct irins **inss;
int globspace;
};
struct ir* ir_make(void);
void ir_delete(struct ir *ir);
void ir_print(struct ir *ir, FILE *f);
void irins_print(struct irins *ins, FILE *f);
const char* condcode_show(enum condcode condcode);
void ref_show(struct ref ref, char *dest); // dest must have size at least 40
const char* ir_str(const char *str); // returns interned string
// returns offset in .data segment
struct ref ir_reserve_global(struct ir *ir, int size);
void ir_insert_before(struct ir *ir, int pos, struct irins *ins);
void ir_append(struct ir *ir, struct irins *ins);
struct irins* irins_make(enum instype type);
struct irins* irins_make_name(enum instype type, const char *name);
struct irins* irins_make_0(enum instype type, struct ref r0);
struct irins* irins_make_01(enum instype type, struct ref r0, struct ref r1);
struct irins* irins_make_012(enum instype type, struct ref r0, struct ref r1, struct ref r2);
struct irins* irins_make_1(enum instype type, struct ref r1);
struct irins* irins_make_12(enum instype type, struct ref r1, struct ref r2);
struct irins* irins_make_jcc(const char *name, enum condcode condcode);
void irins_delete(struct irins *ins);
void irins_which_refs(const struct irins *ins, bool haveref[3]);
const char* gen_label_name(void);
struct ref ref_reg(int reg);
struct ref ref_mem(int reg, int offset, enum refrel rel);
struct ref ref_imm(int imm);
struct ref ref_next_register(void);
bool ref_equal(struct ref r1, struct ref r2);
|