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