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