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