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