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