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