]> git.xonotic.org Git - xonotic/gmqcc.git/blob - ir.c
Set the full const/var qualifier; only generate warnings about unimplemented function...
[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, 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, 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(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.file = "<@no context>";
739     self->context.line = 0;
740     self->opcode = op;
741     self->_ops[0] = NULL;
742     self->_ops[1] = NULL;
743     self->_ops[2] = NULL;
744     self->bops[0] = NULL;
745     self->bops[1] = NULL;
746
747     self->phi    = NULL;
748     self->params = NULL;
749
750     self->eid = 0;
751
752     self->likely = true;
753     return self;
754 }
755
756 static void ir_instr_delete_quick(ir_instr *self)
757 {
758     vec_free(self->phi);
759     vec_free(self->params);
760     mem_d(self);
761 }
762
763 void ir_instr_delete(ir_instr *self)
764 {
765     size_t i;
766     /* The following calls can only delete from
767      * vectors, we still want to delete this instruction
768      * so ignore the return value. Since with the warn_unused_result attribute
769      * gcc doesn't care about an explicit: (void)foo(); to ignore the result,
770      * I have to improvise here and use if(foo());
771      */
772     for (i = 0; i < vec_size(self->phi); ++i) {
773         size_t idx;
774         if (vec_ir_instr_find(self->phi[i].value->writes, self, &idx))
775             vec_remove(self->phi[i].value->writes, idx, 1);
776         if (vec_ir_instr_find(self->phi[i].value->reads, self, &idx))
777             vec_remove(self->phi[i].value->reads, idx, 1);
778     }
779     vec_free(self->phi);
780     for (i = 0; i < vec_size(self->params); ++i) {
781         size_t idx;
782         if (vec_ir_instr_find(self->params[i]->writes, self, &idx))
783             vec_remove(self->params[i]->writes, idx, 1);
784         if (vec_ir_instr_find(self->params[i]->reads, self, &idx))
785             vec_remove(self->params[i]->reads, idx, 1);
786     }
787     vec_free(self->params);
788     (void)!ir_instr_op(self, 0, NULL, false);
789     (void)!ir_instr_op(self, 1, NULL, false);
790     (void)!ir_instr_op(self, 2, NULL, false);
791     mem_d(self);
792 }
793
794 bool ir_instr_op(ir_instr *self, int op, ir_value *v, bool writing)
795 {
796     if (self->_ops[op]) {
797         size_t idx;
798         if (writing && vec_ir_instr_find(self->_ops[op]->writes, self, &idx))
799             vec_remove(self->_ops[op]->writes, idx, 1);
800         else if (vec_ir_instr_find(self->_ops[op]->reads, self, &idx))
801             vec_remove(self->_ops[op]->reads, idx, 1);
802     }
803     if (v) {
804         if (writing)
805             vec_push(v->writes, self);
806         else
807             vec_push(v->reads, self);
808     }
809     self->_ops[op] = v;
810     return true;
811 }
812
813 /***********************************************************************
814  *IR Value
815  */
816
817 void ir_value_code_setaddr(ir_value *self, int32_t gaddr)
818 {
819     self->code.globaladdr = gaddr;
820     if (self->members[0]) self->members[0]->code.globaladdr = gaddr;
821     if (self->members[1]) self->members[1]->code.globaladdr = gaddr;
822     if (self->members[2]) self->members[2]->code.globaladdr = gaddr;
823 }
824
825 int32_t ir_value_code_addr(const ir_value *self)
826 {
827     if (self->store == store_return)
828         return OFS_RETURN + self->code.addroffset;
829     return self->code.globaladdr + self->code.addroffset;
830 }
831
832 ir_value* ir_value_var(const char *name, int storetype, int vtype)
833 {
834     ir_value *self;
835     self = (ir_value*)mem_a(sizeof(*self));
836     self->vtype = vtype;
837     self->fieldtype = TYPE_VOID;
838     self->outtype = TYPE_VOID;
839     self->store = storetype;
840
841     self->reads  = NULL;
842     self->writes = NULL;
843
844     self->cvq          = CV_NONE;
845     self->hasvalue     = false;
846     self->context.file = "<@no context>";
847     self->context.line = 0;
848     self->name = NULL;
849     if (name && !ir_value_set_name(self, name)) {
850         irerror(self->context, "out of memory");
851         mem_d(self);
852         return NULL;
853     }
854
855     memset(&self->constval, 0, sizeof(self->constval));
856     memset(&self->code,     0, sizeof(self->code));
857
858     self->members[0] = NULL;
859     self->members[1] = NULL;
860     self->members[2] = NULL;
861     self->memberof = NULL;
862
863     self->life = NULL;
864     return self;
865 }
866
867 ir_value* ir_value_vector_member(ir_value *self, unsigned int member)
868 {
869     ir_value *m;
870     if (member >= 3)
871         return NULL;
872
873     if (self->members[member])
874         return self->members[member];
875
876     if (self->vtype == TYPE_VECTOR)
877     {
878         m = ir_value_var(self->name, self->store, TYPE_FLOAT);
879         if (!m)
880             return NULL;
881         m->context = self->context;
882
883         self->members[member] = m;
884         m->code.addroffset = member;
885     }
886     else if (self->vtype == TYPE_FIELD)
887     {
888         if (self->fieldtype != TYPE_VECTOR)
889             return NULL;
890         m = ir_value_var(self->name, self->store, TYPE_FIELD);
891         if (!m)
892             return NULL;
893         m->fieldtype = TYPE_FLOAT;
894         m->context = self->context;
895
896         self->members[member] = m;
897         m->code.addroffset = member;
898     }
899     else
900     {
901         irerror(self->context, "invalid member access on %s", self->name);
902         return NULL;
903     }
904
905     m->memberof = self;
906     return m;
907 }
908
909 ir_value* ir_value_out(ir_function *owner, const char *name, int storetype, int vtype)
910 {
911     ir_value *v = ir_value_var(name, storetype, vtype);
912     if (!v)
913         return NULL;
914     ir_function_collect_value(owner, v);
915     return v;
916 }
917
918 void ir_value_delete(ir_value* self)
919 {
920     size_t i;
921     if (self->name)
922         mem_d((void*)self->name);
923     if (self->hasvalue)
924     {
925         if (self->vtype == TYPE_STRING)
926             mem_d((void*)self->constval.vstring);
927     }
928     for (i = 0; i < 3; ++i) {
929         if (self->members[i])
930             ir_value_delete(self->members[i]);
931     }
932     vec_free(self->reads);
933     vec_free(self->writes);
934     vec_free(self->life);
935     mem_d(self);
936 }
937
938 bool ir_value_set_name(ir_value *self, const char *name)
939 {
940     if (self->name)
941         mem_d((void*)self->name);
942     self->name = util_strdup(name);
943     return !!self->name;
944 }
945
946 bool ir_value_set_float(ir_value *self, float f)
947 {
948     if (self->vtype != TYPE_FLOAT)
949         return false;
950     self->constval.vfloat = f;
951     self->hasvalue = true;
952     return true;
953 }
954
955 bool ir_value_set_func(ir_value *self, int f)
956 {
957     if (self->vtype != TYPE_FUNCTION)
958         return false;
959     self->constval.vint = f;
960     self->hasvalue = true;
961     return true;
962 }
963
964 bool ir_value_set_vector(ir_value *self, vector v)
965 {
966     if (self->vtype != TYPE_VECTOR)
967         return false;
968     self->constval.vvec = v;
969     self->hasvalue = true;
970     return true;
971 }
972
973 bool ir_value_set_field(ir_value *self, ir_value *fld)
974 {
975     if (self->vtype != TYPE_FIELD)
976         return false;
977     self->constval.vpointer = fld;
978     self->hasvalue = true;
979     return true;
980 }
981
982 static char *ir_strdup(const char *str)
983 {
984     if (str && !*str) {
985         /* actually dup empty strings */
986         char *out = mem_a(1);
987         *out = 0;
988         return out;
989     }
990     return util_strdup(str);
991 }
992
993 bool ir_value_set_string(ir_value *self, const char *str)
994 {
995     if (self->vtype != TYPE_STRING)
996         return false;
997     self->constval.vstring = ir_strdup(str);
998     self->hasvalue = true;
999     return true;
1000 }
1001
1002 #if 0
1003 bool ir_value_set_int(ir_value *self, int i)
1004 {
1005     if (self->vtype != TYPE_INTEGER)
1006         return false;
1007     self->constval.vint = i;
1008     self->hasvalue = true;
1009     return true;
1010 }
1011 #endif
1012
1013 bool ir_value_lives(ir_value *self, size_t at)
1014 {
1015     size_t i;
1016     for (i = 0; i < vec_size(self->life); ++i)
1017     {
1018         ir_life_entry_t *life = &self->life[i];
1019         if (life->start <= at && at <= life->end)
1020             return true;
1021         if (life->start > at) /* since it's ordered */
1022             return false;
1023     }
1024     return false;
1025 }
1026
1027 bool ir_value_life_insert(ir_value *self, size_t idx, ir_life_entry_t e)
1028 {
1029     size_t k;
1030     vec_push(self->life, e);
1031     for (k = vec_size(self->life)-1; k > idx; --k)
1032         self->life[k] = self->life[k-1];
1033     self->life[idx] = e;
1034     return true;
1035 }
1036
1037 bool ir_value_life_merge(ir_value *self, size_t s)
1038 {
1039     size_t i;
1040     ir_life_entry_t *life = NULL;
1041     ir_life_entry_t *before = NULL;
1042     ir_life_entry_t new_entry;
1043
1044     /* Find the first range >= s */
1045     for (i = 0; i < vec_size(self->life); ++i)
1046     {
1047         before = life;
1048         life = &self->life[i];
1049         if (life->start > s)
1050             break;
1051     }
1052     /* nothing found? append */
1053     if (i == vec_size(self->life)) {
1054         ir_life_entry_t e;
1055         if (life && life->end+1 == s)
1056         {
1057             /* previous life range can be merged in */
1058             life->end++;
1059             return true;
1060         }
1061         if (life && life->end >= s)
1062             return false;
1063         e.start = e.end = s;
1064         vec_push(self->life, e);
1065         return true;
1066     }
1067     /* found */
1068     if (before)
1069     {
1070         if (before->end + 1 == s &&
1071             life->start - 1 == s)
1072         {
1073             /* merge */
1074             before->end = life->end;
1075             vec_remove(self->life, i, 1);
1076             return true;
1077         }
1078         if (before->end + 1 == s)
1079         {
1080             /* extend before */
1081             before->end++;
1082             return true;
1083         }
1084         /* already contained */
1085         if (before->end >= s)
1086             return false;
1087     }
1088     /* extend */
1089     if (life->start - 1 == s)
1090     {
1091         life->start--;
1092         return true;
1093     }
1094     /* insert a new entry */
1095     new_entry.start = new_entry.end = s;
1096     return ir_value_life_insert(self, i, new_entry);
1097 }
1098
1099 bool ir_value_life_merge_into(ir_value *self, const ir_value *other)
1100 {
1101     size_t i, myi;
1102
1103     if (!vec_size(other->life))
1104         return true;
1105
1106     if (!vec_size(self->life)) {
1107         size_t count = vec_size(other->life);
1108         ir_life_entry_t *life = vec_add(self->life, count);
1109         memcpy(life, other->life, count * sizeof(*life));
1110         return true;
1111     }
1112
1113     myi = 0;
1114     for (i = 0; i < vec_size(other->life); ++i)
1115     {
1116         const ir_life_entry_t *life = &other->life[i];
1117         while (true)
1118         {
1119             ir_life_entry_t *entry = &self->life[myi];
1120
1121             if (life->end+1 < entry->start)
1122             {
1123                 /* adding an interval before entry */
1124                 if (!ir_value_life_insert(self, myi, *life))
1125                     return false;
1126                 ++myi;
1127                 break;
1128             }
1129
1130             if (life->start <  entry->start &&
1131                 life->end+1 >= entry->start)
1132             {
1133                 /* starts earlier and overlaps */
1134                 entry->start = life->start;
1135             }
1136
1137             if (life->end   >  entry->end &&
1138                 life->start <= entry->end+1)
1139             {
1140                 /* ends later and overlaps */
1141                 entry->end = life->end;
1142             }
1143
1144             /* see if our change combines it with the next ranges */
1145             while (myi+1 < vec_size(self->life) &&
1146                    entry->end+1 >= self->life[1+myi].start)
1147             {
1148                 /* overlaps with (myi+1) */
1149                 if (entry->end < self->life[1+myi].end)
1150                     entry->end = self->life[1+myi].end;
1151                 vec_remove(self->life, myi+1, 1);
1152                 entry = &self->life[myi];
1153             }
1154
1155             /* see if we're after the entry */
1156             if (life->start > entry->end)
1157             {
1158                 ++myi;
1159                 /* append if we're at the end */
1160                 if (myi >= vec_size(self->life)) {
1161                     vec_push(self->life, *life);
1162                     break;
1163                 }
1164                 /* otherweise check the next range */
1165                 continue;
1166             }
1167             break;
1168         }
1169     }
1170     return true;
1171 }
1172
1173 bool ir_values_overlap(const ir_value *a, const ir_value *b)
1174 {
1175     /* For any life entry in A see if it overlaps with
1176      * any life entry in B.
1177      * Note that the life entries are orderes, so we can make a
1178      * more efficient algorithm there than naively translating the
1179      * statement above.
1180      */
1181
1182     ir_life_entry_t *la, *lb, *enda, *endb;
1183
1184     /* first of all, if either has no life range, they cannot clash */
1185     if (!vec_size(a->life) || !vec_size(b->life))
1186         return false;
1187
1188     la = a->life;
1189     lb = b->life;
1190     enda = la + vec_size(a->life);
1191     endb = lb + vec_size(b->life);
1192     while (true)
1193     {
1194         /* check if the entries overlap, for that,
1195          * both must start before the other one ends.
1196          */
1197         if (la->start < lb->end &&
1198             lb->start < la->end)
1199         {
1200             return true;
1201         }
1202
1203         /* entries are ordered
1204          * one entry is earlier than the other
1205          * that earlier entry will be moved forward
1206          */
1207         if (la->start < lb->start)
1208         {
1209             /* order: A B, move A forward
1210              * check if we hit the end with A
1211              */
1212             if (++la == enda)
1213                 break;
1214         }
1215         else /* if (lb->start < la->start)  actually <= */
1216         {
1217             /* order: B A, move B forward
1218              * check if we hit the end with B
1219              */
1220             if (++lb == endb)
1221                 break;
1222         }
1223     }
1224     return false;
1225 }
1226
1227 /***********************************************************************
1228  *IR main operations
1229  */
1230
1231 bool ir_block_create_store_op(ir_block *self, int op, ir_value *target, ir_value *what)
1232 {
1233     ir_instr *in;
1234     if (self->final) {
1235         irerror(self->context, "unreachable statement (%s)", self->label);
1236         return false;
1237     }
1238     in = ir_instr_new(self, op);
1239     if (!in)
1240         return false;
1241
1242     if (target->store == store_value &&
1243         (op < INSTR_STOREP_F || op > INSTR_STOREP_FNC))
1244     {
1245         irerror(self->context, "cannot store to an SSA value");
1246         irerror(self->context, "trying to store: %s <- %s", target->name, what->name);
1247         irerror(self->context, "instruction: %s", asm_instr[op].m);
1248         return false;
1249     }
1250
1251     if (!ir_instr_op(in, 0, target, true) ||
1252         !ir_instr_op(in, 1, what, false))
1253     {
1254         return false;
1255     }
1256     vec_push(self->instr, in);
1257     return true;
1258 }
1259
1260 bool ir_block_create_store(ir_block *self, ir_value *target, ir_value *what)
1261 {
1262     int op = 0;
1263     int vtype;
1264     if (target->vtype == TYPE_VARIANT)
1265         vtype = what->vtype;
1266     else
1267         vtype = target->vtype;
1268
1269 #if 0
1270     if      (vtype == TYPE_FLOAT   && what->vtype == TYPE_INTEGER)
1271         op = INSTR_CONV_ITOF;
1272     else if (vtype == TYPE_INTEGER && what->vtype == TYPE_FLOAT)
1273         op = INSTR_CONV_FTOI;
1274 #endif
1275         op = type_store_instr[vtype];
1276
1277     if (OPTS_FLAG(ADJUST_VECTOR_FIELDS)) {
1278         if (op == INSTR_STORE_FLD && what->fieldtype == TYPE_VECTOR)
1279             op = INSTR_STORE_V;
1280     }
1281
1282     return ir_block_create_store_op(self, op, target, what);
1283 }
1284
1285 bool ir_block_create_storep(ir_block *self, ir_value *target, ir_value *what)
1286 {
1287     int op = 0;
1288     int vtype;
1289
1290     if (target->vtype != TYPE_POINTER)
1291         return false;
1292
1293     /* storing using pointer - target is a pointer, type must be
1294      * inferred from source
1295      */
1296     vtype = what->vtype;
1297
1298     op = type_storep_instr[vtype];
1299     if (OPTS_FLAG(ADJUST_VECTOR_FIELDS)) {
1300         if (op == INSTR_STOREP_FLD && what->fieldtype == TYPE_VECTOR)
1301             op = INSTR_STOREP_V;
1302     }
1303
1304     return ir_block_create_store_op(self, op, target, what);
1305 }
1306
1307 bool ir_block_create_return(ir_block *self, ir_value *v)
1308 {
1309     ir_instr *in;
1310     if (self->final) {
1311         irerror(self->context, "unreachable statement (%s)", self->label);
1312         return false;
1313     }
1314     self->final = true;
1315     self->is_return = true;
1316     in = ir_instr_new(self, INSTR_RETURN);
1317     if (!in)
1318         return false;
1319
1320     if (v && !ir_instr_op(in, 0, v, false))
1321         return false;
1322
1323     vec_push(self->instr, in);
1324     return true;
1325 }
1326
1327 bool ir_block_create_if(ir_block *self, ir_value *v,
1328                         ir_block *ontrue, ir_block *onfalse)
1329 {
1330     ir_instr *in;
1331     if (self->final) {
1332         irerror(self->context, "unreachable statement (%s)", self->label);
1333         return false;
1334     }
1335     self->final = true;
1336     /*in = ir_instr_new(self, (v->vtype == TYPE_STRING ? INSTR_IF_S : INSTR_IF_F));*/
1337     in = ir_instr_new(self, VINSTR_COND);
1338     if (!in)
1339         return false;
1340
1341     if (!ir_instr_op(in, 0, v, false)) {
1342         ir_instr_delete(in);
1343         return false;
1344     }
1345
1346     in->bops[0] = ontrue;
1347     in->bops[1] = onfalse;
1348
1349     vec_push(self->instr, in);
1350
1351     vec_push(self->exits, ontrue);
1352     vec_push(self->exits, onfalse);
1353     vec_push(ontrue->entries,  self);
1354     vec_push(onfalse->entries, self);
1355     return true;
1356 }
1357
1358 bool ir_block_create_jump(ir_block *self, ir_block *to)
1359 {
1360     ir_instr *in;
1361     if (self->final) {
1362         irerror(self->context, "unreachable statement (%s)", self->label);
1363         return false;
1364     }
1365     self->final = true;
1366     in = ir_instr_new(self, VINSTR_JUMP);
1367     if (!in)
1368         return false;
1369
1370     in->bops[0] = to;
1371     vec_push(self->instr, in);
1372
1373     vec_push(self->exits, to);
1374     vec_push(to->entries, self);
1375     return true;
1376 }
1377
1378 bool ir_block_create_goto(ir_block *self, ir_block *to)
1379 {
1380     ir_instr *in;
1381     if (self->final) {
1382         irerror(self->context, "unreachable statement (%s)", self->label);
1383         return false;
1384     }
1385     self->final = true;
1386     in = ir_instr_new(self, INSTR_GOTO);
1387     if (!in)
1388         return false;
1389
1390     in->bops[0] = to;
1391     vec_push(self->instr, in);
1392
1393     vec_push(self->exits, to);
1394     vec_push(to->entries, self);
1395     return true;
1396 }
1397
1398 ir_instr* ir_block_create_phi(ir_block *self, const char *label, int ot)
1399 {
1400     ir_value *out;
1401     ir_instr *in;
1402     in = ir_instr_new(self, VINSTR_PHI);
1403     if (!in)
1404         return NULL;
1405     out = ir_value_out(self->owner, label, store_value, ot);
1406     if (!out) {
1407         ir_instr_delete(in);
1408         return NULL;
1409     }
1410     if (!ir_instr_op(in, 0, out, true)) {
1411         ir_instr_delete(in);
1412         ir_value_delete(out);
1413         return NULL;
1414     }
1415     vec_push(self->instr, in);
1416     return in;
1417 }
1418
1419 ir_value* ir_phi_value(ir_instr *self)
1420 {
1421     return self->_ops[0];
1422 }
1423
1424 void ir_phi_add(ir_instr* self, ir_block *b, ir_value *v)
1425 {
1426     ir_phi_entry_t pe;
1427
1428     if (!vec_ir_block_find(self->owner->entries, b, NULL)) {
1429         /* Must not be possible to cause this, otherwise the AST
1430          * is doing something wrong.
1431          */
1432         irerror(self->context, "Invalid entry block for PHI");
1433         abort();
1434     }
1435
1436     pe.value = v;
1437     pe.from = b;
1438     vec_push(v->reads, self);
1439     vec_push(self->phi, pe);
1440 }
1441
1442 /* call related code */
1443 ir_instr* ir_block_create_call(ir_block *self, const char *label, ir_value *func)
1444 {
1445     ir_value *out;
1446     ir_instr *in;
1447     in = ir_instr_new(self, INSTR_CALL0);
1448     if (!in)
1449         return NULL;
1450     out = ir_value_out(self->owner, label, (func->outtype == TYPE_VOID) ? store_return : store_value, func->outtype);
1451     if (!out) {
1452         ir_instr_delete(in);
1453         return NULL;
1454     }
1455     if (!ir_instr_op(in, 0, out, true) ||
1456         !ir_instr_op(in, 1, func, false))
1457     {
1458         ir_instr_delete(in);
1459         ir_value_delete(out);
1460         return NULL;
1461     }
1462     vec_push(self->instr, in);
1463     return in;
1464 }
1465
1466 ir_value* ir_call_value(ir_instr *self)
1467 {
1468     return self->_ops[0];
1469 }
1470
1471 void ir_call_param(ir_instr* self, ir_value *v)
1472 {
1473     vec_push(self->params, v);
1474     vec_push(v->reads, self);
1475 }
1476
1477 /* binary op related code */
1478
1479 ir_value* ir_block_create_binop(ir_block *self,
1480                                 const char *label, int opcode,
1481                                 ir_value *left, ir_value *right)
1482 {
1483     int ot = TYPE_VOID;
1484     switch (opcode) {
1485         case INSTR_ADD_F:
1486         case INSTR_SUB_F:
1487         case INSTR_DIV_F:
1488         case INSTR_MUL_F:
1489         case INSTR_MUL_V:
1490         case INSTR_AND:
1491         case INSTR_OR:
1492 #if 0
1493         case INSTR_AND_I:
1494         case INSTR_AND_IF:
1495         case INSTR_AND_FI:
1496         case INSTR_OR_I:
1497         case INSTR_OR_IF:
1498         case INSTR_OR_FI:
1499 #endif
1500         case INSTR_BITAND:
1501         case INSTR_BITOR:
1502 #if 0
1503         case INSTR_SUB_S: /* -- offset of string as float */
1504         case INSTR_MUL_IF:
1505         case INSTR_MUL_FI:
1506         case INSTR_DIV_IF:
1507         case INSTR_DIV_FI:
1508         case INSTR_BITOR_IF:
1509         case INSTR_BITOR_FI:
1510         case INSTR_BITAND_FI:
1511         case INSTR_BITAND_IF:
1512         case INSTR_EQ_I:
1513         case INSTR_NE_I:
1514 #endif
1515             ot = TYPE_FLOAT;
1516             break;
1517 #if 0
1518         case INSTR_ADD_I:
1519         case INSTR_ADD_IF:
1520         case INSTR_ADD_FI:
1521         case INSTR_SUB_I:
1522         case INSTR_SUB_FI:
1523         case INSTR_SUB_IF:
1524         case INSTR_MUL_I:
1525         case INSTR_DIV_I:
1526         case INSTR_BITAND_I:
1527         case INSTR_BITOR_I:
1528         case INSTR_XOR_I:
1529         case INSTR_RSHIFT_I:
1530         case INSTR_LSHIFT_I:
1531             ot = TYPE_INTEGER;
1532             break;
1533 #endif
1534         case INSTR_ADD_V:
1535         case INSTR_SUB_V:
1536         case INSTR_MUL_VF:
1537         case INSTR_MUL_FV:
1538 #if 0
1539         case INSTR_DIV_VF:
1540         case INSTR_MUL_IV:
1541         case INSTR_MUL_VI:
1542 #endif
1543             ot = TYPE_VECTOR;
1544             break;
1545 #if 0
1546         case INSTR_ADD_SF:
1547             ot = TYPE_POINTER;
1548             break;
1549 #endif
1550         default:
1551             /* ranges: */
1552             /* boolean operations result in floats */
1553             if (opcode >= INSTR_EQ_F && opcode <= INSTR_GT)
1554                 ot = TYPE_FLOAT;
1555             else if (opcode >= INSTR_LE && opcode <= INSTR_GT)
1556                 ot = TYPE_FLOAT;
1557 #if 0
1558             else if (opcode >= INSTR_LE_I && opcode <= INSTR_EQ_FI)
1559                 ot = TYPE_FLOAT;
1560 #endif
1561             break;
1562     };
1563     if (ot == TYPE_VOID) {
1564         /* The AST or parser were supposed to check this! */
1565         return NULL;
1566     }
1567
1568     return ir_block_create_general_instr(self, label, opcode, left, right, ot);
1569 }
1570
1571 ir_value* ir_block_create_unary(ir_block *self,
1572                                 const char *label, int opcode,
1573                                 ir_value *operand)
1574 {
1575     int ot = TYPE_FLOAT;
1576     switch (opcode) {
1577         case INSTR_NOT_F:
1578         case INSTR_NOT_V:
1579         case INSTR_NOT_S:
1580         case INSTR_NOT_ENT:
1581         case INSTR_NOT_FNC:
1582 #if 0
1583         case INSTR_NOT_I:
1584 #endif
1585             ot = TYPE_FLOAT;
1586             break;
1587         /* QC doesn't have other unary operations. We expect extensions to fill
1588          * the above list, otherwise we assume out-type = in-type, eg for an
1589          * unary minus
1590          */
1591         default:
1592             ot = operand->vtype;
1593             break;
1594     };
1595     if (ot == TYPE_VOID) {
1596         /* The AST or parser were supposed to check this! */
1597         return NULL;
1598     }
1599
1600     /* let's use the general instruction creator and pass NULL for OPB */
1601     return ir_block_create_general_instr(self, label, opcode, operand, NULL, ot);
1602 }
1603
1604 ir_value* ir_block_create_general_instr(ir_block *self, const char *label,
1605                                         int op, ir_value *a, ir_value *b, int outype)
1606 {
1607     ir_instr *instr;
1608     ir_value *out;
1609
1610     out = ir_value_out(self->owner, label, store_value, outype);
1611     if (!out)
1612         return NULL;
1613
1614     instr = ir_instr_new(self, op);
1615     if (!instr) {
1616         ir_value_delete(out);
1617         return NULL;
1618     }
1619
1620     if (!ir_instr_op(instr, 0, out, true) ||
1621         !ir_instr_op(instr, 1, a, false) ||
1622         !ir_instr_op(instr, 2, b, false) )
1623     {
1624         goto on_error;
1625     }
1626
1627     vec_push(self->instr, instr);
1628
1629     return out;
1630 on_error:
1631     ir_instr_delete(instr);
1632     ir_value_delete(out);
1633     return NULL;
1634 }
1635
1636 ir_value* ir_block_create_fieldaddress(ir_block *self, const char *label, ir_value *ent, ir_value *field)
1637 {
1638     ir_value *v;
1639
1640     /* Support for various pointer types todo if so desired */
1641     if (ent->vtype != TYPE_ENTITY)
1642         return NULL;
1643
1644     if (field->vtype != TYPE_FIELD)
1645         return NULL;
1646
1647     v = ir_block_create_general_instr(self, label, INSTR_ADDRESS, ent, field, TYPE_POINTER);
1648     v->fieldtype = field->fieldtype;
1649     return v;
1650 }
1651
1652 ir_value* ir_block_create_load_from_ent(ir_block *self, const char *label, ir_value *ent, ir_value *field, int outype)
1653 {
1654     int op;
1655     if (ent->vtype != TYPE_ENTITY)
1656         return NULL;
1657
1658     /* at some point we could redirect for TYPE_POINTER... but that could lead to carelessness */
1659     if (field->vtype != TYPE_FIELD)
1660         return NULL;
1661
1662     switch (outype)
1663     {
1664         case TYPE_FLOAT:    op = INSTR_LOAD_F;   break;
1665         case TYPE_VECTOR:   op = INSTR_LOAD_V;   break;
1666         case TYPE_STRING:   op = INSTR_LOAD_S;   break;
1667         case TYPE_FIELD:    op = INSTR_LOAD_FLD; break;
1668         case TYPE_ENTITY:   op = INSTR_LOAD_ENT; break;
1669         case TYPE_FUNCTION: op = INSTR_LOAD_FNC; break;
1670 #if 0
1671         case TYPE_POINTER: op = INSTR_LOAD_I;   break;
1672         case TYPE_INTEGER: op = INSTR_LOAD_I;   break;
1673 #endif
1674         default:
1675             irerror(self->context, "invalid type for ir_block_create_load_from_ent: %s", type_name[outype]);
1676             return NULL;
1677     }
1678
1679     return ir_block_create_general_instr(self, label, op, ent, field, outype);
1680 }
1681
1682 ir_value* ir_block_create_add(ir_block *self,
1683                               const char *label,
1684                               ir_value *left, ir_value *right)
1685 {
1686     int op = 0;
1687     int l = left->vtype;
1688     int r = right->vtype;
1689     if (l == r) {
1690         switch (l) {
1691             default:
1692                 irerror(self->context, "invalid type for ir_block_create_add: %s", type_name[l]);
1693                 return NULL;
1694             case TYPE_FLOAT:
1695                 op = INSTR_ADD_F;
1696                 break;
1697 #if 0
1698             case TYPE_INTEGER:
1699                 op = INSTR_ADD_I;
1700                 break;
1701 #endif
1702             case TYPE_VECTOR:
1703                 op = INSTR_ADD_V;
1704                 break;
1705         }
1706     } else {
1707 #if 0
1708         if ( (l == TYPE_FLOAT && r == TYPE_INTEGER) )
1709             op = INSTR_ADD_FI;
1710         else if ( (l == TYPE_INTEGER && r == TYPE_FLOAT) )
1711             op = INSTR_ADD_IF;
1712         else
1713 #endif
1714         {
1715             irerror(self->context, "invalid type for ir_block_create_add: %s", type_name[l]);
1716             return NULL;
1717         }
1718     }
1719     return ir_block_create_binop(self, label, op, left, right);
1720 }
1721
1722 ir_value* ir_block_create_sub(ir_block *self,
1723                               const char *label,
1724                               ir_value *left, ir_value *right)
1725 {
1726     int op = 0;
1727     int l = left->vtype;
1728     int r = right->vtype;
1729     if (l == r) {
1730
1731         switch (l) {
1732             default:
1733                 irerror(self->context, "invalid type for ir_block_create_sub: %s", type_name[l]);
1734                 return NULL;
1735             case TYPE_FLOAT:
1736                 op = INSTR_SUB_F;
1737                 break;
1738 #if 0
1739             case TYPE_INTEGER:
1740                 op = INSTR_SUB_I;
1741                 break;
1742 #endif
1743             case TYPE_VECTOR:
1744                 op = INSTR_SUB_V;
1745                 break;
1746         }
1747     } else {
1748 #if 0
1749         if ( (l == TYPE_FLOAT && r == TYPE_INTEGER) )
1750             op = INSTR_SUB_FI;
1751         else if ( (l == TYPE_INTEGER && r == TYPE_FLOAT) )
1752             op = INSTR_SUB_IF;
1753         else
1754 #endif
1755         {
1756             irerror(self->context, "invalid type for ir_block_create_sub: %s", type_name[l]);
1757             return NULL;
1758         }
1759     }
1760     return ir_block_create_binop(self, label, op, left, right);
1761 }
1762
1763 ir_value* ir_block_create_mul(ir_block *self,
1764                               const char *label,
1765                               ir_value *left, ir_value *right)
1766 {
1767     int op = 0;
1768     int l = left->vtype;
1769     int r = right->vtype;
1770     if (l == r) {
1771
1772         switch (l) {
1773             default:
1774                 irerror(self->context, "invalid type for ir_block_create_mul: %s", type_name[l]);
1775                 return NULL;
1776             case TYPE_FLOAT:
1777                 op = INSTR_MUL_F;
1778                 break;
1779 #if 0
1780             case TYPE_INTEGER:
1781                 op = INSTR_MUL_I;
1782                 break;
1783 #endif
1784             case TYPE_VECTOR:
1785                 op = INSTR_MUL_V;
1786                 break;
1787         }
1788     } else {
1789         if ( (l == TYPE_VECTOR && r == TYPE_FLOAT) )
1790             op = INSTR_MUL_VF;
1791         else if ( (l == TYPE_FLOAT && r == TYPE_VECTOR) )
1792             op = INSTR_MUL_FV;
1793 #if 0
1794         else if ( (l == TYPE_VECTOR && r == TYPE_INTEGER) )
1795             op = INSTR_MUL_VI;
1796         else if ( (l == TYPE_INTEGER && r == TYPE_VECTOR) )
1797             op = INSTR_MUL_IV;
1798         else if ( (l == TYPE_FLOAT && r == TYPE_INTEGER) )
1799             op = INSTR_MUL_FI;
1800         else if ( (l == TYPE_INTEGER && r == TYPE_FLOAT) )
1801             op = INSTR_MUL_IF;
1802 #endif
1803         else {
1804             irerror(self->context, "invalid type for ir_block_create_mul: %s", type_name[l]);
1805             return NULL;
1806         }
1807     }
1808     return ir_block_create_binop(self, label, op, left, right);
1809 }
1810
1811 ir_value* ir_block_create_div(ir_block *self,
1812                               const char *label,
1813                               ir_value *left, ir_value *right)
1814 {
1815     int op = 0;
1816     int l = left->vtype;
1817     int r = right->vtype;
1818     if (l == r) {
1819
1820         switch (l) {
1821             default:
1822                 irerror(self->context, "invalid type for ir_block_create_div: %s", type_name[l]);
1823                 return NULL;
1824             case TYPE_FLOAT:
1825                 op = INSTR_DIV_F;
1826                 break;
1827 #if 0
1828             case TYPE_INTEGER:
1829                 op = INSTR_DIV_I;
1830                 break;
1831 #endif
1832         }
1833     } else {
1834 #if 0
1835         if ( (l == TYPE_VECTOR && r == TYPE_FLOAT) )
1836             op = INSTR_DIV_VF;
1837         else if ( (l == TYPE_FLOAT && r == TYPE_INTEGER) )
1838             op = INSTR_DIV_FI;
1839         else if ( (l == TYPE_INTEGER && r == TYPE_FLOAT) )
1840             op = INSTR_DIV_IF;
1841         else
1842 #endif
1843         {
1844             irerror(self->context, "invalid type for ir_block_create_div: %s", type_name[l]);
1845             return NULL;
1846         }
1847     }
1848     return ir_block_create_binop(self, label, op, left, right);
1849 }
1850
1851 /* PHI resolving breaks the SSA, and must thus be the last
1852  * step before life-range calculation.
1853  */
1854
1855 static bool ir_block_naive_phi(ir_block *self);
1856 bool ir_function_naive_phi(ir_function *self)
1857 {
1858     size_t i;
1859
1860     for (i = 0; i < vec_size(self->blocks); ++i)
1861     {
1862         if (!ir_block_naive_phi(self->blocks[i]))
1863             return false;
1864     }
1865     return true;
1866 }
1867
1868 #if 0
1869 static bool ir_naive_phi_emit_store(ir_block *block, size_t iid, ir_value *old, ir_value *what)
1870 {
1871     ir_instr *instr;
1872     size_t i;
1873
1874     /* create a store */
1875     if (!ir_block_create_store(block, old, what))
1876         return false;
1877
1878     /* we now move it up */
1879     instr = vec_last(block->instr);
1880     for (i = vec_size(block->instr)-1; i > iid; --i)
1881         block->instr[i] = block->instr[i-1];
1882     block->instr[i] = instr;
1883
1884     return true;
1885 }
1886 #endif
1887
1888 static bool ir_block_naive_phi(ir_block *self)
1889 {
1890     size_t i, p; /*, w;*/
1891     /* FIXME: optionally, create_phi can add the phis
1892      * to a list so we don't need to loop through blocks
1893      * - anyway: "don't optimize YET"
1894      */
1895     for (i = 0; i < vec_size(self->instr); ++i)
1896     {
1897         ir_instr *instr = self->instr[i];
1898         if (instr->opcode != VINSTR_PHI)
1899             continue;
1900
1901         vec_remove(self->instr, i, 1);
1902         --i; /* NOTE: i+1 below */
1903
1904         for (p = 0; p < vec_size(instr->phi); ++p)
1905         {
1906             ir_value *v = instr->phi[p].value;
1907             ir_block *b = instr->phi[p].from;
1908
1909             if (v->store == store_value &&
1910                 vec_size(v->reads) == 1 &&
1911                 vec_size(v->writes) == 1)
1912             {
1913                 /* replace the value */
1914                 if (!ir_instr_op(v->writes[0], 0, instr->_ops[0], true))
1915                     return false;
1916             }
1917             else
1918             {
1919                 /* force a move instruction */
1920                 ir_instr *prevjump = vec_last(b->instr);
1921                 vec_pop(b->instr);
1922                 b->final = false;
1923                 instr->_ops[0]->store = store_global;
1924                 if (!ir_block_create_store(b, instr->_ops[0], v))
1925                     return false;
1926                 instr->_ops[0]->store = store_value;
1927                 vec_push(b->instr, prevjump);
1928                 b->final = true;
1929             }
1930
1931 #if 0
1932             ir_value *v = instr->phi[p].value;
1933             for (w = 0; w < vec_size(v->writes); ++w) {
1934                 ir_value *old;
1935
1936                 if (!v->writes[w]->_ops[0])
1937                     continue;
1938
1939                 /* When the write was to a global, we have to emit a mov */
1940                 old = v->writes[w]->_ops[0];
1941
1942                 /* The original instruction now writes to the PHI target local */
1943                 if (v->writes[w]->_ops[0] == v)
1944                     v->writes[w]->_ops[0] = instr->_ops[0];
1945
1946                 if (old->store != store_value && old->store != store_local && old->store != store_param)
1947                 {
1948                     /* If it originally wrote to a global we need to store the value
1949                      * there as welli
1950                      */
1951                     if (!ir_naive_phi_emit_store(self, i+1, old, v))
1952                         return false;
1953                     if (i+1 < vec_size(self->instr))
1954                         instr = self->instr[i+1];
1955                     else
1956                         instr = NULL;
1957                     /* In case I forget and access instr later, it'll be NULL
1958                      * when it's a problem, to make sure we crash, rather than accessing
1959                      * invalid data.
1960                      */
1961                 }
1962                 else
1963                 {
1964                     /* If it didn't, we can replace all reads by the phi target now. */
1965                     size_t r;
1966                     for (r = 0; r < vec_size(old->reads); ++r)
1967                     {
1968                         size_t op;
1969                         ir_instr *ri = old->reads[r];
1970                         for (op = 0; op < vec_size(ri->phi); ++op) {
1971                             if (ri->phi[op].value == old)
1972                                 ri->phi[op].value = v;
1973                         }
1974                         for (op = 0; op < 3; ++op) {
1975                             if (ri->_ops[op] == old)
1976                                 ri->_ops[op] = v;
1977                         }
1978                     }
1979                 }
1980             }
1981 #endif
1982         }
1983         ir_instr_delete(instr);
1984     }
1985     return true;
1986 }
1987
1988 /***********************************************************************
1989  *IR Temp allocation code
1990  * Propagating value life ranges by walking through the function backwards
1991  * until no more changes are made.
1992  * In theory this should happen once more than once for every nested loop
1993  * level.
1994  * Though this implementation might run an additional time for if nests.
1995  */
1996
1997 /* Enumerate instructions used by value's life-ranges
1998  */
1999 static void ir_block_enumerate(ir_block *self, size_t *_eid)
2000 {
2001     size_t i;
2002     size_t eid = *_eid;
2003     for (i = 0; i < vec_size(self->instr); ++i)
2004     {
2005         self->instr[i]->eid = eid++;
2006     }
2007     *_eid = eid;
2008 }
2009
2010 /* Enumerate blocks and instructions.
2011  * The block-enumeration is unordered!
2012  * We do not really use the block enumreation, however
2013  * the instruction enumeration is important for life-ranges.
2014  */
2015 void ir_function_enumerate(ir_function *self)
2016 {
2017     size_t i;
2018     size_t instruction_id = 0;
2019     for (i = 0; i < vec_size(self->blocks); ++i)
2020     {
2021         self->blocks[i]->eid = i;
2022         self->blocks[i]->run_id = 0;
2023         ir_block_enumerate(self->blocks[i], &instruction_id);
2024     }
2025 }
2026
2027 static bool ir_block_life_propagate(ir_block *b, ir_block *prev, bool *changed);
2028 bool ir_function_calculate_liferanges(ir_function *self)
2029 {
2030     size_t i;
2031     bool changed;
2032
2033     do {
2034         self->run_id++;
2035         changed = false;
2036         for (i = 0; i != vec_size(self->blocks); ++i)
2037         {
2038             if (self->blocks[i]->is_return)
2039             {
2040                 vec_free(self->blocks[i]->living);
2041                 if (!ir_block_life_propagate(self->blocks[i], NULL, &changed))
2042                     return false;
2043             }
2044         }
2045     } while (changed);
2046     if (vec_size(self->blocks)) {
2047         ir_block *block = self->blocks[0];
2048         for (i = 0; i < vec_size(block->living); ++i) {
2049             ir_value *v = block->living[i];
2050             if (v->memberof || v->store != store_local)
2051                 continue;
2052             if (irwarning(v->context, WARN_USED_UNINITIALIZED,
2053                           "variable `%s` may be used uninitialized in this function", v->name))
2054             {
2055                 return false;
2056             }
2057         }
2058     }
2059     return true;
2060 }
2061
2062 /* Local-value allocator
2063  * After finishing creating the liferange of all values used in a function
2064  * we can allocate their global-positions.
2065  * This is the counterpart to register-allocation in register machines.
2066  */
2067 typedef struct {
2068     ir_value **locals;
2069     size_t    *sizes;
2070     size_t    *positions;
2071 } function_allocator;
2072
2073 static bool function_allocator_alloc(function_allocator *alloc, const ir_value *var)
2074 {
2075     ir_value *slot;
2076     size_t vsize = type_sizeof[var->vtype];
2077
2078     slot = ir_value_var("reg", store_global, var->vtype);
2079     if (!slot)
2080         return false;
2081
2082     if (!ir_value_life_merge_into(slot, var))
2083         goto localerror;
2084
2085     vec_push(alloc->locals, slot);
2086     vec_push(alloc->sizes, vsize);
2087
2088     return true;
2089
2090 localerror:
2091     ir_value_delete(slot);
2092     return false;
2093 }
2094
2095 bool ir_function_allocate_locals(ir_function *self)
2096 {
2097     size_t i, a;
2098     bool   retval = true;
2099     size_t pos;
2100
2101     ir_value *slot;
2102     const ir_value *v;
2103
2104     function_allocator alloc;
2105
2106     if (!vec_size(self->locals) && !vec_size(self->values))
2107         return true;
2108
2109     alloc.locals    = NULL;
2110     alloc.sizes     = NULL;
2111     alloc.positions = NULL;
2112
2113     for (i = 0; i < vec_size(self->locals); ++i)
2114     {
2115         if (!function_allocator_alloc(&alloc, self->locals[i]))
2116             goto error;
2117     }
2118
2119     /* Allocate a slot for any value that still exists */
2120     for (i = 0; i < vec_size(self->values); ++i)
2121     {
2122         v = self->values[i];
2123
2124         if (!vec_size(v->life))
2125             continue;
2126
2127         for (a = 0; a < vec_size(alloc.locals); ++a)
2128         {
2129             slot = alloc.locals[a];
2130
2131             if (ir_values_overlap(v, slot))
2132                 continue;
2133
2134             if (!ir_value_life_merge_into(slot, v))
2135                 goto error;
2136
2137             /* adjust size for this slot */
2138             if (alloc.sizes[a] < type_sizeof[v->vtype])
2139                 alloc.sizes[a] = type_sizeof[v->vtype];
2140
2141             self->values[i]->code.local = a;
2142             break;
2143         }
2144         if (a >= vec_size(alloc.locals)) {
2145             self->values[i]->code.local = vec_size(alloc.locals);
2146             if (!function_allocator_alloc(&alloc, v))
2147                 goto error;
2148         }
2149     }
2150
2151     if (!alloc.sizes) {
2152         goto cleanup;
2153     }
2154
2155     /* Adjust slot positions based on sizes */
2156     vec_push(alloc.positions, 0);
2157
2158     if (vec_size(alloc.sizes))
2159         pos = alloc.positions[0] + alloc.sizes[0];
2160     else
2161         pos = 0;
2162     for (i = 1; i < vec_size(alloc.sizes); ++i)
2163     {
2164         pos = alloc.positions[i-1] + alloc.sizes[i-1];
2165         vec_push(alloc.positions, pos);
2166     }
2167
2168     self->allocated_locals = pos + vec_last(alloc.sizes);
2169
2170     /* Take over the actual slot positions */
2171     for (i = 0; i < vec_size(self->values); ++i) {
2172         self->values[i]->code.local = alloc.positions[self->values[i]->code.local];
2173     }
2174
2175     goto cleanup;
2176
2177 error:
2178     retval = false;
2179 cleanup:
2180     for (i = 0; i < vec_size(alloc.locals); ++i)
2181         ir_value_delete(alloc.locals[i]);
2182     vec_free(alloc.locals);
2183     vec_free(alloc.sizes);
2184     vec_free(alloc.positions);
2185     return retval;
2186 }
2187
2188 /* Get information about which operand
2189  * is read from, or written to.
2190  */
2191 static void ir_op_read_write(int op, size_t *read, size_t *write)
2192 {
2193     switch (op)
2194     {
2195     case VINSTR_JUMP:
2196     case INSTR_GOTO:
2197         *write = 0;
2198         *read = 0;
2199         break;
2200     case INSTR_IF:
2201     case INSTR_IFNOT:
2202 #if 0
2203     case INSTR_IF_S:
2204     case INSTR_IFNOT_S:
2205 #endif
2206     case INSTR_RETURN:
2207     case VINSTR_COND:
2208         *write = 0;
2209         *read = 1;
2210         break;
2211     case INSTR_STOREP_F:
2212     case INSTR_STOREP_V:
2213     case INSTR_STOREP_S:
2214     case INSTR_STOREP_ENT:
2215     case INSTR_STOREP_FLD:
2216     case INSTR_STOREP_FNC:
2217         *write = 0;
2218         *read  = 7;
2219         break;
2220     default:
2221         *write = 1;
2222         *read = 6;
2223         break;
2224     };
2225 }
2226
2227 static bool ir_block_living_add_instr(ir_block *self, size_t eid)
2228 {
2229     size_t i;
2230     bool changed = false;
2231     bool tempbool;
2232     for (i = 0; i != vec_size(self->living); ++i)
2233     {
2234         tempbool = ir_value_life_merge(self->living[i], eid);
2235         /* debug
2236         if (tempbool)
2237             irerror(self->context, "block_living_add_instr() value instruction added %s: %i", self->living[i]->_name, (int)eid);
2238         */
2239         changed = changed || tempbool;
2240     }
2241     return changed;
2242 }
2243
2244 static bool ir_block_life_prop_previous(ir_block* self, ir_block *prev, bool *changed)
2245 {
2246     size_t i;
2247
2248     (void)changed;
2249
2250     /* values which have been read in a previous iteration are now
2251      * in the "living" array even if the previous block doesn't use them.
2252      * So we have to remove whatever does not exist in the previous block.
2253      * They will be re-added on-read, but the liferange merge won't cause
2254      * a change.
2255      */
2256     for (i = 0; i < vec_size(self->living); ++i)
2257     {
2258         if (!vec_ir_value_find(prev->living, self->living[i], NULL)) {
2259             vec_remove(self->living, i, 1);
2260             --i;
2261         }
2262     }
2263
2264     /* Whatever the previous block still has in its living set
2265      * must now be added to ours as well.
2266      */
2267     for (i = 0; i < vec_size(prev->living); ++i)
2268     {
2269         if (vec_ir_value_find(self->living, prev->living[i], NULL))
2270             continue;
2271         vec_push(self->living, prev->living[i]);
2272         /*
2273         irerror(self->contextt from prev: %s", self->label, prev->living[i]->_name);
2274         */
2275     }
2276     return true;
2277 }
2278
2279 static bool ir_block_life_propagate(ir_block *self, ir_block *prev, bool *changed)
2280 {
2281     ir_instr *instr;
2282     ir_value *value;
2283     bool  tempbool;
2284     size_t i, o, p;
2285     /* bitmasks which operands are read from or written to */
2286     size_t read, write;
2287     char dbg_ind[16] = { '#', '0' };
2288     (void)dbg_ind;
2289
2290     if (prev)
2291     {
2292         if (!ir_block_life_prop_previous(self, prev, changed))
2293             return false;
2294     }
2295
2296     i = vec_size(self->instr);
2297     while (i)
2298     { --i;
2299         instr = self->instr[i];
2300
2301         /* PHI operands are always read operands */
2302         for (p = 0; p < vec_size(instr->phi); ++p)
2303         {
2304             value = instr->phi[p].value;
2305             if (value->memberof)
2306                 value = value->memberof;
2307             if (!vec_ir_value_find(self->living, value, NULL))
2308                 vec_push(self->living, value);
2309         }
2310
2311         /* call params are read operands too */
2312         for (p = 0; p < vec_size(instr->params); ++p)
2313         {
2314             value = instr->params[p];
2315             if (value->memberof)
2316                 value = value->memberof;
2317             if (!vec_ir_value_find(self->living, value, NULL))
2318                 vec_push(self->living, value);
2319         }
2320
2321         /* See which operands are read and write operands */
2322         ir_op_read_write(instr->opcode, &read, &write);
2323
2324         if (instr->opcode == INSTR_MUL_VF)
2325         {
2326             /* the float source will get an additional lifetime */
2327             tempbool = ir_value_life_merge(instr->_ops[2], instr->eid+1);
2328             *changed = *changed || tempbool;
2329         }
2330         else if (instr->opcode == INSTR_MUL_FV)
2331         {
2332             /* the float source will get an additional lifetime */
2333             tempbool = ir_value_life_merge(instr->_ops[1], instr->eid+1);
2334             *changed = *changed || tempbool;
2335         }
2336
2337         /* Go through the 3 main operands */
2338         for (o = 0; o < 3; ++o)
2339         {
2340             if (!instr->_ops[o]) /* no such operand */
2341                 continue;
2342
2343             value = instr->_ops[o];
2344             if (value->memberof)
2345                 value = value->memberof;
2346
2347             /* We only care about locals */
2348             /* we also calculate parameter liferanges so that locals
2349              * can take up parameter slots */
2350             if (value->store != store_value &&
2351                 value->store != store_local &&
2352                 value->store != store_param)
2353                 continue;
2354
2355             /* read operands */
2356             if (read & (1<<o))
2357             {
2358                 if (!vec_ir_value_find(self->living, value, NULL))
2359                     vec_push(self->living, value);
2360             }
2361
2362             /* write operands */
2363             /* When we write to a local, we consider it "dead" for the
2364              * remaining upper part of the function, since in SSA a value
2365              * can only be written once (== created)
2366              */
2367             if (write & (1<<o))
2368             {
2369                 size_t idx;
2370                 bool in_living = vec_ir_value_find(self->living, value, &idx);
2371                 if (!in_living)
2372                 {
2373                     /* If the value isn't alive it hasn't been read before... */
2374                     /* TODO: See if the warning can be emitted during parsing or AST processing
2375                      * otherwise have warning printed here.
2376                      * IF printing a warning here: include filecontext_t,
2377                      * and make sure it's only printed once
2378                      * since this function is run multiple times.
2379                      */
2380                     /* For now: debug info: */
2381                     /* con_err( "Value only written %s\n", value->name); */
2382                     tempbool = ir_value_life_merge(value, instr->eid);
2383                     *changed = *changed || tempbool;
2384                     /*
2385                     ir_instr_dump(instr, dbg_ind, printf);
2386                     abort();
2387                     */
2388                 } else {
2389                     /* since 'living' won't contain it
2390                      * anymore, merge the value, since
2391                      * (A) doesn't.
2392                      */
2393                     tempbool = ir_value_life_merge(value, instr->eid);
2394                     /*
2395                     if (tempbool)
2396                         con_err( "value added id %s %i\n", value->name, (int)instr->eid);
2397                     */
2398                     *changed = *changed || tempbool;
2399                     /* Then remove */
2400                     vec_remove(self->living, idx, 1);
2401                 }
2402             }
2403         }
2404         /* (A) */
2405         tempbool = ir_block_living_add_instr(self, instr->eid);
2406         /*con_err( "living added values\n");*/
2407         *changed = *changed || tempbool;
2408
2409     }
2410
2411     if (self->run_id == self->owner->run_id)
2412         return true;
2413
2414     self->run_id = self->owner->run_id;
2415
2416     for (i = 0; i < vec_size(self->entries); ++i)
2417     {
2418         ir_block *entry = self->entries[i];
2419         ir_block_life_propagate(entry, self, changed);
2420     }
2421
2422     return true;
2423 }
2424
2425 /***********************************************************************
2426  *IR Code-Generation
2427  *
2428  * Since the IR has the convention of putting 'write' operands
2429  * at the beginning, we have to rotate the operands of instructions
2430  * properly in order to generate valid QCVM code.
2431  *
2432  * Having destinations at a fixed position is more convenient. In QC
2433  * this is *mostly* OPC,  but FTE adds at least 2 instructions which
2434  * read from from OPA,  and store to OPB rather than OPC.   Which is
2435  * partially the reason why the implementation of these instructions
2436  * in darkplaces has been delayed for so long.
2437  *
2438  * Breaking conventions is annoying...
2439  */
2440 static bool ir_builder_gen_global(ir_builder *self, ir_value *global, bool islocal);
2441
2442 static bool gen_global_field(ir_value *global)
2443 {
2444     if (global->hasvalue)
2445     {
2446         ir_value *fld = global->constval.vpointer;
2447         if (!fld) {
2448             irerror(global->context, "Invalid field constant with no field: %s", global->name);
2449             return false;
2450         }
2451
2452         /* Now, in this case, a relocation would be impossible to code
2453          * since it looks like this:
2454          * .vector v = origin;     <- parse error, wtf is 'origin'?
2455          * .vector origin;
2456          *
2457          * But we will need a general relocation support later anyway
2458          * for functions... might as well support that here.
2459          */
2460         if (!fld->code.globaladdr) {
2461             irerror(global->context, "FIXME: Relocation support");
2462             return false;
2463         }
2464
2465         /* copy the field's value */
2466         ir_value_code_setaddr(global, vec_size(code_globals));
2467         vec_push(code_globals, code_globals[fld->code.globaladdr]);
2468         if (global->fieldtype == TYPE_VECTOR) {
2469             vec_push(code_globals, code_globals[fld->code.globaladdr]+1);
2470             vec_push(code_globals, code_globals[fld->code.globaladdr]+2);
2471         }
2472     }
2473     else
2474     {
2475         ir_value_code_setaddr(global, vec_size(code_globals));
2476         vec_push(code_globals, 0);
2477         if (global->fieldtype == TYPE_VECTOR) {
2478             vec_push(code_globals, 0);
2479             vec_push(code_globals, 0);
2480         }
2481     }
2482     if (global->code.globaladdr < 0)
2483         return false;
2484     return true;
2485 }
2486
2487 static bool gen_global_pointer(ir_value *global)
2488 {
2489     if (global->hasvalue)
2490     {
2491         ir_value *target = global->constval.vpointer;
2492         if (!target) {
2493             irerror(global->context, "Invalid pointer constant: %s", global->name);
2494             /* NULL pointers are pointing to the NULL constant, which also
2495              * sits at address 0, but still has an ir_value for itself.
2496              */
2497             return false;
2498         }
2499
2500         /* Here, relocations ARE possible - in fteqcc-enhanced-qc:
2501          * void() foo; <- proto
2502          * void() *fooptr = &foo;
2503          * void() foo = { code }
2504          */
2505         if (!target->code.globaladdr) {
2506             /* FIXME: Check for the constant nullptr ir_value!
2507              * because then code.globaladdr being 0 is valid.
2508              */
2509             irerror(global->context, "FIXME: Relocation support");
2510             return false;
2511         }
2512
2513         ir_value_code_setaddr(global, vec_size(code_globals));
2514         vec_push(code_globals, target->code.globaladdr);
2515     }
2516     else
2517     {
2518         ir_value_code_setaddr(global, vec_size(code_globals));
2519         vec_push(code_globals, 0);
2520     }
2521     if (global->code.globaladdr < 0)
2522         return false;
2523     return true;
2524 }
2525
2526 static bool gen_blocks_recursive(ir_function *func, ir_block *block)
2527 {
2528     prog_section_statement stmt;
2529     ir_instr *instr;
2530     ir_block *target;
2531     ir_block *ontrue;
2532     ir_block *onfalse;
2533     size_t    stidx;
2534     size_t    i;
2535
2536 tailcall:
2537     block->generated = true;
2538     block->code_start = vec_size(code_statements);
2539     for (i = 0; i < vec_size(block->instr); ++i)
2540     {
2541         instr = block->instr[i];
2542
2543         if (instr->opcode == VINSTR_PHI) {
2544             irerror(block->context, "cannot generate virtual instruction (phi)");
2545             return false;
2546         }
2547
2548         if (instr->opcode == VINSTR_JUMP) {
2549             target = instr->bops[0];
2550             /* for uncoditional jumps, if the target hasn't been generated
2551              * yet, we generate them right here.
2552              */
2553             if (!target->generated) {
2554                 block = target;
2555                 goto tailcall;
2556             }
2557
2558             /* otherwise we generate a jump instruction */
2559             stmt.opcode = INSTR_GOTO;
2560             stmt.o1.s1 = (target->code_start) - vec_size(code_statements);
2561             stmt.o2.s1 = 0;
2562             stmt.o3.s1 = 0;
2563             vec_push(code_statements, stmt);
2564
2565             /* no further instructions can be in this block */
2566             return true;
2567         }
2568
2569         if (instr->opcode == VINSTR_COND) {
2570             ontrue  = instr->bops[0];
2571             onfalse = instr->bops[1];
2572             /* TODO: have the AST signal which block should
2573              * come first: eg. optimize IFs without ELSE...
2574              */
2575
2576             stmt.o1.u1 = ir_value_code_addr(instr->_ops[0]);
2577             stmt.o2.u1 = 0;
2578             stmt.o3.s1 = 0;
2579
2580             if (ontrue->generated) {
2581                 stmt.opcode = INSTR_IF;
2582                 stmt.o2.s1 = (ontrue->code_start) - vec_size(code_statements);
2583                 vec_push(code_statements, stmt);
2584             }
2585             if (onfalse->generated) {
2586                 stmt.opcode = INSTR_IFNOT;
2587                 stmt.o2.s1 = (onfalse->code_start) - vec_size(code_statements);
2588                 vec_push(code_statements, stmt);
2589             }
2590             if (!ontrue->generated) {
2591                 if (onfalse->generated) {
2592                     block = ontrue;
2593                     goto tailcall;
2594                 }
2595             }
2596             if (!onfalse->generated) {
2597                 if (ontrue->generated) {
2598                     block = onfalse;
2599                     goto tailcall;
2600                 }
2601             }
2602             /* neither ontrue nor onfalse exist */
2603             stmt.opcode = INSTR_IFNOT;
2604             if (!instr->likely) {
2605                 /* Honor the likelyhood hint */
2606                 ir_block *tmp = onfalse;
2607                 stmt.opcode = INSTR_IF;
2608                 onfalse = ontrue;
2609                 ontrue = tmp;
2610             }
2611             stidx = vec_size(code_statements);
2612             vec_push(code_statements, stmt);
2613             /* on false we jump, so add ontrue-path */
2614             if (!gen_blocks_recursive(func, ontrue))
2615                 return false;
2616             /* fixup the jump address */
2617             code_statements[stidx].o2.s1 = vec_size(code_statements) - stidx;
2618             /* generate onfalse path */
2619             if (onfalse->generated) {
2620                 /* fixup the jump address */
2621                 code_statements[stidx].o2.s1 = (onfalse->code_start) - (stidx);
2622                 stmt.opcode = vec_last(code_statements).opcode;
2623                 if (stmt.opcode == INSTR_GOTO ||
2624                     stmt.opcode == INSTR_IF ||
2625                     stmt.opcode == INSTR_IFNOT ||
2626                     stmt.opcode == INSTR_RETURN ||
2627                     stmt.opcode == INSTR_DONE)
2628                 {
2629                     /* no use jumping from here */
2630                     return true;
2631                 }
2632                 /* may have been generated in the previous recursive call */
2633                 stmt.opcode = INSTR_GOTO;
2634                 stmt.o1.s1 = (onfalse->code_start) - vec_size(code_statements);
2635                 stmt.o2.s1 = 0;
2636                 stmt.o3.s1 = 0;
2637                 vec_push(code_statements, stmt);
2638                 return true;
2639             }
2640             /* if not, generate now */
2641             block = onfalse;
2642             goto tailcall;
2643         }
2644
2645         if (instr->opcode >= INSTR_CALL0 && instr->opcode <= INSTR_CALL8) {
2646             /* Trivial call translation:
2647              * copy all params to OFS_PARM*
2648              * if the output's storetype is not store_return,
2649              * add append a STORE instruction!
2650              *
2651              * NOTES on how to do it better without much trouble:
2652              * -) The liferanges!
2653              *      Simply check the liferange of all parameters for
2654              *      other CALLs. For each param with no CALL in its
2655              *      liferange, we can store it in an OFS_PARM at
2656              *      generation already. This would even include later
2657              *      reuse.... probably... :)
2658              */
2659             size_t p, first;
2660             ir_value *retvalue;
2661
2662             first = vec_size(instr->params);
2663             if (first > 8)
2664                 first = 8;
2665             for (p = 0; p < first; ++p)
2666             {
2667                 ir_value *param = instr->params[p];
2668
2669                 stmt.opcode = INSTR_STORE_F;
2670                 stmt.o3.u1 = 0;
2671
2672                 if (param->vtype == TYPE_FIELD)
2673                     stmt.opcode = field_store_instr[param->fieldtype];
2674                 else
2675                     stmt.opcode = type_store_instr[param->vtype];
2676                 stmt.o1.u1 = ir_value_code_addr(param);
2677                 stmt.o2.u1 = OFS_PARM0 + 3 * p;
2678                 vec_push(code_statements, stmt);
2679             }
2680             /* Now handle extparams */
2681             first = vec_size(instr->params);
2682             for (; p < first; ++p)
2683             {
2684                 ir_builder *ir = func->owner;
2685                 ir_value *param = instr->params[p];
2686                 ir_value *targetparam;
2687
2688                 if (p-8 >= vec_size(ir->extparams)) {
2689                     irerror(instr->context, "Not enough extparam-globals have been created");
2690                     return false;
2691                 }
2692
2693                 targetparam = ir->extparams[p-8];
2694
2695                 stmt.opcode = INSTR_STORE_F;
2696                 stmt.o3.u1 = 0;
2697
2698                 if (param->vtype == TYPE_FIELD)
2699                     stmt.opcode = field_store_instr[param->fieldtype];
2700                 else
2701                     stmt.opcode = type_store_instr[param->vtype];
2702                 stmt.o1.u1 = ir_value_code_addr(param);
2703                 stmt.o2.u1 = ir_value_code_addr(targetparam);
2704                 vec_push(code_statements, stmt);
2705             }
2706
2707             stmt.opcode = INSTR_CALL0 + vec_size(instr->params);
2708             if (stmt.opcode > INSTR_CALL8)
2709                 stmt.opcode = INSTR_CALL8;
2710             stmt.o1.u1 = ir_value_code_addr(instr->_ops[1]);
2711             stmt.o2.u1 = 0;
2712             stmt.o3.u1 = 0;
2713             vec_push(code_statements, stmt);
2714
2715             retvalue = instr->_ops[0];
2716             if (retvalue && retvalue->store != store_return && vec_size(retvalue->life))
2717             {
2718                 /* not to be kept in OFS_RETURN */
2719                 if (retvalue->vtype == TYPE_FIELD)
2720                     stmt.opcode = field_store_instr[retvalue->vtype];
2721                 else
2722                     stmt.opcode = type_store_instr[retvalue->vtype];
2723                 stmt.o1.u1 = OFS_RETURN;
2724                 stmt.o2.u1 = ir_value_code_addr(retvalue);
2725                 stmt.o3.u1 = 0;
2726                 vec_push(code_statements, stmt);
2727             }
2728             continue;
2729         }
2730
2731         if (instr->opcode == INSTR_STATE) {
2732             irerror(block->context, "TODO: state instruction");
2733             return false;
2734         }
2735
2736         stmt.opcode = instr->opcode;
2737         stmt.o1.u1 = 0;
2738         stmt.o2.u1 = 0;
2739         stmt.o3.u1 = 0;
2740
2741         /* This is the general order of operands */
2742         if (instr->_ops[0])
2743             stmt.o3.u1 = ir_value_code_addr(instr->_ops[0]);
2744
2745         if (instr->_ops[1])
2746             stmt.o1.u1 = ir_value_code_addr(instr->_ops[1]);
2747
2748         if (instr->_ops[2])
2749             stmt.o2.u1 = ir_value_code_addr(instr->_ops[2]);
2750
2751         if (stmt.opcode == INSTR_RETURN || stmt.opcode == INSTR_DONE)
2752         {
2753             stmt.o1.u1 = stmt.o3.u1;
2754             stmt.o3.u1 = 0;
2755         }
2756         else if ((stmt.opcode >= INSTR_STORE_F &&
2757                   stmt.opcode <= INSTR_STORE_FNC) ||
2758                  (stmt.opcode >= INSTR_STOREP_F &&
2759                   stmt.opcode <= INSTR_STOREP_FNC))
2760         {
2761             /* 2-operand instructions with A -> B */
2762             stmt.o2.u1 = stmt.o3.u1;
2763             stmt.o3.u1 = 0;
2764         }
2765
2766         vec_push(code_statements, stmt);
2767     }
2768     return true;
2769 }
2770
2771 static bool gen_function_code(ir_function *self)
2772 {
2773     ir_block *block;
2774     prog_section_statement stmt;
2775
2776     /* Starting from entry point, we generate blocks "as they come"
2777      * for now. Dead blocks will not be translated obviously.
2778      */
2779     if (!vec_size(self->blocks)) {
2780         irerror(self->context, "Function '%s' declared without body.", self->name);
2781         return false;
2782     }
2783
2784     block = self->blocks[0];
2785     if (block->generated)
2786         return true;
2787
2788     if (!gen_blocks_recursive(self, block)) {
2789         irerror(self->context, "failed to generate blocks for '%s'", self->name);
2790         return false;
2791     }
2792
2793     /* otherwise code_write crashes since it debug-prints functions until AINSTR_END */
2794     stmt.opcode = AINSTR_END;
2795     stmt.o1.u1 = 0;
2796     stmt.o2.u1 = 0;
2797     stmt.o3.u1 = 0;
2798     vec_push(code_statements, stmt);
2799     return true;
2800 }
2801
2802 static qcint ir_builder_filestring(ir_builder *ir, const char *filename)
2803 {
2804     /* NOTE: filename pointers are copied, we never strdup them,
2805      * thus we can use pointer-comparison to find the string.
2806      */
2807     size_t i;
2808     qcint  str;
2809
2810     for (i = 0; i < vec_size(ir->filenames); ++i) {
2811         if (ir->filenames[i] == filename)
2812             return ir->filestrings[i];
2813     }
2814
2815     str = code_genstring(filename);
2816     vec_push(ir->filenames, filename);
2817     vec_push(ir->filestrings, str);
2818     return str;
2819 }
2820
2821 static bool gen_global_function(ir_builder *ir, ir_value *global)
2822 {
2823     prog_section_function fun;
2824     ir_function          *irfun;
2825
2826     size_t i;
2827     size_t local_var_end;
2828
2829     if (!global->hasvalue || (!global->constval.vfunc))
2830     {
2831         irerror(global->context, "Invalid state of function-global: not constant: %s", global->name);
2832         return false;
2833     }
2834
2835     irfun = global->constval.vfunc;
2836
2837     fun.name    = global->code.name;
2838     fun.file    = ir_builder_filestring(ir, global->context.file);
2839     fun.profile = 0; /* always 0 */
2840     fun.nargs   = vec_size(irfun->params);
2841     if (fun.nargs > 8)
2842         fun.nargs = 8;
2843
2844     for (i = 0;i < 8; ++i) {
2845         if (i >= fun.nargs)
2846             fun.argsize[i] = 0;
2847         else
2848             fun.argsize[i] = type_sizeof[irfun->params[i]];
2849     }
2850
2851     fun.firstlocal = vec_size(code_globals);
2852
2853     local_var_end = fun.firstlocal;
2854     for (i = 0; i < vec_size(irfun->locals); ++i) {
2855         if (!ir_builder_gen_global(ir, irfun->locals[i], true)) {
2856             irerror(irfun->locals[i]->context, "Failed to generate local %s", irfun->locals[i]->name);
2857             return false;
2858         }
2859     }
2860     if (vec_size(irfun->locals)) {
2861         ir_value *last = vec_last(irfun->locals);
2862         local_var_end = last->code.globaladdr;
2863         local_var_end += type_sizeof[last->vtype];
2864     }
2865     for (i = 0; i < vec_size(irfun->values); ++i)
2866     {
2867         /* generate code.globaladdr for ssa values */
2868         ir_value *v = irfun->values[i];
2869         ir_value_code_setaddr(v, local_var_end + v->code.local);
2870     }
2871     for (i = 0; i < irfun->allocated_locals; ++i) {
2872         /* fill the locals with zeros */
2873         vec_push(code_globals, 0);
2874     }
2875
2876     fun.locals = vec_size(code_globals) - fun.firstlocal;
2877
2878     if (irfun->builtin)
2879         fun.entry = irfun->builtin;
2880     else {
2881         irfun->code_function_def = vec_size(code_functions);
2882         fun.entry = vec_size(code_statements);
2883     }
2884
2885     vec_push(code_functions, fun);
2886     return true;
2887 }
2888
2889 static void ir_gen_extparam(ir_builder *ir)
2890 {
2891     prog_section_def def;
2892     ir_value        *global;
2893     char             name[128];
2894
2895     snprintf(name, sizeof(name), "EXTPARM#%i", (int)(vec_size(ir->extparams)+8));
2896     global = ir_value_var(name, store_global, TYPE_VECTOR);
2897
2898     def.name = code_genstring(name);
2899     def.type = TYPE_VECTOR;
2900     def.offset = vec_size(code_globals);
2901
2902     vec_push(code_defs, def);
2903     ir_value_code_setaddr(global, def.offset);
2904     vec_push(code_globals, 0);
2905     vec_push(code_globals, 0);
2906     vec_push(code_globals, 0);
2907
2908     vec_push(ir->extparams, global);
2909 }
2910
2911 static bool gen_function_extparam_copy(ir_function *self)
2912 {
2913     size_t i, ext, numparams;
2914
2915     ir_builder *ir = self->owner;
2916     ir_value   *ep;
2917     prog_section_statement stmt;
2918
2919     numparams = vec_size(self->params);
2920     if (!numparams)
2921         return true;
2922
2923     stmt.opcode = INSTR_STORE_F;
2924     stmt.o3.s1 = 0;
2925     for (i = 8; i < numparams; ++i) {
2926         ext = i - 8;
2927         if (ext >= vec_size(ir->extparams))
2928             ir_gen_extparam(ir);
2929
2930         ep = ir->extparams[ext];
2931
2932         stmt.opcode = type_store_instr[self->locals[i]->vtype];
2933         if (self->locals[i]->vtype == TYPE_FIELD &&
2934             self->locals[i]->fieldtype == TYPE_VECTOR)
2935         {
2936             stmt.opcode = INSTR_STORE_V;
2937         }
2938         stmt.o1.u1 = ir_value_code_addr(ep);
2939         stmt.o2.u1 = ir_value_code_addr(self->locals[i]);
2940         vec_push(code_statements, stmt);
2941     }
2942
2943     return true;
2944 }
2945
2946 static bool gen_global_function_code(ir_builder *ir, ir_value *global)
2947 {
2948     prog_section_function *fundef;
2949     ir_function           *irfun;
2950
2951     (void)ir;
2952
2953     irfun = global->constval.vfunc;
2954     if (!irfun) {
2955         if (global->cvq == CV_NONE) {
2956             irwarning(global->context, WARN_IMPLICIT_FUNCTION_POINTER,
2957                       "function `%s` has no body and in QC implicitly becomes a function-pointer", global->name);
2958         }
2959         /* this was a function pointer, don't generate code for those */
2960         return true;
2961     }
2962
2963     if (irfun->builtin)
2964         return true;
2965
2966     if (irfun->code_function_def < 0) {
2967         irerror(irfun->context, "`%s`: IR global wasn't generated, failed to access function-def", irfun->name);
2968         return false;
2969     }
2970     fundef = &code_functions[irfun->code_function_def];
2971
2972     fundef->entry = vec_size(code_statements);
2973     if (!gen_function_extparam_copy(irfun)) {
2974         irerror(irfun->context, "Failed to generate extparam-copy code for function %s", irfun->name);
2975         return false;
2976     }
2977     if (!gen_function_code(irfun)) {
2978         irerror(irfun->context, "Failed to generate code for function %s", irfun->name);
2979         return false;
2980     }
2981     return true;
2982 }
2983
2984 static bool ir_builder_gen_global(ir_builder *self, ir_value *global, bool islocal)
2985 {
2986     size_t           i;
2987     int32_t         *iptr;
2988     prog_section_def def;
2989
2990     def.type   = global->vtype;
2991     def.offset = vec_size(code_globals);
2992
2993     if (global->name) {
2994         if (global->name[0] == '#') {
2995             if (!self->str_immediate)
2996                 self->str_immediate = code_genstring("IMMEDIATE");
2997             def.name = global->code.name = self->str_immediate;
2998         }
2999         else
3000             def.name = global->code.name = code_genstring(global->name);
3001     }
3002     else
3003         def.name   = 0;
3004
3005     switch (global->vtype)
3006     {
3007     case TYPE_VOID:
3008         if (!strcmp(global->name, "end_sys_globals")) {
3009             /* TODO: remember this point... all the defs before this one
3010              * should be checksummed and added to progdefs.h when we generate it.
3011              */
3012         }
3013         else if (!strcmp(global->name, "end_sys_fields")) {
3014             /* TODO: same as above but for entity-fields rather than globsl
3015              */
3016         }
3017         else
3018             irwarning(global->context, WARN_VOID_VARIABLES, "unrecognized variable of type void `%s`",
3019                       global->name);
3020         /* I'd argue setting it to 0 is sufficient, but maybe some depend on knowing how far
3021          * the system fields actually go? Though the engine knows this anyway...
3022          * Maybe this could be an -foption
3023          * fteqcc creates data for end_sys_* - of size 1, so let's do the same
3024          */
3025         ir_value_code_setaddr(global, vec_size(code_globals));
3026         vec_push(code_globals, 0);
3027         /* Add the def */
3028         vec_push(code_defs, def);
3029         return true;
3030     case TYPE_POINTER:
3031         vec_push(code_defs, def);
3032         return gen_global_pointer(global);
3033     case TYPE_FIELD:
3034         vec_push(code_defs, def);
3035         return gen_global_field(global);
3036     case TYPE_ENTITY:
3037         /* fall through */
3038     case TYPE_FLOAT:
3039     {
3040         ir_value_code_setaddr(global, vec_size(code_globals));
3041         if (global->hasvalue) {
3042             iptr = (int32_t*)&global->constval.ivec[0];
3043             vec_push(code_globals, *iptr);
3044         } else {
3045             vec_push(code_globals, 0);
3046             if (!islocal)
3047                 def.type |= DEF_SAVEGLOBAL;
3048         }
3049         vec_push(code_defs, def);
3050
3051         return global->code.globaladdr >= 0;
3052     }
3053     case TYPE_STRING:
3054     {
3055         ir_value_code_setaddr(global, vec_size(code_globals));
3056         if (global->hasvalue) {
3057             vec_push(code_globals, code_genstring(global->constval.vstring));
3058         } else {
3059             vec_push(code_globals, 0);
3060             if (!islocal)
3061                 def.type |= DEF_SAVEGLOBAL;
3062         }
3063         vec_push(code_defs, def);
3064         return global->code.globaladdr >= 0;
3065     }
3066     case TYPE_VECTOR:
3067     {
3068         size_t d;
3069         ir_value_code_setaddr(global, vec_size(code_globals));
3070         if (global->hasvalue) {
3071             iptr = (int32_t*)&global->constval.ivec[0];
3072             vec_push(code_globals, iptr[0]);
3073             if (global->code.globaladdr < 0)
3074                 return false;
3075             for (d = 1; d < type_sizeof[global->vtype]; ++d)
3076             {
3077                 vec_push(code_globals, iptr[d]);
3078             }
3079         } else {
3080             vec_push(code_globals, 0);
3081             if (global->code.globaladdr < 0)
3082                 return false;
3083             for (d = 1; d < type_sizeof[global->vtype]; ++d)
3084             {
3085                 vec_push(code_globals, 0);
3086             }
3087             if (!islocal)
3088                 def.type |= DEF_SAVEGLOBAL;
3089         }
3090
3091         vec_push(code_defs, def);
3092         return global->code.globaladdr >= 0;
3093     }
3094     case TYPE_FUNCTION:
3095         ir_value_code_setaddr(global, vec_size(code_globals));
3096         if (!global->hasvalue) {
3097             vec_push(code_globals, 0);
3098             if (global->code.globaladdr < 0)
3099                 return false;
3100         } else {
3101             vec_push(code_globals, vec_size(code_functions));
3102             if (!gen_global_function(self, global))
3103                 return false;
3104             if (!islocal)
3105                 def.type |= DEF_SAVEGLOBAL;
3106         }
3107         vec_push(code_defs, def);
3108         return true;
3109     case TYPE_VARIANT:
3110         /* assume biggest type */
3111             ir_value_code_setaddr(global, vec_size(code_globals));
3112             vec_push(code_globals, 0);
3113             for (i = 1; i < type_sizeof[TYPE_VARIANT]; ++i)
3114                 vec_push(code_globals, 0);
3115             return true;
3116     default:
3117         /* refuse to create 'void' type or any other fancy business. */
3118         irerror(global->context, "Invalid type for global variable `%s`: %s",
3119                 global->name, type_name[global->vtype]);
3120         return false;
3121     }
3122 }
3123
3124 static bool ir_builder_gen_field(ir_builder *self, ir_value *field)
3125 {
3126     prog_section_def def;
3127     prog_section_field fld;
3128
3129     (void)self;
3130
3131     def.type   = (uint16_t)field->vtype;
3132     def.offset = (uint16_t)vec_size(code_globals);
3133
3134     /* create a global named the same as the field */
3135     if (opts_standard == COMPILER_GMQCC) {
3136         /* in our standard, the global gets a dot prefix */
3137         size_t len = strlen(field->name);
3138         char name[1024];
3139
3140         /* we really don't want to have to allocate this, and 1024
3141          * bytes is more than enough for a variable/field name
3142          */
3143         if (len+2 >= sizeof(name)) {
3144             irerror(field->context, "invalid field name size: %u", (unsigned int)len);
3145             return false;
3146         }
3147
3148         name[0] = '.';
3149         memcpy(name+1, field->name, len); /* no strncpy - we used strlen above */
3150         name[len+1] = 0;
3151
3152         def.name = code_genstring(name);
3153         fld.name = def.name + 1; /* we reuse that string table entry */
3154     } else {
3155         /* in plain QC, there cannot be a global with the same name,
3156          * and so we also name the global the same.
3157          * FIXME: fteqcc should create a global as well
3158          * check if it actually uses the same name. Probably does
3159          */
3160         def.name = code_genstring(field->name);
3161         fld.name = def.name;
3162     }
3163
3164     field->code.name = def.name;
3165
3166     vec_push(code_defs, def);
3167
3168     fld.type = field->fieldtype;
3169
3170     if (fld.type == TYPE_VOID) {
3171         irerror(field->context, "field is missing a type: %s - don't know its size", field->name);
3172         return false;
3173     }
3174
3175     fld.offset = code_alloc_field(type_sizeof[field->fieldtype]);
3176
3177     vec_push(code_fields, fld);
3178
3179     ir_value_code_setaddr(field, vec_size(code_globals));
3180     vec_push(code_globals, fld.offset);
3181     if (fld.type == TYPE_VECTOR) {
3182         vec_push(code_globals, fld.offset+1);
3183         vec_push(code_globals, fld.offset+2);
3184     }
3185
3186     return field->code.globaladdr >= 0;
3187 }
3188
3189 bool ir_builder_generate(ir_builder *self, const char *filename)
3190 {
3191     prog_section_statement stmt;
3192     size_t i;
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     vec_push(code_statements, stmt);
3234
3235     if (!opts_pp_only)
3236         con_out("writing '%s'...\n", filename);
3237     return code_write(filename);
3238 }
3239
3240 /***********************************************************************
3241  *IR DEBUG Dump functions...
3242  */
3243
3244 #define IND_BUFSZ 1024
3245
3246 #ifdef WIN32
3247 # define strncat(dst, src, sz) strncat_s(dst, sz, src, _TRUNCATE)
3248 #endif
3249
3250 const char *qc_opname(int op)
3251 {
3252     if (op < 0) return "<INVALID>";
3253     if (op < (int)( sizeof(asm_instr) / sizeof(asm_instr[0]) ))
3254         return asm_instr[op].m;
3255     switch (op) {
3256         case VINSTR_PHI:  return "PHI";
3257         case VINSTR_JUMP: return "JUMP";
3258         case VINSTR_COND: return "COND";
3259         default:          return "<UNK>";
3260     }
3261 }
3262
3263 void ir_builder_dump(ir_builder *b, int (*oprintf)(const char*, ...))
3264 {
3265     size_t i;
3266     char indent[IND_BUFSZ];
3267     indent[0] = '\t';
3268     indent[1] = 0;
3269
3270     oprintf("module %s\n", b->name);
3271     for (i = 0; i < vec_size(b->globals); ++i)
3272     {
3273         oprintf("global ");
3274         if (b->globals[i]->hasvalue)
3275             oprintf("%s = ", b->globals[i]->name);
3276         ir_value_dump(b->globals[i], oprintf);
3277         oprintf("\n");
3278     }
3279     for (i = 0; i < vec_size(b->functions); ++i)
3280         ir_function_dump(b->functions[i], indent, oprintf);
3281     oprintf("endmodule %s\n", b->name);
3282 }
3283
3284 void ir_function_dump(ir_function *f, char *ind,
3285                       int (*oprintf)(const char*, ...))
3286 {
3287     size_t i;
3288     if (f->builtin != 0) {
3289         oprintf("%sfunction %s = builtin %i\n", ind, f->name, -f->builtin);
3290         return;
3291     }
3292     oprintf("%sfunction %s\n", ind, f->name);
3293     strncat(ind, "\t", IND_BUFSZ);
3294     if (vec_size(f->locals))
3295     {
3296         oprintf("%s%i locals:\n", ind, (int)vec_size(f->locals));
3297         for (i = 0; i < vec_size(f->locals); ++i) {
3298             oprintf("%s\t", ind);
3299             ir_value_dump(f->locals[i], oprintf);
3300             oprintf("\n");
3301         }
3302     }
3303     oprintf("%sliferanges:\n", ind);
3304     for (i = 0; i < vec_size(f->locals); ++i) {
3305         size_t l;
3306         ir_value *v = f->locals[i];
3307         oprintf("%s\t%s: unique ", ind, v->name);
3308         for (l = 0; l < vec_size(v->life); ++l) {
3309             oprintf("[%i,%i] ", v->life[l].start, v->life[l].end);
3310         }
3311         oprintf("\n");
3312     }
3313     for (i = 0; i < vec_size(f->values); ++i) {
3314         size_t l;
3315         ir_value *v = f->values[i];
3316         oprintf("%s\t%s: @%i ", ind, v->name, (int)v->code.local);
3317         for (l = 0; l < vec_size(v->life); ++l) {
3318             oprintf("[%i,%i] ", v->life[l].start, v->life[l].end);
3319         }
3320         oprintf("\n");
3321     }
3322     if (vec_size(f->blocks))
3323     {
3324         oprintf("%slife passes (check): %i\n", ind, (int)f->run_id);
3325         for (i = 0; i < vec_size(f->blocks); ++i) {
3326             if (f->blocks[i]->run_id != f->run_id) {
3327                 oprintf("%slife pass check fail! %i != %i\n", ind, (int)f->blocks[i]->run_id, (int)f->run_id);
3328             }
3329             ir_block_dump(f->blocks[i], ind, oprintf);
3330         }
3331
3332     }
3333     ind[strlen(ind)-1] = 0;
3334     oprintf("%sendfunction %s\n", ind, f->name);
3335 }
3336
3337 void ir_block_dump(ir_block* b, char *ind,
3338                    int (*oprintf)(const char*, ...))
3339 {
3340     size_t i;
3341     oprintf("%s:%s\n", ind, b->label);
3342     strncat(ind, "\t", IND_BUFSZ);
3343
3344     for (i = 0; i < vec_size(b->instr); ++i)
3345         ir_instr_dump(b->instr[i], ind, oprintf);
3346     ind[strlen(ind)-1] = 0;
3347 }
3348
3349 void dump_phi(ir_instr *in, int (*oprintf)(const char*, ...))
3350 {
3351     size_t i;
3352     oprintf("%s <- phi ", in->_ops[0]->name);
3353     for (i = 0; i < vec_size(in->phi); ++i)
3354     {
3355         oprintf("([%s] : %s) ", in->phi[i].from->label,
3356                                 in->phi[i].value->name);
3357     }
3358     oprintf("\n");
3359 }
3360
3361 void ir_instr_dump(ir_instr *in, char *ind,
3362                        int (*oprintf)(const char*, ...))
3363 {
3364     size_t i;
3365     const char *comma = NULL;
3366
3367     oprintf("%s (%i) ", ind, (int)in->eid);
3368
3369     if (in->opcode == VINSTR_PHI) {
3370         dump_phi(in, oprintf);
3371         return;
3372     }
3373
3374     strncat(ind, "\t", IND_BUFSZ);
3375
3376     if (in->_ops[0] && (in->_ops[1] || in->_ops[2])) {
3377         ir_value_dump(in->_ops[0], oprintf);
3378         if (in->_ops[1] || in->_ops[2])
3379             oprintf(" <- ");
3380     }
3381     if (in->opcode == INSTR_CALL0) {
3382         oprintf("CALL%i\t", vec_size(in->params));
3383     } else
3384         oprintf("%s\t", qc_opname(in->opcode));
3385
3386     if (in->_ops[0] && !(in->_ops[1] || in->_ops[2])) {
3387         ir_value_dump(in->_ops[0], oprintf);
3388         comma = ",\t";
3389     }
3390     else
3391     {
3392         for (i = 1; i != 3; ++i) {
3393             if (in->_ops[i]) {
3394                 if (comma)
3395                     oprintf(comma);
3396                 ir_value_dump(in->_ops[i], oprintf);
3397                 comma = ",\t";
3398             }
3399         }
3400     }
3401     if (in->bops[0]) {
3402         if (comma)
3403             oprintf(comma);
3404         oprintf("[%s]", in->bops[0]->label);
3405         comma = ",\t";
3406     }
3407     if (in->bops[1])
3408         oprintf("%s[%s]", comma, in->bops[1]->label);
3409     if (vec_size(in->params)) {
3410         oprintf("\tparams: ");
3411         for (i = 0; i != vec_size(in->params); ++i) {
3412             oprintf("%s, ", in->params[i]->name);
3413         }
3414     }
3415     oprintf("\n");
3416     ind[strlen(ind)-1] = 0;
3417 }
3418
3419 void ir_value_dump_string(const char *str, int (*oprintf)(const char*, ...))
3420 {
3421     oprintf("\"");
3422     for (; *str; ++str) {
3423         switch (*str) {
3424             case '\n': oprintf("\\n"); break;
3425             case '\r': oprintf("\\r"); break;
3426             case '\t': oprintf("\\t"); break;
3427             case '\v': oprintf("\\v"); break;
3428             case '\f': oprintf("\\f"); break;
3429             case '\b': oprintf("\\b"); break;
3430             case '\a': oprintf("\\a"); break;
3431             case '\\': oprintf("\\\\"); break;
3432             case '"': oprintf("\\\""); break;
3433             default: oprintf("%c", *str); break;
3434         }
3435     }
3436     oprintf("\"");
3437 }
3438
3439 void ir_value_dump(ir_value* v, int (*oprintf)(const char*, ...))
3440 {
3441     if (v->hasvalue) {
3442         switch (v->vtype) {
3443             default:
3444             case TYPE_VOID:
3445                 oprintf("(void)");
3446                 break;
3447             case TYPE_FUNCTION:
3448                 oprintf("fn:%s", v->name);
3449                 break;
3450             case TYPE_FLOAT:
3451                 oprintf("%g", v->constval.vfloat);
3452                 break;
3453             case TYPE_VECTOR:
3454                 oprintf("'%g %g %g'",
3455                         v->constval.vvec.x,
3456                         v->constval.vvec.y,
3457                         v->constval.vvec.z);
3458                 break;
3459             case TYPE_ENTITY:
3460                 oprintf("(entity)");
3461                 break;
3462             case TYPE_STRING:
3463                 ir_value_dump_string(v->constval.vstring, oprintf);
3464                 break;
3465 #if 0
3466             case TYPE_INTEGER:
3467                 oprintf("%i", v->constval.vint);
3468                 break;
3469 #endif
3470             case TYPE_POINTER:
3471                 oprintf("&%s",
3472                     v->constval.vpointer->name);
3473                 break;
3474         }
3475     } else {
3476         oprintf("%s", v->name);
3477     }
3478 }
3479
3480 void ir_value_dump_life(const ir_value *self, int (*oprintf)(const char*,...))
3481 {
3482     size_t i;
3483     oprintf("Life of %12s:", self->name);
3484     for (i = 0; i < vec_size(self->life); ++i)
3485     {
3486         oprintf(" + [%i, %i]\n", self->life[i].start, self->life[i].end);
3487     }
3488 }