]> de.git.xonotic.org Git - xonotic/gmqcc.git/blob - ir.h
cc7f5816fcc77040528f4f1b064a35ccec6a7d0f
[xonotic/gmqcc.git] / ir.h
1 #ifndef QCIR_H__
2 #define QCIR_H__
3
4 #include "astir.h"
5
6 /* ir_value */
7
8 typedef struct
9 {
10     /* both inclusive */
11     size_t start;
12     size_t end;
13 } ir_life_entry_t;
14
15 struct ir_function_s;
16 typedef struct ir_value_s {
17     char      *name;
18     int  vtype;
19     int store;
20     filecontext_t context;
21
22     MEM_VECTOR_MAKE(struct ir_instr_s*, reads);
23     MEM_VECTOR_MAKE(struct ir_instr_s*, writes);
24
25     /* constantvalues */
26     union {
27         float    vfloat;
28         int      vint;
29         vector_t vvec;
30         char    *vstring;
31         struct ir_value_s *vpointer;
32     } cvalue;
33     qbool has_constval;
34
35     /* For the temp allocator */
36     MEM_VECTOR_MAKE(ir_life_entry_t, life);
37 } ir_value;
38
39 /* ir_value can be a variable, or created by an operation */
40 ir_value* ir_value_var(const char *name, int st, int vtype);
41 /* if a result of an operation: the function should store
42  * it to remember to delete it / garbage collect it
43  */
44 ir_value* ir_value_out(struct ir_function_s *owner, const char *name, int st, int vtype);
45 void      ir_value_delete(ir_value*);
46 void      ir_value_set_name(ir_value*, const char *name);
47
48 MEM_VECTOR_PROTO(ir_value, struct ir_instr_s*, reads)
49 MEM_VECTOR_PROTO(ir_value, struct ir_instr_s*, writes)
50
51 qbool   ir_value_set_float(ir_value*, float f);
52 qbool   ir_value_set_int(ir_value*, int i);
53 qbool   ir_value_set_string(ir_value*, const char *s);
54 qbool   ir_value_set_vector(ir_value*, qc_vec_t v);
55 /*qbool   ir_value_set_pointer_v(ir_value*, ir_value* p); */
56 /*qbool   ir_value_set_pointer_i(ir_value*, int i);       */
57
58 MEM_VECTOR_PROTO(ir_value, ir_life_entry_t, life)
59 /* merge an instruction into the life-range */
60 /* returns false if the lifepoint was already known */
61 qbool ir_value_life_merge(ir_value*, size_t);
62 /* check if a value lives at a specific point */
63 qbool ir_value_lives(ir_value*, size_t);
64
65 void ir_value_dump(ir_value*, int (*oprintf)(const char*,...));
66 void ir_value_dump_life(ir_value *self, int (*oprintf)(const char*,...));
67
68 typedef struct ir_phi_entry_s
69 {
70     ir_value          *value;
71     struct ir_block_s *from;
72 } ir_phi_entry_t;
73
74 /* instruction */
75 typedef struct ir_instr_s
76 {
77     ir_op_t       opcode;
78     filecontext_t context;
79     ir_value*     (_ops[3]);
80     struct ir_block_s* (bops[2]);
81
82     MEM_VECTOR_MAKE(ir_phi_entry_t, phi);
83
84     /* For the temp-allocation */
85     size_t eid;
86
87     struct ir_block_s *owner;
88 } ir_instr;
89
90 ir_instr* ir_instr_new(struct ir_block_s *owner, ir_op_t opcode);
91 void      ir_instr_delete(ir_instr*);
92
93 MEM_VECTOR_PROTO(ir_value, ir_phi_entry_t, phi)
94 void ir_instr_op(ir_instr*, int op, ir_value *value, qbool writing);
95
96 void ir_instr_dump(ir_instr* in, char *ind, int (*oprintf)(const char*,...));
97
98 /* block */
99 typedef struct ir_block_s
100 {
101     char      *label;
102     lex_ctx_t  context;
103     qbool      final; /* once a jump is added we're done */
104
105     MEM_VECTOR_MAKE(ir_instr*, instr);
106     MEM_VECTOR_MAKE(struct ir_block_s*, entries);
107     MEM_VECTOR_MAKE(struct ir_block_s*, exits);
108     MEM_VECTOR_MAKE(ir_value*, living);
109
110     /* For the temp-allocation */
111     size_t eid;
112     qbool  is_return;
113     size_t run_id;
114
115     struct ir_function_s *owner;
116 } ir_block;
117
118 ir_block* ir_block_new(struct ir_function_s *owner, const char *label);
119 void      ir_block_delete(ir_block*);
120
121 void      ir_block_set_label(ir_block*, const char *label);
122
123 MEM_VECTOR_PROTO(ir_block, ir_instr*, instr)
124 MEM_VECTOR_PROTO_ALL(ir_block, ir_block*, exits)
125 MEM_VECTOR_PROTO_ALL(ir_block, ir_block*, entries)
126
127 ir_value* ir_block_create_binop(ir_block*, const char *label, ir_op_t op,
128                                 ir_value *left, ir_value *right);
129 qbool   ir_block_create_store_op(ir_block*, ir_op_t op, ir_value *target, ir_value *what);
130 qbool   ir_block_create_store(ir_block*, ir_value *target, ir_value *what);
131
132 ir_value* ir_block_create_add(ir_block*, const char *label, ir_value *l, ir_value *r);
133 ir_value* ir_block_create_sub(ir_block*, const char *label, ir_value *l, ir_value *r);
134 ir_value* ir_block_create_mul(ir_block*, const char *label, ir_value *l, ir_value *r);
135 ir_value* ir_block_create_div(ir_block*, const char *label, ir_value *l, ir_value *r);
136 ir_instr* ir_block_create_phi(ir_block*, const char *label, int vtype);
137 ir_value* ir_phi_value(ir_instr*);
138 void      ir_phi_add(ir_instr*, ir_block *b, ir_value *v);
139
140 void      ir_block_create_return(ir_block*, ir_value *opt_value);
141
142 void      ir_block_create_if(ir_block*, ir_value *cond,
143                              ir_block *ontrue, ir_block *onfalse);
144 /* A 'goto' is an actual 'goto' coded in QC, whereas
145  * a 'jump' is a virtual construct which simply names the
146  * next block to go to.
147  * A goto usually becomes an OP_GOTO in the resulting code,
148  * whereas a 'jump' usually doesn't add any actual instruction.
149  */
150 void      ir_block_create_jump(ir_block*, ir_block *to);
151 void      ir_block_create_goto(ir_block*, ir_block *to);
152
153 MEM_VECTOR_PROTO_ALL(ir_block, ir_value*, living)
154
155 void ir_block_dump(ir_block*, char *ind, int (*oprintf)(const char*,...));
156
157 /* function */
158
159 typedef struct ir_function_s
160 {
161     char *name;
162     int   retype;
163     MEM_VECTOR_MAKE(int, params);
164     MEM_VECTOR_MAKE(ir_block*, blocks);
165
166     /* values generated from operations
167      * which might get optimized away, so anything
168      * in there needs to be deleted in the dtor.
169      */
170     MEM_VECTOR_MAKE(ir_value*, values);
171
172     /* locally defined variables */
173     MEM_VECTOR_MAKE(ir_value*, locals);
174
175     ir_block*     first;
176     ir_block*     last;
177
178     lex_ctx_t     context;
179
180     /* for temp allocation */
181     size_t run_id;
182
183     struct ir_builder_s *owner;
184 } ir_function;
185
186 ir_function* ir_function_new(struct ir_builder_s *owner);
187 void         ir_function_delete(ir_function*);
188
189 void ir_function_collect_value(ir_function*, ir_value *value);
190
191 void ir_function_set_name(ir_function*, const char *name);
192 MEM_VECTOR_PROTO(ir_function, int, params)
193 MEM_VECTOR_PROTO(ir_function, ir_block*, blocks)
194
195 ir_value* ir_function_get_local(ir_function *self, const char *name);
196 ir_value* ir_function_create_local(ir_function *self, const char *name, int vtype);
197
198 void ir_function_finalize(ir_function*);
199 /*
200 void ir_function_naive_phi(ir_function*);
201 void ir_function_enumerate(ir_function*);
202 void ir_function_calculate_liferanges(ir_function*);
203 */
204
205 ir_block* ir_function_create_block(ir_function*, const char *label);
206
207 void ir_function_dump(ir_function*, char *ind, int (*oprintf)(const char*,...));
208
209 /* builder */
210 typedef struct ir_builder_s
211 {
212     char *name;
213     MEM_VECTOR_MAKE(ir_function*, functions);
214     MEM_VECTOR_MAKE(ir_value*, globals);
215 } ir_builder;
216
217 ir_builder* ir_builder_new(const char *modulename);
218 void        ir_builder_delete(ir_builder*);
219
220 void ir_builder_set_name(ir_builder *self, const char *name);
221
222 MEM_VECTOR_PROTO(ir_builder, ir_function*, functions)
223 MEM_VECTOR_PROTO(ir_builder, ir_value*, globals)
224
225 ir_function* ir_builder_get_function(ir_builder*, const char *fun);
226 ir_function* ir_builder_create_function(ir_builder*, const char *name);
227
228 ir_value* ir_builder_get_global(ir_builder*, const char *fun);
229 ir_value* ir_builder_create_global(ir_builder*, const char *name, int vtype);
230
231 void ir_builder_dump(ir_builder*, int (*oprintf)(const char*, ...));
232
233 #endif