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