]> git.xonotic.org Git - xonotic/gmqcc.git/blob - ir.c
Add a # prefix to EXTPARM%i
[xonotic/gmqcc.git] / ir.c
1 /*
2  * Copyright (C) 2012
3  *     Wolfgang Bumiller
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a copy of
6  * this software and associated documentation files (the "Software"), to deal in
7  * the Software without restriction, including without limitation the rights to
8  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
9  * of the Software, and to permit persons to whom the Software is furnished to do
10  * so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be included in all
13  * copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21  * SOFTWARE.
22  */
23 #include <stdlib.h>
24 #include <string.h>
25 #include "gmqcc.h"
26 #include "ir.h"
27
28 /***********************************************************************
29  * Type sizes used at multiple points in the IR codegen
30  */
31
32 const char *type_name[TYPE_COUNT] = {
33     "void",
34     "string",
35     "float",
36     "vector",
37     "entity",
38     "field",
39     "function",
40     "pointer",
41     "integer",
42     "variant",
43     "struct",
44     "union",
45     "array"
46 };
47
48 size_t type_sizeof[TYPE_COUNT] = {
49     1, /* TYPE_VOID     */
50     1, /* TYPE_STRING   */
51     1, /* TYPE_FLOAT    */
52     3, /* TYPE_VECTOR   */
53     1, /* TYPE_ENTITY   */
54     1, /* TYPE_FIELD    */
55     1, /* TYPE_FUNCTION */
56     1, /* TYPE_POINTER  */
57     1, /* TYPE_INTEGER  */
58     3, /* TYPE_VARIANT  */
59     0, /* TYPE_STRUCT   */
60     0, /* TYPE_UNION    */
61     0, /* TYPE_ARRAY    */
62 };
63
64 uint16_t type_store_instr[TYPE_COUNT] = {
65     INSTR_STORE_F, /* should use I when having integer support */
66     INSTR_STORE_S,
67     INSTR_STORE_F,
68     INSTR_STORE_V,
69     INSTR_STORE_ENT,
70     INSTR_STORE_FLD,
71     INSTR_STORE_FNC,
72     INSTR_STORE_ENT, /* should use I */
73 #if 0
74     INSTR_STORE_I, /* integer type */
75 #else
76     INSTR_STORE_F,
77 #endif
78
79     INSTR_STORE_V, /* variant, should never be accessed */
80
81     AINSTR_END, /* struct */
82     AINSTR_END, /* union  */
83     AINSTR_END, /* array  */
84 };
85
86 uint16_t field_store_instr[TYPE_COUNT] = {
87     INSTR_STORE_FLD,
88     INSTR_STORE_FLD,
89     INSTR_STORE_FLD,
90     INSTR_STORE_V,
91     INSTR_STORE_FLD,
92     INSTR_STORE_FLD,
93     INSTR_STORE_FLD,
94     INSTR_STORE_FLD,
95 #if 0
96     INSTR_STORE_FLD, /* integer type */
97 #else
98     INSTR_STORE_FLD,
99 #endif
100
101     INSTR_STORE_V, /* variant, should never be accessed */
102
103     AINSTR_END, /* struct */
104     AINSTR_END, /* union  */
105     AINSTR_END, /* array  */
106 };
107
108 uint16_t type_storep_instr[TYPE_COUNT] = {
109     INSTR_STOREP_F, /* should use I when having integer support */
110     INSTR_STOREP_S,
111     INSTR_STOREP_F,
112     INSTR_STOREP_V,
113     INSTR_STOREP_ENT,
114     INSTR_STOREP_FLD,
115     INSTR_STOREP_FNC,
116     INSTR_STOREP_ENT, /* should use I */
117 #if 0
118     INSTR_STOREP_ENT, /* integer type */
119 #else
120     INSTR_STOREP_F,
121 #endif
122
123     INSTR_STOREP_V, /* variant, should never be accessed */
124
125     AINSTR_END, /* struct */
126     AINSTR_END, /* union  */
127     AINSTR_END, /* array  */
128 };
129
130 uint16_t type_eq_instr[TYPE_COUNT] = {
131     INSTR_EQ_F, /* should use I when having integer support */
132     INSTR_EQ_S,
133     INSTR_EQ_F,
134     INSTR_EQ_V,
135     INSTR_EQ_E,
136     INSTR_EQ_E, /* FLD has no comparison */
137     INSTR_EQ_FNC,
138     INSTR_EQ_E, /* should use I */
139 #if 0
140     INSTR_EQ_I,
141 #else
142     INSTR_EQ_F,
143 #endif
144
145     INSTR_EQ_V, /* variant, should never be accessed */
146
147     AINSTR_END, /* struct */
148     AINSTR_END, /* union  */
149     AINSTR_END, /* array  */
150 };
151
152 uint16_t type_ne_instr[TYPE_COUNT] = {
153     INSTR_NE_F, /* should use I when having integer support */
154     INSTR_NE_S,
155     INSTR_NE_F,
156     INSTR_NE_V,
157     INSTR_NE_E,
158     INSTR_NE_E, /* FLD has no comparison */
159     INSTR_NE_FNC,
160     INSTR_NE_E, /* should use I */
161 #if 0
162     INSTR_NE_I,
163 #else
164     INSTR_NE_F,
165 #endif
166
167     INSTR_NE_V, /* variant, should never be accessed */
168
169     AINSTR_END, /* struct */
170     AINSTR_END, /* union  */
171     AINSTR_END, /* array  */
172 };
173
174 static void irerror(lex_ctx ctx, const char *msg, ...)
175 {
176     va_list ap;
177     va_start(ap, msg);
178     con_cvprintmsg((void*)&ctx, LVL_ERROR, "internal error", msg, ap);
179     va_end(ap);
180 }
181
182 static bool irwarning(lex_ctx ctx, int warntype, const char *fmt, ...)
183 {
184         va_list ap;
185         int lvl = LVL_WARNING;
186
187     if (warntype && !OPTS_WARN(warntype))
188         return false;
189
190     if (opts_werror)
191             lvl = LVL_ERROR;
192
193         va_start(ap, fmt);
194     con_vprintmsg(lvl, ctx.file, ctx.line, "warning", fmt, ap);
195         va_end(ap);
196
197         return opts_werror;
198 }
199
200 /***********************************************************************
201  * Vector utility functions
202  */
203
204 bool GMQCC_WARN vec_ir_value_find(ir_value **vec, ir_value *what, size_t *idx)
205 {
206     size_t i;
207     size_t len = vec_size(vec);
208     for (i = 0; i < len; ++i) {
209         if (vec[i] == what) {
210             if (idx) *idx = i;
211             return true;
212         }
213     }
214     return false;
215 }
216
217 bool GMQCC_WARN vec_ir_block_find(ir_block **vec, ir_block *what, size_t *idx)
218 {
219     size_t i;
220     size_t len = vec_size(vec);
221     for (i = 0; i < len; ++i) {
222         if (vec[i] == what) {
223             if (idx) *idx = i;
224             return true;
225         }
226     }
227     return false;
228 }
229
230 bool GMQCC_WARN vec_ir_instr_find(ir_instr **vec, ir_instr *what, size_t *idx)
231 {
232     size_t i;
233     size_t len = vec_size(vec);
234     for (i = 0; i < len; ++i) {
235         if (vec[i] == what) {
236             if (idx) *idx = i;
237             return true;
238         }
239     }
240     return false;
241 }
242
243 /***********************************************************************
244  * IR Builder
245  */
246
247 static void ir_block_delete_quick(ir_block* self);
248 static void ir_instr_delete_quick(ir_instr *self);
249 static void ir_function_delete_quick(ir_function *self);
250
251 ir_builder* ir_builder_new(const char *modulename)
252 {
253     ir_builder* self;
254
255     self = (ir_builder*)mem_a(sizeof(*self));
256     if (!self)
257         return NULL;
258
259     self->functions   = NULL;
260     self->globals     = NULL;
261     self->fields      = NULL;
262     self->extparams   = NULL;
263     self->filenames   = NULL;
264     self->filestrings = NULL;
265
266     self->str_immediate = 0;
267     self->name = NULL;
268     if (!ir_builder_set_name(self, modulename)) {
269         mem_d(self);
270         return NULL;
271     }
272
273     return self;
274 }
275
276 void ir_builder_delete(ir_builder* self)
277 {
278     size_t i;
279     mem_d((void*)self->name);
280     for (i = 0; i != vec_size(self->functions); ++i) {
281         ir_function_delete_quick(self->functions[i]);
282     }
283     vec_free(self->functions);
284     for (i = 0; i != vec_size(self->extparams); ++i) {
285         ir_value_delete(self->extparams[i]);
286     }
287     vec_free(self->extparams);
288     for (i = 0; i != vec_size(self->globals); ++i) {
289         ir_value_delete(self->globals[i]);
290     }
291     vec_free(self->globals);
292     for (i = 0; i != vec_size(self->fields); ++i) {
293         ir_value_delete(self->fields[i]);
294     }
295     vec_free(self->fields);
296     vec_free(self->filenames);
297     vec_free(self->filestrings);
298     mem_d(self);
299 }
300
301 bool ir_builder_set_name(ir_builder *self, const char *name)
302 {
303     if (self->name)
304         mem_d((void*)self->name);
305     self->name = util_strdup(name);
306     return !!self->name;
307 }
308
309 ir_function* ir_builder_get_function(ir_builder *self, const char *name)
310 {
311     size_t i;
312     for (i = 0; i < vec_size(self->functions); ++i) {
313         if (!strcmp(name, self->functions[i]->name))
314             return self->functions[i];
315     }
316     return NULL;
317 }
318
319 ir_function* ir_builder_create_function(ir_builder *self, const char *name, int outtype)
320 {
321     ir_function *fn = ir_builder_get_function(self, name);
322     if (fn) {
323         return NULL;
324     }
325
326     fn = ir_function_new(self, outtype);
327     if (!ir_function_set_name(fn, name))
328     {
329         ir_function_delete(fn);
330         return NULL;
331     }
332     vec_push(self->functions, fn);
333
334     fn->value = ir_builder_create_global(self, fn->name, TYPE_FUNCTION);
335     if (!fn->value) {
336         ir_function_delete(fn);
337         return NULL;
338     }
339
340     fn->value->isconst = true;
341     fn->value->outtype = outtype;
342     fn->value->constval.vfunc = fn;
343     fn->value->context = fn->context;
344
345     return fn;
346 }
347
348 ir_value* ir_builder_get_global(ir_builder *self, const char *name)
349 {
350     size_t i;
351     for (i = 0; i < vec_size(self->globals); ++i) {
352         if (!strcmp(self->globals[i]->name, name))
353             return self->globals[i];
354     }
355     return NULL;
356 }
357
358 ir_value* ir_builder_create_global(ir_builder *self, const char *name, int vtype)
359 {
360     ir_value *ve;
361
362     if (name && name[0] != '#')
363     {
364         ve = ir_builder_get_global(self, name);
365         if (ve) {
366             return NULL;
367         }
368     }
369
370     ve = ir_value_var(name, store_global, vtype);
371     vec_push(self->globals, ve);
372     return ve;
373 }
374
375 ir_value* ir_builder_get_field(ir_builder *self, const char *name)
376 {
377     size_t i;
378     for (i = 0; i < vec_size(self->fields); ++i) {
379         if (!strcmp(self->fields[i]->name, name))
380             return self->fields[i];
381     }
382     return NULL;
383 }
384
385
386 ir_value* ir_builder_create_field(ir_builder *self, const char *name, int vtype)
387 {
388     ir_value *ve = ir_builder_get_field(self, name);
389     if (ve) {
390         return NULL;
391     }
392
393     ve = ir_value_var(name, store_global, TYPE_FIELD);
394     ve->fieldtype = vtype;
395     vec_push(self->fields, ve);
396     return ve;
397 }
398
399 /***********************************************************************
400  *IR Function
401  */
402
403 bool ir_function_naive_phi(ir_function*);
404 void ir_function_enumerate(ir_function*);
405 bool ir_function_calculate_liferanges(ir_function*);
406 bool ir_function_allocate_locals(ir_function*);
407
408 ir_function* ir_function_new(ir_builder* owner, int outtype)
409 {
410     ir_function *self;
411     self = (ir_function*)mem_a(sizeof(*self));
412
413     if (!self)
414         return NULL;
415
416     memset(self, 0, sizeof(*self));
417
418     self->name = NULL;
419     if (!ir_function_set_name(self, "<@unnamed>")) {
420         mem_d(self);
421         return NULL;
422     }
423     self->owner = owner;
424     self->context.file = "<@no context>";
425     self->context.line = 0;
426     self->outtype = outtype;
427     self->value = NULL;
428     self->builtin = 0;
429
430     self->params = NULL;
431     self->blocks = NULL;
432     self->values = NULL;
433     self->locals = NULL;
434
435     self->max_parameters = 0;
436
437     self->code_function_def = -1;
438     self->allocated_locals = 0;
439
440     self->run_id = 0;
441     return self;
442 }
443
444 bool ir_function_set_name(ir_function *self, const char *name)
445 {
446     if (self->name)
447         mem_d((void*)self->name);
448     self->name = util_strdup(name);
449     return !!self->name;
450 }
451
452 static void ir_function_delete_quick(ir_function *self)
453 {
454     size_t i;
455     mem_d((void*)self->name);
456
457     for (i = 0; i != vec_size(self->blocks); ++i)
458         ir_block_delete_quick(self->blocks[i]);
459     vec_free(self->blocks);
460
461     vec_free(self->params);
462
463     for (i = 0; i != vec_size(self->values); ++i)
464         ir_value_delete(self->values[i]);
465     vec_free(self->values);
466
467     for (i = 0; i != vec_size(self->locals); ++i)
468         ir_value_delete(self->locals[i]);
469     vec_free(self->locals);
470
471     /* self->value is deleted by the builder */
472
473     mem_d(self);
474 }
475
476 void ir_function_delete(ir_function *self)
477 {
478     size_t i;
479     mem_d((void*)self->name);
480
481     for (i = 0; i != vec_size(self->blocks); ++i)
482         ir_block_delete(self->blocks[i]);
483     vec_free(self->blocks);
484
485     vec_free(self->params);
486
487     for (i = 0; i != vec_size(self->values); ++i)
488         ir_value_delete(self->values[i]);
489     vec_free(self->values);
490
491     for (i = 0; i != vec_size(self->locals); ++i)
492         ir_value_delete(self->locals[i]);
493     vec_free(self->locals);
494
495     /* self->value is deleted by the builder */
496
497     mem_d(self);
498 }
499
500 void ir_function_collect_value(ir_function *self, ir_value *v)
501 {
502     vec_push(self->values, v);
503 }
504
505 ir_block* ir_function_create_block(ir_function *self, const char *label)
506 {
507     ir_block* bn = ir_block_new(self, label);
508     memcpy(&bn->context, &self->context, sizeof(self->context));
509     vec_push(self->blocks, bn);
510     return bn;
511 }
512
513 bool ir_function_finalize(ir_function *self)
514 {
515     if (self->builtin)
516         return true;
517
518     if (!ir_function_naive_phi(self))
519         return false;
520
521     ir_function_enumerate(self);
522
523     if (!ir_function_calculate_liferanges(self))
524         return false;
525
526     if (!ir_function_allocate_locals(self))
527         return false;
528     return true;
529 }
530
531 ir_value* ir_function_get_local(ir_function *self, const char *name)
532 {
533     size_t i;
534     for (i = 0; i < vec_size(self->locals); ++i) {
535         if (!strcmp(self->locals[i]->name, name))
536             return self->locals[i];
537     }
538     return NULL;
539 }
540
541 ir_value* ir_function_create_local(ir_function *self, const char *name, int vtype, bool param)
542 {
543     ir_value *ve;
544
545     /*
546     if (ir_function_get_local(self, name))
547         return NULL;
548     */
549
550     if (param &&
551         vec_size(self->locals) &&
552         self->locals[vec_size(self->locals)-1]->store != store_param) {
553         irerror(self->context, "cannot add parameters after adding locals");
554         return NULL;
555     }
556
557     ve = ir_value_var(name, (param ? store_param : store_local), vtype);
558     vec_push(self->locals, ve);
559     return ve;
560 }
561
562 /***********************************************************************
563  *IR Block
564  */
565
566 ir_block* ir_block_new(ir_function* owner, const char *name)
567 {
568     ir_block *self;
569     self = (ir_block*)mem_a(sizeof(*self));
570     if (!self)
571         return NULL;
572
573     memset(self, 0, sizeof(*self));
574
575     self->label = NULL;
576     if (name && !ir_block_set_label(self, name)) {
577         mem_d(self);
578         return NULL;
579     }
580     self->owner = owner;
581     self->context.file = "<@no context>";
582     self->context.line = 0;
583     self->final = false;
584
585     self->instr   = NULL;
586     self->entries = NULL;
587     self->exits   = NULL;
588
589     self->eid = 0;
590     self->is_return = false;
591     self->run_id = 0;
592
593     self->living = NULL;
594
595     self->generated = false;
596
597     return self;
598 }
599
600 static void ir_block_delete_quick(ir_block* self)
601 {
602     size_t i;
603     if (self->label) mem_d(self->label);
604     for (i = 0; i != vec_size(self->instr); ++i)
605         ir_instr_delete_quick(self->instr[i]);
606     vec_free(self->instr);
607     vec_free(self->entries);
608     vec_free(self->exits);
609     vec_free(self->living);
610     mem_d(self);
611 }
612
613 void ir_block_delete(ir_block* self)
614 {
615     size_t i;
616     if (self->label) mem_d(self->label);
617     for (i = 0; i != vec_size(self->instr); ++i)
618         ir_instr_delete(self->instr[i]);
619     vec_free(self->instr);
620     vec_free(self->entries);
621     vec_free(self->exits);
622     vec_free(self->living);
623     mem_d(self);
624 }
625
626 bool ir_block_set_label(ir_block *self, const char *name)
627 {
628     if (self->label)
629         mem_d((void*)self->label);
630     self->label = util_strdup(name);
631     return !!self->label;
632 }
633
634 /***********************************************************************
635  *IR Instructions
636  */
637
638 ir_instr* ir_instr_new(ir_block* owner, int op)
639 {
640     ir_instr *self;
641     self = (ir_instr*)mem_a(sizeof(*self));
642     if (!self)
643         return NULL;
644
645     self->owner = owner;
646     self->context.file = "<@no context>";
647     self->context.line = 0;
648     self->opcode = op;
649     self->_ops[0] = NULL;
650     self->_ops[1] = NULL;
651     self->_ops[2] = NULL;
652     self->bops[0] = NULL;
653     self->bops[1] = NULL;
654
655     self->phi    = NULL;
656     self->params = NULL;
657
658     self->eid = 0;
659     return self;
660 }
661
662 static void ir_instr_delete_quick(ir_instr *self)
663 {
664     vec_free(self->phi);
665     vec_free(self->params);
666     mem_d(self);
667 }
668
669 void ir_instr_delete(ir_instr *self)
670 {
671     size_t i;
672     /* The following calls can only delete from
673      * vectors, we still want to delete this instruction
674      * so ignore the return value. Since with the warn_unused_result attribute
675      * gcc doesn't care about an explicit: (void)foo(); to ignore the result,
676      * I have to improvise here and use if(foo());
677      */
678     for (i = 0; i < vec_size(self->phi); ++i) {
679         size_t idx;
680         if (vec_ir_instr_find(self->phi[i].value->writes, self, &idx))
681             vec_remove(self->phi[i].value->writes, idx, 1);
682         if (vec_ir_instr_find(self->phi[i].value->reads, self, &idx))
683             vec_remove(self->phi[i].value->reads, idx, 1);
684     }
685     vec_free(self->phi);
686     for (i = 0; i < vec_size(self->params); ++i) {
687         size_t idx;
688         if (vec_ir_instr_find(self->params[i]->writes, self, &idx))
689             vec_remove(self->params[i]->writes, idx, 1);
690         if (vec_ir_instr_find(self->params[i]->reads, self, &idx))
691             vec_remove(self->params[i]->reads, idx, 1);
692     }
693     vec_free(self->params);
694     (void)!ir_instr_op(self, 0, NULL, false);
695     (void)!ir_instr_op(self, 1, NULL, false);
696     (void)!ir_instr_op(self, 2, NULL, false);
697     mem_d(self);
698 }
699
700 bool ir_instr_op(ir_instr *self, int op, ir_value *v, bool writing)
701 {
702     if (self->_ops[op]) {
703         size_t idx;
704         if (writing && vec_ir_instr_find(self->_ops[op]->writes, self, &idx))
705             vec_remove(self->_ops[op]->writes, idx, 1);
706         else if (vec_ir_instr_find(self->_ops[op]->reads, self, &idx))
707             vec_remove(self->_ops[op]->reads, idx, 1);
708     }
709     if (v) {
710         if (writing)
711             vec_push(v->writes, self);
712         else
713             vec_push(v->reads, self);
714     }
715     self->_ops[op] = v;
716     return true;
717 }
718
719 /***********************************************************************
720  *IR Value
721  */
722
723 void ir_value_code_setaddr(ir_value *self, int32_t gaddr)
724 {
725     self->code.globaladdr = gaddr;
726     if (self->members[0]) self->members[0]->code.globaladdr = gaddr;
727     if (self->members[1]) self->members[1]->code.globaladdr = gaddr;
728     if (self->members[2]) self->members[2]->code.globaladdr = gaddr;
729 }
730
731 int32_t ir_value_code_addr(const ir_value *self)
732 {
733     if (self->store == store_return)
734         return OFS_RETURN + self->code.addroffset;
735     return self->code.globaladdr + self->code.addroffset;
736 }
737
738 ir_value* ir_value_var(const char *name, int storetype, int vtype)
739 {
740     ir_value *self;
741     self = (ir_value*)mem_a(sizeof(*self));
742     self->vtype = vtype;
743     self->fieldtype = TYPE_VOID;
744     self->outtype = TYPE_VOID;
745     self->store = storetype;
746
747     self->reads  = NULL;
748     self->writes = NULL;
749
750     self->isconst = false;
751     self->context.file = "<@no context>";
752     self->context.line = 0;
753     self->name = NULL;
754     if (name && !ir_value_set_name(self, name)) {
755         irerror(self->context, "out of memory");
756         mem_d(self);
757         return NULL;
758     }
759
760     memset(&self->constval, 0, sizeof(self->constval));
761     memset(&self->code,     0, sizeof(self->code));
762
763     self->members[0] = NULL;
764     self->members[1] = NULL;
765     self->members[2] = NULL;
766     self->memberof = NULL;
767
768     self->life = NULL;
769     return self;
770 }
771
772 ir_value* ir_value_vector_member(ir_value *self, unsigned int member)
773 {
774     ir_value *m;
775     if (member >= 3)
776         return NULL;
777
778     if (self->members[member])
779         return self->members[member];
780
781     if (self->vtype == TYPE_VECTOR)
782     {
783         m = ir_value_var(self->name, self->store, TYPE_FLOAT);
784         if (!m)
785             return NULL;
786         m->context = self->context;
787
788         self->members[member] = m;
789         m->code.addroffset = member;
790     }
791     else if (self->vtype == TYPE_FIELD)
792     {
793         if (self->fieldtype != TYPE_VECTOR)
794             return NULL;
795         m = ir_value_var(self->name, self->store, TYPE_FIELD);
796         if (!m)
797             return NULL;
798         m->fieldtype = TYPE_FLOAT;
799         m->context = self->context;
800
801         self->members[member] = m;
802         m->code.addroffset = member;
803     }
804     else
805     {
806         irerror(self->context, "invalid member access on %s", self->name);
807         return NULL;
808     }
809
810     m->memberof = self;
811     return m;
812 }
813
814 ir_value* ir_value_out(ir_function *owner, const char *name, int storetype, int vtype)
815 {
816     ir_value *v = ir_value_var(name, storetype, vtype);
817     if (!v)
818         return NULL;
819     ir_function_collect_value(owner, v);
820     return v;
821 }
822
823 void ir_value_delete(ir_value* self)
824 {
825     size_t i;
826     if (self->name)
827         mem_d((void*)self->name);
828     if (self->isconst)
829     {
830         if (self->vtype == TYPE_STRING)
831             mem_d((void*)self->constval.vstring);
832     }
833     for (i = 0; i < 3; ++i) {
834         if (self->members[i])
835             ir_value_delete(self->members[i]);
836     }
837     vec_free(self->reads);
838     vec_free(self->writes);
839     vec_free(self->life);
840     mem_d(self);
841 }
842
843 bool ir_value_set_name(ir_value *self, const char *name)
844 {
845     if (self->name)
846         mem_d((void*)self->name);
847     self->name = util_strdup(name);
848     return !!self->name;
849 }
850
851 bool ir_value_set_float(ir_value *self, float f)
852 {
853     if (self->vtype != TYPE_FLOAT)
854         return false;
855     self->constval.vfloat = f;
856     self->isconst = true;
857     return true;
858 }
859
860 bool ir_value_set_func(ir_value *self, int f)
861 {
862     if (self->vtype != TYPE_FUNCTION)
863         return false;
864     self->constval.vint = f;
865     self->isconst = true;
866     return true;
867 }
868
869 bool ir_value_set_vector(ir_value *self, vector v)
870 {
871     if (self->vtype != TYPE_VECTOR)
872         return false;
873     self->constval.vvec = v;
874     self->isconst = true;
875     return true;
876 }
877
878 bool ir_value_set_field(ir_value *self, ir_value *fld)
879 {
880     if (self->vtype != TYPE_FIELD)
881         return false;
882     self->constval.vpointer = fld;
883     self->isconst = true;
884     return true;
885 }
886
887 static char *ir_strdup(const char *str)
888 {
889     if (str && !*str) {
890         /* actually dup empty strings */
891         char *out = mem_a(1);
892         *out = 0;
893         return out;
894     }
895     return util_strdup(str);
896 }
897
898 bool ir_value_set_string(ir_value *self, const char *str)
899 {
900     if (self->vtype != TYPE_STRING)
901         return false;
902     self->constval.vstring = ir_strdup(str);
903     self->isconst = true;
904     return true;
905 }
906
907 #if 0
908 bool ir_value_set_int(ir_value *self, int i)
909 {
910     if (self->vtype != TYPE_INTEGER)
911         return false;
912     self->constval.vint = i;
913     self->isconst = true;
914     return true;
915 }
916 #endif
917
918 bool ir_value_lives(ir_value *self, size_t at)
919 {
920     size_t i;
921     for (i = 0; i < vec_size(self->life); ++i)
922     {
923         ir_life_entry_t *life = &self->life[i];
924         if (life->start <= at && at <= life->end)
925             return true;
926         if (life->start > at) /* since it's ordered */
927             return false;
928     }
929     return false;
930 }
931
932 bool ir_value_life_insert(ir_value *self, size_t idx, ir_life_entry_t e)
933 {
934     size_t k;
935     vec_push(self->life, e);
936     for (k = vec_size(self->life)-1; k > idx; --k)
937         self->life[k] = self->life[k-1];
938     self->life[idx] = e;
939     return true;
940 }
941
942 bool ir_value_life_merge(ir_value *self, size_t s)
943 {
944     size_t i;
945     ir_life_entry_t *life = NULL;
946     ir_life_entry_t *before = NULL;
947     ir_life_entry_t new_entry;
948
949     /* Find the first range >= s */
950     for (i = 0; i < vec_size(self->life); ++i)
951     {
952         before = life;
953         life = &self->life[i];
954         if (life->start > s)
955             break;
956     }
957     /* nothing found? append */
958     if (i == vec_size(self->life)) {
959         ir_life_entry_t e;
960         if (life && life->end+1 == s)
961         {
962             /* previous life range can be merged in */
963             life->end++;
964             return true;
965         }
966         if (life && life->end >= s)
967             return false;
968         e.start = e.end = s;
969         vec_push(self->life, e);
970         return true;
971     }
972     /* found */
973     if (before)
974     {
975         if (before->end + 1 == s &&
976             life->start - 1 == s)
977         {
978             /* merge */
979             before->end = life->end;
980             vec_remove(self->life, i, 1);
981             return true;
982         }
983         if (before->end + 1 == s)
984         {
985             /* extend before */
986             before->end++;
987             return true;
988         }
989         /* already contained */
990         if (before->end >= s)
991             return false;
992     }
993     /* extend */
994     if (life->start - 1 == s)
995     {
996         life->start--;
997         return true;
998     }
999     /* insert a new entry */
1000     new_entry.start = new_entry.end = s;
1001     return ir_value_life_insert(self, i, new_entry);
1002 }
1003
1004 bool ir_value_life_merge_into(ir_value *self, const ir_value *other)
1005 {
1006     size_t i, myi;
1007
1008     if (!vec_size(other->life))
1009         return true;
1010
1011     if (!vec_size(self->life)) {
1012         size_t count = vec_size(other->life);
1013         ir_life_entry_t *life = vec_add(self->life, count);
1014         memcpy(life, other->life, count * sizeof(*life));
1015         return true;
1016     }
1017
1018     myi = 0;
1019     for (i = 0; i < vec_size(other->life); ++i)
1020     {
1021         const ir_life_entry_t *life = &other->life[i];
1022         while (true)
1023         {
1024             ir_life_entry_t *entry = &self->life[myi];
1025
1026             if (life->end+1 < entry->start)
1027             {
1028                 /* adding an interval before entry */
1029                 if (!ir_value_life_insert(self, myi, *life))
1030                     return false;
1031                 ++myi;
1032                 break;
1033             }
1034
1035             if (life->start <  entry->start &&
1036                 life->end+1 >= entry->start)
1037             {
1038                 /* starts earlier and overlaps */
1039                 entry->start = life->start;
1040             }
1041
1042             if (life->end   >  entry->end &&
1043                 life->start <= entry->end+1)
1044             {
1045                 /* ends later and overlaps */
1046                 entry->end = life->end;
1047             }
1048
1049             /* see if our change combines it with the next ranges */
1050             while (myi+1 < vec_size(self->life) &&
1051                    entry->end+1 >= self->life[1+myi].start)
1052             {
1053                 /* overlaps with (myi+1) */
1054                 if (entry->end < self->life[1+myi].end)
1055                     entry->end = self->life[1+myi].end;
1056                 vec_remove(self->life, myi+1, 1);
1057                 entry = &self->life[myi];
1058             }
1059
1060             /* see if we're after the entry */
1061             if (life->start > entry->end)
1062             {
1063                 ++myi;
1064                 /* append if we're at the end */
1065                 if (myi >= vec_size(self->life)) {
1066                     vec_push(self->life, *life);
1067                     break;
1068                 }
1069                 /* otherweise check the next range */
1070                 continue;
1071             }
1072             break;
1073         }
1074     }
1075     return true;
1076 }
1077
1078 bool ir_values_overlap(const ir_value *a, const ir_value *b)
1079 {
1080     /* For any life entry in A see if it overlaps with
1081      * any life entry in B.
1082      * Note that the life entries are orderes, so we can make a
1083      * more efficient algorithm there than naively translating the
1084      * statement above.
1085      */
1086
1087     ir_life_entry_t *la, *lb, *enda, *endb;
1088
1089     /* first of all, if either has no life range, they cannot clash */
1090     if (!vec_size(a->life) || !vec_size(b->life))
1091         return false;
1092
1093     la = a->life;
1094     lb = b->life;
1095     enda = la + vec_size(a->life);
1096     endb = lb + vec_size(b->life);
1097     while (true)
1098     {
1099         /* check if the entries overlap, for that,
1100          * both must start before the other one ends.
1101          */
1102         if (la->start < lb->end &&
1103             lb->start < la->end)
1104         {
1105             return true;
1106         }
1107
1108         /* entries are ordered
1109          * one entry is earlier than the other
1110          * that earlier entry will be moved forward
1111          */
1112         if (la->start < lb->start)
1113         {
1114             /* order: A B, move A forward
1115              * check if we hit the end with A
1116              */
1117             if (++la == enda)
1118                 break;
1119         }
1120         else /* if (lb->start < la->start)  actually <= */
1121         {
1122             /* order: B A, move B forward
1123              * check if we hit the end with B
1124              */
1125             if (++lb == endb)
1126                 break;
1127         }
1128     }
1129     return false;
1130 }
1131
1132 /***********************************************************************
1133  *IR main operations
1134  */
1135
1136 bool ir_block_create_store_op(ir_block *self, int op, ir_value *target, ir_value *what)
1137 {
1138     ir_instr *in = ir_instr_new(self, op);
1139     if (!in)
1140         return false;
1141
1142     if (target->store == store_value &&
1143         (op < INSTR_STOREP_F || op > INSTR_STOREP_FNC))
1144     {
1145         irerror(self->context, "cannot store to an SSA value");
1146         irerror(self->context, "trying to store: %s <- %s", target->name, what->name);
1147         irerror(self->context, "instruction: %s", asm_instr[op].m);
1148         return false;
1149     }
1150
1151     if (!ir_instr_op(in, 0, target, true) ||
1152         !ir_instr_op(in, 1, what, false))
1153     {
1154         return false;
1155     }
1156     vec_push(self->instr, in);
1157     return true;
1158 }
1159
1160 bool ir_block_create_store(ir_block *self, ir_value *target, ir_value *what)
1161 {
1162     int op = 0;
1163     int vtype;
1164     if (target->vtype == TYPE_VARIANT)
1165         vtype = what->vtype;
1166     else
1167         vtype = target->vtype;
1168
1169 #if 0
1170     if      (vtype == TYPE_FLOAT   && what->vtype == TYPE_INTEGER)
1171         op = INSTR_CONV_ITOF;
1172     else if (vtype == TYPE_INTEGER && what->vtype == TYPE_FLOAT)
1173         op = INSTR_CONV_FTOI;
1174 #endif
1175         op = type_store_instr[vtype];
1176
1177     if (OPTS_FLAG(ADJUST_VECTOR_FIELDS)) {
1178         if (op == INSTR_STORE_FLD && what->fieldtype == TYPE_VECTOR)
1179             op = INSTR_STORE_V;
1180     }
1181
1182     return ir_block_create_store_op(self, op, target, what);
1183 }
1184
1185 bool ir_block_create_storep(ir_block *self, ir_value *target, ir_value *what)
1186 {
1187     int op = 0;
1188     int vtype;
1189
1190     if (target->vtype != TYPE_POINTER)
1191         return false;
1192
1193     /* storing using pointer - target is a pointer, type must be
1194      * inferred from source
1195      */
1196     vtype = what->vtype;
1197
1198     op = type_storep_instr[vtype];
1199     if (OPTS_FLAG(ADJUST_VECTOR_FIELDS)) {
1200         if (op == INSTR_STOREP_FLD && what->fieldtype == TYPE_VECTOR)
1201             op = INSTR_STOREP_V;
1202     }
1203
1204     return ir_block_create_store_op(self, op, target, what);
1205 }
1206
1207 bool ir_block_create_return(ir_block *self, ir_value *v)
1208 {
1209     ir_instr *in;
1210     if (self->final) {
1211         irerror(self->context, "block already ended (%s)", self->label);
1212         return false;
1213     }
1214     self->final = true;
1215     self->is_return = true;
1216     in = ir_instr_new(self, INSTR_RETURN);
1217     if (!in)
1218         return false;
1219
1220     if (v && !ir_instr_op(in, 0, v, false))
1221         return false;
1222
1223     vec_push(self->instr, in);
1224     return true;
1225 }
1226
1227 bool ir_block_create_if(ir_block *self, ir_value *v,
1228                         ir_block *ontrue, ir_block *onfalse)
1229 {
1230     ir_instr *in;
1231     if (self->final) {
1232         irerror(self->context, "block already ended (%s)", self->label);
1233         return false;
1234     }
1235     self->final = true;
1236     /*in = ir_instr_new(self, (v->vtype == TYPE_STRING ? INSTR_IF_S : INSTR_IF_F));*/
1237     in = ir_instr_new(self, VINSTR_COND);
1238     if (!in)
1239         return false;
1240
1241     if (!ir_instr_op(in, 0, v, false)) {
1242         ir_instr_delete(in);
1243         return false;
1244     }
1245
1246     in->bops[0] = ontrue;
1247     in->bops[1] = onfalse;
1248
1249     vec_push(self->instr, in);
1250
1251     vec_push(self->exits, ontrue);
1252     vec_push(self->exits, onfalse);
1253     vec_push(ontrue->entries,  self);
1254     vec_push(onfalse->entries, self);
1255     return true;
1256 }
1257
1258 bool ir_block_create_jump(ir_block *self, ir_block *to)
1259 {
1260     ir_instr *in;
1261     if (self->final) {
1262         irerror(self->context, "block already ended (%s)", self->label);
1263         return false;
1264     }
1265     self->final = true;
1266     in = ir_instr_new(self, VINSTR_JUMP);
1267     if (!in)
1268         return false;
1269
1270     in->bops[0] = to;
1271     vec_push(self->instr, in);
1272
1273     vec_push(self->exits, to);
1274     vec_push(to->entries, self);
1275     return true;
1276 }
1277
1278 bool ir_block_create_goto(ir_block *self, ir_block *to)
1279 {
1280     ir_instr *in;
1281     if (self->final) {
1282         irerror(self->context, "block already ended (%s)", self->label);
1283         return false;
1284     }
1285     self->final = true;
1286     in = ir_instr_new(self, INSTR_GOTO);
1287     if (!in)
1288         return false;
1289
1290     in->bops[0] = to;
1291     vec_push(self->instr, in);
1292
1293     vec_push(self->exits, to);
1294     vec_push(to->entries, self);
1295     return true;
1296 }
1297
1298 ir_instr* ir_block_create_phi(ir_block *self, const char *label, int ot)
1299 {
1300     ir_value *out;
1301     ir_instr *in;
1302     in = ir_instr_new(self, VINSTR_PHI);
1303     if (!in)
1304         return NULL;
1305     out = ir_value_out(self->owner, label, store_value, ot);
1306     if (!out) {
1307         ir_instr_delete(in);
1308         return NULL;
1309     }
1310     if (!ir_instr_op(in, 0, out, true)) {
1311         ir_instr_delete(in);
1312         ir_value_delete(out);
1313         return NULL;
1314     }
1315     vec_push(self->instr, in);
1316     return in;
1317 }
1318
1319 ir_value* ir_phi_value(ir_instr *self)
1320 {
1321     return self->_ops[0];
1322 }
1323
1324 void ir_phi_add(ir_instr* self, ir_block *b, ir_value *v)
1325 {
1326     ir_phi_entry_t pe;
1327
1328     if (!vec_ir_block_find(self->owner->entries, b, NULL)) {
1329         /* Must not be possible to cause this, otherwise the AST
1330          * is doing something wrong.
1331          */
1332         irerror(self->context, "Invalid entry block for PHI");
1333         abort();
1334     }
1335
1336     pe.value = v;
1337     pe.from = b;
1338     vec_push(v->reads, self);
1339     vec_push(self->phi, pe);
1340 }
1341
1342 /* call related code */
1343 ir_instr* ir_block_create_call(ir_block *self, const char *label, ir_value *func)
1344 {
1345     ir_value *out;
1346     ir_instr *in;
1347     in = ir_instr_new(self, INSTR_CALL0);
1348     if (!in)
1349         return NULL;
1350     out = ir_value_out(self->owner, label, (func->outtype == TYPE_VOID) ? store_return : store_value, func->outtype);
1351     if (!out) {
1352         ir_instr_delete(in);
1353         return NULL;
1354     }
1355     if (!ir_instr_op(in, 0, out, true) ||
1356         !ir_instr_op(in, 1, func, false))
1357     {
1358         ir_instr_delete(in);
1359         ir_value_delete(out);
1360         return NULL;
1361     }
1362     vec_push(self->instr, in);
1363     return in;
1364 }
1365
1366 ir_value* ir_call_value(ir_instr *self)
1367 {
1368     return self->_ops[0];
1369 }
1370
1371 void ir_call_param(ir_instr* self, ir_value *v)
1372 {
1373     vec_push(self->params, v);
1374     vec_push(v->reads, self);
1375 }
1376
1377 /* binary op related code */
1378
1379 ir_value* ir_block_create_binop(ir_block *self,
1380                                 const char *label, int opcode,
1381                                 ir_value *left, ir_value *right)
1382 {
1383     int ot = TYPE_VOID;
1384     switch (opcode) {
1385         case INSTR_ADD_F:
1386         case INSTR_SUB_F:
1387         case INSTR_DIV_F:
1388         case INSTR_MUL_F:
1389         case INSTR_MUL_V:
1390         case INSTR_AND:
1391         case INSTR_OR:
1392 #if 0
1393         case INSTR_AND_I:
1394         case INSTR_AND_IF:
1395         case INSTR_AND_FI:
1396         case INSTR_OR_I:
1397         case INSTR_OR_IF:
1398         case INSTR_OR_FI:
1399 #endif
1400         case INSTR_BITAND:
1401         case INSTR_BITOR:
1402 #if 0
1403         case INSTR_SUB_S: /* -- offset of string as float */
1404         case INSTR_MUL_IF:
1405         case INSTR_MUL_FI:
1406         case INSTR_DIV_IF:
1407         case INSTR_DIV_FI:
1408         case INSTR_BITOR_IF:
1409         case INSTR_BITOR_FI:
1410         case INSTR_BITAND_FI:
1411         case INSTR_BITAND_IF:
1412         case INSTR_EQ_I:
1413         case INSTR_NE_I:
1414 #endif
1415             ot = TYPE_FLOAT;
1416             break;
1417 #if 0
1418         case INSTR_ADD_I:
1419         case INSTR_ADD_IF:
1420         case INSTR_ADD_FI:
1421         case INSTR_SUB_I:
1422         case INSTR_SUB_FI:
1423         case INSTR_SUB_IF:
1424         case INSTR_MUL_I:
1425         case INSTR_DIV_I:
1426         case INSTR_BITAND_I:
1427         case INSTR_BITOR_I:
1428         case INSTR_XOR_I:
1429         case INSTR_RSHIFT_I:
1430         case INSTR_LSHIFT_I:
1431             ot = TYPE_INTEGER;
1432             break;
1433 #endif
1434         case INSTR_ADD_V:
1435         case INSTR_SUB_V:
1436         case INSTR_MUL_VF:
1437         case INSTR_MUL_FV:
1438 #if 0
1439         case INSTR_DIV_VF:
1440         case INSTR_MUL_IV:
1441         case INSTR_MUL_VI:
1442 #endif
1443             ot = TYPE_VECTOR;
1444             break;
1445 #if 0
1446         case INSTR_ADD_SF:
1447             ot = TYPE_POINTER;
1448             break;
1449 #endif
1450         default:
1451             /* ranges: */
1452             /* boolean operations result in floats */
1453             if (opcode >= INSTR_EQ_F && opcode <= INSTR_GT)
1454                 ot = TYPE_FLOAT;
1455             else if (opcode >= INSTR_LE && opcode <= INSTR_GT)
1456                 ot = TYPE_FLOAT;
1457 #if 0
1458             else if (opcode >= INSTR_LE_I && opcode <= INSTR_EQ_FI)
1459                 ot = TYPE_FLOAT;
1460 #endif
1461             break;
1462     };
1463     if (ot == TYPE_VOID) {
1464         /* The AST or parser were supposed to check this! */
1465         return NULL;
1466     }
1467
1468     return ir_block_create_general_instr(self, label, opcode, left, right, ot);
1469 }
1470
1471 ir_value* ir_block_create_unary(ir_block *self,
1472                                 const char *label, int opcode,
1473                                 ir_value *operand)
1474 {
1475     int ot = TYPE_FLOAT;
1476     switch (opcode) {
1477         case INSTR_NOT_F:
1478         case INSTR_NOT_V:
1479         case INSTR_NOT_S:
1480         case INSTR_NOT_ENT:
1481         case INSTR_NOT_FNC:
1482 #if 0
1483         case INSTR_NOT_I:
1484 #endif
1485             ot = TYPE_FLOAT;
1486             break;
1487         /* QC doesn't have other unary operations. We expect extensions to fill
1488          * the above list, otherwise we assume out-type = in-type, eg for an
1489          * unary minus
1490          */
1491         default:
1492             ot = operand->vtype;
1493             break;
1494     };
1495     if (ot == TYPE_VOID) {
1496         /* The AST or parser were supposed to check this! */
1497         return NULL;
1498     }
1499
1500     /* let's use the general instruction creator and pass NULL for OPB */
1501     return ir_block_create_general_instr(self, label, opcode, operand, NULL, ot);
1502 }
1503
1504 ir_value* ir_block_create_general_instr(ir_block *self, const char *label,
1505                                         int op, ir_value *a, ir_value *b, int outype)
1506 {
1507     ir_instr *instr;
1508     ir_value *out;
1509
1510     out = ir_value_out(self->owner, label, store_value, outype);
1511     if (!out)
1512         return NULL;
1513
1514     instr = ir_instr_new(self, op);
1515     if (!instr) {
1516         ir_value_delete(out);
1517         return NULL;
1518     }
1519
1520     if (!ir_instr_op(instr, 0, out, true) ||
1521         !ir_instr_op(instr, 1, a, false) ||
1522         !ir_instr_op(instr, 2, b, false) )
1523     {
1524         goto on_error;
1525     }
1526
1527     vec_push(self->instr, instr);
1528
1529     return out;
1530 on_error:
1531     ir_instr_delete(instr);
1532     ir_value_delete(out);
1533     return NULL;
1534 }
1535
1536 ir_value* ir_block_create_fieldaddress(ir_block *self, const char *label, ir_value *ent, ir_value *field)
1537 {
1538     ir_value *v;
1539
1540     /* Support for various pointer types todo if so desired */
1541     if (ent->vtype != TYPE_ENTITY)
1542         return NULL;
1543
1544     if (field->vtype != TYPE_FIELD)
1545         return NULL;
1546
1547     v = ir_block_create_general_instr(self, label, INSTR_ADDRESS, ent, field, TYPE_POINTER);
1548     v->fieldtype = field->fieldtype;
1549     return v;
1550 }
1551
1552 ir_value* ir_block_create_load_from_ent(ir_block *self, const char *label, ir_value *ent, ir_value *field, int outype)
1553 {
1554     int op;
1555     if (ent->vtype != TYPE_ENTITY)
1556         return NULL;
1557
1558     /* at some point we could redirect for TYPE_POINTER... but that could lead to carelessness */
1559     if (field->vtype != TYPE_FIELD)
1560         return NULL;
1561
1562     switch (outype)
1563     {
1564         case TYPE_FLOAT:    op = INSTR_LOAD_F;   break;
1565         case TYPE_VECTOR:   op = INSTR_LOAD_V;   break;
1566         case TYPE_STRING:   op = INSTR_LOAD_S;   break;
1567         case TYPE_FIELD:    op = INSTR_LOAD_FLD; break;
1568         case TYPE_ENTITY:   op = INSTR_LOAD_ENT; break;
1569         case TYPE_FUNCTION: op = INSTR_LOAD_FNC; break;
1570 #if 0
1571         case TYPE_POINTER: op = INSTR_LOAD_I;   break;
1572         case TYPE_INTEGER: op = INSTR_LOAD_I;   break;
1573 #endif
1574         default:
1575             irerror(self->context, "invalid type for ir_block_create_load_from_ent: %s", type_name[outype]);
1576             return NULL;
1577     }
1578
1579     return ir_block_create_general_instr(self, label, op, ent, field, outype);
1580 }
1581
1582 ir_value* ir_block_create_add(ir_block *self,
1583                               const char *label,
1584                               ir_value *left, ir_value *right)
1585 {
1586     int op = 0;
1587     int l = left->vtype;
1588     int r = right->vtype;
1589     if (l == r) {
1590         switch (l) {
1591             default:
1592                 irerror(self->context, "invalid type for ir_block_create_add: %s", type_name[l]);
1593                 return NULL;
1594             case TYPE_FLOAT:
1595                 op = INSTR_ADD_F;
1596                 break;
1597 #if 0
1598             case TYPE_INTEGER:
1599                 op = INSTR_ADD_I;
1600                 break;
1601 #endif
1602             case TYPE_VECTOR:
1603                 op = INSTR_ADD_V;
1604                 break;
1605         }
1606     } else {
1607 #if 0
1608         if ( (l == TYPE_FLOAT && r == TYPE_INTEGER) )
1609             op = INSTR_ADD_FI;
1610         else if ( (l == TYPE_INTEGER && r == TYPE_FLOAT) )
1611             op = INSTR_ADD_IF;
1612         else
1613 #endif
1614         {
1615             irerror(self->context, "invalid type for ir_block_create_add: %s", type_name[l]);
1616             return NULL;
1617         }
1618     }
1619     return ir_block_create_binop(self, label, op, left, right);
1620 }
1621
1622 ir_value* ir_block_create_sub(ir_block *self,
1623                               const char *label,
1624                               ir_value *left, ir_value *right)
1625 {
1626     int op = 0;
1627     int l = left->vtype;
1628     int r = right->vtype;
1629     if (l == r) {
1630
1631         switch (l) {
1632             default:
1633                 irerror(self->context, "invalid type for ir_block_create_sub: %s", type_name[l]);
1634                 return NULL;
1635             case TYPE_FLOAT:
1636                 op = INSTR_SUB_F;
1637                 break;
1638 #if 0
1639             case TYPE_INTEGER:
1640                 op = INSTR_SUB_I;
1641                 break;
1642 #endif
1643             case TYPE_VECTOR:
1644                 op = INSTR_SUB_V;
1645                 break;
1646         }
1647     } else {
1648 #if 0
1649         if ( (l == TYPE_FLOAT && r == TYPE_INTEGER) )
1650             op = INSTR_SUB_FI;
1651         else if ( (l == TYPE_INTEGER && r == TYPE_FLOAT) )
1652             op = INSTR_SUB_IF;
1653         else
1654 #endif
1655         {
1656             irerror(self->context, "invalid type for ir_block_create_sub: %s", type_name[l]);
1657             return NULL;
1658         }
1659     }
1660     return ir_block_create_binop(self, label, op, left, right);
1661 }
1662
1663 ir_value* ir_block_create_mul(ir_block *self,
1664                               const char *label,
1665                               ir_value *left, ir_value *right)
1666 {
1667     int op = 0;
1668     int l = left->vtype;
1669     int r = right->vtype;
1670     if (l == r) {
1671
1672         switch (l) {
1673             default:
1674                 irerror(self->context, "invalid type for ir_block_create_mul: %s", type_name[l]);
1675                 return NULL;
1676             case TYPE_FLOAT:
1677                 op = INSTR_MUL_F;
1678                 break;
1679 #if 0
1680             case TYPE_INTEGER:
1681                 op = INSTR_MUL_I;
1682                 break;
1683 #endif
1684             case TYPE_VECTOR:
1685                 op = INSTR_MUL_V;
1686                 break;
1687         }
1688     } else {
1689         if ( (l == TYPE_VECTOR && r == TYPE_FLOAT) )
1690             op = INSTR_MUL_VF;
1691         else if ( (l == TYPE_FLOAT && r == TYPE_VECTOR) )
1692             op = INSTR_MUL_FV;
1693 #if 0
1694         else if ( (l == TYPE_VECTOR && r == TYPE_INTEGER) )
1695             op = INSTR_MUL_VI;
1696         else if ( (l == TYPE_INTEGER && r == TYPE_VECTOR) )
1697             op = INSTR_MUL_IV;
1698         else if ( (l == TYPE_FLOAT && r == TYPE_INTEGER) )
1699             op = INSTR_MUL_FI;
1700         else if ( (l == TYPE_INTEGER && r == TYPE_FLOAT) )
1701             op = INSTR_MUL_IF;
1702 #endif
1703         else {
1704             irerror(self->context, "invalid type for ir_block_create_mul: %s", type_name[l]);
1705             return NULL;
1706         }
1707     }
1708     return ir_block_create_binop(self, label, op, left, right);
1709 }
1710
1711 ir_value* ir_block_create_div(ir_block *self,
1712                               const char *label,
1713                               ir_value *left, ir_value *right)
1714 {
1715     int op = 0;
1716     int l = left->vtype;
1717     int r = right->vtype;
1718     if (l == r) {
1719
1720         switch (l) {
1721             default:
1722                 irerror(self->context, "invalid type for ir_block_create_div: %s", type_name[l]);
1723                 return NULL;
1724             case TYPE_FLOAT:
1725                 op = INSTR_DIV_F;
1726                 break;
1727 #if 0
1728             case TYPE_INTEGER:
1729                 op = INSTR_DIV_I;
1730                 break;
1731 #endif
1732         }
1733     } else {
1734 #if 0
1735         if ( (l == TYPE_VECTOR && r == TYPE_FLOAT) )
1736             op = INSTR_DIV_VF;
1737         else if ( (l == TYPE_FLOAT && r == TYPE_INTEGER) )
1738             op = INSTR_DIV_FI;
1739         else if ( (l == TYPE_INTEGER && r == TYPE_FLOAT) )
1740             op = INSTR_DIV_IF;
1741         else
1742 #endif
1743         {
1744             irerror(self->context, "invalid type for ir_block_create_div: %s", type_name[l]);
1745             return NULL;
1746         }
1747     }
1748     return ir_block_create_binop(self, label, op, left, right);
1749 }
1750
1751 /* PHI resolving breaks the SSA, and must thus be the last
1752  * step before life-range calculation.
1753  */
1754
1755 static bool ir_block_naive_phi(ir_block *self);
1756 bool ir_function_naive_phi(ir_function *self)
1757 {
1758     size_t i;
1759
1760     for (i = 0; i < vec_size(self->blocks); ++i)
1761     {
1762         if (!ir_block_naive_phi(self->blocks[i]))
1763             return false;
1764     }
1765     return true;
1766 }
1767
1768 static bool ir_naive_phi_emit_store(ir_block *block, size_t iid, ir_value *old, ir_value *what)
1769 {
1770     ir_instr *instr;
1771     size_t i;
1772
1773     /* create a store */
1774     if (!ir_block_create_store(block, old, what))
1775         return false;
1776
1777     /* we now move it up */
1778     instr = vec_last(block->instr);
1779     for (i = vec_size(block->instr)-1; i > iid; --i)
1780         block->instr[i] = block->instr[i-1];
1781     block->instr[i] = instr;
1782
1783     return true;
1784 }
1785
1786 static bool ir_block_naive_phi(ir_block *self)
1787 {
1788     size_t i, p, w;
1789     /* FIXME: optionally, create_phi can add the phis
1790      * to a list so we don't need to loop through blocks
1791      * - anyway: "don't optimize YET"
1792      */
1793     for (i = 0; i < vec_size(self->instr); ++i)
1794     {
1795         ir_instr *instr = self->instr[i];
1796         if (instr->opcode != VINSTR_PHI)
1797             continue;
1798
1799         vec_remove(self->instr, i, 1);
1800         --i; /* NOTE: i+1 below */
1801
1802         for (p = 0; p < vec_size(instr->phi); ++p)
1803         {
1804             ir_value *v = instr->phi[p].value;
1805             for (w = 0; w < vec_size(v->writes); ++w) {
1806                 ir_value *old;
1807
1808                 if (!v->writes[w]->_ops[0])
1809                     continue;
1810
1811                 /* When the write was to a global, we have to emit a mov */
1812                 old = v->writes[w]->_ops[0];
1813
1814                 /* The original instruction now writes to the PHI target local */
1815                 if (v->writes[w]->_ops[0] == v)
1816                     v->writes[w]->_ops[0] = instr->_ops[0];
1817
1818                 if (old->store != store_value && old->store != store_local && old->store != store_param)
1819                 {
1820                     /* If it originally wrote to a global we need to store the value
1821                      * there as welli
1822                      */
1823                     if (!ir_naive_phi_emit_store(self, i+1, old, v))
1824                         return false;
1825                     if (i+1 < vec_size(self->instr))
1826                         instr = self->instr[i+1];
1827                     else
1828                         instr = NULL;
1829                     /* In case I forget and access instr later, it'll be NULL
1830                      * when it's a problem, to make sure we crash, rather than accessing
1831                      * invalid data.
1832                      */
1833                 }
1834                 else
1835                 {
1836                     /* If it didn't, we can replace all reads by the phi target now. */
1837                     size_t r;
1838                     for (r = 0; r < vec_size(old->reads); ++r)
1839                     {
1840                         size_t op;
1841                         ir_instr *ri = old->reads[r];
1842                         for (op = 0; op < vec_size(ri->phi); ++op) {
1843                             if (ri->phi[op].value == old)
1844                                 ri->phi[op].value = v;
1845                         }
1846                         for (op = 0; op < 3; ++op) {
1847                             if (ri->_ops[op] == old)
1848                                 ri->_ops[op] = v;
1849                         }
1850                     }
1851                 }
1852             }
1853         }
1854         ir_instr_delete(instr);
1855     }
1856     return true;
1857 }
1858
1859 /***********************************************************************
1860  *IR Temp allocation code
1861  * Propagating value life ranges by walking through the function backwards
1862  * until no more changes are made.
1863  * In theory this should happen once more than once for every nested loop
1864  * level.
1865  * Though this implementation might run an additional time for if nests.
1866  */
1867
1868 /* Enumerate instructions used by value's life-ranges
1869  */
1870 static void ir_block_enumerate(ir_block *self, size_t *_eid)
1871 {
1872     size_t i;
1873     size_t eid = *_eid;
1874     for (i = 0; i < vec_size(self->instr); ++i)
1875     {
1876         self->instr[i]->eid = eid++;
1877     }
1878     *_eid = eid;
1879 }
1880
1881 /* Enumerate blocks and instructions.
1882  * The block-enumeration is unordered!
1883  * We do not really use the block enumreation, however
1884  * the instruction enumeration is important for life-ranges.
1885  */
1886 void ir_function_enumerate(ir_function *self)
1887 {
1888     size_t i;
1889     size_t instruction_id = 0;
1890     for (i = 0; i < vec_size(self->blocks); ++i)
1891     {
1892         self->blocks[i]->eid = i;
1893         self->blocks[i]->run_id = 0;
1894         ir_block_enumerate(self->blocks[i], &instruction_id);
1895     }
1896 }
1897
1898 static bool ir_block_life_propagate(ir_block *b, ir_block *prev, bool *changed);
1899 bool ir_function_calculate_liferanges(ir_function *self)
1900 {
1901     size_t i;
1902     bool changed;
1903
1904     do {
1905         self->run_id++;
1906         changed = false;
1907         for (i = 0; i != vec_size(self->blocks); ++i)
1908         {
1909             if (self->blocks[i]->is_return)
1910             {
1911                 vec_free(self->blocks[i]->living);
1912                 if (!ir_block_life_propagate(self->blocks[i], NULL, &changed))
1913                     return false;
1914             }
1915         }
1916     } while (changed);
1917     if (vec_size(self->blocks)) {
1918         ir_block *block = self->blocks[0];
1919         for (i = 0; i < vec_size(block->living); ++i) {
1920             ir_value *v = block->living[i];
1921             if (v->memberof || v->store != store_local)
1922                 continue;
1923             if (irwarning(v->context, WARN_USED_UNINITIALIZED,
1924                           "variable `%s` may be used uninitialized in this function", v->name))
1925             {
1926                 return false;
1927             }
1928         }
1929     }
1930     return true;
1931 }
1932
1933 /* Local-value allocator
1934  * After finishing creating the liferange of all values used in a function
1935  * we can allocate their global-positions.
1936  * This is the counterpart to register-allocation in register machines.
1937  */
1938 typedef struct {
1939     ir_value **locals;
1940     size_t    *sizes;
1941     size_t    *positions;
1942 } function_allocator;
1943
1944 static bool function_allocator_alloc(function_allocator *alloc, const ir_value *var)
1945 {
1946     ir_value *slot;
1947     size_t vsize = type_sizeof[var->vtype];
1948
1949     slot = ir_value_var("reg", store_global, var->vtype);
1950     if (!slot)
1951         return false;
1952
1953     if (!ir_value_life_merge_into(slot, var))
1954         goto localerror;
1955
1956     vec_push(alloc->locals, slot);
1957     vec_push(alloc->sizes, vsize);
1958
1959     return true;
1960
1961 localerror:
1962     ir_value_delete(slot);
1963     return false;
1964 }
1965
1966 bool ir_function_allocate_locals(ir_function *self)
1967 {
1968     size_t i, a;
1969     bool   retval = true;
1970     size_t pos;
1971
1972     ir_value *slot;
1973     const ir_value *v;
1974
1975     function_allocator alloc;
1976
1977     if (!vec_size(self->locals) && !vec_size(self->values))
1978         return true;
1979
1980     alloc.locals    = NULL;
1981     alloc.sizes     = NULL;
1982     alloc.positions = NULL;
1983
1984     for (i = 0; i < vec_size(self->locals); ++i)
1985     {
1986         if (!function_allocator_alloc(&alloc, self->locals[i]))
1987             goto error;
1988     }
1989
1990     /* Allocate a slot for any value that still exists */
1991     for (i = 0; i < vec_size(self->values); ++i)
1992     {
1993         v = self->values[i];
1994
1995         if (!vec_size(v->life))
1996             continue;
1997
1998         for (a = 0; a < vec_size(alloc.locals); ++a)
1999         {
2000             slot = alloc.locals[a];
2001
2002             if (ir_values_overlap(v, slot))
2003                 continue;
2004
2005             if (!ir_value_life_merge_into(slot, v))
2006                 goto error;
2007
2008             /* adjust size for this slot */
2009             if (alloc.sizes[a] < type_sizeof[v->vtype])
2010                 alloc.sizes[a] = type_sizeof[v->vtype];
2011
2012             self->values[i]->code.local = a;
2013             break;
2014         }
2015         if (a >= vec_size(alloc.locals)) {
2016             self->values[i]->code.local = vec_size(alloc.locals);
2017             if (!function_allocator_alloc(&alloc, v))
2018                 goto error;
2019         }
2020     }
2021
2022     if (!alloc.sizes) {
2023         goto cleanup;
2024     }
2025
2026     /* Adjust slot positions based on sizes */
2027     vec_push(alloc.positions, 0);
2028
2029     if (vec_size(alloc.sizes))
2030         pos = alloc.positions[0] + alloc.sizes[0];
2031     else
2032         pos = 0;
2033     for (i = 1; i < vec_size(alloc.sizes); ++i)
2034     {
2035         pos = alloc.positions[i-1] + alloc.sizes[i-1];
2036         vec_push(alloc.positions, pos);
2037     }
2038
2039     self->allocated_locals = pos + vec_last(alloc.sizes);
2040
2041     /* Take over the actual slot positions */
2042     for (i = 0; i < vec_size(self->values); ++i) {
2043         self->values[i]->code.local = alloc.positions[self->values[i]->code.local];
2044     }
2045
2046     goto cleanup;
2047
2048 error:
2049     retval = false;
2050 cleanup:
2051     for (i = 0; i < vec_size(alloc.locals); ++i)
2052         ir_value_delete(alloc.locals[i]);
2053     vec_free(alloc.locals);
2054     vec_free(alloc.sizes);
2055     vec_free(alloc.positions);
2056     return retval;
2057 }
2058
2059 /* Get information about which operand
2060  * is read from, or written to.
2061  */
2062 static void ir_op_read_write(int op, size_t *read, size_t *write)
2063 {
2064     switch (op)
2065     {
2066     case VINSTR_JUMP:
2067     case INSTR_GOTO:
2068         *write = 0;
2069         *read = 0;
2070         break;
2071     case INSTR_IF:
2072     case INSTR_IFNOT:
2073 #if 0
2074     case INSTR_IF_S:
2075     case INSTR_IFNOT_S:
2076 #endif
2077     case INSTR_RETURN:
2078     case VINSTR_COND:
2079         *write = 0;
2080         *read = 1;
2081         break;
2082     case INSTR_STOREP_F:
2083     case INSTR_STOREP_V:
2084     case INSTR_STOREP_S:
2085     case INSTR_STOREP_ENT:
2086     case INSTR_STOREP_FLD:
2087     case INSTR_STOREP_FNC:
2088         *write = 0;
2089         *read  = 7;
2090         break;
2091     default:
2092         *write = 1;
2093         *read = 6;
2094         break;
2095     };
2096 }
2097
2098 static bool ir_block_living_add_instr(ir_block *self, size_t eid)
2099 {
2100     size_t i;
2101     bool changed = false;
2102     bool tempbool;
2103     for (i = 0; i != vec_size(self->living); ++i)
2104     {
2105         tempbool = ir_value_life_merge(self->living[i], eid);
2106         /* debug
2107         if (tempbool)
2108             irerror(self->context, "block_living_add_instr() value instruction added %s: %i", self->living[i]->_name, (int)eid);
2109         */
2110         changed = changed || tempbool;
2111     }
2112     return changed;
2113 }
2114
2115 static bool ir_block_life_prop_previous(ir_block* self, ir_block *prev, bool *changed)
2116 {
2117     size_t i;
2118     /* values which have been read in a previous iteration are now
2119      * in the "living" array even if the previous block doesn't use them.
2120      * So we have to remove whatever does not exist in the previous block.
2121      * They will be re-added on-read, but the liferange merge won't cause
2122      * a change.
2123      */
2124     for (i = 0; i < vec_size(self->living); ++i)
2125     {
2126         if (!vec_ir_value_find(prev->living, self->living[i], NULL)) {
2127             vec_remove(self->living, i, 1);
2128             --i;
2129         }
2130     }
2131
2132     /* Whatever the previous block still has in its living set
2133      * must now be added to ours as well.
2134      */
2135     for (i = 0; i < vec_size(prev->living); ++i)
2136     {
2137         if (vec_ir_value_find(self->living, prev->living[i], NULL))
2138             continue;
2139         vec_push(self->living, prev->living[i]);
2140         /*
2141         irerror(self->contextt from prev: %s", self->label, prev->living[i]->_name);
2142         */
2143     }
2144     return true;
2145 }
2146
2147 static bool ir_block_life_propagate(ir_block *self, ir_block *prev, bool *changed)
2148 {
2149     ir_instr *instr;
2150     ir_value *value;
2151     bool  tempbool;
2152     size_t i, o, p;
2153     /* bitmasks which operands are read from or written to */
2154     size_t read, write;
2155     char dbg_ind[16] = { '#', '0' };
2156     (void)dbg_ind;
2157
2158     if (prev)
2159     {
2160         if (!ir_block_life_prop_previous(self, prev, changed))
2161             return false;
2162     }
2163
2164     i = vec_size(self->instr);
2165     while (i)
2166     { --i;
2167         instr = self->instr[i];
2168
2169         /* PHI operands are always read operands */
2170         for (p = 0; p < vec_size(instr->phi); ++p)
2171         {
2172             value = instr->phi[p].value;
2173             if (value->memberof)
2174                 value = value->memberof;
2175             if (!vec_ir_value_find(self->living, value, NULL))
2176                 vec_push(self->living, value);
2177         }
2178
2179         /* call params are read operands too */
2180         for (p = 0; p < vec_size(instr->params); ++p)
2181         {
2182             value = instr->params[p];
2183             if (value->memberof)
2184                 value = value->memberof;
2185             if (!vec_ir_value_find(self->living, value, NULL))
2186                 vec_push(self->living, value);
2187         }
2188
2189         /* See which operands are read and write operands */
2190         ir_op_read_write(instr->opcode, &read, &write);
2191
2192         if (instr->opcode == INSTR_MUL_VF)
2193         {
2194             /* the float source will get an additional lifetime */
2195             tempbool = ir_value_life_merge(instr->_ops[2], instr->eid+1);
2196             *changed = *changed || tempbool;
2197         }
2198         else if (instr->opcode == INSTR_MUL_FV)
2199         {
2200             /* the float source will get an additional lifetime */
2201             tempbool = ir_value_life_merge(instr->_ops[1], instr->eid+1);
2202             *changed = *changed || tempbool;
2203         }
2204
2205         /* Go through the 3 main operands */
2206         for (o = 0; o < 3; ++o)
2207         {
2208             if (!instr->_ops[o]) /* no such operand */
2209                 continue;
2210
2211             value = instr->_ops[o];
2212             if (value->memberof)
2213                 value = value->memberof;
2214
2215             /* We only care about locals */
2216             /* we also calculate parameter liferanges so that locals
2217              * can take up parameter slots */
2218             if (value->store != store_value &&
2219                 value->store != store_local &&
2220                 value->store != store_param)
2221                 continue;
2222
2223             /* read operands */
2224             if (read & (1<<o))
2225             {
2226                 if (!vec_ir_value_find(self->living, value, NULL))
2227                     vec_push(self->living, value);
2228             }
2229
2230             /* write operands */
2231             /* When we write to a local, we consider it "dead" for the
2232              * remaining upper part of the function, since in SSA a value
2233              * can only be written once (== created)
2234              */
2235             if (write & (1<<o))
2236             {
2237                 size_t idx;
2238                 bool in_living = vec_ir_value_find(self->living, value, &idx);
2239                 if (!in_living)
2240                 {
2241                     /* If the value isn't alive it hasn't been read before... */
2242                     /* TODO: See if the warning can be emitted during parsing or AST processing
2243                      * otherwise have warning printed here.
2244                      * IF printing a warning here: include filecontext_t,
2245                      * and make sure it's only printed once
2246                      * since this function is run multiple times.
2247                      */
2248                     /* For now: debug info: */
2249                     /* con_err( "Value only written %s\n", value->name); */
2250                     tempbool = ir_value_life_merge(value, instr->eid);
2251                     *changed = *changed || tempbool;
2252                     /*
2253                     ir_instr_dump(instr, dbg_ind, printf);
2254                     abort();
2255                     */
2256                 } else {
2257                     /* since 'living' won't contain it
2258                      * anymore, merge the value, since
2259                      * (A) doesn't.
2260                      */
2261                     tempbool = ir_value_life_merge(value, instr->eid);
2262                     /*
2263                     if (tempbool)
2264                         con_err( "value added id %s %i\n", value->name, (int)instr->eid);
2265                     */
2266                     *changed = *changed || tempbool;
2267                     /* Then remove */
2268                     vec_remove(self->living, idx, 1);
2269                 }
2270             }
2271         }
2272         /* (A) */
2273         tempbool = ir_block_living_add_instr(self, instr->eid);
2274         /*con_err( "living added values\n");*/
2275         *changed = *changed || tempbool;
2276
2277     }
2278
2279     if (self->run_id == self->owner->run_id)
2280         return true;
2281
2282     self->run_id = self->owner->run_id;
2283
2284     for (i = 0; i < vec_size(self->entries); ++i)
2285     {
2286         ir_block *entry = self->entries[i];
2287         ir_block_life_propagate(entry, self, changed);
2288     }
2289
2290     return true;
2291 }
2292
2293 /***********************************************************************
2294  *IR Code-Generation
2295  *
2296  * Since the IR has the convention of putting 'write' operands
2297  * at the beginning, we have to rotate the operands of instructions
2298  * properly in order to generate valid QCVM code.
2299  *
2300  * Having destinations at a fixed position is more convenient. In QC
2301  * this is *mostly* OPC,  but FTE adds at least 2 instructions which
2302  * read from from OPA,  and store to OPB rather than OPC.   Which is
2303  * partially the reason why the implementation of these instructions
2304  * in darkplaces has been delayed for so long.
2305  *
2306  * Breaking conventions is annoying...
2307  */
2308 static bool ir_builder_gen_global(ir_builder *self, ir_value *global, bool islocal);
2309
2310 static bool gen_global_field(ir_value *global)
2311 {
2312     if (global->isconst)
2313     {
2314         ir_value *fld = global->constval.vpointer;
2315         if (!fld) {
2316             irerror(global->context, "Invalid field constant with no field: %s", global->name);
2317             return false;
2318         }
2319
2320         /* Now, in this case, a relocation would be impossible to code
2321          * since it looks like this:
2322          * .vector v = origin;     <- parse error, wtf is 'origin'?
2323          * .vector origin;
2324          *
2325          * But we will need a general relocation support later anyway
2326          * for functions... might as well support that here.
2327          */
2328         if (!fld->code.globaladdr) {
2329             irerror(global->context, "FIXME: Relocation support");
2330             return false;
2331         }
2332
2333         /* copy the field's value */
2334         ir_value_code_setaddr(global, vec_size(code_globals));
2335         vec_push(code_globals, code_globals[fld->code.globaladdr]);
2336         if (global->fieldtype == TYPE_VECTOR) {
2337             vec_push(code_globals, code_globals[fld->code.globaladdr]+1);
2338             vec_push(code_globals, code_globals[fld->code.globaladdr]+2);
2339         }
2340     }
2341     else
2342     {
2343         ir_value_code_setaddr(global, vec_size(code_globals));
2344         vec_push(code_globals, 0);
2345         if (global->fieldtype == TYPE_VECTOR) {
2346             vec_push(code_globals, 0);
2347             vec_push(code_globals, 0);
2348         }
2349     }
2350     if (global->code.globaladdr < 0)
2351         return false;
2352     return true;
2353 }
2354
2355 static bool gen_global_pointer(ir_value *global)
2356 {
2357     if (global->isconst)
2358     {
2359         ir_value *target = global->constval.vpointer;
2360         if (!target) {
2361             irerror(global->context, "Invalid pointer constant: %s", global->name);
2362             /* NULL pointers are pointing to the NULL constant, which also
2363              * sits at address 0, but still has an ir_value for itself.
2364              */
2365             return false;
2366         }
2367
2368         /* Here, relocations ARE possible - in fteqcc-enhanced-qc:
2369          * void() foo; <- proto
2370          * void() *fooptr = &foo;
2371          * void() foo = { code }
2372          */
2373         if (!target->code.globaladdr) {
2374             /* FIXME: Check for the constant nullptr ir_value!
2375              * because then code.globaladdr being 0 is valid.
2376              */
2377             irerror(global->context, "FIXME: Relocation support");
2378             return false;
2379         }
2380
2381         ir_value_code_setaddr(global, vec_size(code_globals));
2382         vec_push(code_globals, target->code.globaladdr);
2383     }
2384     else
2385     {
2386         ir_value_code_setaddr(global, vec_size(code_globals));
2387         vec_push(code_globals, 0);
2388     }
2389     if (global->code.globaladdr < 0)
2390         return false;
2391     return true;
2392 }
2393
2394 static bool gen_blocks_recursive(ir_function *func, ir_block *block)
2395 {
2396     prog_section_statement stmt;
2397     ir_instr *instr;
2398     ir_block *target;
2399     ir_block *ontrue;
2400     ir_block *onfalse;
2401     size_t    stidx;
2402     size_t    i;
2403
2404 tailcall:
2405     block->generated = true;
2406     block->code_start = vec_size(code_statements);
2407     for (i = 0; i < vec_size(block->instr); ++i)
2408     {
2409         instr = block->instr[i];
2410
2411         if (instr->opcode == VINSTR_PHI) {
2412             irerror(block->context, "cannot generate virtual instruction (phi)");
2413             return false;
2414         }
2415
2416         if (instr->opcode == VINSTR_JUMP) {
2417             target = instr->bops[0];
2418             /* for uncoditional jumps, if the target hasn't been generated
2419              * yet, we generate them right here.
2420              */
2421             if (!target->generated) {
2422                 block = target;
2423                 goto tailcall;
2424             }
2425
2426             /* otherwise we generate a jump instruction */
2427             stmt.opcode = INSTR_GOTO;
2428             stmt.o1.s1 = (target->code_start) - vec_size(code_statements);
2429             stmt.o2.s1 = 0;
2430             stmt.o3.s1 = 0;
2431             vec_push(code_statements, stmt);
2432
2433             /* no further instructions can be in this block */
2434             return true;
2435         }
2436
2437         if (instr->opcode == VINSTR_COND) {
2438             ontrue  = instr->bops[0];
2439             onfalse = instr->bops[1];
2440             /* TODO: have the AST signal which block should
2441              * come first: eg. optimize IFs without ELSE...
2442              */
2443
2444             stmt.o1.u1 = ir_value_code_addr(instr->_ops[0]);
2445             stmt.o2.u1 = 0;
2446             stmt.o3.s1 = 0;
2447
2448             if (ontrue->generated) {
2449                 stmt.opcode = INSTR_IF;
2450                 stmt.o2.s1 = (ontrue->code_start) - vec_size(code_statements);
2451                 vec_push(code_statements, stmt);
2452             }
2453             if (onfalse->generated) {
2454                 stmt.opcode = INSTR_IFNOT;
2455                 stmt.o2.s1 = (onfalse->code_start) - vec_size(code_statements);
2456                 vec_push(code_statements, stmt);
2457             }
2458             if (!ontrue->generated) {
2459                 if (onfalse->generated) {
2460                     block = ontrue;
2461                     goto tailcall;
2462                 }
2463             }
2464             if (!onfalse->generated) {
2465                 if (ontrue->generated) {
2466                     block = onfalse;
2467                     goto tailcall;
2468                 }
2469             }
2470             /* neither ontrue nor onfalse exist */
2471             stmt.opcode = INSTR_IFNOT;
2472             stidx = vec_size(code_statements);
2473             vec_push(code_statements, stmt);
2474             /* on false we jump, so add ontrue-path */
2475             if (!gen_blocks_recursive(func, ontrue))
2476                 return false;
2477             /* fixup the jump address */
2478             code_statements[stidx].o2.s1 = vec_size(code_statements) - stidx;
2479             /* generate onfalse path */
2480             if (onfalse->generated) {
2481                 /* fixup the jump address */
2482                 code_statements[stidx].o2.s1 = (onfalse->code_start) - (stidx);
2483                 /* may have been generated in the previous recursive call */
2484                 stmt.opcode = INSTR_GOTO;
2485                 stmt.o1.s1 = (onfalse->code_start) - vec_size(code_statements);
2486                 stmt.o2.s1 = 0;
2487                 stmt.o3.s1 = 0;
2488                 vec_push(code_statements, stmt);
2489                 return true;
2490             }
2491             /* if not, generate now */
2492             block = onfalse;
2493             goto tailcall;
2494         }
2495
2496         if (instr->opcode >= INSTR_CALL0 && instr->opcode <= INSTR_CALL8) {
2497             /* Trivial call translation:
2498              * copy all params to OFS_PARM*
2499              * if the output's storetype is not store_return,
2500              * add append a STORE instruction!
2501              *
2502              * NOTES on how to do it better without much trouble:
2503              * -) The liferanges!
2504              *      Simply check the liferange of all parameters for
2505              *      other CALLs. For each param with no CALL in its
2506              *      liferange, we can store it in an OFS_PARM at
2507              *      generation already. This would even include later
2508              *      reuse.... probably... :)
2509              */
2510             size_t p;
2511             ir_value *retvalue;
2512
2513             for (p = 0; p < vec_size(instr->params); ++p)
2514             {
2515                 ir_value *param = instr->params[p];
2516
2517                 stmt.opcode = INSTR_STORE_F;
2518                 stmt.o3.u1 = 0;
2519
2520                 if (param->vtype == TYPE_FIELD)
2521                     stmt.opcode = field_store_instr[param->fieldtype];
2522                 else
2523                     stmt.opcode = type_store_instr[param->vtype];
2524                 stmt.o1.u1 = ir_value_code_addr(param);
2525                 stmt.o2.u1 = OFS_PARM0 + 3 * p;
2526                 vec_push(code_statements, stmt);
2527             }
2528             stmt.opcode = INSTR_CALL0 + vec_size(instr->params);
2529             if (stmt.opcode > INSTR_CALL8)
2530                 stmt.opcode = INSTR_CALL8;
2531             stmt.o1.u1 = ir_value_code_addr(instr->_ops[1]);
2532             stmt.o2.u1 = 0;
2533             stmt.o3.u1 = 0;
2534             vec_push(code_statements, stmt);
2535
2536             retvalue = instr->_ops[0];
2537             if (retvalue && retvalue->store != store_return && vec_size(retvalue->life))
2538             {
2539                 /* not to be kept in OFS_RETURN */
2540                 if (retvalue->vtype == TYPE_FIELD)
2541                     stmt.opcode = field_store_instr[retvalue->vtype];
2542                 else
2543                     stmt.opcode = type_store_instr[retvalue->vtype];
2544                 stmt.o1.u1 = OFS_RETURN;
2545                 stmt.o2.u1 = ir_value_code_addr(retvalue);
2546                 stmt.o3.u1 = 0;
2547                 vec_push(code_statements, stmt);
2548             }
2549             continue;
2550         }
2551
2552         if (instr->opcode == INSTR_STATE) {
2553             irerror(block->context, "TODO: state instruction");
2554             return false;
2555         }
2556
2557         stmt.opcode = instr->opcode;
2558         stmt.o1.u1 = 0;
2559         stmt.o2.u1 = 0;
2560         stmt.o3.u1 = 0;
2561
2562         /* This is the general order of operands */
2563         if (instr->_ops[0])
2564             stmt.o3.u1 = ir_value_code_addr(instr->_ops[0]);
2565
2566         if (instr->_ops[1])
2567             stmt.o1.u1 = ir_value_code_addr(instr->_ops[1]);
2568
2569         if (instr->_ops[2])
2570             stmt.o2.u1 = ir_value_code_addr(instr->_ops[2]);
2571
2572         if (stmt.opcode == INSTR_RETURN || stmt.opcode == INSTR_DONE)
2573         {
2574             stmt.o1.u1 = stmt.o3.u1;
2575             stmt.o3.u1 = 0;
2576         }
2577         else if ((stmt.opcode >= INSTR_STORE_F &&
2578                   stmt.opcode <= INSTR_STORE_FNC) ||
2579                  (stmt.opcode >= INSTR_STOREP_F &&
2580                   stmt.opcode <= INSTR_STOREP_FNC))
2581         {
2582             /* 2-operand instructions with A -> B */
2583             stmt.o2.u1 = stmt.o3.u1;
2584             stmt.o3.u1 = 0;
2585         }
2586
2587         vec_push(code_statements, stmt);
2588     }
2589     return true;
2590 }
2591
2592 static bool gen_function_code(ir_function *self)
2593 {
2594     ir_block *block;
2595     prog_section_statement stmt;
2596
2597     /* Starting from entry point, we generate blocks "as they come"
2598      * for now. Dead blocks will not be translated obviously.
2599      */
2600     if (!vec_size(self->blocks)) {
2601         irerror(self->context, "Function '%s' declared without body.", self->name);
2602         return false;
2603     }
2604
2605     block = self->blocks[0];
2606     if (block->generated)
2607         return true;
2608
2609     if (!gen_blocks_recursive(self, block)) {
2610         irerror(self->context, "failed to generate blocks for '%s'", self->name);
2611         return false;
2612     }
2613
2614     /* otherwise code_write crashes since it debug-prints functions until AINSTR_END */
2615     stmt.opcode = AINSTR_END;
2616     stmt.o1.u1 = 0;
2617     stmt.o2.u1 = 0;
2618     stmt.o3.u1 = 0;
2619     vec_push(code_statements, stmt);
2620     return true;
2621 }
2622
2623 static qcint ir_builder_filestring(ir_builder *ir, const char *filename)
2624 {
2625     /* NOTE: filename pointers are copied, we never strdup them,
2626      * thus we can use pointer-comparison to find the string.
2627      */
2628     size_t i;
2629     qcint  str;
2630
2631     for (i = 0; i < vec_size(ir->filenames); ++i) {
2632         if (ir->filenames[i] == filename)
2633             return ir->filestrings[i];
2634     }
2635
2636     str = code_genstring(filename);
2637     vec_push(ir->filenames, filename);
2638     vec_push(ir->filestrings, str);
2639     return str;
2640 }
2641
2642 static bool gen_global_function(ir_builder *ir, ir_value *global)
2643 {
2644     prog_section_function fun;
2645     ir_function          *irfun;
2646
2647     size_t i;
2648     size_t local_var_end;
2649
2650     if (!global->isconst || (!global->constval.vfunc))
2651     {
2652         irerror(global->context, "Invalid state of function-global: not constant: %s", global->name);
2653         return false;
2654     }
2655
2656     irfun = global->constval.vfunc;
2657
2658     fun.name    = global->code.name;
2659     fun.file    = ir_builder_filestring(ir, global->context.file);
2660     fun.profile = 0; /* always 0 */
2661     fun.nargs   = vec_size(irfun->params);
2662
2663     for (i = 0;i < 8; ++i) {
2664         if (i >= fun.nargs)
2665             fun.argsize[i] = 0;
2666         else
2667             fun.argsize[i] = type_sizeof[irfun->params[i]];
2668     }
2669
2670     fun.firstlocal = vec_size(code_globals);
2671
2672     local_var_end = fun.firstlocal;
2673     for (i = 0; i < vec_size(irfun->locals); ++i) {
2674         if (!ir_builder_gen_global(ir, irfun->locals[i], true)) {
2675             irerror(irfun->locals[i]->context, "Failed to generate local %s", irfun->locals[i]->name);
2676             return false;
2677         }
2678     }
2679     if (vec_size(irfun->locals)) {
2680         ir_value *last = vec_last(irfun->locals);
2681         local_var_end = last->code.globaladdr;
2682         local_var_end += type_sizeof[last->vtype];
2683     }
2684     for (i = 0; i < vec_size(irfun->values); ++i)
2685     {
2686         /* generate code.globaladdr for ssa values */
2687         ir_value *v = irfun->values[i];
2688         ir_value_code_setaddr(v, local_var_end + v->code.local);
2689     }
2690     for (i = 0; i < irfun->allocated_locals; ++i) {
2691         /* fill the locals with zeros */
2692         vec_push(code_globals, 0);
2693     }
2694
2695     fun.locals = vec_size(code_globals) - fun.firstlocal;
2696
2697     if (irfun->builtin)
2698         fun.entry = irfun->builtin;
2699     else {
2700         irfun->code_function_def = vec_size(code_functions);
2701         fun.entry = vec_size(code_statements);
2702     }
2703
2704     vec_push(code_functions, fun);
2705     return true;
2706 }
2707
2708 static void ir_gen_extparam(ir_builder *ir)
2709 {
2710     prog_section_def def;
2711     ir_value        *global;
2712     char             name[128];
2713
2714     snprintf(name, sizeof(name), "#EXTPARM%i", (int)(vec_size(ir->extparams)+8));
2715     global = ir_value_var(name, store_global, TYPE_VECTOR);
2716
2717     def.name = code_genstring(name);
2718     def.type = TYPE_VECTOR;
2719     def.offset = vec_size(code_globals);
2720
2721     vec_push(code_defs, def);
2722     ir_value_code_setaddr(global, def.offset);
2723     vec_push(code_globals, 0);
2724     vec_push(code_globals, 0);
2725     vec_push(code_globals, 0);
2726
2727     vec_push(ir->extparams, global);
2728 }
2729
2730 static bool gen_function_extparam_copy(ir_function *self)
2731 {
2732     size_t i, ext;
2733
2734     ir_builder *ir = self->owner;
2735     ir_value   *ep;
2736     prog_section_statement stmt;
2737
2738     if (!self->max_parameters)
2739         return true;
2740
2741     stmt.opcode = INSTR_STORE_F;
2742     stmt.o3.s1 = 0;
2743     for (i = 8; i < self->max_parameters; ++i) {
2744         ext = i - 8;
2745         if (ext >= vec_size(ir->extparams))
2746             ir_gen_extparam(ir);
2747
2748         ep = ir->extparams[ext];
2749
2750         stmt.opcode = type_store_instr[self->locals[i]->vtype];
2751         if (self->locals[i]->vtype == TYPE_FIELD &&
2752             self->locals[i]->fieldtype == TYPE_VECTOR)
2753         {
2754             stmt.opcode = INSTR_STORE_V;
2755         }
2756         stmt.o1.u1 = ir_value_code_addr(ep);
2757         stmt.o2.u1 = ir_value_code_addr(self->locals[i]);
2758         vec_push(code_statements, stmt);
2759     }
2760
2761     return true;
2762 }
2763
2764 static bool gen_global_function_code(ir_builder *ir, ir_value *global)
2765 {
2766     prog_section_function *fundef;
2767     ir_function           *irfun;
2768
2769     irfun = global->constval.vfunc;
2770     if (!irfun) {
2771         irwarning(global->context, WARN_IMPLICIT_FUNCTION_POINTER,
2772                   "function `%s` has no body and in QC implicitly becomes a function-pointer", global->name);
2773         /* this was a function pointer, don't generate code for those */
2774         return true;
2775     }
2776
2777     if (irfun->builtin)
2778         return true;
2779
2780     if (irfun->code_function_def < 0) {
2781         irerror(irfun->context, "`%s`: IR global wasn't generated, failed to access function-def", irfun->name);
2782         return false;
2783     }
2784     fundef = &code_functions[irfun->code_function_def];
2785
2786     fundef->entry = vec_size(code_statements);
2787     if (!gen_function_extparam_copy(irfun)) {
2788         irerror(irfun->context, "Failed to generate extparam-copy code for function %s", irfun->name);
2789         return false;
2790     }
2791     if (!gen_function_code(irfun)) {
2792         irerror(irfun->context, "Failed to generate code for function %s", irfun->name);
2793         return false;
2794     }
2795     return true;
2796 }
2797
2798 static bool ir_builder_gen_global(ir_builder *self, ir_value *global, bool islocal)
2799 {
2800     size_t           i;
2801     int32_t         *iptr;
2802     prog_section_def def;
2803
2804     def.type   = global->vtype;
2805     def.offset = vec_size(code_globals);
2806
2807     if (global->name) {
2808         if (global->name[0] == '#') {
2809             if (!self->str_immediate)
2810                 self->str_immediate = code_genstring("IMMEDIATE");
2811             def.name = global->code.name = self->str_immediate;
2812         }
2813         else
2814             def.name = global->code.name = code_genstring(global->name);
2815     }
2816     else
2817         def.name   = 0;
2818
2819     switch (global->vtype)
2820     {
2821     case TYPE_VOID:
2822         if (!strcmp(global->name, "end_sys_globals")) {
2823             /* TODO: remember this point... all the defs before this one
2824              * should be checksummed and added to progdefs.h when we generate it.
2825              */
2826         }
2827         else if (!strcmp(global->name, "end_sys_fields")) {
2828             /* TODO: same as above but for entity-fields rather than globsl
2829              */
2830         }
2831         else
2832             irwarning(global->context, WARN_VOID_VARIABLES, "unrecognized variable of type void `%s`",
2833                       global->name);
2834         /* I'd argue setting it to 0 is sufficient, but maybe some depend on knowing how far
2835          * the system fields actually go? Though the engine knows this anyway...
2836          * Maybe this could be an -foption
2837          * fteqcc creates data for end_sys_* - of size 1, so let's do the same
2838          */
2839         ir_value_code_setaddr(global, vec_size(code_globals));
2840         vec_push(code_globals, 0);
2841         /* Add the def */
2842         vec_push(code_defs, def);
2843         return true;
2844     case TYPE_POINTER:
2845         vec_push(code_defs, def);
2846         return gen_global_pointer(global);
2847     case TYPE_FIELD:
2848         vec_push(code_defs, def);
2849         return gen_global_field(global);
2850     case TYPE_ENTITY:
2851         /* fall through */
2852     case TYPE_FLOAT:
2853     {
2854         ir_value_code_setaddr(global, vec_size(code_globals));
2855         if (global->isconst) {
2856             iptr = (int32_t*)&global->constval.ivec[0];
2857             vec_push(code_globals, *iptr);
2858         } else {
2859             vec_push(code_globals, 0);
2860             if (!islocal)
2861                 def.type |= DEF_SAVEGLOBAL;
2862         }
2863         vec_push(code_defs, def);
2864
2865         return global->code.globaladdr >= 0;
2866     }
2867     case TYPE_STRING:
2868     {
2869         ir_value_code_setaddr(global, vec_size(code_globals));
2870         if (global->isconst) {
2871             vec_push(code_globals, code_genstring(global->constval.vstring));
2872         } else {
2873             vec_push(code_globals, 0);
2874             if (!islocal)
2875                 def.type |= DEF_SAVEGLOBAL;
2876         }
2877         vec_push(code_defs, def);
2878         return global->code.globaladdr >= 0;
2879     }
2880     case TYPE_VECTOR:
2881     {
2882         size_t d;
2883         ir_value_code_setaddr(global, vec_size(code_globals));
2884         if (global->isconst) {
2885             iptr = (int32_t*)&global->constval.ivec[0];
2886             vec_push(code_globals, iptr[0]);
2887             if (global->code.globaladdr < 0)
2888                 return false;
2889             for (d = 1; d < type_sizeof[global->vtype]; ++d)
2890             {
2891                 vec_push(code_globals, iptr[d]);
2892             }
2893         } else {
2894             vec_push(code_globals, 0);
2895             if (global->code.globaladdr < 0)
2896                 return false;
2897             for (d = 1; d < type_sizeof[global->vtype]; ++d)
2898             {
2899                 vec_push(code_globals, 0);
2900             }
2901             if (!islocal)
2902                 def.type |= DEF_SAVEGLOBAL;
2903         }
2904
2905         vec_push(code_defs, def);
2906         return global->code.globaladdr >= 0;
2907     }
2908     case TYPE_FUNCTION:
2909         ir_value_code_setaddr(global, vec_size(code_globals));
2910         if (!global->isconst) {
2911             vec_push(code_globals, 0);
2912             if (global->code.globaladdr < 0)
2913                 return false;
2914         } else {
2915             vec_push(code_globals, vec_size(code_functions));
2916             if (!gen_global_function(self, global))
2917                 return false;
2918             if (!islocal)
2919                 def.type |= DEF_SAVEGLOBAL;
2920         }
2921         vec_push(code_defs, def);
2922         return true;
2923     case TYPE_VARIANT:
2924         /* assume biggest type */
2925             ir_value_code_setaddr(global, vec_size(code_globals));
2926             vec_push(code_globals, 0);
2927             for (i = 1; i < type_sizeof[TYPE_VARIANT]; ++i)
2928                 vec_push(code_globals, 0);
2929             return true;
2930     default:
2931         /* refuse to create 'void' type or any other fancy business. */
2932         irerror(global->context, "Invalid type for global variable `%s`: %s",
2933                 global->name, type_name[global->vtype]);
2934         return false;
2935     }
2936 }
2937
2938 static bool ir_builder_gen_field(ir_builder *self, ir_value *field)
2939 {
2940     prog_section_def def;
2941     prog_section_field fld;
2942
2943     def.type   = field->vtype;
2944     def.offset = vec_size(code_globals);
2945
2946     /* create a global named the same as the field */
2947     if (opts_standard == COMPILER_GMQCC) {
2948         /* in our standard, the global gets a dot prefix */
2949         size_t len = strlen(field->name);
2950         char name[1024];
2951
2952         /* we really don't want to have to allocate this, and 1024
2953          * bytes is more than enough for a variable/field name
2954          */
2955         if (len+2 >= sizeof(name)) {
2956             irerror(field->context, "invalid field name size: %u", (unsigned int)len);
2957             return false;
2958         }
2959
2960         name[0] = '.';
2961         memcpy(name+1, field->name, len); /* no strncpy - we used strlen above */
2962         name[len+1] = 0;
2963
2964         def.name = code_genstring(name);
2965         fld.name = def.name + 1; /* we reuse that string table entry */
2966     } else {
2967         /* in plain QC, there cannot be a global with the same name,
2968          * and so we also name the global the same.
2969          * FIXME: fteqcc should create a global as well
2970          * check if it actually uses the same name. Probably does
2971          */
2972         def.name = code_genstring(field->name);
2973         fld.name = def.name;
2974     }
2975
2976     field->code.name = def.name;
2977
2978     vec_push(code_defs, def);
2979
2980     fld.type = field->fieldtype;
2981
2982     if (fld.type == TYPE_VOID) {
2983         irerror(field->context, "field is missing a type: %s - don't know its size", field->name);
2984         return false;
2985     }
2986
2987     fld.offset = code_alloc_field(type_sizeof[field->fieldtype]);
2988
2989     vec_push(code_fields, fld);
2990
2991     ir_value_code_setaddr(field, vec_size(code_globals));
2992     vec_push(code_globals, fld.offset);
2993     if (fld.type == TYPE_VECTOR) {
2994         vec_push(code_globals, fld.offset+1);
2995         vec_push(code_globals, fld.offset+2);
2996     }
2997
2998     return field->code.globaladdr >= 0;
2999 }
3000
3001 bool ir_builder_generate(ir_builder *self, const char *filename)
3002 {
3003     prog_section_statement stmt;
3004     size_t i;
3005
3006     code_init();
3007
3008     for (i = 0; i < vec_size(self->globals); ++i)
3009     {
3010         if (!ir_builder_gen_global(self, self->globals[i], false)) {
3011             return false;
3012         }
3013     }
3014
3015     for (i = 0; i < vec_size(self->fields); ++i)
3016     {
3017         if (!ir_builder_gen_field(self, self->fields[i])) {
3018             return false;
3019         }
3020     }
3021
3022     /* generate function code */
3023     for (i = 0; i < vec_size(self->globals); ++i)
3024     {
3025         if (self->globals[i]->vtype == TYPE_FUNCTION) {
3026             if (!gen_global_function_code(self, self->globals[i])) {
3027                 return false;
3028             }
3029         }
3030     }
3031
3032     /* DP errors if the last instruction is not an INSTR_DONE
3033      * and for debugging purposes we add an additional AINSTR_END
3034      * to the end of functions, so here it goes:
3035      */
3036     stmt.opcode = INSTR_DONE;
3037     stmt.o1.u1 = 0;
3038     stmt.o2.u1 = 0;
3039     stmt.o3.u1 = 0;
3040     vec_push(code_statements, stmt);
3041
3042     if (!opts_pp_only)
3043         con_out("writing '%s'...\n", filename);
3044     return code_write(filename);
3045 }
3046
3047 /***********************************************************************
3048  *IR DEBUG Dump functions...
3049  */
3050
3051 #define IND_BUFSZ 1024
3052
3053 #ifdef WIN32
3054 # define strncat(dst, src, sz) strncat_s(dst, sz, src, _TRUNCATE)
3055 #endif
3056
3057 const char *qc_opname(int op)
3058 {
3059     if (op < 0) return "<INVALID>";
3060     if (op < ( sizeof(asm_instr) / sizeof(asm_instr[0]) ))
3061         return asm_instr[op].m;
3062     switch (op) {
3063         case VINSTR_PHI:  return "PHI";
3064         case VINSTR_JUMP: return "JUMP";
3065         case VINSTR_COND: return "COND";
3066         default:          return "<UNK>";
3067     }
3068 }
3069
3070 void ir_builder_dump(ir_builder *b, int (*oprintf)(const char*, ...))
3071 {
3072     size_t i;
3073     char indent[IND_BUFSZ];
3074     indent[0] = '\t';
3075     indent[1] = 0;
3076
3077     oprintf("module %s\n", b->name);
3078     for (i = 0; i < vec_size(b->globals); ++i)
3079     {
3080         oprintf("global ");
3081         if (b->globals[i]->isconst)
3082             oprintf("%s = ", b->globals[i]->name);
3083         ir_value_dump(b->globals[i], oprintf);
3084         oprintf("\n");
3085     }
3086     for (i = 0; i < vec_size(b->functions); ++i)
3087         ir_function_dump(b->functions[i], indent, oprintf);
3088     oprintf("endmodule %s\n", b->name);
3089 }
3090
3091 void ir_function_dump(ir_function *f, char *ind,
3092                       int (*oprintf)(const char*, ...))
3093 {
3094     size_t i;
3095     if (f->builtin != 0) {
3096         oprintf("%sfunction %s = builtin %i\n", ind, f->name, -f->builtin);
3097         return;
3098     }
3099     oprintf("%sfunction %s\n", ind, f->name);
3100     strncat(ind, "\t", IND_BUFSZ);
3101     if (vec_size(f->locals))
3102     {
3103         oprintf("%s%i locals:\n", ind, (int)vec_size(f->locals));
3104         for (i = 0; i < vec_size(f->locals); ++i) {
3105             oprintf("%s\t", ind);
3106             ir_value_dump(f->locals[i], oprintf);
3107             oprintf("\n");
3108         }
3109     }
3110     oprintf("%sliferanges:\n", ind);
3111     for (i = 0; i < vec_size(f->locals); ++i) {
3112         size_t l;
3113         ir_value *v = f->locals[i];
3114         oprintf("%s\t%s: unique ", ind, v->name);
3115         for (l = 0; l < vec_size(v->life); ++l) {
3116             oprintf("[%i,%i] ", v->life[l].start, v->life[l].end);
3117         }
3118         oprintf("\n");
3119     }
3120     for (i = 0; i < vec_size(f->values); ++i) {
3121         size_t l;
3122         ir_value *v = f->values[i];
3123         oprintf("%s\t%s: @%i ", ind, v->name, (int)v->code.local);
3124         for (l = 0; l < vec_size(v->life); ++l) {
3125             oprintf("[%i,%i] ", v->life[l].start, v->life[l].end);
3126         }
3127         oprintf("\n");
3128     }
3129     if (vec_size(f->blocks))
3130     {
3131         oprintf("%slife passes (check): %i\n", ind, (int)f->run_id);
3132         for (i = 0; i < vec_size(f->blocks); ++i) {
3133             if (f->blocks[i]->run_id != f->run_id) {
3134                 oprintf("%slife pass check fail! %i != %i\n", ind, (int)f->blocks[i]->run_id, (int)f->run_id);
3135             }
3136             ir_block_dump(f->blocks[i], ind, oprintf);
3137         }
3138
3139     }
3140     ind[strlen(ind)-1] = 0;
3141     oprintf("%sendfunction %s\n", ind, f->name);
3142 }
3143
3144 void ir_block_dump(ir_block* b, char *ind,
3145                    int (*oprintf)(const char*, ...))
3146 {
3147     size_t i;
3148     oprintf("%s:%s\n", ind, b->label);
3149     strncat(ind, "\t", IND_BUFSZ);
3150
3151     for (i = 0; i < vec_size(b->instr); ++i)
3152         ir_instr_dump(b->instr[i], ind, oprintf);
3153     ind[strlen(ind)-1] = 0;
3154 }
3155
3156 void dump_phi(ir_instr *in, char *ind,
3157               int (*oprintf)(const char*, ...))
3158 {
3159     size_t i;
3160     oprintf("%s <- phi ", in->_ops[0]->name);
3161     for (i = 0; i < vec_size(in->phi); ++i)
3162     {
3163         oprintf("([%s] : %s) ", in->phi[i].from->label,
3164                                 in->phi[i].value->name);
3165     }
3166     oprintf("\n");
3167 }
3168
3169 void ir_instr_dump(ir_instr *in, char *ind,
3170                        int (*oprintf)(const char*, ...))
3171 {
3172     size_t i;
3173     const char *comma = NULL;
3174
3175     oprintf("%s (%i) ", ind, (int)in->eid);
3176
3177     if (in->opcode == VINSTR_PHI) {
3178         dump_phi(in, ind, oprintf);
3179         return;
3180     }
3181
3182     strncat(ind, "\t", IND_BUFSZ);
3183
3184     if (in->_ops[0] && (in->_ops[1] || in->_ops[2])) {
3185         ir_value_dump(in->_ops[0], oprintf);
3186         if (in->_ops[1] || in->_ops[2])
3187             oprintf(" <- ");
3188     }
3189     if (in->opcode == INSTR_CALL0) {
3190         oprintf("CALL%i\t", vec_size(in->params));
3191     } else
3192         oprintf("%s\t", qc_opname(in->opcode));
3193
3194     if (in->_ops[0] && !(in->_ops[1] || in->_ops[2])) {
3195         ir_value_dump(in->_ops[0], oprintf);
3196         comma = ",\t";
3197     }
3198     else
3199     {
3200         for (i = 1; i != 3; ++i) {
3201             if (in->_ops[i]) {
3202                 if (comma)
3203                     oprintf(comma);
3204                 ir_value_dump(in->_ops[i], oprintf);
3205                 comma = ",\t";
3206             }
3207         }
3208     }
3209     if (in->bops[0]) {
3210         if (comma)
3211             oprintf(comma);
3212         oprintf("[%s]", in->bops[0]->label);
3213         comma = ",\t";
3214     }
3215     if (in->bops[1])
3216         oprintf("%s[%s]", comma, in->bops[1]->label);
3217     if (vec_size(in->params)) {
3218         oprintf("\tparams: ");
3219         for (i = 0; i != vec_size(in->params); ++i) {
3220             oprintf("%s, ", in->params[i]->name);
3221         }
3222     }
3223     oprintf("\n");
3224     ind[strlen(ind)-1] = 0;
3225 }
3226
3227 void ir_value_dump(ir_value* v, int (*oprintf)(const char*, ...))
3228 {
3229     if (v->isconst) {
3230         switch (v->vtype) {
3231             default:
3232             case TYPE_VOID:
3233                 oprintf("(void)");
3234                 break;
3235             case TYPE_FUNCTION:
3236                 oprintf("fn:%s", v->name);
3237                 break;
3238             case TYPE_FLOAT:
3239                 oprintf("%g", v->constval.vfloat);
3240                 break;
3241             case TYPE_VECTOR:
3242                 oprintf("'%g %g %g'",
3243                         v->constval.vvec.x,
3244                         v->constval.vvec.y,
3245                         v->constval.vvec.z);
3246                 break;
3247             case TYPE_ENTITY:
3248                 oprintf("(entity)");
3249                 break;
3250             case TYPE_STRING:
3251                 oprintf("\"%s\"", v->constval.vstring);
3252                 break;
3253 #if 0
3254             case TYPE_INTEGER:
3255                 oprintf("%i", v->constval.vint);
3256                 break;
3257 #endif
3258             case TYPE_POINTER:
3259                 oprintf("&%s",
3260                     v->constval.vpointer->name);
3261                 break;
3262         }
3263     } else {
3264         oprintf("%s", v->name);
3265     }
3266 }
3267
3268 void ir_value_dump_life(const ir_value *self, int (*oprintf)(const char*,...))
3269 {
3270     size_t i;
3271     oprintf("Life of %12s:", self->name);
3272     for (i = 0; i < vec_size(self->life); ++i)
3273     {
3274         oprintf(" + [%i, %i]\n", self->life[i].start, self->life[i].end);
3275     }
3276 }