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