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