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