]> de.git.xonotic.org Git - xonotic/gmqcc.git/blob - ir.c
fixing a few leaks - code_write doesn't delete the code object anymore, code_cleanup...
[xonotic/gmqcc.git] / ir.c
1 /*
2  * Copyright (C) 2012, 2013
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     "nil",
48     "<no-expression>"
49 };
50
51 static size_t type_sizeof_[TYPE_COUNT] = {
52     1, /* TYPE_VOID     */
53     1, /* TYPE_STRING   */
54     1, /* TYPE_FLOAT    */
55     3, /* TYPE_VECTOR   */
56     1, /* TYPE_ENTITY   */
57     1, /* TYPE_FIELD    */
58     1, /* TYPE_FUNCTION */
59     1, /* TYPE_POINTER  */
60     1, /* TYPE_INTEGER  */
61     3, /* TYPE_VARIANT  */
62     0, /* TYPE_STRUCT   */
63     0, /* TYPE_UNION    */
64     0, /* TYPE_ARRAY    */
65     0, /* TYPE_NIL      */
66     0, /* TYPE_NOESPR   */
67 };
68
69 const uint16_t type_store_instr[TYPE_COUNT] = {
70     INSTR_STORE_F, /* should use I when having integer support */
71     INSTR_STORE_S,
72     INSTR_STORE_F,
73     INSTR_STORE_V,
74     INSTR_STORE_ENT,
75     INSTR_STORE_FLD,
76     INSTR_STORE_FNC,
77     INSTR_STORE_ENT, /* should use I */
78 #if 0
79     INSTR_STORE_I, /* integer type */
80 #else
81     INSTR_STORE_F,
82 #endif
83
84     INSTR_STORE_V, /* variant, should never be accessed */
85
86     VINSTR_END, /* struct */
87     VINSTR_END, /* union  */
88     VINSTR_END, /* array  */
89     VINSTR_END, /* nil    */
90     VINSTR_END, /* noexpr */
91 };
92
93 const uint16_t field_store_instr[TYPE_COUNT] = {
94     INSTR_STORE_FLD,
95     INSTR_STORE_FLD,
96     INSTR_STORE_FLD,
97     INSTR_STORE_V,
98     INSTR_STORE_FLD,
99     INSTR_STORE_FLD,
100     INSTR_STORE_FLD,
101     INSTR_STORE_FLD,
102 #if 0
103     INSTR_STORE_FLD, /* integer type */
104 #else
105     INSTR_STORE_FLD,
106 #endif
107
108     INSTR_STORE_V, /* variant, should never be accessed */
109
110     VINSTR_END, /* struct */
111     VINSTR_END, /* union  */
112     VINSTR_END, /* array  */
113     VINSTR_END, /* nil    */
114     VINSTR_END, /* noexpr */
115 };
116
117 const uint16_t type_storep_instr[TYPE_COUNT] = {
118     INSTR_STOREP_F, /* should use I when having integer support */
119     INSTR_STOREP_S,
120     INSTR_STOREP_F,
121     INSTR_STOREP_V,
122     INSTR_STOREP_ENT,
123     INSTR_STOREP_FLD,
124     INSTR_STOREP_FNC,
125     INSTR_STOREP_ENT, /* should use I */
126 #if 0
127     INSTR_STOREP_ENT, /* integer type */
128 #else
129     INSTR_STOREP_F,
130 #endif
131
132     INSTR_STOREP_V, /* variant, should never be accessed */
133
134     VINSTR_END, /* struct */
135     VINSTR_END, /* union  */
136     VINSTR_END, /* array  */
137     VINSTR_END, /* nil    */
138     VINSTR_END, /* noexpr */
139 };
140
141 const uint16_t type_eq_instr[TYPE_COUNT] = {
142     INSTR_EQ_F, /* should use I when having integer support */
143     INSTR_EQ_S,
144     INSTR_EQ_F,
145     INSTR_EQ_V,
146     INSTR_EQ_E,
147     INSTR_EQ_E, /* FLD has no comparison */
148     INSTR_EQ_FNC,
149     INSTR_EQ_E, /* should use I */
150 #if 0
151     INSTR_EQ_I,
152 #else
153     INSTR_EQ_F,
154 #endif
155
156     INSTR_EQ_V, /* variant, should never be accessed */
157
158     VINSTR_END, /* struct */
159     VINSTR_END, /* union  */
160     VINSTR_END, /* array  */
161     VINSTR_END, /* nil    */
162     VINSTR_END, /* noexpr */
163 };
164
165 const uint16_t type_ne_instr[TYPE_COUNT] = {
166     INSTR_NE_F, /* should use I when having integer support */
167     INSTR_NE_S,
168     INSTR_NE_F,
169     INSTR_NE_V,
170     INSTR_NE_E,
171     INSTR_NE_E, /* FLD has no comparison */
172     INSTR_NE_FNC,
173     INSTR_NE_E, /* should use I */
174 #if 0
175     INSTR_NE_I,
176 #else
177     INSTR_NE_F,
178 #endif
179
180     INSTR_NE_V, /* variant, should never be accessed */
181
182     VINSTR_END, /* struct */
183     VINSTR_END, /* union  */
184     VINSTR_END, /* array  */
185     VINSTR_END, /* nil    */
186     VINSTR_END, /* noexpr */
187 };
188
189 const uint16_t type_not_instr[TYPE_COUNT] = {
190     INSTR_NOT_F, /* should use I when having integer support */
191     VINSTR_END,  /* not to be used, depends on string related -f flags */
192     INSTR_NOT_F,
193     INSTR_NOT_V,
194     INSTR_NOT_ENT,
195     INSTR_NOT_ENT,
196     INSTR_NOT_FNC,
197     INSTR_NOT_ENT, /* should use I */
198 #if 0
199     INSTR_NOT_I, /* integer type */
200 #else
201     INSTR_NOT_F,
202 #endif
203
204     INSTR_NOT_V, /* variant, should never be accessed */
205
206     VINSTR_END, /* struct */
207     VINSTR_END, /* union  */
208     VINSTR_END, /* array  */
209     VINSTR_END, /* nil    */
210     VINSTR_END, /* noexpr */
211 };
212
213 /* protos */
214 static ir_value* ir_gen_extparam_proto(ir_builder *ir);
215 static void      ir_gen_extparam      (code_t *, ir_builder *ir);
216
217 /* error functions */
218
219 static void irerror(lex_ctx ctx, const char *msg, ...)
220 {
221     va_list ap;
222     va_start(ap, msg);
223     con_cvprintmsg((void*)&ctx, LVL_ERROR, "internal error", msg, ap);
224     va_end(ap);
225 }
226
227 static bool irwarning(lex_ctx ctx, int warntype, const char *fmt, ...)
228 {
229     bool    r;
230     va_list ap;
231     va_start(ap, fmt);
232     r = vcompile_warning(ctx, warntype, fmt, ap);
233     va_end(ap);
234     return r;
235 }
236
237 /***********************************************************************
238  * Vector utility functions
239  */
240
241 bool GMQCC_WARN vec_ir_value_find(ir_value **vec, const ir_value *what, size_t *idx)
242 {
243     size_t i;
244     size_t len = vec_size(vec);
245     for (i = 0; i < len; ++i) {
246         if (vec[i] == what) {
247             if (idx) *idx = i;
248             return true;
249         }
250     }
251     return false;
252 }
253
254 bool GMQCC_WARN vec_ir_block_find(ir_block **vec, ir_block *what, size_t *idx)
255 {
256     size_t i;
257     size_t len = vec_size(vec);
258     for (i = 0; i < len; ++i) {
259         if (vec[i] == what) {
260             if (idx) *idx = i;
261             return true;
262         }
263     }
264     return false;
265 }
266
267 bool GMQCC_WARN vec_ir_instr_find(ir_instr **vec, ir_instr *what, size_t *idx)
268 {
269     size_t i;
270     size_t len = vec_size(vec);
271     for (i = 0; i < len; ++i) {
272         if (vec[i] == what) {
273             if (idx) *idx = i;
274             return true;
275         }
276     }
277     return false;
278 }
279
280 /***********************************************************************
281  * IR Builder
282  */
283
284 static void ir_block_delete_quick(ir_block* self);
285 static void ir_instr_delete_quick(ir_instr *self);
286 static void ir_function_delete_quick(ir_function *self);
287
288 ir_builder* ir_builder_new(const char *modulename)
289 {
290     ir_builder* self;
291
292     self = (ir_builder*)mem_a(sizeof(*self));
293     if (!self)
294         return NULL;
295
296     self->functions   = NULL;
297     self->globals     = NULL;
298     self->fields      = NULL;
299     self->filenames   = NULL;
300     self->filestrings = NULL;
301     self->htglobals   = util_htnew(IR_HT_SIZE);
302     self->htfields    = util_htnew(IR_HT_SIZE);
303     self->htfunctions = util_htnew(IR_HT_SIZE);
304
305     self->extparams       = NULL;
306     self->extparam_protos = NULL;
307
308     self->first_common_globaltemp = 0;
309     self->max_globaltemps         = 0;
310     self->first_common_local      = 0;
311     self->max_locals              = 0;
312
313     self->str_immediate = 0;
314     self->name = NULL;
315     if (!ir_builder_set_name(self, modulename)) {
316         mem_d(self);
317         return NULL;
318     }
319
320     self->nil = ir_value_var("nil", store_value, TYPE_NIL);
321     self->nil->cvq = CV_CONST;
322
323     self->reserved_va_count = NULL;
324
325     return self;
326 }
327
328 void ir_builder_delete(ir_builder* self)
329 {
330     size_t i;
331     util_htdel(self->htglobals);
332     util_htdel(self->htfields);
333     util_htdel(self->htfunctions);
334     mem_d((void*)self->name);
335     for (i = 0; i != vec_size(self->functions); ++i) {
336         ir_function_delete_quick(self->functions[i]);
337     }
338     vec_free(self->functions);
339     for (i = 0; i != vec_size(self->extparams); ++i) {
340         ir_value_delete(self->extparams[i]);
341     }
342     vec_free(self->extparams);
343     vec_free(self->extparam_protos);
344     for (i = 0; i != vec_size(self->globals); ++i) {
345         ir_value_delete(self->globals[i]);
346     }
347     vec_free(self->globals);
348     for (i = 0; i != vec_size(self->fields); ++i) {
349         ir_value_delete(self->fields[i]);
350     }
351     ir_value_delete(self->nil);
352     vec_free(self->fields);
353     vec_free(self->filenames);
354     vec_free(self->filestrings);
355     mem_d(self);
356 }
357
358 bool ir_builder_set_name(ir_builder *self, const char *name)
359 {
360     if (self->name)
361         mem_d((void*)self->name);
362     self->name = util_strdup(name);
363     return !!self->name;
364 }
365
366 ir_function* ir_builder_get_function(ir_builder *self, const char *name)
367 {
368     return (ir_function*)util_htget(self->htfunctions, name);
369 }
370
371 ir_function* ir_builder_create_function(ir_builder *self, const char *name, int outtype)
372 {
373     ir_function *fn = ir_builder_get_function(self, name);
374     if (fn) {
375         return NULL;
376     }
377
378     fn = ir_function_new(self, outtype);
379     if (!ir_function_set_name(fn, name))
380     {
381         ir_function_delete(fn);
382         return NULL;
383     }
384     vec_push(self->functions, fn);
385     util_htset(self->htfunctions, name, fn);
386
387     fn->value = ir_builder_create_global(self, fn->name, TYPE_FUNCTION);
388     if (!fn->value) {
389         ir_function_delete(fn);
390         return NULL;
391     }
392
393     fn->value->hasvalue = true;
394     fn->value->outtype = outtype;
395     fn->value->constval.vfunc = fn;
396     fn->value->context = fn->context;
397
398     return fn;
399 }
400
401 ir_value* ir_builder_get_global(ir_builder *self, const char *name)
402 {
403     return (ir_value*)util_htget(self->htglobals, name);
404 }
405
406 ir_value* ir_builder_create_global(ir_builder *self, const char *name, int vtype)
407 {
408     ir_value *ve;
409
410     if (name && name[0] != '#')
411     {
412         ve = ir_builder_get_global(self, name);
413         if (ve) {
414             return NULL;
415         }
416     }
417
418     ve = ir_value_var(name, store_global, vtype);
419     vec_push(self->globals, ve);
420     util_htset(self->htglobals, name, ve);
421     return ve;
422 }
423
424 ir_value* ir_builder_get_va_count(ir_builder *self)
425 {
426     if (self->reserved_va_count)
427         return self->reserved_va_count;
428     return (self->reserved_va_count = ir_builder_create_global(self, "reserved:va_count", TYPE_FLOAT));
429 }
430
431 ir_value* ir_builder_get_field(ir_builder *self, const char *name)
432 {
433     return (ir_value*)util_htget(self->htfields, name);
434 }
435
436
437 ir_value* ir_builder_create_field(ir_builder *self, const char *name, int vtype)
438 {
439     ir_value *ve = ir_builder_get_field(self, name);
440     if (ve) {
441         return NULL;
442     }
443
444     ve = ir_value_var(name, store_global, TYPE_FIELD);
445     ve->fieldtype = vtype;
446     vec_push(self->fields, ve);
447     util_htset(self->htfields, name, ve);
448     return ve;
449 }
450
451 /***********************************************************************
452  *IR Function
453  */
454
455 bool ir_function_naive_phi(ir_function*);
456 void ir_function_enumerate(ir_function*);
457 bool ir_function_calculate_liferanges(ir_function*);
458 bool ir_function_allocate_locals(ir_function*);
459
460 ir_function* ir_function_new(ir_builder* owner, int outtype)
461 {
462     ir_function *self;
463     self = (ir_function*)mem_a(sizeof(*self));
464
465     if (!self)
466         return NULL;
467
468     memset(self, 0, sizeof(*self));
469
470     self->name = NULL;
471     if (!ir_function_set_name(self, "<@unnamed>")) {
472         mem_d(self);
473         return NULL;
474     }
475     self->flags = 0;
476
477     self->owner = owner;
478     self->context.file = "<@no context>";
479     self->context.line = 0;
480     self->outtype = outtype;
481     self->value = NULL;
482     self->builtin = 0;
483
484     self->params = NULL;
485     self->blocks = NULL;
486     self->values = NULL;
487     self->locals = NULL;
488
489     self->max_varargs = 0;
490
491     self->code_function_def = -1;
492     self->allocated_locals = 0;
493     self->globaltemps      = 0;
494
495     self->run_id = 0;
496     return self;
497 }
498
499 bool ir_function_set_name(ir_function *self, const char *name)
500 {
501     if (self->name)
502         mem_d((void*)self->name);
503     self->name = util_strdup(name);
504     return !!self->name;
505 }
506
507 static void ir_function_delete_quick(ir_function *self)
508 {
509     size_t i;
510     mem_d((void*)self->name);
511
512     for (i = 0; i != vec_size(self->blocks); ++i)
513         ir_block_delete_quick(self->blocks[i]);
514     vec_free(self->blocks);
515
516     vec_free(self->params);
517
518     for (i = 0; i != vec_size(self->values); ++i)
519         ir_value_delete(self->values[i]);
520     vec_free(self->values);
521
522     for (i = 0; i != vec_size(self->locals); ++i)
523         ir_value_delete(self->locals[i]);
524     vec_free(self->locals);
525
526     /* self->value is deleted by the builder */
527
528     mem_d(self);
529 }
530
531 void ir_function_delete(ir_function *self)
532 {
533     size_t i;
534     mem_d((void*)self->name);
535
536     for (i = 0; i != vec_size(self->blocks); ++i)
537         ir_block_delete(self->blocks[i]);
538     vec_free(self->blocks);
539
540     vec_free(self->params);
541
542     for (i = 0; i != vec_size(self->values); ++i)
543         ir_value_delete(self->values[i]);
544     vec_free(self->values);
545
546     for (i = 0; i != vec_size(self->locals); ++i)
547         ir_value_delete(self->locals[i]);
548     vec_free(self->locals);
549
550     /* self->value is deleted by the builder */
551
552     mem_d(self);
553 }
554
555 void ir_function_collect_value(ir_function *self, ir_value *v)
556 {
557     vec_push(self->values, v);
558 }
559
560 ir_block* ir_function_create_block(lex_ctx ctx, ir_function *self, const char *label)
561 {
562     ir_block* bn = ir_block_new(self, label);
563     bn->context = ctx;
564     vec_push(self->blocks, bn);
565     return bn;
566 }
567
568 static bool instr_is_operation(uint16_t op)
569 {
570     return ( (op >= INSTR_MUL_F  && op <= INSTR_GT) ||
571              (op >= INSTR_LOAD_F && op <= INSTR_LOAD_FNC) ||
572              (op == INSTR_ADDRESS) ||
573              (op >= INSTR_NOT_F  && op <= INSTR_NOT_FNC) ||
574              (op >= INSTR_AND    && op <= INSTR_BITOR) ||
575              (op >= INSTR_CALL0  && op <= INSTR_CALL8) );
576 }
577
578 bool ir_function_pass_peephole(ir_function *self)
579 {
580     size_t b;
581
582     for (b = 0; b < vec_size(self->blocks); ++b) {
583         size_t    i;
584         ir_block *block = self->blocks[b];
585
586         for (i = 0; i < vec_size(block->instr); ++i) {
587             ir_instr *inst;
588             inst = block->instr[i];
589
590             if (i >= 1 &&
591                 (inst->opcode >= INSTR_STORE_F &&
592                  inst->opcode <= INSTR_STORE_FNC))
593             {
594                 ir_instr *store;
595                 ir_instr *oper;
596                 ir_value *value;
597
598                 store = inst;
599
600                 oper  = block->instr[i-1];
601                 if (!instr_is_operation(oper->opcode))
602                     continue;
603
604                 if (OPTS_FLAG(LEGACY_VECTOR_MATHS)) {
605                     if (oper->opcode == INSTR_MUL_VF && oper->_ops[2]->memberof == oper->_ops[1])
606                         continue;
607                     if (oper->opcode == INSTR_MUL_FV && oper->_ops[1]->memberof == oper->_ops[2])
608                         continue;
609                 }
610
611                 value = oper->_ops[0];
612
613                 /* only do it for SSA values */
614                 if (value->store != store_value)
615                     continue;
616
617                 /* don't optimize out the temp if it's used later again */
618                 if (vec_size(value->reads) != 1)
619                     continue;
620
621                 /* The very next store must use this value */
622                 if (value->reads[0] != store)
623                     continue;
624
625                 /* And of course the store must _read_ from it, so it's in
626                  * OP 1 */
627                 if (store->_ops[1] != value)
628                     continue;
629
630                 ++opts_optimizationcount[OPTIM_PEEPHOLE];
631                 (void)!ir_instr_op(oper, 0, store->_ops[0], true);
632
633                 vec_remove(block->instr, i, 1);
634                 ir_instr_delete(store);
635             }
636             else if (inst->opcode == VINSTR_COND)
637             {
638                 /* COND on a value resulting from a NOT could
639                  * remove the NOT and swap its operands
640                  */
641                 while (true) {
642                     ir_block *tmp;
643                     size_t    inotid;
644                     ir_instr *inot;
645                     ir_value *value;
646                     value = inst->_ops[0];
647
648                     if (value->store != store_value ||
649                         vec_size(value->reads) != 1 ||
650                         value->reads[0] != inst)
651                     {
652                         break;
653                     }
654
655                     inot = value->writes[0];
656                     if (inot->_ops[0] != value ||
657                         inot->opcode < INSTR_NOT_F ||
658                         inot->opcode > INSTR_NOT_FNC ||
659                         inot->opcode == INSTR_NOT_V || /* can't do these */
660                         inot->opcode == INSTR_NOT_S)
661                     {
662                         break;
663                     }
664
665                     /* count */
666                     ++opts_optimizationcount[OPTIM_PEEPHOLE];
667                     /* change operand */
668                     (void)!ir_instr_op(inst, 0, inot->_ops[1], false);
669                     /* remove NOT */
670                     tmp = inot->owner;
671                     for (inotid = 0; inotid < vec_size(tmp->instr); ++inotid) {
672                         if (tmp->instr[inotid] == inot)
673                             break;
674                     }
675                     if (inotid >= vec_size(tmp->instr)) {
676                         compile_error(inst->context, "sanity-check failed: failed to find instruction to optimize out");
677                         return false;
678                     }
679                     vec_remove(tmp->instr, inotid, 1);
680                     ir_instr_delete(inot);
681                     /* swap ontrue/onfalse */
682                     tmp = inst->bops[0];
683                     inst->bops[0] = inst->bops[1];
684                     inst->bops[1] = tmp;
685                 }
686                 continue;
687             }
688         }
689     }
690
691     return true;
692 }
693
694 bool ir_function_pass_tailrecursion(ir_function *self)
695 {
696     size_t b, p;
697
698     for (b = 0; b < vec_size(self->blocks); ++b) {
699         ir_value *funcval;
700         ir_instr *ret, *call, *store = NULL;
701         ir_block *block = self->blocks[b];
702
703         if (!block->final || vec_size(block->instr) < 2)
704             continue;
705
706         ret = block->instr[vec_size(block->instr)-1];
707         if (ret->opcode != INSTR_DONE && ret->opcode != INSTR_RETURN)
708             continue;
709
710         call = block->instr[vec_size(block->instr)-2];
711         if (call->opcode >= INSTR_STORE_F && call->opcode <= INSTR_STORE_FNC) {
712             /* account for the unoptimized
713              * CALL
714              * STORE %return, %tmp
715              * RETURN %tmp
716              * version
717              */
718             if (vec_size(block->instr) < 3)
719                 continue;
720
721             store = call;
722             call = block->instr[vec_size(block->instr)-3];
723         }
724
725         if (call->opcode < INSTR_CALL0 || call->opcode > INSTR_CALL8)
726             continue;
727
728         if (store) {
729             /* optimize out the STORE */
730             if (ret->_ops[0]   &&
731                 ret->_ops[0]   == store->_ops[0] &&
732                 store->_ops[1] == call->_ops[0])
733             {
734                 ++opts_optimizationcount[OPTIM_PEEPHOLE];
735                 call->_ops[0] = store->_ops[0];
736                 vec_remove(block->instr, vec_size(block->instr) - 2, 1);
737                 ir_instr_delete(store);
738             }
739             else
740                 continue;
741         }
742
743         if (!call->_ops[0])
744             continue;
745
746         funcval = call->_ops[1];
747         if (!funcval)
748             continue;
749         if (funcval->vtype != TYPE_FUNCTION || funcval->constval.vfunc != self)
750             continue;
751
752         /* now we have a CALL and a RET, check if it's a tailcall */
753         if (ret->_ops[0] && call->_ops[0] != ret->_ops[0])
754             continue;
755
756         ++opts_optimizationcount[OPTIM_TAIL_RECURSION];
757         vec_shrinkby(block->instr, 2);
758
759         block->final = false; /* open it back up */
760
761         /* emite parameter-stores */
762         for (p = 0; p < vec_size(call->params); ++p) {
763             /* assert(call->params_count <= self->locals_count); */
764             if (!ir_block_create_store(block, call->context, self->locals[p], call->params[p])) {
765                 irerror(call->context, "failed to create tailcall store instruction for parameter %i", (int)p);
766                 return false;
767             }
768         }
769         if (!ir_block_create_jump(block, call->context, self->blocks[0])) {
770             irerror(call->context, "failed to create tailcall jump");
771             return false;
772         }
773
774         ir_instr_delete(call);
775         ir_instr_delete(ret);
776     }
777
778     return true;
779 }
780
781 bool ir_function_finalize(ir_function *self)
782 {
783     size_t i;
784
785     if (self->builtin)
786         return true;
787
788     if (OPTS_OPTIMIZATION(OPTIM_PEEPHOLE)) {
789         if (!ir_function_pass_peephole(self)) {
790             irerror(self->context, "generic optimization pass broke something in `%s`", self->name);
791             return false;
792         }
793     }
794
795     if (OPTS_OPTIMIZATION(OPTIM_TAIL_RECURSION)) {
796         if (!ir_function_pass_tailrecursion(self)) {
797             irerror(self->context, "tail-recursion optimization pass broke something in `%s`", self->name);
798             return false;
799         }
800     }
801
802     if (!ir_function_naive_phi(self)) {
803         irerror(self->context, "internal error: ir_function_naive_phi failed");
804         return false;
805     }
806
807     for (i = 0; i < vec_size(self->locals); ++i) {
808         ir_value *v = self->locals[i];
809         if (v->vtype == TYPE_VECTOR ||
810             (v->vtype == TYPE_FIELD && v->outtype == TYPE_VECTOR))
811         {
812             ir_value_vector_member(v, 0);
813             ir_value_vector_member(v, 1);
814             ir_value_vector_member(v, 2);
815         }
816     }
817     for (i = 0; i < vec_size(self->values); ++i) {
818         ir_value *v = self->values[i];
819         if (v->vtype == TYPE_VECTOR ||
820             (v->vtype == TYPE_FIELD && v->outtype == TYPE_VECTOR))
821         {
822             ir_value_vector_member(v, 0);
823             ir_value_vector_member(v, 1);
824             ir_value_vector_member(v, 2);
825         }
826     }
827
828     ir_function_enumerate(self);
829
830     if (!ir_function_calculate_liferanges(self))
831         return false;
832     if (!ir_function_allocate_locals(self))
833         return false;
834     return true;
835 }
836
837 ir_value* ir_function_create_local(ir_function *self, const char *name, int vtype, bool param)
838 {
839     ir_value *ve;
840
841     if (param &&
842         vec_size(self->locals) &&
843         self->locals[vec_size(self->locals)-1]->store != store_param) {
844         irerror(self->context, "cannot add parameters after adding locals");
845         return NULL;
846     }
847
848     ve = ir_value_var(name, (param ? store_param : store_local), vtype);
849     if (param)
850         ve->locked = true;
851     vec_push(self->locals, ve);
852     return ve;
853 }
854
855 /***********************************************************************
856  *IR Block
857  */
858
859 ir_block* ir_block_new(ir_function* owner, const char *name)
860 {
861     ir_block *self;
862     self = (ir_block*)mem_a(sizeof(*self));
863     if (!self)
864         return NULL;
865
866     memset(self, 0, sizeof(*self));
867
868     self->label = NULL;
869     if (name && !ir_block_set_label(self, name)) {
870         mem_d(self);
871         return NULL;
872     }
873     self->owner = owner;
874     self->context.file = "<@no context>";
875     self->context.line = 0;
876     self->final = false;
877
878     self->instr   = NULL;
879     self->entries = NULL;
880     self->exits   = NULL;
881
882     self->eid = 0;
883     self->is_return = false;
884
885     self->living = NULL;
886
887     self->generated = false;
888
889     return self;
890 }
891
892 static void ir_block_delete_quick(ir_block* self)
893 {
894     size_t i;
895     if (self->label) mem_d(self->label);
896     for (i = 0; i != vec_size(self->instr); ++i)
897         ir_instr_delete_quick(self->instr[i]);
898     vec_free(self->instr);
899     vec_free(self->entries);
900     vec_free(self->exits);
901     vec_free(self->living);
902     mem_d(self);
903 }
904
905 void ir_block_delete(ir_block* self)
906 {
907     size_t i;
908     if (self->label) mem_d(self->label);
909     for (i = 0; i != vec_size(self->instr); ++i)
910         ir_instr_delete(self->instr[i]);
911     vec_free(self->instr);
912     vec_free(self->entries);
913     vec_free(self->exits);
914     vec_free(self->living);
915     mem_d(self);
916 }
917
918 bool ir_block_set_label(ir_block *self, const char *name)
919 {
920     if (self->label)
921         mem_d((void*)self->label);
922     self->label = util_strdup(name);
923     return !!self->label;
924 }
925
926 /***********************************************************************
927  *IR Instructions
928  */
929
930 ir_instr* ir_instr_new(lex_ctx ctx, ir_block* owner, int op)
931 {
932     ir_instr *self;
933     self = (ir_instr*)mem_a(sizeof(*self));
934     if (!self)
935         return NULL;
936
937     self->owner = owner;
938     self->context = ctx;
939     self->opcode = op;
940     self->_ops[0] = NULL;
941     self->_ops[1] = NULL;
942     self->_ops[2] = NULL;
943     self->bops[0] = NULL;
944     self->bops[1] = NULL;
945
946     self->phi    = NULL;
947     self->params = NULL;
948
949     self->eid = 0;
950
951     self->likely = true;
952     return self;
953 }
954
955 static void ir_instr_delete_quick(ir_instr *self)
956 {
957     vec_free(self->phi);
958     vec_free(self->params);
959     mem_d(self);
960 }
961
962 void ir_instr_delete(ir_instr *self)
963 {
964     size_t i;
965     /* The following calls can only delete from
966      * vectors, we still want to delete this instruction
967      * so ignore the return value. Since with the warn_unused_result attribute
968      * gcc doesn't care about an explicit: (void)foo(); to ignore the result,
969      * I have to improvise here and use if(foo());
970      */
971     for (i = 0; i < vec_size(self->phi); ++i) {
972         size_t idx;
973         if (vec_ir_instr_find(self->phi[i].value->writes, self, &idx))
974             vec_remove(self->phi[i].value->writes, idx, 1);
975         if (vec_ir_instr_find(self->phi[i].value->reads, self, &idx))
976             vec_remove(self->phi[i].value->reads, idx, 1);
977     }
978     vec_free(self->phi);
979     for (i = 0; i < vec_size(self->params); ++i) {
980         size_t idx;
981         if (vec_ir_instr_find(self->params[i]->writes, self, &idx))
982             vec_remove(self->params[i]->writes, idx, 1);
983         if (vec_ir_instr_find(self->params[i]->reads, self, &idx))
984             vec_remove(self->params[i]->reads, idx, 1);
985     }
986     vec_free(self->params);
987     (void)!ir_instr_op(self, 0, NULL, false);
988     (void)!ir_instr_op(self, 1, NULL, false);
989     (void)!ir_instr_op(self, 2, NULL, false);
990     mem_d(self);
991 }
992
993 bool ir_instr_op(ir_instr *self, int op, ir_value *v, bool writing)
994 {
995     if (self->_ops[op]) {
996         size_t idx;
997         if (writing && vec_ir_instr_find(self->_ops[op]->writes, self, &idx))
998             vec_remove(self->_ops[op]->writes, idx, 1);
999         else if (vec_ir_instr_find(self->_ops[op]->reads, self, &idx))
1000             vec_remove(self->_ops[op]->reads, idx, 1);
1001     }
1002     if (v) {
1003         if (writing)
1004             vec_push(v->writes, self);
1005         else
1006             vec_push(v->reads, self);
1007     }
1008     self->_ops[op] = v;
1009     return true;
1010 }
1011
1012 /***********************************************************************
1013  *IR Value
1014  */
1015
1016 void ir_value_code_setaddr(ir_value *self, int32_t gaddr)
1017 {
1018     self->code.globaladdr = gaddr;
1019     if (self->members[0]) self->members[0]->code.globaladdr = gaddr;
1020     if (self->members[1]) self->members[1]->code.globaladdr = gaddr;
1021     if (self->members[2]) self->members[2]->code.globaladdr = gaddr;
1022 }
1023
1024 int32_t ir_value_code_addr(const ir_value *self)
1025 {
1026     if (self->store == store_return)
1027         return OFS_RETURN + self->code.addroffset;
1028     return self->code.globaladdr + self->code.addroffset;
1029 }
1030
1031 ir_value* ir_value_var(const char *name, int storetype, int vtype)
1032 {
1033     ir_value *self;
1034     self = (ir_value*)mem_a(sizeof(*self));
1035     self->vtype = vtype;
1036     self->fieldtype = TYPE_VOID;
1037     self->outtype = TYPE_VOID;
1038     self->store = storetype;
1039     self->flags = 0;
1040
1041     self->reads  = NULL;
1042     self->writes = NULL;
1043
1044     self->cvq          = CV_NONE;
1045     self->hasvalue     = false;
1046     self->context.file = "<@no context>";
1047     self->context.line = 0;
1048     self->name = NULL;
1049     if (name && !ir_value_set_name(self, name)) {
1050         irerror(self->context, "out of memory");
1051         mem_d(self);
1052         return NULL;
1053     }
1054
1055     memset(&self->constval, 0, sizeof(self->constval));
1056     memset(&self->code,     0, sizeof(self->code));
1057
1058     self->members[0] = NULL;
1059     self->members[1] = NULL;
1060     self->members[2] = NULL;
1061     self->memberof = NULL;
1062
1063     self->unique_life = false;
1064     self->locked      = false;
1065     self->callparam   = false;
1066
1067     self->life = NULL;
1068     return self;
1069 }
1070
1071 ir_value* ir_value_vector_member(ir_value *self, unsigned int member)
1072 {
1073     char     *name;
1074     size_t    len;
1075     ir_value *m;
1076     if (member >= 3)
1077         return NULL;
1078
1079     if (self->members[member])
1080         return self->members[member];
1081
1082     if (self->name) {
1083         len = strlen(self->name);
1084         name = (char*)mem_a(len + 3);
1085         memcpy(name, self->name, len);
1086         name[len+0] = '_';
1087         name[len+1] = 'x' + member;
1088         name[len+2] = '\0';
1089     }
1090     else
1091         name = NULL;
1092
1093     if (self->vtype == TYPE_VECTOR)
1094     {
1095         m = ir_value_var(name, self->store, TYPE_FLOAT);
1096         if (name)
1097             mem_d(name);
1098         if (!m)
1099             return NULL;
1100         m->context = self->context;
1101
1102         self->members[member] = m;
1103         m->code.addroffset = member;
1104     }
1105     else if (self->vtype == TYPE_FIELD)
1106     {
1107         if (self->fieldtype != TYPE_VECTOR)
1108             return NULL;
1109         m = ir_value_var(name, self->store, TYPE_FIELD);
1110         if (name)
1111             mem_d(name);
1112         if (!m)
1113             return NULL;
1114         m->fieldtype = TYPE_FLOAT;
1115         m->context = self->context;
1116
1117         self->members[member] = m;
1118         m->code.addroffset = member;
1119     }
1120     else
1121     {
1122         irerror(self->context, "invalid member access on %s", self->name);
1123         return NULL;
1124     }
1125
1126     m->memberof = self;
1127     return m;
1128 }
1129
1130 static GMQCC_INLINE size_t ir_value_sizeof(const ir_value *self)
1131 {
1132     if (self->vtype == TYPE_FIELD && self->fieldtype == TYPE_VECTOR)
1133         return type_sizeof_[TYPE_VECTOR];
1134     return type_sizeof_[self->vtype];
1135 }
1136
1137 ir_value* ir_value_out(ir_function *owner, const char *name, int storetype, int vtype)
1138 {
1139     ir_value *v = ir_value_var(name, storetype, vtype);
1140     if (!v)
1141         return NULL;
1142     ir_function_collect_value(owner, v);
1143     return v;
1144 }
1145
1146 void ir_value_delete(ir_value* self)
1147 {
1148     size_t i;
1149     if (self->name)
1150         mem_d((void*)self->name);
1151     if (self->hasvalue)
1152     {
1153         if (self->vtype == TYPE_STRING)
1154             mem_d((void*)self->constval.vstring);
1155     }
1156     for (i = 0; i < 3; ++i) {
1157         if (self->members[i])
1158             ir_value_delete(self->members[i]);
1159     }
1160     vec_free(self->reads);
1161     vec_free(self->writes);
1162     vec_free(self->life);
1163     mem_d(self);
1164 }
1165
1166 bool ir_value_set_name(ir_value *self, const char *name)
1167 {
1168     if (self->name)
1169         mem_d((void*)self->name);
1170     self->name = util_strdup(name);
1171     return !!self->name;
1172 }
1173
1174 bool ir_value_set_float(ir_value *self, float f)
1175 {
1176     if (self->vtype != TYPE_FLOAT)
1177         return false;
1178     self->constval.vfloat = f;
1179     self->hasvalue = true;
1180     return true;
1181 }
1182
1183 bool ir_value_set_func(ir_value *self, int f)
1184 {
1185     if (self->vtype != TYPE_FUNCTION)
1186         return false;
1187     self->constval.vint = f;
1188     self->hasvalue = true;
1189     return true;
1190 }
1191
1192 bool ir_value_set_vector(ir_value *self, vector v)
1193 {
1194     if (self->vtype != TYPE_VECTOR)
1195         return false;
1196     self->constval.vvec = v;
1197     self->hasvalue = true;
1198     return true;
1199 }
1200
1201 bool ir_value_set_field(ir_value *self, ir_value *fld)
1202 {
1203     if (self->vtype != TYPE_FIELD)
1204         return false;
1205     self->constval.vpointer = fld;
1206     self->hasvalue = true;
1207     return true;
1208 }
1209
1210 bool ir_value_set_string(ir_value *self, const char *str)
1211 {
1212     if (self->vtype != TYPE_STRING)
1213         return false;
1214     self->constval.vstring = util_strdupe(str);
1215     self->hasvalue = true;
1216     return true;
1217 }
1218
1219 #if 0
1220 bool ir_value_set_int(ir_value *self, int i)
1221 {
1222     if (self->vtype != TYPE_INTEGER)
1223         return false;
1224     self->constval.vint = i;
1225     self->hasvalue = true;
1226     return true;
1227 }
1228 #endif
1229
1230 bool ir_value_lives(ir_value *self, size_t at)
1231 {
1232     size_t i;
1233     for (i = 0; i < vec_size(self->life); ++i)
1234     {
1235         ir_life_entry_t *life = &self->life[i];
1236         if (life->start <= at && at <= life->end)
1237             return true;
1238         if (life->start > at) /* since it's ordered */
1239             return false;
1240     }
1241     return false;
1242 }
1243
1244 bool ir_value_life_insert(ir_value *self, size_t idx, ir_life_entry_t e)
1245 {
1246     size_t k;
1247     vec_push(self->life, e);
1248     for (k = vec_size(self->life)-1; k > idx; --k)
1249         self->life[k] = self->life[k-1];
1250     self->life[idx] = e;
1251     return true;
1252 }
1253
1254 bool ir_value_life_merge(ir_value *self, size_t s)
1255 {
1256     size_t i;
1257     const size_t vs = vec_size(self->life);
1258     ir_life_entry_t *life = NULL;
1259     ir_life_entry_t *before = NULL;
1260     ir_life_entry_t new_entry;
1261
1262     /* Find the first range >= s */
1263     for (i = 0; i < vs; ++i)
1264     {
1265         before = life;
1266         life = &self->life[i];
1267         if (life->start > s)
1268             break;
1269     }
1270     /* nothing found? append */
1271     if (i == vs) {
1272         ir_life_entry_t e;
1273         if (life && life->end+1 == s)
1274         {
1275             /* previous life range can be merged in */
1276             life->end++;
1277             return true;
1278         }
1279         if (life && life->end >= s)
1280             return false;
1281         e.start = e.end = s;
1282         vec_push(self->life, e);
1283         return true;
1284     }
1285     /* found */
1286     if (before)
1287     {
1288         if (before->end + 1 == s &&
1289             life->start - 1 == s)
1290         {
1291             /* merge */
1292             before->end = life->end;
1293             vec_remove(self->life, i, 1);
1294             return true;
1295         }
1296         if (before->end + 1 == s)
1297         {
1298             /* extend before */
1299             before->end++;
1300             return true;
1301         }
1302         /* already contained */
1303         if (before->end >= s)
1304             return false;
1305     }
1306     /* extend */
1307     if (life->start - 1 == s)
1308     {
1309         life->start--;
1310         return true;
1311     }
1312     /* insert a new entry */
1313     new_entry.start = new_entry.end = s;
1314     return ir_value_life_insert(self, i, new_entry);
1315 }
1316
1317 bool ir_value_life_merge_into(ir_value *self, const ir_value *other)
1318 {
1319     size_t i, myi;
1320
1321     if (!vec_size(other->life))
1322         return true;
1323
1324     if (!vec_size(self->life)) {
1325         size_t count = vec_size(other->life);
1326         ir_life_entry_t *life = vec_add(self->life, count);
1327         memcpy(life, other->life, count * sizeof(*life));
1328         return true;
1329     }
1330
1331     myi = 0;
1332     for (i = 0; i < vec_size(other->life); ++i)
1333     {
1334         const ir_life_entry_t *life = &other->life[i];
1335         while (true)
1336         {
1337             ir_life_entry_t *entry = &self->life[myi];
1338
1339             if (life->end+1 < entry->start)
1340             {
1341                 /* adding an interval before entry */
1342                 if (!ir_value_life_insert(self, myi, *life))
1343                     return false;
1344                 ++myi;
1345                 break;
1346             }
1347
1348             if (life->start <  entry->start &&
1349                 life->end+1 >= entry->start)
1350             {
1351                 /* starts earlier and overlaps */
1352                 entry->start = life->start;
1353             }
1354
1355             if (life->end   >  entry->end &&
1356                 life->start <= entry->end+1)
1357             {
1358                 /* ends later and overlaps */
1359                 entry->end = life->end;
1360             }
1361
1362             /* see if our change combines it with the next ranges */
1363             while (myi+1 < vec_size(self->life) &&
1364                    entry->end+1 >= self->life[1+myi].start)
1365             {
1366                 /* overlaps with (myi+1) */
1367                 if (entry->end < self->life[1+myi].end)
1368                     entry->end = self->life[1+myi].end;
1369                 vec_remove(self->life, myi+1, 1);
1370                 entry = &self->life[myi];
1371             }
1372
1373             /* see if we're after the entry */
1374             if (life->start > entry->end)
1375             {
1376                 ++myi;
1377                 /* append if we're at the end */
1378                 if (myi >= vec_size(self->life)) {
1379                     vec_push(self->life, *life);
1380                     break;
1381                 }
1382                 /* otherweise check the next range */
1383                 continue;
1384             }
1385             break;
1386         }
1387     }
1388     return true;
1389 }
1390
1391 bool ir_values_overlap(const ir_value *a, const ir_value *b)
1392 {
1393     /* For any life entry in A see if it overlaps with
1394      * any life entry in B.
1395      * Note that the life entries are orderes, so we can make a
1396      * more efficient algorithm there than naively translating the
1397      * statement above.
1398      */
1399
1400     ir_life_entry_t *la, *lb, *enda, *endb;
1401
1402     /* first of all, if either has no life range, they cannot clash */
1403     if (!vec_size(a->life) || !vec_size(b->life))
1404         return false;
1405
1406     la = a->life;
1407     lb = b->life;
1408     enda = la + vec_size(a->life);
1409     endb = lb + vec_size(b->life);
1410     while (true)
1411     {
1412         /* check if the entries overlap, for that,
1413          * both must start before the other one ends.
1414          */
1415         if (la->start < lb->end &&
1416             lb->start < la->end)
1417         {
1418             return true;
1419         }
1420
1421         /* entries are ordered
1422          * one entry is earlier than the other
1423          * that earlier entry will be moved forward
1424          */
1425         if (la->start < lb->start)
1426         {
1427             /* order: A B, move A forward
1428              * check if we hit the end with A
1429              */
1430             if (++la == enda)
1431                 break;
1432         }
1433         else /* if (lb->start < la->start)  actually <= */
1434         {
1435             /* order: B A, move B forward
1436              * check if we hit the end with B
1437              */
1438             if (++lb == endb)
1439                 break;
1440         }
1441     }
1442     return false;
1443 }
1444
1445 /***********************************************************************
1446  *IR main operations
1447  */
1448
1449 static bool ir_check_unreachable(ir_block *self)
1450 {
1451     /* The IR should never have to deal with unreachable code */
1452     if (!self->final/* || OPTS_FLAG(ALLOW_UNREACHABLE_CODE)*/)
1453         return true;
1454     irerror(self->context, "unreachable statement (%s)", self->label);
1455     return false;
1456 }
1457
1458 bool ir_block_create_store_op(ir_block *self, lex_ctx ctx, int op, ir_value *target, ir_value *what)
1459 {
1460     ir_instr *in;
1461     if (!ir_check_unreachable(self))
1462         return false;
1463
1464     if (target->store == store_value &&
1465         (op < INSTR_STOREP_F || op > INSTR_STOREP_FNC))
1466     {
1467         irerror(self->context, "cannot store to an SSA value");
1468         irerror(self->context, "trying to store: %s <- %s", target->name, what->name);
1469         irerror(self->context, "instruction: %s", asm_instr[op].m);
1470         return false;
1471     }
1472
1473     in = ir_instr_new(ctx, self, op);
1474     if (!in)
1475         return false;
1476
1477     if (!ir_instr_op(in, 0, target, (op < INSTR_STOREP_F || op > INSTR_STOREP_FNC)) ||
1478         !ir_instr_op(in, 1, what, false))
1479     {
1480         ir_instr_delete(in);
1481         return false;
1482     }
1483     vec_push(self->instr, in);
1484     return true;
1485 }
1486
1487 bool ir_block_create_store(ir_block *self, lex_ctx ctx, ir_value *target, ir_value *what)
1488 {
1489     int op = 0;
1490     int vtype;
1491     if (target->vtype == TYPE_VARIANT)
1492         vtype = what->vtype;
1493     else
1494         vtype = target->vtype;
1495
1496 #if 0
1497     if      (vtype == TYPE_FLOAT   && what->vtype == TYPE_INTEGER)
1498         op = INSTR_CONV_ITOF;
1499     else if (vtype == TYPE_INTEGER && what->vtype == TYPE_FLOAT)
1500         op = INSTR_CONV_FTOI;
1501 #endif
1502         op = type_store_instr[vtype];
1503
1504     if (OPTS_FLAG(ADJUST_VECTOR_FIELDS)) {
1505         if (op == INSTR_STORE_FLD && what->fieldtype == TYPE_VECTOR)
1506             op = INSTR_STORE_V;
1507     }
1508
1509     return ir_block_create_store_op(self, ctx, op, target, what);
1510 }
1511
1512 bool ir_block_create_storep(ir_block *self, lex_ctx ctx, ir_value *target, ir_value *what)
1513 {
1514     int op = 0;
1515     int vtype;
1516
1517     if (target->vtype != TYPE_POINTER)
1518         return false;
1519
1520     /* storing using pointer - target is a pointer, type must be
1521      * inferred from source
1522      */
1523     vtype = what->vtype;
1524
1525     op = type_storep_instr[vtype];
1526     if (OPTS_FLAG(ADJUST_VECTOR_FIELDS)) {
1527         if (op == INSTR_STOREP_FLD && what->fieldtype == TYPE_VECTOR)
1528             op = INSTR_STOREP_V;
1529     }
1530
1531     return ir_block_create_store_op(self, ctx, op, target, what);
1532 }
1533
1534 bool ir_block_create_return(ir_block *self, lex_ctx ctx, ir_value *v)
1535 {
1536     ir_instr *in;
1537     if (!ir_check_unreachable(self))
1538         return false;
1539     self->final = true;
1540     self->is_return = true;
1541     in = ir_instr_new(ctx, self, INSTR_RETURN);
1542     if (!in)
1543         return false;
1544
1545     if (v && !ir_instr_op(in, 0, v, false)) {
1546         ir_instr_delete(in);
1547         return false;
1548     }
1549
1550     vec_push(self->instr, in);
1551     return true;
1552 }
1553
1554 bool ir_block_create_if(ir_block *self, lex_ctx ctx, ir_value *v,
1555                         ir_block *ontrue, ir_block *onfalse)
1556 {
1557     ir_instr *in;
1558     if (!ir_check_unreachable(self))
1559         return false;
1560     self->final = true;
1561     /*in = ir_instr_new(ctx, self, (v->vtype == TYPE_STRING ? INSTR_IF_S : INSTR_IF_F));*/
1562     in = ir_instr_new(ctx, self, VINSTR_COND);
1563     if (!in)
1564         return false;
1565
1566     if (!ir_instr_op(in, 0, v, false)) {
1567         ir_instr_delete(in);
1568         return false;
1569     }
1570
1571     in->bops[0] = ontrue;
1572     in->bops[1] = onfalse;
1573
1574     vec_push(self->instr, in);
1575
1576     vec_push(self->exits, ontrue);
1577     vec_push(self->exits, onfalse);
1578     vec_push(ontrue->entries,  self);
1579     vec_push(onfalse->entries, self);
1580     return true;
1581 }
1582
1583 bool ir_block_create_jump(ir_block *self, lex_ctx ctx, ir_block *to)
1584 {
1585     ir_instr *in;
1586     if (!ir_check_unreachable(self))
1587         return false;
1588     self->final = true;
1589     in = ir_instr_new(ctx, self, VINSTR_JUMP);
1590     if (!in)
1591         return false;
1592
1593     in->bops[0] = to;
1594     vec_push(self->instr, in);
1595
1596     vec_push(self->exits, to);
1597     vec_push(to->entries, self);
1598     return true;
1599 }
1600
1601 bool ir_block_create_goto(ir_block *self, lex_ctx ctx, ir_block *to)
1602 {
1603     self->owner->flags |= IR_FLAG_HAS_GOTO;
1604     return ir_block_create_jump(self, ctx, to);
1605 }
1606
1607 ir_instr* ir_block_create_phi(ir_block *self, lex_ctx ctx, const char *label, int ot)
1608 {
1609     ir_value *out;
1610     ir_instr *in;
1611     if (!ir_check_unreachable(self))
1612         return NULL;
1613     in = ir_instr_new(ctx, self, VINSTR_PHI);
1614     if (!in)
1615         return NULL;
1616     out = ir_value_out(self->owner, label, store_value, ot);
1617     if (!out) {
1618         ir_instr_delete(in);
1619         return NULL;
1620     }
1621     if (!ir_instr_op(in, 0, out, true)) {
1622         ir_instr_delete(in);
1623         ir_value_delete(out);
1624         return NULL;
1625     }
1626     vec_push(self->instr, in);
1627     return in;
1628 }
1629
1630 ir_value* ir_phi_value(ir_instr *self)
1631 {
1632     return self->_ops[0];
1633 }
1634
1635 void ir_phi_add(ir_instr* self, ir_block *b, ir_value *v)
1636 {
1637     ir_phi_entry_t pe;
1638
1639     if (!vec_ir_block_find(self->owner->entries, b, NULL)) {
1640         /* Must not be possible to cause this, otherwise the AST
1641          * is doing something wrong.
1642          */
1643         irerror(self->context, "Invalid entry block for PHI");
1644         exit(EXIT_FAILURE);
1645     }
1646
1647     pe.value = v;
1648     pe.from = b;
1649     vec_push(v->reads, self);
1650     vec_push(self->phi, pe);
1651 }
1652
1653 /* call related code */
1654 ir_instr* ir_block_create_call(ir_block *self, lex_ctx ctx, const char *label, ir_value *func, bool noreturn)
1655 {
1656     ir_value *out;
1657     ir_instr *in;
1658     if (!ir_check_unreachable(self))
1659         return NULL;
1660     in = ir_instr_new(ctx, self, (noreturn ? VINSTR_NRCALL : INSTR_CALL0));
1661     if (!in)
1662         return NULL;
1663     if (noreturn) {
1664         self->final = true;
1665         self->is_return = true;
1666     }
1667     out = ir_value_out(self->owner, label, (func->outtype == TYPE_VOID) ? store_return : store_value, func->outtype);
1668     if (!out) {
1669         ir_instr_delete(in);
1670         return NULL;
1671     }
1672     if (!ir_instr_op(in, 0, out, true) ||
1673         !ir_instr_op(in, 1, func, false))
1674     {
1675         ir_instr_delete(in);
1676         ir_value_delete(out);
1677         return NULL;
1678     }
1679     vec_push(self->instr, in);
1680     /*
1681     if (noreturn) {
1682         if (!ir_block_create_return(self, ctx, NULL)) {
1683             compile_error(ctx, "internal error: failed to generate dummy-return instruction");
1684             ir_instr_delete(in);
1685             return NULL;
1686         }
1687     }
1688     */
1689     return in;
1690 }
1691
1692 ir_value* ir_call_value(ir_instr *self)
1693 {
1694     return self->_ops[0];
1695 }
1696
1697 void ir_call_param(ir_instr* self, ir_value *v)
1698 {
1699     vec_push(self->params, v);
1700     vec_push(v->reads, self);
1701 }
1702
1703 /* binary op related code */
1704
1705 ir_value* ir_block_create_binop(ir_block *self, lex_ctx ctx,
1706                                 const char *label, int opcode,
1707                                 ir_value *left, ir_value *right)
1708 {
1709     int ot = TYPE_VOID;
1710     switch (opcode) {
1711         case INSTR_ADD_F:
1712         case INSTR_SUB_F:
1713         case INSTR_DIV_F:
1714         case INSTR_MUL_F:
1715         case INSTR_MUL_V:
1716         case INSTR_AND:
1717         case INSTR_OR:
1718 #if 0
1719         case INSTR_AND_I:
1720         case INSTR_AND_IF:
1721         case INSTR_AND_FI:
1722         case INSTR_OR_I:
1723         case INSTR_OR_IF:
1724         case INSTR_OR_FI:
1725 #endif
1726         case INSTR_BITAND:
1727         case INSTR_BITOR:
1728 #if 0
1729         case INSTR_SUB_S: /* -- offset of string as float */
1730         case INSTR_MUL_IF:
1731         case INSTR_MUL_FI:
1732         case INSTR_DIV_IF:
1733         case INSTR_DIV_FI:
1734         case INSTR_BITOR_IF:
1735         case INSTR_BITOR_FI:
1736         case INSTR_BITAND_FI:
1737         case INSTR_BITAND_IF:
1738         case INSTR_EQ_I:
1739         case INSTR_NE_I:
1740 #endif
1741             ot = TYPE_FLOAT;
1742             break;
1743 #if 0
1744         case INSTR_ADD_I:
1745         case INSTR_ADD_IF:
1746         case INSTR_ADD_FI:
1747         case INSTR_SUB_I:
1748         case INSTR_SUB_FI:
1749         case INSTR_SUB_IF:
1750         case INSTR_MUL_I:
1751         case INSTR_DIV_I:
1752         case INSTR_BITAND_I:
1753         case INSTR_BITOR_I:
1754         case INSTR_XOR_I:
1755         case INSTR_RSHIFT_I:
1756         case INSTR_LSHIFT_I:
1757             ot = TYPE_INTEGER;
1758             break;
1759 #endif
1760         case INSTR_ADD_V:
1761         case INSTR_SUB_V:
1762         case INSTR_MUL_VF:
1763         case INSTR_MUL_FV:
1764 #if 0
1765         case INSTR_DIV_VF:
1766         case INSTR_MUL_IV:
1767         case INSTR_MUL_VI:
1768 #endif
1769             ot = TYPE_VECTOR;
1770             break;
1771 #if 0
1772         case INSTR_ADD_SF:
1773             ot = TYPE_POINTER;
1774             break;
1775 #endif
1776         default:
1777             /* ranges: */
1778             /* boolean operations result in floats */
1779             if (opcode >= INSTR_EQ_F && opcode <= INSTR_GT)
1780                 ot = TYPE_FLOAT;
1781             else if (opcode >= INSTR_LE && opcode <= INSTR_GT)
1782                 ot = TYPE_FLOAT;
1783 #if 0
1784             else if (opcode >= INSTR_LE_I && opcode <= INSTR_EQ_FI)
1785                 ot = TYPE_FLOAT;
1786 #endif
1787             break;
1788     };
1789     if (ot == TYPE_VOID) {
1790         /* The AST or parser were supposed to check this! */
1791         return NULL;
1792     }
1793
1794     return ir_block_create_general_instr(self, ctx, label, opcode, left, right, ot);
1795 }
1796
1797 ir_value* ir_block_create_unary(ir_block *self, lex_ctx ctx,
1798                                 const char *label, int opcode,
1799                                 ir_value *operand)
1800 {
1801     int ot = TYPE_FLOAT;
1802     switch (opcode) {
1803         case INSTR_NOT_F:
1804         case INSTR_NOT_V:
1805         case INSTR_NOT_S:
1806         case INSTR_NOT_ENT:
1807         case INSTR_NOT_FNC:
1808 #if 0
1809         case INSTR_NOT_I:
1810 #endif
1811             ot = TYPE_FLOAT;
1812             break;
1813         /* QC doesn't have other unary operations. We expect extensions to fill
1814          * the above list, otherwise we assume out-type = in-type, eg for an
1815          * unary minus
1816          */
1817         default:
1818             ot = operand->vtype;
1819             break;
1820     };
1821     if (ot == TYPE_VOID) {
1822         /* The AST or parser were supposed to check this! */
1823         return NULL;
1824     }
1825
1826     /* let's use the general instruction creator and pass NULL for OPB */
1827     return ir_block_create_general_instr(self, ctx, label, opcode, operand, NULL, ot);
1828 }
1829
1830 ir_value* ir_block_create_general_instr(ir_block *self, lex_ctx ctx, const char *label,
1831                                         int op, ir_value *a, ir_value *b, int outype)
1832 {
1833     ir_instr *instr;
1834     ir_value *out;
1835
1836     out = ir_value_out(self->owner, label, store_value, outype);
1837     if (!out)
1838         return NULL;
1839
1840     instr = ir_instr_new(ctx, self, op);
1841     if (!instr) {
1842         ir_value_delete(out);
1843         return NULL;
1844     }
1845
1846     if (!ir_instr_op(instr, 0, out, true) ||
1847         !ir_instr_op(instr, 1, a, false) ||
1848         !ir_instr_op(instr, 2, b, false) )
1849     {
1850         goto on_error;
1851     }
1852
1853     vec_push(self->instr, instr);
1854
1855     return out;
1856 on_error:
1857     ir_instr_delete(instr);
1858     ir_value_delete(out);
1859     return NULL;
1860 }
1861
1862 ir_value* ir_block_create_fieldaddress(ir_block *self, lex_ctx ctx, const char *label, ir_value *ent, ir_value *field)
1863 {
1864     ir_value *v;
1865
1866     /* Support for various pointer types todo if so desired */
1867     if (ent->vtype != TYPE_ENTITY)
1868         return NULL;
1869
1870     if (field->vtype != TYPE_FIELD)
1871         return NULL;
1872
1873     v = ir_block_create_general_instr(self, ctx, label, INSTR_ADDRESS, ent, field, TYPE_POINTER);
1874     v->fieldtype = field->fieldtype;
1875     return v;
1876 }
1877
1878 ir_value* ir_block_create_load_from_ent(ir_block *self, lex_ctx ctx, const char *label, ir_value *ent, ir_value *field, int outype)
1879 {
1880     int op;
1881     if (ent->vtype != TYPE_ENTITY)
1882         return NULL;
1883
1884     /* at some point we could redirect for TYPE_POINTER... but that could lead to carelessness */
1885     if (field->vtype != TYPE_FIELD)
1886         return NULL;
1887
1888     switch (outype)
1889     {
1890         case TYPE_FLOAT:    op = INSTR_LOAD_F;   break;
1891         case TYPE_VECTOR:   op = INSTR_LOAD_V;   break;
1892         case TYPE_STRING:   op = INSTR_LOAD_S;   break;
1893         case TYPE_FIELD:    op = INSTR_LOAD_FLD; break;
1894         case TYPE_ENTITY:   op = INSTR_LOAD_ENT; break;
1895         case TYPE_FUNCTION: op = INSTR_LOAD_FNC; break;
1896 #if 0
1897         case TYPE_POINTER: op = INSTR_LOAD_I;   break;
1898         case TYPE_INTEGER: op = INSTR_LOAD_I;   break;
1899 #endif
1900         default:
1901             irerror(self->context, "invalid type for ir_block_create_load_from_ent: %s", type_name[outype]);
1902             return NULL;
1903     }
1904
1905     return ir_block_create_general_instr(self, ctx, label, op, ent, field, outype);
1906 }
1907
1908 /* PHI resolving breaks the SSA, and must thus be the last
1909  * step before life-range calculation.
1910  */
1911
1912 static bool ir_block_naive_phi(ir_block *self);
1913 bool ir_function_naive_phi(ir_function *self)
1914 {
1915     size_t i;
1916
1917     for (i = 0; i < vec_size(self->blocks); ++i)
1918     {
1919         if (!ir_block_naive_phi(self->blocks[i]))
1920             return false;
1921     }
1922     return true;
1923 }
1924
1925 static bool ir_block_naive_phi(ir_block *self)
1926 {
1927     size_t i, p; /*, w;*/
1928     /* FIXME: optionally, create_phi can add the phis
1929      * to a list so we don't need to loop through blocks
1930      * - anyway: "don't optimize YET"
1931      */
1932     for (i = 0; i < vec_size(self->instr); ++i)
1933     {
1934         ir_instr *instr = self->instr[i];
1935         if (instr->opcode != VINSTR_PHI)
1936             continue;
1937
1938         vec_remove(self->instr, i, 1);
1939         --i; /* NOTE: i+1 below */
1940
1941         for (p = 0; p < vec_size(instr->phi); ++p)
1942         {
1943             ir_value *v = instr->phi[p].value;
1944             ir_block *b = instr->phi[p].from;
1945
1946             if (v->store == store_value &&
1947                 vec_size(v->reads) == 1 &&
1948                 vec_size(v->writes) == 1)
1949             {
1950                 /* replace the value */
1951                 if (!ir_instr_op(v->writes[0], 0, instr->_ops[0], true))
1952                     return false;
1953             }
1954             else
1955             {
1956                 /* force a move instruction */
1957                 ir_instr *prevjump = vec_last(b->instr);
1958                 vec_pop(b->instr);
1959                 b->final = false;
1960                 instr->_ops[0]->store = store_global;
1961                 if (!ir_block_create_store(b, instr->context, instr->_ops[0], v))
1962                     return false;
1963                 instr->_ops[0]->store = store_value;
1964                 vec_push(b->instr, prevjump);
1965                 b->final = true;
1966             }
1967         }
1968         ir_instr_delete(instr);
1969     }
1970     return true;
1971 }
1972
1973 /***********************************************************************
1974  *IR Temp allocation code
1975  * Propagating value life ranges by walking through the function backwards
1976  * until no more changes are made.
1977  * In theory this should happen once more than once for every nested loop
1978  * level.
1979  * Though this implementation might run an additional time for if nests.
1980  */
1981
1982 /* Enumerate instructions used by value's life-ranges
1983  */
1984 static void ir_block_enumerate(ir_block *self, size_t *_eid)
1985 {
1986     size_t i;
1987     size_t eid = *_eid;
1988     for (i = 0; i < vec_size(self->instr); ++i)
1989     {
1990         self->instr[i]->eid = eid++;
1991     }
1992     *_eid = eid;
1993 }
1994
1995 /* Enumerate blocks and instructions.
1996  * The block-enumeration is unordered!
1997  * We do not really use the block enumreation, however
1998  * the instruction enumeration is important for life-ranges.
1999  */
2000 void ir_function_enumerate(ir_function *self)
2001 {
2002     size_t i;
2003     size_t instruction_id = 0;
2004     for (i = 0; i < vec_size(self->blocks); ++i)
2005     {
2006         /* each block now gets an additional "entry" instruction id
2007          * we can use to avoid point-life issues
2008          */
2009         self->blocks[i]->entry_id = instruction_id;
2010         ++instruction_id;
2011
2012         self->blocks[i]->eid = i;
2013         ir_block_enumerate(self->blocks[i], &instruction_id);
2014     }
2015 }
2016
2017 /* Local-value allocator
2018  * After finishing creating the liferange of all values used in a function
2019  * we can allocate their global-positions.
2020  * This is the counterpart to register-allocation in register machines.
2021  */
2022 typedef struct {
2023     ir_value **locals;
2024     size_t    *sizes;
2025     size_t    *positions;
2026     bool      *unique;
2027 } function_allocator;
2028
2029 static bool function_allocator_alloc(function_allocator *alloc, ir_value *var)
2030 {
2031     ir_value *slot;
2032     size_t vsize = ir_value_sizeof(var);
2033
2034     var->code.local = vec_size(alloc->locals);
2035
2036     slot = ir_value_var("reg", store_global, var->vtype);
2037     if (!slot)
2038         return false;
2039
2040     if (!ir_value_life_merge_into(slot, var))
2041         goto localerror;
2042
2043     vec_push(alloc->locals, slot);
2044     vec_push(alloc->sizes, vsize);
2045     vec_push(alloc->unique, var->unique_life);
2046
2047     return true;
2048
2049 localerror:
2050     ir_value_delete(slot);
2051     return false;
2052 }
2053
2054 static bool ir_function_allocator_assign(ir_function *self, function_allocator *alloc, ir_value *v)
2055 {
2056     size_t a;
2057     ir_value *slot;
2058
2059     if (v->unique_life)
2060         return function_allocator_alloc(alloc, v);
2061
2062     for (a = 0; a < vec_size(alloc->locals); ++a)
2063     {
2064         /* if it's reserved for a unique liferange: skip */
2065         if (alloc->unique[a])
2066             continue;
2067
2068         slot = alloc->locals[a];
2069
2070         /* never resize parameters
2071          * will be required later when overlapping temps + locals
2072          */
2073         if (a < vec_size(self->params) &&
2074             alloc->sizes[a] < ir_value_sizeof(v))
2075         {
2076             continue;
2077         }
2078
2079         if (ir_values_overlap(v, slot))
2080             continue;
2081
2082         if (!ir_value_life_merge_into(slot, v))
2083             return false;
2084
2085         /* adjust size for this slot */
2086         if (alloc->sizes[a] < ir_value_sizeof(v))
2087             alloc->sizes[a] = ir_value_sizeof(v);
2088
2089         v->code.local = a;
2090         return true;
2091     }
2092     if (a >= vec_size(alloc->locals)) {
2093         if (!function_allocator_alloc(alloc, v))
2094             return false;
2095     }
2096     return true;
2097 }
2098
2099 bool ir_function_allocate_locals(ir_function *self)
2100 {
2101     size_t i;
2102     bool   retval = true;
2103     size_t pos;
2104     bool   opt_gt = OPTS_OPTIMIZATION(OPTIM_GLOBAL_TEMPS);
2105
2106     ir_value *v;
2107
2108     function_allocator lockalloc, globalloc;
2109
2110     if (!vec_size(self->locals) && !vec_size(self->values))
2111         return true;
2112
2113     globalloc.locals    = NULL;
2114     globalloc.sizes     = NULL;
2115     globalloc.positions = NULL;
2116     globalloc.unique    = NULL;
2117     lockalloc.locals    = NULL;
2118     lockalloc.sizes     = NULL;
2119     lockalloc.positions = NULL;
2120     lockalloc.unique    = NULL;
2121
2122     for (i = 0; i < vec_size(self->locals); ++i)
2123     {
2124         v = self->locals[i];
2125         if ((self->flags & IR_FLAG_MASK_NO_LOCAL_TEMPS) || !OPTS_OPTIMIZATION(OPTIM_LOCAL_TEMPS)) {
2126             v->locked      = true;
2127             v->unique_life = true;
2128         }
2129         else if (i >= vec_size(self->params))
2130             break;
2131         else
2132             v->locked = true; /* lock parameters locals */
2133         if (!function_allocator_alloc((v->locked || !opt_gt ? &lockalloc : &globalloc), v))
2134             goto error;
2135     }
2136     for (; i < vec_size(self->locals); ++i)
2137     {
2138         v = self->locals[i];
2139         if (!vec_size(v->life))
2140             continue;
2141         if (!ir_function_allocator_assign(self, (v->locked || !opt_gt ? &lockalloc : &globalloc), v))
2142             goto error;
2143     }
2144
2145     /* Allocate a slot for any value that still exists */
2146     for (i = 0; i < vec_size(self->values); ++i)
2147     {
2148         v = self->values[i];
2149
2150         if (!vec_size(v->life))
2151             continue;
2152
2153         /* CALL optimization:
2154          * If the value is a parameter-temp: 1 write, 1 read from a CALL
2155          * and it's not "locked", write it to the OFS_PARM directly.
2156          */
2157         if (OPTS_OPTIMIZATION(OPTIM_CALL_STORES) && !v->locked && !v->unique_life) {
2158             if (vec_size(v->reads) == 1 && vec_size(v->writes) == 1 &&
2159                 (v->reads[0]->opcode == VINSTR_NRCALL ||
2160                  (v->reads[0]->opcode >= INSTR_CALL0 && v->reads[0]->opcode <= INSTR_CALL8)
2161                 )
2162                )
2163             {
2164                 size_t    param;
2165                 ir_instr *call = v->reads[0];
2166                 if (!vec_ir_value_find(call->params, v, &param)) {
2167                     irerror(call->context, "internal error: unlocked parameter %s not found", v->name);
2168                     goto error;
2169                 }
2170                 ++opts_optimizationcount[OPTIM_CALL_STORES];
2171                 v->callparam = true;
2172                 if (param < 8)
2173                     ir_value_code_setaddr(v, OFS_PARM0 + 3*param);
2174                 else {
2175                     size_t nprotos = vec_size(self->owner->extparam_protos);
2176                     ir_value *ep;
2177                     param -= 8;
2178                     if (nprotos > param)
2179                         ep = self->owner->extparam_protos[param];
2180                     else
2181                     {
2182                         ep = ir_gen_extparam_proto(self->owner);
2183                         while (++nprotos <= param)
2184                             ep = ir_gen_extparam_proto(self->owner);
2185                     }
2186                     ir_instr_op(v->writes[0], 0, ep, true);
2187                     call->params[param+8] = ep;
2188                 }
2189                 continue;
2190             }
2191             if (vec_size(v->writes) == 1 && v->writes[0]->opcode == INSTR_CALL0)
2192             {
2193                 v->store = store_return;
2194                 if (v->members[0]) v->members[0]->store = store_return;
2195                 if (v->members[1]) v->members[1]->store = store_return;
2196                 if (v->members[2]) v->members[2]->store = store_return;
2197                 ++opts_optimizationcount[OPTIM_CALL_STORES];
2198                 continue;
2199             }
2200         }
2201
2202         if (!ir_function_allocator_assign(self, (v->locked || !opt_gt ? &lockalloc : &globalloc), v))
2203             goto error;
2204     }
2205
2206     if (!lockalloc.sizes && !globalloc.sizes) {
2207         goto cleanup;
2208     }
2209     vec_push(lockalloc.positions, 0);
2210     vec_push(globalloc.positions, 0);
2211
2212     /* Adjust slot positions based on sizes */
2213     if (lockalloc.sizes) {
2214         pos = (vec_size(lockalloc.sizes) ? lockalloc.positions[0] : 0);
2215         for (i = 1; i < vec_size(lockalloc.sizes); ++i)
2216         {
2217             pos = lockalloc.positions[i-1] + lockalloc.sizes[i-1];
2218             vec_push(lockalloc.positions, pos);
2219         }
2220         self->allocated_locals = pos + vec_last(lockalloc.sizes);
2221     }
2222     if (globalloc.sizes) {
2223         pos = (vec_size(globalloc.sizes) ? globalloc.positions[0] : 0);
2224         for (i = 1; i < vec_size(globalloc.sizes); ++i)
2225         {
2226             pos = globalloc.positions[i-1] + globalloc.sizes[i-1];
2227             vec_push(globalloc.positions, pos);
2228         }
2229         self->globaltemps = pos + vec_last(globalloc.sizes);
2230     }
2231
2232     /* Locals need to know their new position */
2233     for (i = 0; i < vec_size(self->locals); ++i) {
2234         v = self->locals[i];
2235         if (v->locked || !opt_gt)
2236             v->code.local = lockalloc.positions[v->code.local];
2237         else
2238             v->code.local = globalloc.positions[v->code.local];
2239     }
2240     /* Take over the actual slot positions on values */
2241     for (i = 0; i < vec_size(self->values); ++i) {
2242         v = self->values[i];
2243         if (v->locked || !opt_gt)
2244             v->code.local = lockalloc.positions[v->code.local];
2245         else
2246             v->code.local = globalloc.positions[v->code.local];
2247     }
2248
2249     goto cleanup;
2250
2251 error:
2252     retval = false;
2253 cleanup:
2254     for (i = 0; i < vec_size(lockalloc.locals); ++i)
2255         ir_value_delete(lockalloc.locals[i]);
2256     for (i = 0; i < vec_size(globalloc.locals); ++i)
2257         ir_value_delete(globalloc.locals[i]);
2258     vec_free(globalloc.unique);
2259     vec_free(globalloc.locals);
2260     vec_free(globalloc.sizes);
2261     vec_free(globalloc.positions);
2262     vec_free(lockalloc.unique);
2263     vec_free(lockalloc.locals);
2264     vec_free(lockalloc.sizes);
2265     vec_free(lockalloc.positions);
2266     return retval;
2267 }
2268
2269 /* Get information about which operand
2270  * is read from, or written to.
2271  */
2272 static void ir_op_read_write(int op, size_t *read, size_t *write)
2273 {
2274     switch (op)
2275     {
2276     case VINSTR_JUMP:
2277     case INSTR_GOTO:
2278         *write = 0;
2279         *read = 0;
2280         break;
2281     case INSTR_IF:
2282     case INSTR_IFNOT:
2283 #if 0
2284     case INSTR_IF_S:
2285     case INSTR_IFNOT_S:
2286 #endif
2287     case INSTR_RETURN:
2288     case VINSTR_COND:
2289         *write = 0;
2290         *read = 1;
2291         break;
2292     case INSTR_STOREP_F:
2293     case INSTR_STOREP_V:
2294     case INSTR_STOREP_S:
2295     case INSTR_STOREP_ENT:
2296     case INSTR_STOREP_FLD:
2297     case INSTR_STOREP_FNC:
2298         *write = 0;
2299         *read  = 7;
2300         break;
2301     default:
2302         *write = 1;
2303         *read = 6;
2304         break;
2305     };
2306 }
2307
2308 static bool ir_block_living_add_instr(ir_block *self, size_t eid)
2309 {
2310     size_t       i;
2311     const size_t vs = vec_size(self->living);
2312     bool         changed = false;
2313     for (i = 0; i != vs; ++i)
2314     {
2315         if (ir_value_life_merge(self->living[i], eid))
2316             changed = true;
2317     }
2318     return changed;
2319 }
2320
2321 static bool ir_block_living_lock(ir_block *self)
2322 {
2323     size_t i;
2324     bool changed = false;
2325     for (i = 0; i != vec_size(self->living); ++i)
2326     {
2327         if (!self->living[i]->locked) {
2328             self->living[i]->locked = true;
2329             changed = true;
2330         }
2331     }
2332     return changed;
2333 }
2334
2335 static bool ir_block_life_propagate(ir_block *self, bool *changed)
2336 {
2337     ir_instr *instr;
2338     ir_value *value;
2339     size_t i, o, p, mem, cnt;
2340     /* bitmasks which operands are read from or written to */
2341     size_t read, write;
2342     char dbg_ind[16];
2343     dbg_ind[0] = '#';
2344     dbg_ind[1] = '0';
2345     (void)dbg_ind;
2346
2347     vec_free(self->living);
2348
2349     p = vec_size(self->exits);
2350     for (i = 0; i < p; ++i) {
2351         ir_block *prev = self->exits[i];
2352         cnt = vec_size(prev->living);
2353         for (o = 0; o < cnt; ++o) {
2354             if (!vec_ir_value_find(self->living, prev->living[o], NULL))
2355                 vec_push(self->living, prev->living[o]);
2356         }
2357     }
2358
2359     i = vec_size(self->instr);
2360     while (i)
2361     { --i;
2362         instr = self->instr[i];
2363
2364         /* See which operands are read and write operands */
2365         ir_op_read_write(instr->opcode, &read, &write);
2366
2367         /* Go through the 3 main operands
2368          * writes first, then reads
2369          */
2370         for (o = 0; o < 3; ++o)
2371         {
2372             if (!instr->_ops[o]) /* no such operand */
2373                 continue;
2374
2375             value = instr->_ops[o];
2376
2377             /* We only care about locals */
2378             /* we also calculate parameter liferanges so that locals
2379              * can take up parameter slots */
2380             if (value->store != store_value &&
2381                 value->store != store_local &&
2382                 value->store != store_param)
2383                 continue;
2384
2385             /* write operands */
2386             /* When we write to a local, we consider it "dead" for the
2387              * remaining upper part of the function, since in SSA a value
2388              * can only be written once (== created)
2389              */
2390             if (write & (1<<o))
2391             {
2392                 size_t idx;
2393                 bool in_living = vec_ir_value_find(self->living, value, &idx);
2394                 if (!in_living)
2395                 {
2396                     /* If the value isn't alive it hasn't been read before... */
2397                     /* TODO: See if the warning can be emitted during parsing or AST processing
2398                      * otherwise have warning printed here.
2399                      * IF printing a warning here: include filecontext_t,
2400                      * and make sure it's only printed once
2401                      * since this function is run multiple times.
2402                      */
2403                     /* con_err( "Value only written %s\n", value->name); */
2404                     if (ir_value_life_merge(value, instr->eid))
2405                         *changed = true;
2406                 } else {
2407                     /* since 'living' won't contain it
2408                      * anymore, merge the value, since
2409                      * (A) doesn't.
2410                      */
2411                     if (ir_value_life_merge(value, instr->eid))
2412                         *changed = true;
2413                     /* Then remove */
2414                     vec_remove(self->living, idx, 1);
2415                 }
2416                 /* Removing a vector removes all members */
2417                 for (mem = 0; mem < 3; ++mem) {
2418                     if (value->members[mem] && vec_ir_value_find(self->living, value->members[mem], &idx)) {
2419                         if (ir_value_life_merge(value->members[mem], instr->eid))
2420                             *changed = true;
2421                         vec_remove(self->living, idx, 1);
2422                     }
2423                 }
2424                 /* Removing the last member removes the vector */
2425                 if (value->memberof) {
2426                     value = value->memberof;
2427                     for (mem = 0; mem < 3; ++mem) {
2428                         if (value->members[mem] && vec_ir_value_find(self->living, value->members[mem], NULL))
2429                             break;
2430                     }
2431                     if (mem == 3 && vec_ir_value_find(self->living, value, &idx)) {
2432                         if (ir_value_life_merge(value, instr->eid))
2433                             *changed = true;
2434                         vec_remove(self->living, idx, 1);
2435                     }
2436                 }
2437             }
2438         }
2439
2440         if (instr->opcode == INSTR_MUL_VF)
2441         {
2442             value = instr->_ops[2];
2443             /* the float source will get an additional lifetime */
2444             if (ir_value_life_merge(value, instr->eid+1))
2445                 *changed = true;
2446             if (value->memberof && ir_value_life_merge(value->memberof, instr->eid+1))
2447                 *changed = true;
2448         }
2449         else if (instr->opcode == INSTR_MUL_FV || instr->opcode == INSTR_LOAD_V)
2450         {
2451             value = instr->_ops[1];
2452             /* the float source will get an additional lifetime */
2453             if (ir_value_life_merge(value, instr->eid+1))
2454                 *changed = true;
2455             if (value->memberof && ir_value_life_merge(value->memberof, instr->eid+1))
2456                 *changed = true;
2457         }
2458
2459         for (o = 0; o < 3; ++o)
2460         {
2461             if (!instr->_ops[o]) /* no such operand */
2462                 continue;
2463
2464             value = instr->_ops[o];
2465
2466             /* We only care about locals */
2467             /* we also calculate parameter liferanges so that locals
2468              * can take up parameter slots */
2469             if (value->store != store_value &&
2470                 value->store != store_local &&
2471                 value->store != store_param)
2472                 continue;
2473
2474             /* read operands */
2475             if (read & (1<<o))
2476             {
2477                 if (!vec_ir_value_find(self->living, value, NULL))
2478                     vec_push(self->living, value);
2479                 /* reading adds the full vector */
2480                 if (value->memberof && !vec_ir_value_find(self->living, value->memberof, NULL))
2481                     vec_push(self->living, value->memberof);
2482                 for (mem = 0; mem < 3; ++mem) {
2483                     if (value->members[mem] && !vec_ir_value_find(self->living, value->members[mem], NULL))
2484                         vec_push(self->living, value->members[mem]);
2485                 }
2486             }
2487         }
2488         /* PHI operands are always read operands */
2489         for (p = 0; p < vec_size(instr->phi); ++p)
2490         {
2491             value = instr->phi[p].value;
2492             if (!vec_ir_value_find(self->living, value, NULL))
2493                 vec_push(self->living, value);
2494             /* reading adds the full vector */
2495             if (value->memberof && !vec_ir_value_find(self->living, value->memberof, NULL))
2496                 vec_push(self->living, value->memberof);
2497             for (mem = 0; mem < 3; ++mem) {
2498                 if (value->members[mem] && !vec_ir_value_find(self->living, value->members[mem], NULL))
2499                     vec_push(self->living, value->members[mem]);
2500             }
2501         }
2502
2503         /* on a call, all these values must be "locked" */
2504         if (instr->opcode >= INSTR_CALL0 && instr->opcode <= INSTR_CALL8) {
2505             if (ir_block_living_lock(self))
2506                 *changed = true;
2507         }
2508         /* call params are read operands too */
2509         for (p = 0; p < vec_size(instr->params); ++p)
2510         {
2511             value = instr->params[p];
2512             if (!vec_ir_value_find(self->living, value, NULL))
2513                 vec_push(self->living, value);
2514             /* reading adds the full vector */
2515             if (value->memberof && !vec_ir_value_find(self->living, value->memberof, NULL))
2516                 vec_push(self->living, value->memberof);
2517             for (mem = 0; mem < 3; ++mem) {
2518                 if (value->members[mem] && !vec_ir_value_find(self->living, value->members[mem], NULL))
2519                     vec_push(self->living, value->members[mem]);
2520             }
2521         }
2522
2523         /* (A) */
2524         if (ir_block_living_add_instr(self, instr->eid))
2525             *changed = true;
2526     }
2527     /* the "entry" instruction ID */
2528     if (ir_block_living_add_instr(self, self->entry_id))
2529         *changed = true;
2530
2531     return true;
2532 }
2533
2534 bool ir_function_calculate_liferanges(ir_function *self)
2535 {
2536     size_t i, s;
2537     bool changed;
2538
2539     /* parameters live at 0 */
2540     for (i = 0; i < vec_size(self->params); ++i)
2541         ir_value_life_merge(self->locals[i], 0);
2542
2543     do {
2544         self->run_id++;
2545         changed = false;
2546         i = vec_size(self->blocks);
2547         while (i--) {
2548             ir_block_life_propagate(self->blocks[i], &changed);
2549         }
2550     } while (changed);
2551
2552     if (vec_size(self->blocks)) {
2553         ir_block *block = self->blocks[0];
2554         for (i = 0; i < vec_size(block->living); ++i) {
2555             ir_value *v = block->living[i];
2556             if (v->store != store_local)
2557                 continue;
2558             if (v->vtype == TYPE_VECTOR)
2559                 continue;
2560             self->flags |= IR_FLAG_HAS_UNINITIALIZED;
2561             /* find the instruction reading from it */
2562             for (s = 0; s < vec_size(v->reads); ++s) {
2563                 if (v->reads[s]->eid == v->life[0].end)
2564                     break;
2565             }
2566             if (s < vec_size(v->reads)) {
2567                 if (irwarning(v->context, WARN_USED_UNINITIALIZED,
2568                               "variable `%s` may be used uninitialized in this function\n"
2569                               " -> %s:%i",
2570                               v->name,
2571                               v->reads[s]->context.file, v->reads[s]->context.line)
2572                    )
2573                 {
2574                     return false;
2575                 }
2576                 continue;
2577             }
2578             if (v->memberof) {
2579                 ir_value *vec = v->memberof;
2580                 for (s = 0; s < vec_size(vec->reads); ++s) {
2581                     if (vec->reads[s]->eid == v->life[0].end)
2582                         break;
2583                 }
2584                 if (s < vec_size(vec->reads)) {
2585                     if (irwarning(v->context, WARN_USED_UNINITIALIZED,
2586                                   "variable `%s` may be used uninitialized in this function\n"
2587                                   " -> %s:%i",
2588                                   v->name,
2589                                   vec->reads[s]->context.file, vec->reads[s]->context.line)
2590                        )
2591                     {
2592                         return false;
2593                     }
2594                     continue;
2595                 }
2596             }
2597             if (irwarning(v->context, WARN_USED_UNINITIALIZED,
2598                           "variable `%s` may be used uninitialized in this function", v->name))
2599             {
2600                 return false;
2601             }
2602         }
2603     }
2604     return true;
2605 }
2606
2607 /***********************************************************************
2608  *IR Code-Generation
2609  *
2610  * Since the IR has the convention of putting 'write' operands
2611  * at the beginning, we have to rotate the operands of instructions
2612  * properly in order to generate valid QCVM code.
2613  *
2614  * Having destinations at a fixed position is more convenient. In QC
2615  * this is *mostly* OPC,  but FTE adds at least 2 instructions which
2616  * read from from OPA,  and store to OPB rather than OPC.   Which is
2617  * partially the reason why the implementation of these instructions
2618  * in darkplaces has been delayed for so long.
2619  *
2620  * Breaking conventions is annoying...
2621  */
2622 static bool ir_builder_gen_global(code_t *, ir_builder *self, ir_value *global, bool islocal);
2623
2624 static bool gen_global_field(code_t *code, ir_value *global)
2625 {
2626     if (global->hasvalue)
2627     {
2628         ir_value *fld = global->constval.vpointer;
2629         if (!fld) {
2630             irerror(global->context, "Invalid field constant with no field: %s", global->name);
2631             return false;
2632         }
2633
2634         /* copy the field's value */
2635         ir_value_code_setaddr(global, vec_size(code->globals));
2636         vec_push(code->globals, fld->code.fieldaddr);
2637         if (global->fieldtype == TYPE_VECTOR) {
2638             vec_push(code->globals, fld->code.fieldaddr+1);
2639             vec_push(code->globals, fld->code.fieldaddr+2);
2640         }
2641     }
2642     else
2643     {
2644         ir_value_code_setaddr(global, vec_size(code->globals));
2645         vec_push(code->globals, 0);
2646         if (global->fieldtype == TYPE_VECTOR) {
2647             vec_push(code->globals, 0);
2648             vec_push(code->globals, 0);
2649         }
2650     }
2651     if (global->code.globaladdr < 0)
2652         return false;
2653     return true;
2654 }
2655
2656 static bool gen_global_pointer(code_t *code, ir_value *global)
2657 {
2658     if (global->hasvalue)
2659     {
2660         ir_value *target = global->constval.vpointer;
2661         if (!target) {
2662             irerror(global->context, "Invalid pointer constant: %s", global->name);
2663             /* NULL pointers are pointing to the NULL constant, which also
2664              * sits at address 0, but still has an ir_value for itself.
2665              */
2666             return false;
2667         }
2668
2669         /* Here, relocations ARE possible - in fteqcc-enhanced-qc:
2670          * void() foo; <- proto
2671          * void() *fooptr = &foo;
2672          * void() foo = { code }
2673          */
2674         if (!target->code.globaladdr) {
2675             /* FIXME: Check for the constant nullptr ir_value!
2676              * because then code.globaladdr being 0 is valid.
2677              */
2678             irerror(global->context, "FIXME: Relocation support");
2679             return false;
2680         }
2681
2682         ir_value_code_setaddr(global, vec_size(code->globals));
2683         vec_push(code->globals, target->code.globaladdr);
2684     }
2685     else
2686     {
2687         ir_value_code_setaddr(global, vec_size(code->globals));
2688         vec_push(code->globals, 0);
2689     }
2690     if (global->code.globaladdr < 0)
2691         return false;
2692     return true;
2693 }
2694
2695 static bool gen_blocks_recursive(code_t *code, ir_function *func, ir_block *block)
2696 {
2697     prog_section_statement stmt;
2698     ir_instr *instr;
2699     ir_block *target;
2700     ir_block *ontrue;
2701     ir_block *onfalse;
2702     size_t    stidx;
2703     size_t    i;
2704
2705     block->generated = true;
2706     block->code_start = vec_size(code->statements);
2707     for (i = 0; i < vec_size(block->instr); ++i)
2708     {
2709         instr = block->instr[i];
2710
2711         if (instr->opcode == VINSTR_PHI) {
2712             irerror(block->context, "cannot generate virtual instruction (phi)");
2713             return false;
2714         }
2715
2716         if (instr->opcode == VINSTR_JUMP) {
2717             target = instr->bops[0];
2718             /* for uncoditional jumps, if the target hasn't been generated
2719              * yet, we generate them right here.
2720              */
2721             if (!target->generated)
2722                 return gen_blocks_recursive(code, func, target);
2723
2724             /* otherwise we generate a jump instruction */
2725             stmt.opcode = INSTR_GOTO;
2726             stmt.o1.s1 = (target->code_start) - vec_size(code->statements);
2727             stmt.o2.s1 = 0;
2728             stmt.o3.s1 = 0;
2729             if (stmt.o1.s1 != 1)
2730                 code_push_statement(code, &stmt, instr->context.line);
2731
2732             /* no further instructions can be in this block */
2733             return true;
2734         }
2735
2736         if (instr->opcode == VINSTR_COND) {
2737             ontrue  = instr->bops[0];
2738             onfalse = instr->bops[1];
2739             /* TODO: have the AST signal which block should
2740              * come first: eg. optimize IFs without ELSE...
2741              */
2742
2743             stmt.o1.u1 = ir_value_code_addr(instr->_ops[0]);
2744             stmt.o2.u1 = 0;
2745             stmt.o3.s1 = 0;
2746
2747             if (ontrue->generated) {
2748                 stmt.opcode = INSTR_IF;
2749                 stmt.o2.s1 = (ontrue->code_start) - vec_size(code->statements);
2750                 if (stmt.o2.s1 != 1)
2751                     code_push_statement(code, &stmt, instr->context.line);
2752             }
2753             if (onfalse->generated) {
2754                 stmt.opcode = INSTR_IFNOT;
2755                 stmt.o2.s1 = (onfalse->code_start) - vec_size(code->statements);
2756                 if (stmt.o2.s1 != 1)
2757                     code_push_statement(code, &stmt, instr->context.line);
2758             }
2759             if (!ontrue->generated) {
2760                 if (onfalse->generated)
2761                     return gen_blocks_recursive(code, func, ontrue);
2762             }
2763             if (!onfalse->generated) {
2764                 if (ontrue->generated)
2765                     return gen_blocks_recursive(code, func, onfalse);
2766             }
2767             /* neither ontrue nor onfalse exist */
2768             stmt.opcode = INSTR_IFNOT;
2769             if (!instr->likely) {
2770                 /* Honor the likelyhood hint */
2771                 ir_block *tmp = onfalse;
2772                 stmt.opcode = INSTR_IF;
2773                 onfalse = ontrue;
2774                 ontrue = tmp;
2775             }
2776             stidx = vec_size(code->statements);
2777             code_push_statement(code, &stmt, instr->context.line);
2778             /* on false we jump, so add ontrue-path */
2779             if (!gen_blocks_recursive(code, func, ontrue))
2780                 return false;
2781             /* fixup the jump address */
2782             code->statements[stidx].o2.s1 = vec_size(code->statements) - stidx;
2783             /* generate onfalse path */
2784             if (onfalse->generated) {
2785                 /* fixup the jump address */
2786                 code->statements[stidx].o2.s1 = (onfalse->code_start) - (stidx);
2787                 if (stidx+2 == vec_size(code->statements) && code->statements[stidx].o2.s1 == 1) {
2788                     code->statements[stidx] = code->statements[stidx+1];
2789                     if (code->statements[stidx].o1.s1 < 0)
2790                         code->statements[stidx].o1.s1++;
2791                     code_pop_statement(code);
2792                 }
2793                 stmt.opcode = vec_last(code->statements).opcode;
2794                 if (stmt.opcode == INSTR_GOTO ||
2795                     stmt.opcode == INSTR_IF ||
2796                     stmt.opcode == INSTR_IFNOT ||
2797                     stmt.opcode == INSTR_RETURN ||
2798                     stmt.opcode == INSTR_DONE)
2799                 {
2800                     /* no use jumping from here */
2801                     return true;
2802                 }
2803                 /* may have been generated in the previous recursive call */
2804                 stmt.opcode = INSTR_GOTO;
2805                 stmt.o1.s1 = (onfalse->code_start) - vec_size(code->statements);
2806                 stmt.o2.s1 = 0;
2807                 stmt.o3.s1 = 0;
2808                 if (stmt.o1.s1 != 1)
2809                     code_push_statement(code, &stmt, instr->context.line);
2810                 return true;
2811             }
2812             else if (stidx+2 == vec_size(code->statements) && code->statements[stidx].o2.s1 == 1) {
2813                 code->statements[stidx] = code->statements[stidx+1];
2814                 if (code->statements[stidx].o1.s1 < 0)
2815                     code->statements[stidx].o1.s1++;
2816                 code_pop_statement(code);
2817             }
2818             /* if not, generate now */
2819             return gen_blocks_recursive(code, func, onfalse);
2820         }
2821
2822         if ( (instr->opcode >= INSTR_CALL0 && instr->opcode <= INSTR_CALL8)
2823            || instr->opcode == VINSTR_NRCALL)
2824         {
2825             size_t p, first;
2826             ir_value *retvalue;
2827
2828             first = vec_size(instr->params);
2829             if (first > 8)
2830                 first = 8;
2831             for (p = 0; p < first; ++p)
2832             {
2833                 ir_value *param = instr->params[p];
2834                 if (param->callparam)
2835                     continue;
2836
2837                 stmt.opcode = INSTR_STORE_F;
2838                 stmt.o3.u1 = 0;
2839
2840                 if (param->vtype == TYPE_FIELD)
2841                     stmt.opcode = field_store_instr[param->fieldtype];
2842                 else if (param->vtype == TYPE_NIL)
2843                     stmt.opcode = INSTR_STORE_V;
2844                 else
2845                     stmt.opcode = type_store_instr[param->vtype];
2846                 stmt.o1.u1 = ir_value_code_addr(param);
2847                 stmt.o2.u1 = OFS_PARM0 + 3 * p;
2848                 code_push_statement(code, &stmt, instr->context.line);
2849             }
2850             /* Now handle extparams */
2851             first = vec_size(instr->params);
2852             for (; p < first; ++p)
2853             {
2854                 ir_builder *ir = func->owner;
2855                 ir_value *param = instr->params[p];
2856                 ir_value *targetparam;
2857
2858                 if (param->callparam)
2859                     continue;
2860
2861                 if (p-8 >= vec_size(ir->extparams))
2862                     ir_gen_extparam(code, ir);
2863
2864                 targetparam = ir->extparams[p-8];
2865
2866                 stmt.opcode = INSTR_STORE_F;
2867                 stmt.o3.u1 = 0;
2868
2869                 if (param->vtype == TYPE_FIELD)
2870                     stmt.opcode = field_store_instr[param->fieldtype];
2871                 else if (param->vtype == TYPE_NIL)
2872                     stmt.opcode = INSTR_STORE_V;
2873                 else
2874                     stmt.opcode = type_store_instr[param->vtype];
2875                 stmt.o1.u1 = ir_value_code_addr(param);
2876                 stmt.o2.u1 = ir_value_code_addr(targetparam);
2877                 code_push_statement(code, &stmt, instr->context.line);
2878             }
2879
2880             stmt.opcode = INSTR_CALL0 + vec_size(instr->params);
2881             if (stmt.opcode > INSTR_CALL8)
2882                 stmt.opcode = INSTR_CALL8;
2883             stmt.o1.u1 = ir_value_code_addr(instr->_ops[1]);
2884             stmt.o2.u1 = 0;
2885             stmt.o3.u1 = 0;
2886             code_push_statement(code, &stmt, instr->context.line);
2887
2888             retvalue = instr->_ops[0];
2889             if (retvalue && retvalue->store != store_return &&
2890                 (retvalue->store == store_global || vec_size(retvalue->life)))
2891             {
2892                 /* not to be kept in OFS_RETURN */
2893                 if (retvalue->vtype == TYPE_FIELD && OPTS_FLAG(ADJUST_VECTOR_FIELDS))
2894                     stmt.opcode = field_store_instr[retvalue->fieldtype];
2895                 else
2896                     stmt.opcode = type_store_instr[retvalue->vtype];
2897                 stmt.o1.u1 = OFS_RETURN;
2898                 stmt.o2.u1 = ir_value_code_addr(retvalue);
2899                 stmt.o3.u1 = 0;
2900                 code_push_statement(code, &stmt, instr->context.line);
2901             }
2902             continue;
2903         }
2904
2905         if (instr->opcode == INSTR_STATE) {
2906             irerror(block->context, "TODO: state instruction");
2907             return false;
2908         }
2909
2910         stmt.opcode = instr->opcode;
2911         stmt.o1.u1 = 0;
2912         stmt.o2.u1 = 0;
2913         stmt.o3.u1 = 0;
2914
2915         /* This is the general order of operands */
2916         if (instr->_ops[0])
2917             stmt.o3.u1 = ir_value_code_addr(instr->_ops[0]);
2918
2919         if (instr->_ops[1])
2920             stmt.o1.u1 = ir_value_code_addr(instr->_ops[1]);
2921
2922         if (instr->_ops[2])
2923             stmt.o2.u1 = ir_value_code_addr(instr->_ops[2]);
2924
2925         if (stmt.opcode == INSTR_RETURN || stmt.opcode == INSTR_DONE)
2926         {
2927             stmt.o1.u1 = stmt.o3.u1;
2928             stmt.o3.u1 = 0;
2929         }
2930         else if ((stmt.opcode >= INSTR_STORE_F &&
2931                   stmt.opcode <= INSTR_STORE_FNC) ||
2932                  (stmt.opcode >= INSTR_STOREP_F &&
2933                   stmt.opcode <= INSTR_STOREP_FNC))
2934         {
2935             /* 2-operand instructions with A -> B */
2936             stmt.o2.u1 = stmt.o3.u1;
2937             stmt.o3.u1 = 0;
2938
2939             /* tiny optimization, don't output
2940              * STORE a, a
2941              */
2942             if (stmt.o2.u1 == stmt.o1.u1 &&
2943                 OPTS_OPTIMIZATION(OPTIM_PEEPHOLE))
2944             {
2945                 ++opts_optimizationcount[OPTIM_PEEPHOLE];
2946                 continue;
2947             }
2948         }
2949
2950         code_push_statement(code, &stmt, instr->context.line);
2951     }
2952     return true;
2953 }
2954
2955 static bool gen_function_code(code_t *code, ir_function *self)
2956 {
2957     ir_block *block;
2958     prog_section_statement stmt, *retst;
2959
2960     /* Starting from entry point, we generate blocks "as they come"
2961      * for now. Dead blocks will not be translated obviously.
2962      */
2963     if (!vec_size(self->blocks)) {
2964         irerror(self->context, "Function '%s' declared without body.", self->name);
2965         return false;
2966     }
2967
2968     block = self->blocks[0];
2969     if (block->generated)
2970         return true;
2971
2972     if (!gen_blocks_recursive(code, self, block)) {
2973         irerror(self->context, "failed to generate blocks for '%s'", self->name);
2974         return false;
2975     }
2976
2977     /* code_write and qcvm -disasm need to know that the function ends here */
2978     retst = &vec_last(code->statements);
2979     if (OPTS_OPTIMIZATION(OPTIM_VOID_RETURN) &&
2980         self->outtype == TYPE_VOID &&
2981         retst->opcode == INSTR_RETURN &&
2982         !retst->o1.u1 && !retst->o2.u1 && !retst->o3.u1)
2983     {
2984         retst->opcode = INSTR_DONE;
2985         ++opts_optimizationcount[OPTIM_VOID_RETURN];
2986     } else {
2987         stmt.opcode = INSTR_DONE;
2988         stmt.o1.u1 = 0;
2989         stmt.o2.u1 = 0;
2990         stmt.o3.u1 = 0;
2991         code_push_statement(code, &stmt, vec_last(code->linenums));
2992     }
2993     return true;
2994 }
2995
2996 static qcint ir_builder_filestring(code_t *code, ir_builder *ir, const char *filename)
2997 {
2998     /* NOTE: filename pointers are copied, we never strdup them,
2999      * thus we can use pointer-comparison to find the string.
3000      */
3001     size_t i;
3002     qcint  str;
3003
3004     for (i = 0; i < vec_size(ir->filenames); ++i) {
3005         if (ir->filenames[i] == filename)
3006             return ir->filestrings[i];
3007     }
3008
3009     str = code_genstring(code, filename);
3010     vec_push(ir->filenames, filename);
3011     vec_push(ir->filestrings, str);
3012     return str;
3013 }
3014
3015 static bool gen_global_function(code_t *code, ir_builder *ir, ir_value *global)
3016 {
3017     prog_section_function fun;
3018     ir_function          *irfun;
3019
3020     size_t i;
3021
3022     if (!global->hasvalue || (!global->constval.vfunc))
3023     {
3024         irerror(global->context, "Invalid state of function-global: not constant: %s", global->name);
3025         return false;
3026     }
3027
3028     irfun = global->constval.vfunc;
3029
3030     fun.name    = global->code.name;
3031     fun.file    = ir_builder_filestring(code, ir, global->context.file);
3032     fun.profile = 0; /* always 0 */
3033     fun.nargs   = vec_size(irfun->params);
3034     if (fun.nargs > 8)
3035         fun.nargs = 8;
3036
3037     for (i = 0;i < 8; ++i) {
3038         if ((int32_t)i >= fun.nargs)
3039             fun.argsize[i] = 0;
3040         else
3041             fun.argsize[i] = type_sizeof_[irfun->params[i]];
3042     }
3043
3044     fun.firstlocal = 0;
3045     fun.locals     = irfun->allocated_locals;
3046
3047     if (irfun->builtin)
3048         fun.entry = irfun->builtin+1;
3049     else {
3050         irfun->code_function_def = vec_size(code->functions);
3051         fun.entry                = vec_size(code->statements);
3052     }
3053
3054     vec_push(code->functions, fun);
3055     return true;
3056 }
3057
3058 static ir_value* ir_gen_extparam_proto(ir_builder *ir)
3059 {
3060     ir_value *global;
3061     char      name[128];
3062
3063     util_snprintf(name, sizeof(name), "EXTPARM#%i", (int)(vec_size(ir->extparam_protos)));
3064     global = ir_value_var(name, store_global, TYPE_VECTOR);
3065
3066     vec_push(ir->extparam_protos, global);
3067     return global;
3068 }
3069
3070 static void ir_gen_extparam(code_t *code, ir_builder *ir)
3071 {
3072     prog_section_def def;
3073     ir_value        *global;
3074
3075     if (vec_size(ir->extparam_protos) < vec_size(ir->extparams)+1)
3076         global = ir_gen_extparam_proto(ir);
3077     else
3078         global = ir->extparam_protos[vec_size(ir->extparams)];
3079
3080     def.name   = code_genstring(code, global->name);
3081     def.type   = TYPE_VECTOR;
3082     def.offset = vec_size(code->globals);
3083
3084     vec_push(code->defs, def);
3085
3086     ir_value_code_setaddr(global, def.offset);
3087
3088     vec_push(code->globals, 0);
3089     vec_push(code->globals, 0);
3090     vec_push(code->globals, 0);
3091
3092     vec_push(ir->extparams, global);
3093 }
3094
3095 static bool gen_function_extparam_copy(code_t *code, ir_function *self)
3096 {
3097     size_t i, ext, numparams;
3098
3099     ir_builder *ir = self->owner;
3100     ir_value   *ep;
3101     prog_section_statement stmt;
3102
3103     numparams = vec_size(self->params);
3104     if (!numparams)
3105         return true;
3106
3107     stmt.opcode = INSTR_STORE_F;
3108     stmt.o3.s1 = 0;
3109     for (i = 8; i < numparams; ++i) {
3110         ext = i - 8;
3111         if (ext >= vec_size(ir->extparams))
3112             ir_gen_extparam(code, ir);
3113
3114         ep = ir->extparams[ext];
3115
3116         stmt.opcode = type_store_instr[self->locals[i]->vtype];
3117         if (self->locals[i]->vtype == TYPE_FIELD &&
3118             self->locals[i]->fieldtype == TYPE_VECTOR)
3119         {
3120             stmt.opcode = INSTR_STORE_V;
3121         }
3122         stmt.o1.u1 = ir_value_code_addr(ep);
3123         stmt.o2.u1 = ir_value_code_addr(self->locals[i]);
3124         code_push_statement(code, &stmt, self->context.line);
3125     }
3126
3127     return true;
3128 }
3129
3130 static bool gen_function_varargs_copy(code_t *code, ir_function *self)
3131 {
3132     size_t i, ext, numparams, maxparams;
3133
3134     ir_builder *ir = self->owner;
3135     ir_value   *ep;
3136     prog_section_statement stmt;
3137
3138     numparams = vec_size(self->params);
3139     if (!numparams)
3140         return true;
3141
3142     stmt.opcode = INSTR_STORE_V;
3143     stmt.o3.s1 = 0;
3144     maxparams = numparams + self->max_varargs;
3145     for (i = numparams; i < maxparams; ++i) {
3146         if (i < 8) {
3147             stmt.o1.u1 = OFS_PARM0 + 3*i;
3148             stmt.o2.u1 = ir_value_code_addr(self->locals[i]);
3149             code_push_statement(code, &stmt, self->context.line);
3150             continue;
3151         }
3152         ext = i - 8;
3153         while (ext >= vec_size(ir->extparams))
3154             ir_gen_extparam(code, ir);
3155
3156         ep = ir->extparams[ext];
3157
3158         stmt.o1.u1 = ir_value_code_addr(ep);
3159         stmt.o2.u1 = ir_value_code_addr(self->locals[i]);
3160         code_push_statement(code, &stmt, self->context.line);
3161     }
3162
3163     return true;
3164 }
3165
3166 static bool gen_function_locals(code_t *code, ir_builder *ir, ir_value *global)
3167 {
3168     prog_section_function *def;
3169     ir_function           *irfun;
3170     size_t                 i;
3171     uint32_t               firstlocal, firstglobal;
3172
3173     irfun = global->constval.vfunc;
3174     def   = code->functions + irfun->code_function_def;
3175
3176     if (OPTS_OPTION_BOOL(OPTION_G) ||
3177         !OPTS_OPTIMIZATION(OPTIM_OVERLAP_LOCALS)        ||
3178         (irfun->flags & IR_FLAG_MASK_NO_OVERLAP))
3179     {
3180         firstlocal = def->firstlocal = vec_size(code->globals);
3181     } else {
3182         firstlocal = def->firstlocal = ir->first_common_local;
3183         ++opts_optimizationcount[OPTIM_OVERLAP_LOCALS];
3184     }
3185
3186     firstglobal = (OPTS_OPTIMIZATION(OPTIM_GLOBAL_TEMPS) ? ir->first_common_globaltemp : firstlocal);
3187
3188     for (i = vec_size(code->globals); i < firstlocal + irfun->allocated_locals; ++i)
3189         vec_push(code->globals, 0);
3190     for (i = 0; i < vec_size(irfun->locals); ++i) {
3191         ir_value *v = irfun->locals[i];
3192         if (v->locked || !OPTS_OPTIMIZATION(OPTIM_GLOBAL_TEMPS)) {
3193             ir_value_code_setaddr(v, firstlocal + v->code.local);
3194             if (!ir_builder_gen_global(code, ir, irfun->locals[i], true)) {
3195                 irerror(irfun->locals[i]->context, "failed to generate local %s", irfun->locals[i]->name);
3196                 return false;
3197             }
3198         }
3199         else
3200             ir_value_code_setaddr(v, firstglobal + v->code.local);
3201     }
3202     for (i = 0; i < vec_size(irfun->values); ++i)
3203     {
3204         ir_value *v = irfun->values[i];
3205         if (v->callparam)
3206             continue;
3207         if (v->locked)
3208             ir_value_code_setaddr(v, firstlocal + v->code.local);
3209         else
3210             ir_value_code_setaddr(v, firstglobal + v->code.local);
3211     }
3212     return true;
3213 }
3214
3215 static bool gen_global_function_code(code_t *code, ir_builder *ir, ir_value *global)
3216 {
3217     prog_section_function *fundef;
3218     ir_function           *irfun;
3219
3220     (void)ir;
3221
3222     irfun = global->constval.vfunc;
3223     if (!irfun) {
3224         if (global->cvq == CV_NONE) {
3225             irwarning(global->context, WARN_IMPLICIT_FUNCTION_POINTER,
3226                       "function `%s` has no body and in QC implicitly becomes a function-pointer", global->name);
3227         }
3228         /* this was a function pointer, don't generate code for those */
3229         return true;
3230     }
3231
3232     if (irfun->builtin)
3233         return true;
3234
3235     if (irfun->code_function_def < 0) {
3236         irerror(irfun->context, "`%s`: IR global wasn't generated, failed to access function-def", irfun->name);
3237         return false;
3238     }
3239     fundef = &code->functions[irfun->code_function_def];
3240
3241     fundef->entry = vec_size(code->statements);
3242     if (!gen_function_locals(code, ir, global)) {
3243         irerror(irfun->context, "Failed to generate locals for function %s", irfun->name);
3244         return false;
3245     }
3246     if (!gen_function_extparam_copy(code, irfun)) {
3247         irerror(irfun->context, "Failed to generate extparam-copy code for function %s", irfun->name);
3248         return false;
3249     }
3250     if (irfun->max_varargs && !gen_function_varargs_copy(code, irfun)) {
3251         irerror(irfun->context, "Failed to generate vararg-copy code for function %s", irfun->name);
3252         return false;
3253     }
3254     if (!gen_function_code(code, irfun)) {
3255         irerror(irfun->context, "Failed to generate code for function %s", irfun->name);
3256         return false;
3257     }
3258     return true;
3259 }
3260
3261 static void gen_vector_defs(code_t *code, prog_section_def def, const char *name)
3262 {
3263     char  *component;
3264     size_t len, i;
3265
3266     if (!name || name[0] == '#' || OPTS_FLAG(SINGLE_VECTOR_DEFS))
3267         return;
3268
3269     def.type = TYPE_FLOAT;
3270
3271     len = strlen(name);
3272
3273     component = (char*)mem_a(len+3);
3274     memcpy(component, name, len);
3275     len += 2;
3276     component[len-0] = 0;
3277     component[len-2] = '_';
3278
3279     component[len-1] = 'x';
3280
3281     for (i = 0; i < 3; ++i) {
3282         def.name = code_genstring(code, component);
3283         vec_push(code->defs, def);
3284         def.offset++;
3285         component[len-1]++;
3286     }
3287
3288     mem_d(component);
3289 }
3290
3291 static void gen_vector_fields(code_t *code, prog_section_field fld, const char *name)
3292 {
3293     char  *component;
3294     size_t len, i;
3295
3296     if (!name || OPTS_FLAG(SINGLE_VECTOR_DEFS))
3297         return;
3298
3299     fld.type = TYPE_FLOAT;
3300
3301     len = strlen(name);
3302
3303     component = (char*)mem_a(len+3);
3304     memcpy(component, name, len);
3305     len += 2;
3306     component[len-0] = 0;
3307     component[len-2] = '_';
3308
3309     component[len-1] = 'x';
3310
3311     for (i = 0; i < 3; ++i) {
3312         fld.name = code_genstring(code, component);
3313         vec_push(code->fields, fld);
3314         fld.offset++;
3315         component[len-1]++;
3316     }
3317
3318     mem_d(component);
3319 }
3320
3321 static bool ir_builder_gen_global(code_t *code, ir_builder *self, ir_value *global, bool islocal)
3322 {
3323     size_t           i;
3324     int32_t         *iptr;
3325     prog_section_def def;
3326     bool             pushdef = opts.optimizeoff;
3327
3328     def.type   = global->vtype;
3329     def.offset = vec_size(code->globals);
3330     def.name   = 0;
3331     if (OPTS_OPTION_BOOL(OPTION_G) || !islocal)
3332     {
3333         pushdef = true;
3334
3335         if (OPTS_OPTIMIZATION(OPTIM_STRIP_CONSTANT_NAMES) &&
3336             !(global->flags & IR_FLAG_INCLUDE_DEF) &&
3337             (global->name[0] == '#' || global->cvq == CV_CONST))
3338         {
3339             pushdef = false;
3340         }
3341
3342         if (pushdef && global->name) {
3343             if (global->name[0] == '#') {
3344                 if (!self->str_immediate)
3345                     self->str_immediate = code_genstring(code, "IMMEDIATE");
3346                 def.name = global->code.name = self->str_immediate;
3347             }
3348             else
3349                 def.name = global->code.name = code_genstring(code, global->name);
3350         }
3351         else
3352             def.name   = 0;
3353         if (islocal) {
3354             def.offset = ir_value_code_addr(global);
3355             vec_push(code->defs, def);
3356             if (global->vtype == TYPE_VECTOR)
3357                 gen_vector_defs(code, def, global->name);
3358             else if (global->vtype == TYPE_FIELD && global->fieldtype == TYPE_VECTOR)
3359                 gen_vector_defs(code, def, global->name);
3360             return true;
3361         }
3362     }
3363     if (islocal)
3364         return true;
3365
3366     switch (global->vtype)
3367     {
3368     case TYPE_VOID:
3369         if (!strcmp(global->name, "end_sys_globals")) {
3370             /* TODO: remember this point... all the defs before this one
3371              * should be checksummed and added to progdefs.h when we generate it.
3372              */
3373         }
3374         else if (!strcmp(global->name, "end_sys_fields")) {
3375             /* TODO: same as above but for entity-fields rather than globsl
3376              */
3377         }
3378         else
3379             irwarning(global->context, WARN_VOID_VARIABLES, "unrecognized variable of type void `%s`",
3380                       global->name);
3381         /* I'd argue setting it to 0 is sufficient, but maybe some depend on knowing how far
3382          * the system fields actually go? Though the engine knows this anyway...
3383          * Maybe this could be an -foption
3384          * fteqcc creates data for end_sys_* - of size 1, so let's do the same
3385          */
3386         ir_value_code_setaddr(global, vec_size(code->globals));
3387         vec_push(code->globals, 0);
3388         /* Add the def */
3389         if (pushdef) vec_push(code->defs, def);
3390         return true;
3391     case TYPE_POINTER:
3392         if (pushdef) vec_push(code->defs, def);
3393         return gen_global_pointer(code, global);
3394     case TYPE_FIELD:
3395         if (pushdef) {
3396             vec_push(code->defs, def);
3397             if (global->fieldtype == TYPE_VECTOR)
3398                 gen_vector_defs(code, def, global->name);
3399         }
3400         return gen_global_field(code, global);
3401     case TYPE_ENTITY:
3402         /* fall through */
3403     case TYPE_FLOAT:
3404     {
3405         ir_value_code_setaddr(global, vec_size(code->globals));
3406         if (global->hasvalue) {
3407             iptr = (int32_t*)&global->constval.ivec[0];
3408             vec_push(code->globals, *iptr);
3409         } else {
3410             vec_push(code->globals, 0);
3411         }
3412         if (!islocal && global->cvq != CV_CONST)
3413             def.type |= DEF_SAVEGLOBAL;
3414         if (pushdef) vec_push(code->defs, def);
3415
3416         return global->code.globaladdr >= 0;
3417     }
3418     case TYPE_STRING:
3419     {
3420         ir_value_code_setaddr(global, vec_size(code->globals));
3421         if (global->hasvalue) {
3422             uint32_t load = code_genstring(code, global->constval.vstring);
3423             vec_push(code->globals, load);
3424         } else {
3425             vec_push(code->globals, 0);
3426         }
3427         if (!islocal && global->cvq != CV_CONST)
3428             def.type |= DEF_SAVEGLOBAL;
3429         if (pushdef) vec_push(code->defs, def);
3430         return global->code.globaladdr >= 0;
3431     }
3432     case TYPE_VECTOR:
3433     {
3434         size_t d;
3435         ir_value_code_setaddr(global, vec_size(code->globals));
3436         if (global->hasvalue) {
3437             iptr = (int32_t*)&global->constval.ivec[0];
3438             vec_push(code->globals, iptr[0]);
3439             if (global->code.globaladdr < 0)
3440                 return false;
3441             for (d = 1; d < type_sizeof_[global->vtype]; ++d) {
3442                 vec_push(code->globals, iptr[d]);
3443             }
3444         } else {
3445             vec_push(code->globals, 0);
3446             if (global->code.globaladdr < 0)
3447                 return false;
3448             for (d = 1; d < type_sizeof_[global->vtype]; ++d) {
3449                 vec_push(code->globals, 0);
3450             }
3451         }
3452         if (!islocal && global->cvq != CV_CONST)
3453             def.type |= DEF_SAVEGLOBAL;
3454
3455         if (pushdef) {
3456             vec_push(code->defs, def);
3457             def.type &= ~DEF_SAVEGLOBAL;
3458             gen_vector_defs(code, def, global->name);
3459         }
3460         return global->code.globaladdr >= 0;
3461     }
3462     case TYPE_FUNCTION:
3463         ir_value_code_setaddr(global, vec_size(code->globals));
3464         if (!global->hasvalue) {
3465             vec_push(code->globals, 0);
3466             if (global->code.globaladdr < 0)
3467                 return false;
3468         } else {
3469             vec_push(code->globals, vec_size(code->functions));
3470             if (!gen_global_function(code, self, global))
3471                 return false;
3472         }
3473         if (!islocal && global->cvq != CV_CONST)
3474             def.type |= DEF_SAVEGLOBAL;
3475         if (pushdef) vec_push(code->defs, def);
3476         return true;
3477     case TYPE_VARIANT:
3478         /* assume biggest type */
3479             ir_value_code_setaddr(global, vec_size(code->globals));
3480             vec_push(code->globals, 0);
3481             for (i = 1; i < type_sizeof_[TYPE_VARIANT]; ++i)
3482                 vec_push(code->globals, 0);
3483             return true;
3484     default:
3485         /* refuse to create 'void' type or any other fancy business. */
3486         irerror(global->context, "Invalid type for global variable `%s`: %s",
3487                 global->name, type_name[global->vtype]);
3488         return false;
3489     }
3490 }
3491
3492 static GMQCC_INLINE void ir_builder_prepare_field(code_t *code, ir_value *field)
3493 {
3494     field->code.fieldaddr = code_alloc_field(code, type_sizeof_[field->fieldtype]);
3495 }
3496
3497 static bool ir_builder_gen_field(code_t *code, ir_builder *self, ir_value *field)
3498 {
3499     prog_section_def def;
3500     prog_section_field fld;
3501
3502     (void)self;
3503
3504     def.type   = (uint16_t)field->vtype;
3505     def.offset = (uint16_t)vec_size(code->globals);
3506
3507     /* create a global named the same as the field */
3508     if (OPTS_OPTION_U32(OPTION_STANDARD) == COMPILER_GMQCC) {
3509         /* in our standard, the global gets a dot prefix */
3510         size_t len = strlen(field->name);
3511         char name[1024];
3512
3513         /* we really don't want to have to allocate this, and 1024
3514          * bytes is more than enough for a variable/field name
3515          */
3516         if (len+2 >= sizeof(name)) {
3517             irerror(field->context, "invalid field name size: %u", (unsigned int)len);
3518             return false;
3519         }
3520
3521         name[0] = '.';
3522         memcpy(name+1, field->name, len); /* no strncpy - we used strlen above */
3523         name[len+1] = 0;
3524
3525         def.name = code_genstring(code, name);
3526         fld.name = def.name + 1; /* we reuse that string table entry */
3527     } else {
3528         /* in plain QC, there cannot be a global with the same name,
3529          * and so we also name the global the same.
3530          * FIXME: fteqcc should create a global as well
3531          * check if it actually uses the same name. Probably does
3532          */
3533         def.name = code_genstring(code, field->name);
3534         fld.name = def.name;
3535     }
3536
3537     field->code.name = def.name;
3538
3539     vec_push(code->defs, def);
3540
3541     fld.type = field->fieldtype;
3542
3543     if (fld.type == TYPE_VOID) {
3544         irerror(field->context, "field is missing a type: %s - don't know its size", field->name);
3545         return false;
3546     }
3547
3548     fld.offset = field->code.fieldaddr;
3549
3550     vec_push(code->fields, fld);
3551
3552     ir_value_code_setaddr(field, vec_size(code->globals));
3553     vec_push(code->globals, fld.offset);
3554     if (fld.type == TYPE_VECTOR) {
3555         vec_push(code->globals, fld.offset+1);
3556         vec_push(code->globals, fld.offset+2);
3557     }
3558
3559     if (field->fieldtype == TYPE_VECTOR) {
3560         gen_vector_defs  (code, def, field->name);
3561         gen_vector_fields(code, fld, field->name);
3562     }
3563
3564     return field->code.globaladdr >= 0;
3565 }
3566
3567 bool ir_builder_generate(code_t *code, ir_builder *self, const char *filename)
3568 {
3569     prog_section_statement stmt;
3570     size_t i;
3571     char  *lnofile = NULL;
3572
3573     code_init();
3574
3575     for (i = 0; i < vec_size(self->fields); ++i)
3576     {
3577         ir_builder_prepare_field(code, self->fields[i]);
3578     }
3579
3580     for (i = 0; i < vec_size(self->globals); ++i)
3581     {
3582         if (!ir_builder_gen_global(code, self, self->globals[i], false)) {
3583             return false;
3584         }
3585         if (self->globals[i]->vtype == TYPE_FUNCTION) {
3586             ir_function *func = self->globals[i]->constval.vfunc;
3587             if (func && self->max_locals < func->allocated_locals &&
3588                 !(func->flags & IR_FLAG_MASK_NO_OVERLAP))
3589             {
3590                 self->max_locals = func->allocated_locals;
3591             }
3592             if (func && self->max_globaltemps < func->globaltemps)
3593                 self->max_globaltemps = func->globaltemps;
3594         }
3595     }
3596
3597     for (i = 0; i < vec_size(self->fields); ++i)
3598     {
3599         if (!ir_builder_gen_field(code, self, self->fields[i])) {
3600             return false;
3601         }
3602     }
3603
3604     /* generate nil */
3605     ir_value_code_setaddr(self->nil, vec_size(code->globals));
3606     vec_push(code->globals, 0);
3607     vec_push(code->globals, 0);
3608     vec_push(code->globals, 0);
3609
3610     /* generate global temps */
3611     self->first_common_globaltemp = vec_size(code->globals);
3612     for (i = 0; i < self->max_globaltemps; ++i) {
3613         vec_push(code->globals, 0);
3614     }
3615     /* generate common locals */
3616     self->first_common_local = vec_size(code->globals);
3617     for (i = 0; i < self->max_locals; ++i) {
3618         vec_push(code->globals, 0);
3619     }
3620
3621     /* generate function code */
3622     for (i = 0; i < vec_size(self->globals); ++i)
3623     {
3624         if (self->globals[i]->vtype == TYPE_FUNCTION) {
3625             if (!gen_global_function_code(code, self, self->globals[i])) {
3626                 return false;
3627             }
3628         }
3629     }
3630
3631     if (vec_size(code->globals) >= 65536) {
3632         irerror(vec_last(self->globals)->context, "This progs file would require more globals than the metadata can handle. Bailing out.");
3633         return false;
3634     }
3635
3636     /* DP errors if the last instruction is not an INSTR_DONE. */
3637     if (vec_last(code->statements).opcode != INSTR_DONE)
3638     {
3639         stmt.opcode = INSTR_DONE;
3640         stmt.o1.u1 = 0;
3641         stmt.o2.u1 = 0;
3642         stmt.o3.u1 = 0;
3643         code_push_statement(code, &stmt, vec_last(code->linenums));
3644     }
3645
3646     if (OPTS_OPTION_BOOL(OPTION_PP_ONLY))
3647         return true;
3648
3649     if (vec_size(code->statements) != vec_size(code->linenums)) {
3650         con_err("Linecounter wrong: %lu != %lu\n",
3651                 (unsigned long)vec_size(code->statements),
3652                 (unsigned long)vec_size(code->linenums));
3653     } else if (OPTS_FLAG(LNO)) {
3654         char  *dot;
3655         size_t filelen = strlen(filename);
3656
3657         memcpy(vec_add(lnofile, filelen+1), filename, filelen+1);
3658         dot = strrchr(lnofile, '.');
3659         if (!dot) {
3660             vec_pop(lnofile);
3661         } else {
3662             vec_shrinkto(lnofile, dot - lnofile);
3663         }
3664         memcpy(vec_add(lnofile, 5), ".lno", 5);
3665     }
3666
3667     if (!OPTS_OPTION_BOOL(OPTION_QUIET)) {
3668         if (lnofile)
3669             con_out("writing '%s' and '%s'...\n", filename, lnofile);
3670         else
3671             con_out("writing '%s'\n", filename);
3672     }
3673     if (!code_write(code, filename, lnofile)) {
3674         vec_free(lnofile);
3675         return false;
3676     }
3677     vec_free(lnofile);
3678     return true;
3679 }
3680
3681 /***********************************************************************
3682  *IR DEBUG Dump functions...
3683  */
3684
3685 #define IND_BUFSZ 1024
3686
3687 #ifdef _MSC_VER
3688 #   define strncat(dst, src, sz) strncat_s(dst, sz, src, _TRUNCATE)
3689 #endif
3690
3691 const char *qc_opname(int op)
3692 {
3693     if (op < 0) return "<INVALID>";
3694     if (op < (int)( sizeof(asm_instr) / sizeof(asm_instr[0]) ))
3695         return asm_instr[op].m;
3696     switch (op) {
3697         case VINSTR_PHI:  return "PHI";
3698         case VINSTR_JUMP: return "JUMP";
3699         case VINSTR_COND: return "COND";
3700         default:          return "<UNK>";
3701     }
3702 }
3703
3704 void ir_builder_dump(ir_builder *b, int (*oprintf)(const char*, ...))
3705 {
3706     size_t i;
3707     char indent[IND_BUFSZ];
3708     indent[0] = '\t';
3709     indent[1] = 0;
3710
3711     oprintf("module %s\n", b->name);
3712     for (i = 0; i < vec_size(b->globals); ++i)
3713     {
3714         oprintf("global ");
3715         if (b->globals[i]->hasvalue)
3716             oprintf("%s = ", b->globals[i]->name);
3717         ir_value_dump(b->globals[i], oprintf);
3718         oprintf("\n");
3719     }
3720     for (i = 0; i < vec_size(b->functions); ++i)
3721         ir_function_dump(b->functions[i], indent, oprintf);
3722     oprintf("endmodule %s\n", b->name);
3723 }
3724
3725 static const char *storenames[] = {
3726     "[global]", "[local]", "[param]", "[value]", "[return]"
3727 };
3728
3729 void ir_function_dump(ir_function *f, char *ind,
3730                       int (*oprintf)(const char*, ...))
3731 {
3732     size_t i;
3733     if (f->builtin != 0) {
3734         oprintf("%sfunction %s = builtin %i\n", ind, f->name, -f->builtin);
3735         return;
3736     }
3737     oprintf("%sfunction %s\n", ind, f->name);
3738     strncat(ind, "\t", IND_BUFSZ);
3739     if (vec_size(f->locals))
3740     {
3741         oprintf("%s%i locals:\n", ind, (int)vec_size(f->locals));
3742         for (i = 0; i < vec_size(f->locals); ++i) {
3743             oprintf("%s\t", ind);
3744             ir_value_dump(f->locals[i], oprintf);
3745             oprintf("\n");
3746         }
3747     }
3748     oprintf("%sliferanges:\n", ind);
3749     for (i = 0; i < vec_size(f->locals); ++i) {
3750         const char *attr = "";
3751         size_t l, m;
3752         ir_value *v = f->locals[i];
3753         if (v->unique_life && v->locked)
3754             attr = "unique,locked ";
3755         else if (v->unique_life)
3756             attr = "unique ";
3757         else if (v->locked)
3758             attr = "locked ";
3759         oprintf("%s\t%s: %s %s %s%s@%i ", ind, v->name, type_name[v->vtype],
3760                 storenames[v->store],
3761                 attr, (v->callparam ? "callparam " : ""),
3762                 (int)v->code.local);
3763         if (!v->life)
3764             oprintf("[null]");
3765         for (l = 0; l < vec_size(v->life); ++l) {
3766             oprintf("[%i,%i] ", v->life[l].start, v->life[l].end);
3767         }
3768         oprintf("\n");
3769         for (m = 0; m < 3; ++m) {
3770             ir_value *vm = v->members[m];
3771             if (!vm)
3772                 continue;
3773             oprintf("%s\t%s: @%i ", ind, vm->name, (int)vm->code.local);
3774             for (l = 0; l < vec_size(vm->life); ++l) {
3775                 oprintf("[%i,%i] ", vm->life[l].start, vm->life[l].end);
3776             }
3777             oprintf("\n");
3778         }
3779     }
3780     for (i = 0; i < vec_size(f->values); ++i) {
3781         const char *attr = "";
3782         size_t l, m;
3783         ir_value *v = f->values[i];
3784         if (v->unique_life && v->locked)
3785             attr = "unique,locked ";
3786         else if (v->unique_life)
3787             attr = "unique ";
3788         else if (v->locked)
3789             attr = "locked ";
3790         oprintf("%s\t%s: %s %s %s%s@%i ", ind, v->name, type_name[v->vtype],
3791                 storenames[v->store],
3792                 attr, (v->callparam ? "callparam " : ""),
3793                 (int)v->code.local);
3794         if (!v->life)
3795             oprintf("[null]");
3796         for (l = 0; l < vec_size(v->life); ++l) {
3797             oprintf("[%i,%i] ", v->life[l].start, v->life[l].end);
3798         }
3799         oprintf("\n");
3800         for (m = 0; m < 3; ++m) {
3801             ir_value *vm = v->members[m];
3802             if (!vm)
3803                 continue;
3804             if (vm->unique_life && vm->locked)
3805                 attr = "unique,locked ";
3806             else if (vm->unique_life)
3807                 attr = "unique ";
3808             else if (vm->locked)
3809                 attr = "locked ";
3810             oprintf("%s\t%s: %s@%i ", ind, vm->name, attr, (int)vm->code.local);
3811             for (l = 0; l < vec_size(vm->life); ++l) {
3812                 oprintf("[%i,%i] ", vm->life[l].start, vm->life[l].end);
3813             }
3814             oprintf("\n");
3815         }
3816     }
3817     if (vec_size(f->blocks))
3818     {
3819         oprintf("%slife passes: %i\n", ind, (int)f->run_id);
3820         for (i = 0; i < vec_size(f->blocks); ++i) {
3821             ir_block_dump(f->blocks[i], ind, oprintf);
3822         }
3823
3824     }
3825     ind[strlen(ind)-1] = 0;
3826     oprintf("%sendfunction %s\n", ind, f->name);
3827 }
3828
3829 void ir_block_dump(ir_block* b, char *ind,
3830                    int (*oprintf)(const char*, ...))
3831 {
3832     size_t i;
3833     oprintf("%s:%s\n", ind, b->label);
3834     strncat(ind, "\t", IND_BUFSZ);
3835
3836     if (b->instr && b->instr[0])
3837         oprintf("%s (%i) [entry]\n", ind, (int)(b->instr[0]->eid-1));
3838     for (i = 0; i < vec_size(b->instr); ++i)
3839         ir_instr_dump(b->instr[i], ind, oprintf);
3840     ind[strlen(ind)-1] = 0;
3841 }
3842
3843 void dump_phi(ir_instr *in, int (*oprintf)(const char*, ...))
3844 {
3845     size_t i;
3846     oprintf("%s <- phi ", in->_ops[0]->name);
3847     for (i = 0; i < vec_size(in->phi); ++i)
3848     {
3849         oprintf("([%s] : %s) ", in->phi[i].from->label,
3850                                 in->phi[i].value->name);
3851     }
3852     oprintf("\n");
3853 }
3854
3855 void ir_instr_dump(ir_instr *in, char *ind,
3856                        int (*oprintf)(const char*, ...))
3857 {
3858     size_t i;
3859     const char *comma = NULL;
3860
3861     oprintf("%s (%i) ", ind, (int)in->eid);
3862
3863     if (in->opcode == VINSTR_PHI) {
3864         dump_phi(in, oprintf);
3865         return;
3866     }
3867
3868     strncat(ind, "\t", IND_BUFSZ);
3869
3870     if (in->_ops[0] && (in->_ops[1] || in->_ops[2])) {
3871         ir_value_dump(in->_ops[0], oprintf);
3872         if (in->_ops[1] || in->_ops[2])
3873             oprintf(" <- ");
3874     }
3875     if (in->opcode == INSTR_CALL0 || in->opcode == VINSTR_NRCALL) {
3876         oprintf("CALL%i\t", vec_size(in->params));
3877     } else
3878         oprintf("%s\t", qc_opname(in->opcode));
3879
3880     if (in->_ops[0] && !(in->_ops[1] || in->_ops[2])) {
3881         ir_value_dump(in->_ops[0], oprintf);
3882         comma = ",\t";
3883     }
3884     else
3885     {
3886         for (i = 1; i != 3; ++i) {
3887             if (in->_ops[i]) {
3888                 if (comma)
3889                     oprintf(comma);
3890                 ir_value_dump(in->_ops[i], oprintf);
3891                 comma = ",\t";
3892             }
3893         }
3894     }
3895     if (in->bops[0]) {
3896         if (comma)
3897             oprintf(comma);
3898         oprintf("[%s]", in->bops[0]->label);
3899         comma = ",\t";
3900     }
3901     if (in->bops[1])
3902         oprintf("%s[%s]", comma, in->bops[1]->label);
3903     if (vec_size(in->params)) {
3904         oprintf("\tparams: ");
3905         for (i = 0; i != vec_size(in->params); ++i) {
3906             oprintf("%s, ", in->params[i]->name);
3907         }
3908     }
3909     oprintf("\n");
3910     ind[strlen(ind)-1] = 0;
3911 }
3912
3913 void ir_value_dump_string(const char *str, int (*oprintf)(const char*, ...))
3914 {
3915     oprintf("\"");
3916     for (; *str; ++str) {
3917         switch (*str) {
3918             case '\n': oprintf("\\n"); break;
3919             case '\r': oprintf("\\r"); break;
3920             case '\t': oprintf("\\t"); break;
3921             case '\v': oprintf("\\v"); break;
3922             case '\f': oprintf("\\f"); break;
3923             case '\b': oprintf("\\b"); break;
3924             case '\a': oprintf("\\a"); break;
3925             case '\\': oprintf("\\\\"); break;
3926             case '"': oprintf("\\\""); break;
3927             default: oprintf("%c", *str); break;
3928         }
3929     }
3930     oprintf("\"");
3931 }
3932
3933 void ir_value_dump(ir_value* v, int (*oprintf)(const char*, ...))
3934 {
3935     if (v->hasvalue) {
3936         switch (v->vtype) {
3937             default:
3938             case TYPE_VOID:
3939                 oprintf("(void)");
3940                 break;
3941             case TYPE_FUNCTION:
3942                 oprintf("fn:%s", v->name);
3943                 break;
3944             case TYPE_FLOAT:
3945                 oprintf("%g", v->constval.vfloat);
3946                 break;
3947             case TYPE_VECTOR:
3948                 oprintf("'%g %g %g'",
3949                         v->constval.vvec.x,
3950                         v->constval.vvec.y,
3951                         v->constval.vvec.z);
3952                 break;
3953             case TYPE_ENTITY:
3954                 oprintf("(entity)");
3955                 break;
3956             case TYPE_STRING:
3957                 ir_value_dump_string(v->constval.vstring, oprintf);
3958                 break;
3959 #if 0
3960             case TYPE_INTEGER:
3961                 oprintf("%i", v->constval.vint);
3962                 break;
3963 #endif
3964             case TYPE_POINTER:
3965                 oprintf("&%s",
3966                     v->constval.vpointer->name);
3967                 break;
3968         }
3969     } else {
3970         oprintf("%s", v->name);
3971     }
3972 }
3973
3974 void ir_value_dump_life(const ir_value *self, int (*oprintf)(const char*,...))
3975 {
3976     size_t i;
3977     oprintf("Life of %12s:", self->name);
3978     for (i = 0; i < vec_size(self->life); ++i)
3979     {
3980         oprintf(" + [%i, %i]\n", self->life[i].start, self->life[i].end);
3981     }
3982 }