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