aboutsummaryrefslogtreecommitdiff
path: root/ir.h
blob: 8496a063fccb414aea980867d6e7a22447329318 (plain)
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
119
120
121
122
123
124
#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
	INS_HWI,   // hwi r1
};

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
	// This can only appear in user-entered asm literals and will be eliminated in the compiler.
	// It should refer to a symbol that is in scope, otherwise an error will be reported.
	REF_VARNAME,  // name
};

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;
	const char *name;  // should be a return value from ir_str()
};

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);
const char* ref_show(struct ref ref);  // returns pointer to static buffer

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_varname(const char *name);
struct ref ref_next_register(void);

bool ref_equal(struct ref r1, struct ref r2);