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