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