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