]> git.xonotic.org Git - xonotic/gmqcc.git/blob - ir.c
25fbc73cf3e9f682138f19da7af9f25fc14acddf
[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 #if 0
1772 static bool ir_naive_phi_emit_store(ir_block *block, size_t iid, ir_value *old, ir_value *what)
1773 {
1774     ir_instr *instr;
1775     size_t i;
1776
1777     /* create a store */
1778     if (!ir_block_create_store(block, old, what))
1779         return false;
1780
1781     /* we now move it up */
1782     instr = vec_last(block->instr);
1783     for (i = vec_size(block->instr)-1; i > iid; --i)
1784         block->instr[i] = block->instr[i-1];
1785     block->instr[i] = instr;
1786
1787     return true;
1788 }
1789 #endif
1790
1791 static bool ir_block_naive_phi(ir_block *self)
1792 {
1793     size_t i, p; /*, w;*/
1794     /* FIXME: optionally, create_phi can add the phis
1795      * to a list so we don't need to loop through blocks
1796      * - anyway: "don't optimize YET"
1797      */
1798     for (i = 0; i < vec_size(self->instr); ++i)
1799     {
1800         ir_instr *instr = self->instr[i];
1801         if (instr->opcode != VINSTR_PHI)
1802             continue;
1803
1804         vec_remove(self->instr, i, 1);
1805         --i; /* NOTE: i+1 below */
1806
1807         for (p = 0; p < vec_size(instr->phi); ++p)
1808         {
1809             ir_value *v = instr->phi[p].value;
1810             ir_block *b = instr->phi[p].from;
1811
1812             if (v->store == store_value &&
1813                 vec_size(v->reads) == 1 &&
1814                 vec_size(v->writes) == 1)
1815             {
1816                 /* replace the value */
1817                 if (!ir_instr_op(v->writes[0], 0, instr->_ops[0], true))
1818                     return false;
1819             }
1820             else
1821             {
1822                 /* force a move instruction */
1823                 ir_instr *prevjump = vec_last(b->instr);
1824                 vec_pop(b->instr);
1825                 b->final = false;
1826                 instr->_ops[0]->store = store_global;
1827                 if (!ir_block_create_store(b, instr->_ops[0], v))
1828                     return false;
1829                 instr->_ops[0]->store = store_value;
1830                 vec_push(b->instr, prevjump);
1831                 b->final = true;
1832             }
1833
1834 #if 0
1835             ir_value *v = instr->phi[p].value;
1836             for (w = 0; w < vec_size(v->writes); ++w) {
1837                 ir_value *old;
1838
1839                 if (!v->writes[w]->_ops[0])
1840                     continue;
1841
1842                 /* When the write was to a global, we have to emit a mov */
1843                 old = v->writes[w]->_ops[0];
1844
1845                 /* The original instruction now writes to the PHI target local */
1846                 if (v->writes[w]->_ops[0] == v)
1847                     v->writes[w]->_ops[0] = instr->_ops[0];
1848
1849                 if (old->store != store_value && old->store != store_local && old->store != store_param)
1850                 {
1851                     /* If it originally wrote to a global we need to store the value
1852                      * there as welli
1853                      */
1854                     if (!ir_naive_phi_emit_store(self, i+1, old, v))
1855                         return false;
1856                     if (i+1 < vec_size(self->instr))
1857                         instr = self->instr[i+1];
1858                     else
1859                         instr = NULL;
1860                     /* In case I forget and access instr later, it'll be NULL
1861                      * when it's a problem, to make sure we crash, rather than accessing
1862                      * invalid data.
1863                      */
1864                 }
1865                 else
1866                 {
1867                     /* If it didn't, we can replace all reads by the phi target now. */
1868                     size_t r;
1869                     for (r = 0; r < vec_size(old->reads); ++r)
1870                     {
1871                         size_t op;
1872                         ir_instr *ri = old->reads[r];
1873                         for (op = 0; op < vec_size(ri->phi); ++op) {
1874                             if (ri->phi[op].value == old)
1875                                 ri->phi[op].value = v;
1876                         }
1877                         for (op = 0; op < 3; ++op) {
1878                             if (ri->_ops[op] == old)
1879                                 ri->_ops[op] = v;
1880                         }
1881                     }
1882                 }
1883             }
1884 #endif
1885         }
1886         ir_instr_delete(instr);
1887     }
1888     return true;
1889 }
1890
1891 /***********************************************************************
1892  *IR Temp allocation code
1893  * Propagating value life ranges by walking through the function backwards
1894  * until no more changes are made.
1895  * In theory this should happen once more than once for every nested loop
1896  * level.
1897  * Though this implementation might run an additional time for if nests.
1898  */
1899
1900 /* Enumerate instructions used by value's life-ranges
1901  */
1902 static void ir_block_enumerate(ir_block *self, size_t *_eid)
1903 {
1904     size_t i;
1905     size_t eid = *_eid;
1906     for (i = 0; i < vec_size(self->instr); ++i)
1907     {
1908         self->instr[i]->eid = eid++;
1909     }
1910     *_eid = eid;
1911 }
1912
1913 /* Enumerate blocks and instructions.
1914  * The block-enumeration is unordered!
1915  * We do not really use the block enumreation, however
1916  * the instruction enumeration is important for life-ranges.
1917  */
1918 void ir_function_enumerate(ir_function *self)
1919 {
1920     size_t i;
1921     size_t instruction_id = 0;
1922     for (i = 0; i < vec_size(self->blocks); ++i)
1923     {
1924         self->blocks[i]->eid = i;
1925         self->blocks[i]->run_id = 0;
1926         ir_block_enumerate(self->blocks[i], &instruction_id);
1927     }
1928 }
1929
1930 static bool ir_block_life_propagate(ir_block *b, ir_block *prev, bool *changed);
1931 bool ir_function_calculate_liferanges(ir_function *self)
1932 {
1933     size_t i;
1934     bool changed;
1935
1936     do {
1937         self->run_id++;
1938         changed = false;
1939         for (i = 0; i != vec_size(self->blocks); ++i)
1940         {
1941             if (self->blocks[i]->is_return)
1942             {
1943                 vec_free(self->blocks[i]->living);
1944                 if (!ir_block_life_propagate(self->blocks[i], NULL, &changed))
1945                     return false;
1946             }
1947         }
1948     } while (changed);
1949     if (vec_size(self->blocks)) {
1950         ir_block *block = self->blocks[0];
1951         for (i = 0; i < vec_size(block->living); ++i) {
1952             ir_value *v = block->living[i];
1953             if (v->memberof || v->store != store_local)
1954                 continue;
1955             if (irwarning(v->context, WARN_USED_UNINITIALIZED,
1956                           "variable `%s` may be used uninitialized in this function", v->name))
1957             {
1958                 return false;
1959             }
1960         }
1961     }
1962     return true;
1963 }
1964
1965 /* Local-value allocator
1966  * After finishing creating the liferange of all values used in a function
1967  * we can allocate their global-positions.
1968  * This is the counterpart to register-allocation in register machines.
1969  */
1970 typedef struct {
1971     ir_value **locals;
1972     size_t    *sizes;
1973     size_t    *positions;
1974 } function_allocator;
1975
1976 static bool function_allocator_alloc(function_allocator *alloc, const ir_value *var)
1977 {
1978     ir_value *slot;
1979     size_t vsize = type_sizeof[var->vtype];
1980
1981     slot = ir_value_var("reg", store_global, var->vtype);
1982     if (!slot)
1983         return false;
1984
1985     if (!ir_value_life_merge_into(slot, var))
1986         goto localerror;
1987
1988     vec_push(alloc->locals, slot);
1989     vec_push(alloc->sizes, vsize);
1990
1991     return true;
1992
1993 localerror:
1994     ir_value_delete(slot);
1995     return false;
1996 }
1997
1998 bool ir_function_allocate_locals(ir_function *self)
1999 {
2000     size_t i, a;
2001     bool   retval = true;
2002     size_t pos;
2003
2004     ir_value *slot;
2005     const ir_value *v;
2006
2007     function_allocator alloc;
2008
2009     if (!vec_size(self->locals) && !vec_size(self->values))
2010         return true;
2011
2012     alloc.locals    = NULL;
2013     alloc.sizes     = NULL;
2014     alloc.positions = NULL;
2015
2016     for (i = 0; i < vec_size(self->locals); ++i)
2017     {
2018         if (!function_allocator_alloc(&alloc, self->locals[i]))
2019             goto error;
2020     }
2021
2022     /* Allocate a slot for any value that still exists */
2023     for (i = 0; i < vec_size(self->values); ++i)
2024     {
2025         v = self->values[i];
2026
2027         if (!vec_size(v->life))
2028             continue;
2029
2030         for (a = 0; a < vec_size(alloc.locals); ++a)
2031         {
2032             slot = alloc.locals[a];
2033
2034             if (ir_values_overlap(v, slot))
2035                 continue;
2036
2037             if (!ir_value_life_merge_into(slot, v))
2038                 goto error;
2039
2040             /* adjust size for this slot */
2041             if (alloc.sizes[a] < type_sizeof[v->vtype])
2042                 alloc.sizes[a] = type_sizeof[v->vtype];
2043
2044             self->values[i]->code.local = a;
2045             break;
2046         }
2047         if (a >= vec_size(alloc.locals)) {
2048             self->values[i]->code.local = vec_size(alloc.locals);
2049             if (!function_allocator_alloc(&alloc, v))
2050                 goto error;
2051         }
2052     }
2053
2054     if (!alloc.sizes) {
2055         goto cleanup;
2056     }
2057
2058     /* Adjust slot positions based on sizes */
2059     vec_push(alloc.positions, 0);
2060
2061     if (vec_size(alloc.sizes))
2062         pos = alloc.positions[0] + alloc.sizes[0];
2063     else
2064         pos = 0;
2065     for (i = 1; i < vec_size(alloc.sizes); ++i)
2066     {
2067         pos = alloc.positions[i-1] + alloc.sizes[i-1];
2068         vec_push(alloc.positions, pos);
2069     }
2070
2071     self->allocated_locals = pos + vec_last(alloc.sizes);
2072
2073     /* Take over the actual slot positions */
2074     for (i = 0; i < vec_size(self->values); ++i) {
2075         self->values[i]->code.local = alloc.positions[self->values[i]->code.local];
2076     }
2077
2078     goto cleanup;
2079
2080 error:
2081     retval = false;
2082 cleanup:
2083     for (i = 0; i < vec_size(alloc.locals); ++i)
2084         ir_value_delete(alloc.locals[i]);
2085     vec_free(alloc.locals);
2086     vec_free(alloc.sizes);
2087     vec_free(alloc.positions);
2088     return retval;
2089 }
2090
2091 /* Get information about which operand
2092  * is read from, or written to.
2093  */
2094 static void ir_op_read_write(int op, size_t *read, size_t *write)
2095 {
2096     switch (op)
2097     {
2098     case VINSTR_JUMP:
2099     case INSTR_GOTO:
2100         *write = 0;
2101         *read = 0;
2102         break;
2103     case INSTR_IF:
2104     case INSTR_IFNOT:
2105 #if 0
2106     case INSTR_IF_S:
2107     case INSTR_IFNOT_S:
2108 #endif
2109     case INSTR_RETURN:
2110     case VINSTR_COND:
2111         *write = 0;
2112         *read = 1;
2113         break;
2114     case INSTR_STOREP_F:
2115     case INSTR_STOREP_V:
2116     case INSTR_STOREP_S:
2117     case INSTR_STOREP_ENT:
2118     case INSTR_STOREP_FLD:
2119     case INSTR_STOREP_FNC:
2120         *write = 0;
2121         *read  = 7;
2122         break;
2123     default:
2124         *write = 1;
2125         *read = 6;
2126         break;
2127     };
2128 }
2129
2130 static bool ir_block_living_add_instr(ir_block *self, size_t eid)
2131 {
2132     size_t i;
2133     bool changed = false;
2134     bool tempbool;
2135     for (i = 0; i != vec_size(self->living); ++i)
2136     {
2137         tempbool = ir_value_life_merge(self->living[i], eid);
2138         /* debug
2139         if (tempbool)
2140             irerror(self->context, "block_living_add_instr() value instruction added %s: %i", self->living[i]->_name, (int)eid);
2141         */
2142         changed = changed || tempbool;
2143     }
2144     return changed;
2145 }
2146
2147 static bool ir_block_life_prop_previous(ir_block* self, ir_block *prev, bool *changed)
2148 {
2149     size_t i;
2150     /* values which have been read in a previous iteration are now
2151      * in the "living" array even if the previous block doesn't use them.
2152      * So we have to remove whatever does not exist in the previous block.
2153      * They will be re-added on-read, but the liferange merge won't cause
2154      * a change.
2155      */
2156     for (i = 0; i < vec_size(self->living); ++i)
2157     {
2158         if (!vec_ir_value_find(prev->living, self->living[i], NULL)) {
2159             vec_remove(self->living, i, 1);
2160             --i;
2161         }
2162     }
2163
2164     /* Whatever the previous block still has in its living set
2165      * must now be added to ours as well.
2166      */
2167     for (i = 0; i < vec_size(prev->living); ++i)
2168     {
2169         if (vec_ir_value_find(self->living, prev->living[i], NULL))
2170             continue;
2171         vec_push(self->living, prev->living[i]);
2172         /*
2173         irerror(self->contextt from prev: %s", self->label, prev->living[i]->_name);
2174         */
2175     }
2176     return true;
2177 }
2178
2179 static bool ir_block_life_propagate(ir_block *self, ir_block *prev, bool *changed)
2180 {
2181     ir_instr *instr;
2182     ir_value *value;
2183     bool  tempbool;
2184     size_t i, o, p;
2185     /* bitmasks which operands are read from or written to */
2186     size_t read, write;
2187     char dbg_ind[16] = { '#', '0' };
2188     (void)dbg_ind;
2189
2190     if (prev)
2191     {
2192         if (!ir_block_life_prop_previous(self, prev, changed))
2193             return false;
2194     }
2195
2196     i = vec_size(self->instr);
2197     while (i)
2198     { --i;
2199         instr = self->instr[i];
2200
2201         /* PHI operands are always read operands */
2202         for (p = 0; p < vec_size(instr->phi); ++p)
2203         {
2204             value = instr->phi[p].value;
2205             if (value->memberof)
2206                 value = value->memberof;
2207             if (!vec_ir_value_find(self->living, value, NULL))
2208                 vec_push(self->living, value);
2209         }
2210
2211         /* call params are read operands too */
2212         for (p = 0; p < vec_size(instr->params); ++p)
2213         {
2214             value = instr->params[p];
2215             if (value->memberof)
2216                 value = value->memberof;
2217             if (!vec_ir_value_find(self->living, value, NULL))
2218                 vec_push(self->living, value);
2219         }
2220
2221         /* See which operands are read and write operands */
2222         ir_op_read_write(instr->opcode, &read, &write);
2223
2224         if (instr->opcode == INSTR_MUL_VF)
2225         {
2226             /* the float source will get an additional lifetime */
2227             tempbool = ir_value_life_merge(instr->_ops[2], instr->eid+1);
2228             *changed = *changed || tempbool;
2229         }
2230         else if (instr->opcode == INSTR_MUL_FV)
2231         {
2232             /* the float source will get an additional lifetime */
2233             tempbool = ir_value_life_merge(instr->_ops[1], instr->eid+1);
2234             *changed = *changed || tempbool;
2235         }
2236
2237         /* Go through the 3 main operands */
2238         for (o = 0; o < 3; ++o)
2239         {
2240             if (!instr->_ops[o]) /* no such operand */
2241                 continue;
2242
2243             value = instr->_ops[o];
2244             if (value->memberof)
2245                 value = value->memberof;
2246
2247             /* We only care about locals */
2248             /* we also calculate parameter liferanges so that locals
2249              * can take up parameter slots */
2250             if (value->store != store_value &&
2251                 value->store != store_local &&
2252                 value->store != store_param)
2253                 continue;
2254
2255             /* read operands */
2256             if (read & (1<<o))
2257             {
2258                 if (!vec_ir_value_find(self->living, value, NULL))
2259                     vec_push(self->living, value);
2260             }
2261
2262             /* write operands */
2263             /* When we write to a local, we consider it "dead" for the
2264              * remaining upper part of the function, since in SSA a value
2265              * can only be written once (== created)
2266              */
2267             if (write & (1<<o))
2268             {
2269                 size_t idx;
2270                 bool in_living = vec_ir_value_find(self->living, value, &idx);
2271                 if (!in_living)
2272                 {
2273                     /* If the value isn't alive it hasn't been read before... */
2274                     /* TODO: See if the warning can be emitted during parsing or AST processing
2275                      * otherwise have warning printed here.
2276                      * IF printing a warning here: include filecontext_t,
2277                      * and make sure it's only printed once
2278                      * since this function is run multiple times.
2279                      */
2280                     /* For now: debug info: */
2281                     /* con_err( "Value only written %s\n", value->name); */
2282                     tempbool = ir_value_life_merge(value, instr->eid);
2283                     *changed = *changed || tempbool;
2284                     /*
2285                     ir_instr_dump(instr, dbg_ind, printf);
2286                     abort();
2287                     */
2288                 } else {
2289                     /* since 'living' won't contain it
2290                      * anymore, merge the value, since
2291                      * (A) doesn't.
2292                      */
2293                     tempbool = ir_value_life_merge(value, instr->eid);
2294                     /*
2295                     if (tempbool)
2296                         con_err( "value added id %s %i\n", value->name, (int)instr->eid);
2297                     */
2298                     *changed = *changed || tempbool;
2299                     /* Then remove */
2300                     vec_remove(self->living, idx, 1);
2301                 }
2302             }
2303         }
2304         /* (A) */
2305         tempbool = ir_block_living_add_instr(self, instr->eid);
2306         /*con_err( "living added values\n");*/
2307         *changed = *changed || tempbool;
2308
2309     }
2310
2311     if (self->run_id == self->owner->run_id)
2312         return true;
2313
2314     self->run_id = self->owner->run_id;
2315
2316     for (i = 0; i < vec_size(self->entries); ++i)
2317     {
2318         ir_block *entry = self->entries[i];
2319         ir_block_life_propagate(entry, self, changed);
2320     }
2321
2322     return true;
2323 }
2324
2325 /***********************************************************************
2326  *IR Code-Generation
2327  *
2328  * Since the IR has the convention of putting 'write' operands
2329  * at the beginning, we have to rotate the operands of instructions
2330  * properly in order to generate valid QCVM code.
2331  *
2332  * Having destinations at a fixed position is more convenient. In QC
2333  * this is *mostly* OPC,  but FTE adds at least 2 instructions which
2334  * read from from OPA,  and store to OPB rather than OPC.   Which is
2335  * partially the reason why the implementation of these instructions
2336  * in darkplaces has been delayed for so long.
2337  *
2338  * Breaking conventions is annoying...
2339  */
2340 static bool ir_builder_gen_global(ir_builder *self, ir_value *global, bool islocal);
2341
2342 static bool gen_global_field(ir_value *global)
2343 {
2344     if (global->isconst)
2345     {
2346         ir_value *fld = global->constval.vpointer;
2347         if (!fld) {
2348             irerror(global->context, "Invalid field constant with no field: %s", global->name);
2349             return false;
2350         }
2351
2352         /* Now, in this case, a relocation would be impossible to code
2353          * since it looks like this:
2354          * .vector v = origin;     <- parse error, wtf is 'origin'?
2355          * .vector origin;
2356          *
2357          * But we will need a general relocation support later anyway
2358          * for functions... might as well support that here.
2359          */
2360         if (!fld->code.globaladdr) {
2361             irerror(global->context, "FIXME: Relocation support");
2362             return false;
2363         }
2364
2365         /* copy the field's value */
2366         ir_value_code_setaddr(global, vec_size(code_globals));
2367         vec_push(code_globals, code_globals[fld->code.globaladdr]);
2368         if (global->fieldtype == TYPE_VECTOR) {
2369             vec_push(code_globals, code_globals[fld->code.globaladdr]+1);
2370             vec_push(code_globals, code_globals[fld->code.globaladdr]+2);
2371         }
2372     }
2373     else
2374     {
2375         ir_value_code_setaddr(global, vec_size(code_globals));
2376         vec_push(code_globals, 0);
2377         if (global->fieldtype == TYPE_VECTOR) {
2378             vec_push(code_globals, 0);
2379             vec_push(code_globals, 0);
2380         }
2381     }
2382     if (global->code.globaladdr < 0)
2383         return false;
2384     return true;
2385 }
2386
2387 static bool gen_global_pointer(ir_value *global)
2388 {
2389     if (global->isconst)
2390     {
2391         ir_value *target = global->constval.vpointer;
2392         if (!target) {
2393             irerror(global->context, "Invalid pointer constant: %s", global->name);
2394             /* NULL pointers are pointing to the NULL constant, which also
2395              * sits at address 0, but still has an ir_value for itself.
2396              */
2397             return false;
2398         }
2399
2400         /* Here, relocations ARE possible - in fteqcc-enhanced-qc:
2401          * void() foo; <- proto
2402          * void() *fooptr = &foo;
2403          * void() foo = { code }
2404          */
2405         if (!target->code.globaladdr) {
2406             /* FIXME: Check for the constant nullptr ir_value!
2407              * because then code.globaladdr being 0 is valid.
2408              */
2409             irerror(global->context, "FIXME: Relocation support");
2410             return false;
2411         }
2412
2413         ir_value_code_setaddr(global, vec_size(code_globals));
2414         vec_push(code_globals, target->code.globaladdr);
2415     }
2416     else
2417     {
2418         ir_value_code_setaddr(global, vec_size(code_globals));
2419         vec_push(code_globals, 0);
2420     }
2421     if (global->code.globaladdr < 0)
2422         return false;
2423     return true;
2424 }
2425
2426 static bool gen_blocks_recursive(ir_function *func, ir_block *block)
2427 {
2428     prog_section_statement stmt;
2429     ir_instr *instr;
2430     ir_block *target;
2431     ir_block *ontrue;
2432     ir_block *onfalse;
2433     size_t    stidx;
2434     size_t    i;
2435
2436 tailcall:
2437     block->generated = true;
2438     block->code_start = vec_size(code_statements);
2439     for (i = 0; i < vec_size(block->instr); ++i)
2440     {
2441         instr = block->instr[i];
2442
2443         if (instr->opcode == VINSTR_PHI) {
2444             irerror(block->context, "cannot generate virtual instruction (phi)");
2445             return false;
2446         }
2447
2448         if (instr->opcode == VINSTR_JUMP) {
2449             target = instr->bops[0];
2450             /* for uncoditional jumps, if the target hasn't been generated
2451              * yet, we generate them right here.
2452              */
2453             if (!target->generated) {
2454                 block = target;
2455                 goto tailcall;
2456             }
2457
2458             /* otherwise we generate a jump instruction */
2459             stmt.opcode = INSTR_GOTO;
2460             stmt.o1.s1 = (target->code_start) - vec_size(code_statements);
2461             stmt.o2.s1 = 0;
2462             stmt.o3.s1 = 0;
2463             vec_push(code_statements, stmt);
2464
2465             /* no further instructions can be in this block */
2466             return true;
2467         }
2468
2469         if (instr->opcode == VINSTR_COND) {
2470             ontrue  = instr->bops[0];
2471             onfalse = instr->bops[1];
2472             /* TODO: have the AST signal which block should
2473              * come first: eg. optimize IFs without ELSE...
2474              */
2475
2476             stmt.o1.u1 = ir_value_code_addr(instr->_ops[0]);
2477             stmt.o2.u1 = 0;
2478             stmt.o3.s1 = 0;
2479
2480             if (ontrue->generated) {
2481                 stmt.opcode = INSTR_IF;
2482                 stmt.o2.s1 = (ontrue->code_start) - vec_size(code_statements);
2483                 vec_push(code_statements, stmt);
2484             }
2485             if (onfalse->generated) {
2486                 stmt.opcode = INSTR_IFNOT;
2487                 stmt.o2.s1 = (onfalse->code_start) - vec_size(code_statements);
2488                 vec_push(code_statements, stmt);
2489             }
2490             if (!ontrue->generated) {
2491                 if (onfalse->generated) {
2492                     block = ontrue;
2493                     goto tailcall;
2494                 }
2495             }
2496             if (!onfalse->generated) {
2497                 if (ontrue->generated) {
2498                     block = onfalse;
2499                     goto tailcall;
2500                 }
2501             }
2502             /* neither ontrue nor onfalse exist */
2503             stmt.opcode = INSTR_IFNOT;
2504             stidx = vec_size(code_statements);
2505             vec_push(code_statements, stmt);
2506             /* on false we jump, so add ontrue-path */
2507             if (!gen_blocks_recursive(func, ontrue))
2508                 return false;
2509             /* fixup the jump address */
2510             code_statements[stidx].o2.s1 = vec_size(code_statements) - stidx;
2511             /* generate onfalse path */
2512             if (onfalse->generated) {
2513                 /* fixup the jump address */
2514                 code_statements[stidx].o2.s1 = (onfalse->code_start) - (stidx);
2515                 /* may have been generated in the previous recursive call */
2516                 stmt.opcode = INSTR_GOTO;
2517                 stmt.o1.s1 = (onfalse->code_start) - vec_size(code_statements);
2518                 stmt.o2.s1 = 0;
2519                 stmt.o3.s1 = 0;
2520                 vec_push(code_statements, stmt);
2521                 return true;
2522             }
2523             /* if not, generate now */
2524             block = onfalse;
2525             goto tailcall;
2526         }
2527
2528         if (instr->opcode >= INSTR_CALL0 && instr->opcode <= INSTR_CALL8) {
2529             /* Trivial call translation:
2530              * copy all params to OFS_PARM*
2531              * if the output's storetype is not store_return,
2532              * add append a STORE instruction!
2533              *
2534              * NOTES on how to do it better without much trouble:
2535              * -) The liferanges!
2536              *      Simply check the liferange of all parameters for
2537              *      other CALLs. For each param with no CALL in its
2538              *      liferange, we can store it in an OFS_PARM at
2539              *      generation already. This would even include later
2540              *      reuse.... probably... :)
2541              */
2542             size_t p, first;
2543             ir_value *retvalue;
2544
2545             first = vec_size(instr->params);
2546             if (first > 8)
2547                 first = 8;
2548             for (p = 0; p < first; ++p)
2549             {
2550                 ir_value *param = instr->params[p];
2551
2552                 stmt.opcode = INSTR_STORE_F;
2553                 stmt.o3.u1 = 0;
2554
2555                 if (param->vtype == TYPE_FIELD)
2556                     stmt.opcode = field_store_instr[param->fieldtype];
2557                 else
2558                     stmt.opcode = type_store_instr[param->vtype];
2559                 stmt.o1.u1 = ir_value_code_addr(param);
2560                 stmt.o2.u1 = OFS_PARM0 + 3 * p;
2561                 vec_push(code_statements, stmt);
2562             }
2563             /* No whandle extparams */
2564             first = vec_size(instr->params);
2565             for (; p < first; ++p)
2566             {
2567                 ir_builder *ir = func->owner;
2568                 ir_value *param = instr->params[p];
2569                 ir_value *target;
2570
2571                 if (p-8 >= vec_size(ir->extparams)) {
2572                     irerror(instr->context, "Not enough extparam-globals have been created");
2573                     return false;
2574                 }
2575
2576                 target = ir->extparams[p-8];
2577
2578                 stmt.opcode = INSTR_STORE_F;
2579                 stmt.o3.u1 = 0;
2580
2581                 if (param->vtype == TYPE_FIELD)
2582                     stmt.opcode = field_store_instr[param->fieldtype];
2583                 else
2584                     stmt.opcode = type_store_instr[param->vtype];
2585                 stmt.o1.u1 = ir_value_code_addr(param);
2586                 stmt.o2.u1 = ir_value_code_addr(target);
2587                 vec_push(code_statements, stmt);
2588             }
2589
2590             stmt.opcode = INSTR_CALL0 + vec_size(instr->params);
2591             if (stmt.opcode > INSTR_CALL8)
2592                 stmt.opcode = INSTR_CALL8;
2593             stmt.o1.u1 = ir_value_code_addr(instr->_ops[1]);
2594             stmt.o2.u1 = 0;
2595             stmt.o3.u1 = 0;
2596             vec_push(code_statements, stmt);
2597
2598             retvalue = instr->_ops[0];
2599             if (retvalue && retvalue->store != store_return && vec_size(retvalue->life))
2600             {
2601                 /* not to be kept in OFS_RETURN */
2602                 if (retvalue->vtype == TYPE_FIELD)
2603                     stmt.opcode = field_store_instr[retvalue->vtype];
2604                 else
2605                     stmt.opcode = type_store_instr[retvalue->vtype];
2606                 stmt.o1.u1 = OFS_RETURN;
2607                 stmt.o2.u1 = ir_value_code_addr(retvalue);
2608                 stmt.o3.u1 = 0;
2609                 vec_push(code_statements, stmt);
2610             }
2611             continue;
2612         }
2613
2614         if (instr->opcode == INSTR_STATE) {
2615             irerror(block->context, "TODO: state instruction");
2616             return false;
2617         }
2618
2619         stmt.opcode = instr->opcode;
2620         stmt.o1.u1 = 0;
2621         stmt.o2.u1 = 0;
2622         stmt.o3.u1 = 0;
2623
2624         /* This is the general order of operands */
2625         if (instr->_ops[0])
2626             stmt.o3.u1 = ir_value_code_addr(instr->_ops[0]);
2627
2628         if (instr->_ops[1])
2629             stmt.o1.u1 = ir_value_code_addr(instr->_ops[1]);
2630
2631         if (instr->_ops[2])
2632             stmt.o2.u1 = ir_value_code_addr(instr->_ops[2]);
2633
2634         if (stmt.opcode == INSTR_RETURN || stmt.opcode == INSTR_DONE)
2635         {
2636             stmt.o1.u1 = stmt.o3.u1;
2637             stmt.o3.u1 = 0;
2638         }
2639         else if ((stmt.opcode >= INSTR_STORE_F &&
2640                   stmt.opcode <= INSTR_STORE_FNC) ||
2641                  (stmt.opcode >= INSTR_STOREP_F &&
2642                   stmt.opcode <= INSTR_STOREP_FNC))
2643         {
2644             /* 2-operand instructions with A -> B */
2645             stmt.o2.u1 = stmt.o3.u1;
2646             stmt.o3.u1 = 0;
2647         }
2648
2649         vec_push(code_statements, stmt);
2650     }
2651     return true;
2652 }
2653
2654 static bool gen_function_code(ir_function *self)
2655 {
2656     ir_block *block;
2657     prog_section_statement stmt;
2658
2659     /* Starting from entry point, we generate blocks "as they come"
2660      * for now. Dead blocks will not be translated obviously.
2661      */
2662     if (!vec_size(self->blocks)) {
2663         irerror(self->context, "Function '%s' declared without body.", self->name);
2664         return false;
2665     }
2666
2667     block = self->blocks[0];
2668     if (block->generated)
2669         return true;
2670
2671     if (!gen_blocks_recursive(self, block)) {
2672         irerror(self->context, "failed to generate blocks for '%s'", self->name);
2673         return false;
2674     }
2675
2676     /* otherwise code_write crashes since it debug-prints functions until AINSTR_END */
2677     stmt.opcode = AINSTR_END;
2678     stmt.o1.u1 = 0;
2679     stmt.o2.u1 = 0;
2680     stmt.o3.u1 = 0;
2681     vec_push(code_statements, stmt);
2682     return true;
2683 }
2684
2685 static qcint ir_builder_filestring(ir_builder *ir, const char *filename)
2686 {
2687     /* NOTE: filename pointers are copied, we never strdup them,
2688      * thus we can use pointer-comparison to find the string.
2689      */
2690     size_t i;
2691     qcint  str;
2692
2693     for (i = 0; i < vec_size(ir->filenames); ++i) {
2694         if (ir->filenames[i] == filename)
2695             return ir->filestrings[i];
2696     }
2697
2698     str = code_genstring(filename);
2699     vec_push(ir->filenames, filename);
2700     vec_push(ir->filestrings, str);
2701     return str;
2702 }
2703
2704 static bool gen_global_function(ir_builder *ir, ir_value *global)
2705 {
2706     prog_section_function fun;
2707     ir_function          *irfun;
2708
2709     size_t i;
2710     size_t local_var_end;
2711
2712     if (!global->isconst || (!global->constval.vfunc))
2713     {
2714         irerror(global->context, "Invalid state of function-global: not constant: %s", global->name);
2715         return false;
2716     }
2717
2718     irfun = global->constval.vfunc;
2719
2720     fun.name    = global->code.name;
2721     fun.file    = ir_builder_filestring(ir, global->context.file);
2722     fun.profile = 0; /* always 0 */
2723     fun.nargs   = vec_size(irfun->params);
2724     if (fun.nargs > 8)
2725         fun.nargs = 8;
2726
2727     for (i = 0;i < 8; ++i) {
2728         if (i >= fun.nargs)
2729             fun.argsize[i] = 0;
2730         else
2731             fun.argsize[i] = type_sizeof[irfun->params[i]];
2732     }
2733
2734     fun.firstlocal = vec_size(code_globals);
2735
2736     local_var_end = fun.firstlocal;
2737     for (i = 0; i < vec_size(irfun->locals); ++i) {
2738         if (!ir_builder_gen_global(ir, irfun->locals[i], true)) {
2739             irerror(irfun->locals[i]->context, "Failed to generate local %s", irfun->locals[i]->name);
2740             return false;
2741         }
2742     }
2743     if (vec_size(irfun->locals)) {
2744         ir_value *last = vec_last(irfun->locals);
2745         local_var_end = last->code.globaladdr;
2746         local_var_end += type_sizeof[last->vtype];
2747     }
2748     for (i = 0; i < vec_size(irfun->values); ++i)
2749     {
2750         /* generate code.globaladdr for ssa values */
2751         ir_value *v = irfun->values[i];
2752         ir_value_code_setaddr(v, local_var_end + v->code.local);
2753     }
2754     for (i = 0; i < irfun->allocated_locals; ++i) {
2755         /* fill the locals with zeros */
2756         vec_push(code_globals, 0);
2757     }
2758
2759     fun.locals = vec_size(code_globals) - fun.firstlocal;
2760
2761     if (irfun->builtin)
2762         fun.entry = irfun->builtin;
2763     else {
2764         irfun->code_function_def = vec_size(code_functions);
2765         fun.entry = vec_size(code_statements);
2766     }
2767
2768     vec_push(code_functions, fun);
2769     return true;
2770 }
2771
2772 static void ir_gen_extparam(ir_builder *ir)
2773 {
2774     prog_section_def def;
2775     ir_value        *global;
2776     char             name[128];
2777
2778     snprintf(name, sizeof(name), "EXTPARM#%i", (int)(vec_size(ir->extparams)+8));
2779     global = ir_value_var(name, store_global, TYPE_VECTOR);
2780
2781     def.name = code_genstring(name);
2782     def.type = TYPE_VECTOR;
2783     def.offset = vec_size(code_globals);
2784
2785     vec_push(code_defs, def);
2786     ir_value_code_setaddr(global, def.offset);
2787     vec_push(code_globals, 0);
2788     vec_push(code_globals, 0);
2789     vec_push(code_globals, 0);
2790
2791     vec_push(ir->extparams, global);
2792 }
2793
2794 static bool gen_function_extparam_copy(ir_function *self)
2795 {
2796     size_t i, ext, numparams;
2797
2798     ir_builder *ir = self->owner;
2799     ir_value   *ep;
2800     prog_section_statement stmt;
2801
2802     numparams = vec_size(self->params);
2803     if (!numparams)
2804         return true;
2805
2806     stmt.opcode = INSTR_STORE_F;
2807     stmt.o3.s1 = 0;
2808     for (i = 8; i < numparams; ++i) {
2809         ext = i - 8;
2810         if (ext >= vec_size(ir->extparams))
2811             ir_gen_extparam(ir);
2812
2813         ep = ir->extparams[ext];
2814
2815         stmt.opcode = type_store_instr[self->locals[i]->vtype];
2816         if (self->locals[i]->vtype == TYPE_FIELD &&
2817             self->locals[i]->fieldtype == TYPE_VECTOR)
2818         {
2819             stmt.opcode = INSTR_STORE_V;
2820         }
2821         stmt.o1.u1 = ir_value_code_addr(ep);
2822         stmt.o2.u1 = ir_value_code_addr(self->locals[i]);
2823         vec_push(code_statements, stmt);
2824     }
2825
2826     return true;
2827 }
2828
2829 static bool gen_global_function_code(ir_builder *ir, ir_value *global)
2830 {
2831     prog_section_function *fundef;
2832     ir_function           *irfun;
2833
2834     irfun = global->constval.vfunc;
2835     if (!irfun) {
2836         irwarning(global->context, WARN_IMPLICIT_FUNCTION_POINTER,
2837                   "function `%s` has no body and in QC implicitly becomes a function-pointer", global->name);
2838         /* this was a function pointer, don't generate code for those */
2839         return true;
2840     }
2841
2842     if (irfun->builtin)
2843         return true;
2844
2845     if (irfun->code_function_def < 0) {
2846         irerror(irfun->context, "`%s`: IR global wasn't generated, failed to access function-def", irfun->name);
2847         return false;
2848     }
2849     fundef = &code_functions[irfun->code_function_def];
2850
2851     fundef->entry = vec_size(code_statements);
2852     if (!gen_function_extparam_copy(irfun)) {
2853         irerror(irfun->context, "Failed to generate extparam-copy code for function %s", irfun->name);
2854         return false;
2855     }
2856     if (!gen_function_code(irfun)) {
2857         irerror(irfun->context, "Failed to generate code for function %s", irfun->name);
2858         return false;
2859     }
2860     return true;
2861 }
2862
2863 static bool ir_builder_gen_global(ir_builder *self, ir_value *global, bool islocal)
2864 {
2865     size_t           i;
2866     int32_t         *iptr;
2867     prog_section_def def;
2868
2869     def.type   = global->vtype;
2870     def.offset = vec_size(code_globals);
2871
2872     if (global->name) {
2873         if (global->name[0] == '#') {
2874             if (!self->str_immediate)
2875                 self->str_immediate = code_genstring("IMMEDIATE");
2876             def.name = global->code.name = self->str_immediate;
2877         }
2878         else
2879             def.name = global->code.name = code_genstring(global->name);
2880     }
2881     else
2882         def.name   = 0;
2883
2884     switch (global->vtype)
2885     {
2886     case TYPE_VOID:
2887         if (!strcmp(global->name, "end_sys_globals")) {
2888             /* TODO: remember this point... all the defs before this one
2889              * should be checksummed and added to progdefs.h when we generate it.
2890              */
2891         }
2892         else if (!strcmp(global->name, "end_sys_fields")) {
2893             /* TODO: same as above but for entity-fields rather than globsl
2894              */
2895         }
2896         else
2897             irwarning(global->context, WARN_VOID_VARIABLES, "unrecognized variable of type void `%s`",
2898                       global->name);
2899         /* I'd argue setting it to 0 is sufficient, but maybe some depend on knowing how far
2900          * the system fields actually go? Though the engine knows this anyway...
2901          * Maybe this could be an -foption
2902          * fteqcc creates data for end_sys_* - of size 1, so let's do the same
2903          */
2904         ir_value_code_setaddr(global, vec_size(code_globals));
2905         vec_push(code_globals, 0);
2906         /* Add the def */
2907         vec_push(code_defs, def);
2908         return true;
2909     case TYPE_POINTER:
2910         vec_push(code_defs, def);
2911         return gen_global_pointer(global);
2912     case TYPE_FIELD:
2913         vec_push(code_defs, def);
2914         return gen_global_field(global);
2915     case TYPE_ENTITY:
2916         /* fall through */
2917     case TYPE_FLOAT:
2918     {
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);
2923         } else {
2924             vec_push(code_globals, 0);
2925             if (!islocal)
2926                 def.type |= DEF_SAVEGLOBAL;
2927         }
2928         vec_push(code_defs, def);
2929
2930         return global->code.globaladdr >= 0;
2931     }
2932     case TYPE_STRING:
2933     {
2934         ir_value_code_setaddr(global, vec_size(code_globals));
2935         if (global->isconst) {
2936             vec_push(code_globals, code_genstring(global->constval.vstring));
2937         } else {
2938             vec_push(code_globals, 0);
2939             if (!islocal)
2940                 def.type |= DEF_SAVEGLOBAL;
2941         }
2942         vec_push(code_defs, def);
2943         return global->code.globaladdr >= 0;
2944     }
2945     case TYPE_VECTOR:
2946     {
2947         size_t d;
2948         ir_value_code_setaddr(global, vec_size(code_globals));
2949         if (global->isconst) {
2950             iptr = (int32_t*)&global->constval.ivec[0];
2951             vec_push(code_globals, iptr[0]);
2952             if (global->code.globaladdr < 0)
2953                 return false;
2954             for (d = 1; d < type_sizeof[global->vtype]; ++d)
2955             {
2956                 vec_push(code_globals, iptr[d]);
2957             }
2958         } else {
2959             vec_push(code_globals, 0);
2960             if (global->code.globaladdr < 0)
2961                 return false;
2962             for (d = 1; d < type_sizeof[global->vtype]; ++d)
2963             {
2964                 vec_push(code_globals, 0);
2965             }
2966             if (!islocal)
2967                 def.type |= DEF_SAVEGLOBAL;
2968         }
2969
2970         vec_push(code_defs, def);
2971         return global->code.globaladdr >= 0;
2972     }
2973     case TYPE_FUNCTION:
2974         ir_value_code_setaddr(global, vec_size(code_globals));
2975         if (!global->isconst) {
2976             vec_push(code_globals, 0);
2977             if (global->code.globaladdr < 0)
2978                 return false;
2979         } else {
2980             vec_push(code_globals, vec_size(code_functions));
2981             if (!gen_global_function(self, global))
2982                 return false;
2983             if (!islocal)
2984                 def.type |= DEF_SAVEGLOBAL;
2985         }
2986         vec_push(code_defs, def);
2987         return true;
2988     case TYPE_VARIANT:
2989         /* assume biggest type */
2990             ir_value_code_setaddr(global, vec_size(code_globals));
2991             vec_push(code_globals, 0);
2992             for (i = 1; i < type_sizeof[TYPE_VARIANT]; ++i)
2993                 vec_push(code_globals, 0);
2994             return true;
2995     default:
2996         /* refuse to create 'void' type or any other fancy business. */
2997         irerror(global->context, "Invalid type for global variable `%s`: %s",
2998                 global->name, type_name[global->vtype]);
2999         return false;
3000     }
3001 }
3002
3003 static bool ir_builder_gen_field(ir_builder *self, ir_value *field)
3004 {
3005     prog_section_def def;
3006     prog_section_field fld;
3007
3008     def.type   = field->vtype;
3009     def.offset = vec_size(code_globals);
3010
3011     /* create a global named the same as the field */
3012     if (opts_standard == COMPILER_GMQCC) {
3013         /* in our standard, the global gets a dot prefix */
3014         size_t len = strlen(field->name);
3015         char name[1024];
3016
3017         /* we really don't want to have to allocate this, and 1024
3018          * bytes is more than enough for a variable/field name
3019          */
3020         if (len+2 >= sizeof(name)) {
3021             irerror(field->context, "invalid field name size: %u", (unsigned int)len);
3022             return false;
3023         }
3024
3025         name[0] = '.';
3026         memcpy(name+1, field->name, len); /* no strncpy - we used strlen above */
3027         name[len+1] = 0;
3028
3029         def.name = code_genstring(name);
3030         fld.name = def.name + 1; /* we reuse that string table entry */
3031     } else {
3032         /* in plain QC, there cannot be a global with the same name,
3033          * and so we also name the global the same.
3034          * FIXME: fteqcc should create a global as well
3035          * check if it actually uses the same name. Probably does
3036          */
3037         def.name = code_genstring(field->name);
3038         fld.name = def.name;
3039     }
3040
3041     field->code.name = def.name;
3042
3043     vec_push(code_defs, def);
3044
3045     fld.type = field->fieldtype;
3046
3047     if (fld.type == TYPE_VOID) {
3048         irerror(field->context, "field is missing a type: %s - don't know its size", field->name);
3049         return false;
3050     }
3051
3052     fld.offset = code_alloc_field(type_sizeof[field->fieldtype]);
3053
3054     vec_push(code_fields, fld);
3055
3056     ir_value_code_setaddr(field, vec_size(code_globals));
3057     vec_push(code_globals, fld.offset);
3058     if (fld.type == TYPE_VECTOR) {
3059         vec_push(code_globals, fld.offset+1);
3060         vec_push(code_globals, fld.offset+2);
3061     }
3062
3063     return field->code.globaladdr >= 0;
3064 }
3065
3066 bool ir_builder_generate(ir_builder *self, const char *filename)
3067 {
3068     prog_section_statement stmt;
3069     size_t i;
3070
3071     code_init();
3072
3073     for (i = 0; i < vec_size(self->globals); ++i)
3074     {
3075         if (!ir_builder_gen_global(self, self->globals[i], false)) {
3076             return false;
3077         }
3078     }
3079
3080     for (i = 0; i < vec_size(self->fields); ++i)
3081     {
3082         if (!ir_builder_gen_field(self, self->fields[i])) {
3083             return false;
3084         }
3085     }
3086
3087     /* generate function code */
3088     for (i = 0; i < vec_size(self->globals); ++i)
3089     {
3090         if (self->globals[i]->vtype == TYPE_FUNCTION) {
3091             if (!gen_global_function_code(self, self->globals[i])) {
3092                 return false;
3093             }
3094         }
3095     }
3096
3097     /* DP errors if the last instruction is not an INSTR_DONE
3098      * and for debugging purposes we add an additional AINSTR_END
3099      * to the end of functions, so here it goes:
3100      */
3101     stmt.opcode = INSTR_DONE;
3102     stmt.o1.u1 = 0;
3103     stmt.o2.u1 = 0;
3104     stmt.o3.u1 = 0;
3105     vec_push(code_statements, stmt);
3106
3107     if (!opts_pp_only)
3108         con_out("writing '%s'...\n", filename);
3109     return code_write(filename);
3110 }
3111
3112 /***********************************************************************
3113  *IR DEBUG Dump functions...
3114  */
3115
3116 #define IND_BUFSZ 1024
3117
3118 #ifdef WIN32
3119 # define strncat(dst, src, sz) strncat_s(dst, sz, src, _TRUNCATE)
3120 #endif
3121
3122 const char *qc_opname(int op)
3123 {
3124     if (op < 0) return "<INVALID>";
3125     if (op < ( sizeof(asm_instr) / sizeof(asm_instr[0]) ))
3126         return asm_instr[op].m;
3127     switch (op) {
3128         case VINSTR_PHI:  return "PHI";
3129         case VINSTR_JUMP: return "JUMP";
3130         case VINSTR_COND: return "COND";
3131         default:          return "<UNK>";
3132     }
3133 }
3134
3135 void ir_builder_dump(ir_builder *b, int (*oprintf)(const char*, ...))
3136 {
3137     size_t i;
3138     char indent[IND_BUFSZ];
3139     indent[0] = '\t';
3140     indent[1] = 0;
3141
3142     oprintf("module %s\n", b->name);
3143     for (i = 0; i < vec_size(b->globals); ++i)
3144     {
3145         oprintf("global ");
3146         if (b->globals[i]->isconst)
3147             oprintf("%s = ", b->globals[i]->name);
3148         ir_value_dump(b->globals[i], oprintf);
3149         oprintf("\n");
3150     }
3151     for (i = 0; i < vec_size(b->functions); ++i)
3152         ir_function_dump(b->functions[i], indent, oprintf);
3153     oprintf("endmodule %s\n", b->name);
3154 }
3155
3156 void ir_function_dump(ir_function *f, char *ind,
3157                       int (*oprintf)(const char*, ...))
3158 {
3159     size_t i;
3160     if (f->builtin != 0) {
3161         oprintf("%sfunction %s = builtin %i\n", ind, f->name, -f->builtin);
3162         return;
3163     }
3164     oprintf("%sfunction %s\n", ind, f->name);
3165     strncat(ind, "\t", IND_BUFSZ);
3166     if (vec_size(f->locals))
3167     {
3168         oprintf("%s%i locals:\n", ind, (int)vec_size(f->locals));
3169         for (i = 0; i < vec_size(f->locals); ++i) {
3170             oprintf("%s\t", ind);
3171             ir_value_dump(f->locals[i], oprintf);
3172             oprintf("\n");
3173         }
3174     }
3175     oprintf("%sliferanges:\n", ind);
3176     for (i = 0; i < vec_size(f->locals); ++i) {
3177         size_t l;
3178         ir_value *v = f->locals[i];
3179         oprintf("%s\t%s: unique ", ind, v->name);
3180         for (l = 0; l < vec_size(v->life); ++l) {
3181             oprintf("[%i,%i] ", v->life[l].start, v->life[l].end);
3182         }
3183         oprintf("\n");
3184     }
3185     for (i = 0; i < vec_size(f->values); ++i) {
3186         size_t l;
3187         ir_value *v = f->values[i];
3188         oprintf("%s\t%s: @%i ", ind, v->name, (int)v->code.local);
3189         for (l = 0; l < vec_size(v->life); ++l) {
3190             oprintf("[%i,%i] ", v->life[l].start, v->life[l].end);
3191         }
3192         oprintf("\n");
3193     }
3194     if (vec_size(f->blocks))
3195     {
3196         oprintf("%slife passes (check): %i\n", ind, (int)f->run_id);
3197         for (i = 0; i < vec_size(f->blocks); ++i) {
3198             if (f->blocks[i]->run_id != f->run_id) {
3199                 oprintf("%slife pass check fail! %i != %i\n", ind, (int)f->blocks[i]->run_id, (int)f->run_id);
3200             }
3201             ir_block_dump(f->blocks[i], ind, oprintf);
3202         }
3203
3204     }
3205     ind[strlen(ind)-1] = 0;
3206     oprintf("%sendfunction %s\n", ind, f->name);
3207 }
3208
3209 void ir_block_dump(ir_block* b, char *ind,
3210                    int (*oprintf)(const char*, ...))
3211 {
3212     size_t i;
3213     oprintf("%s:%s\n", ind, b->label);
3214     strncat(ind, "\t", IND_BUFSZ);
3215
3216     for (i = 0; i < vec_size(b->instr); ++i)
3217         ir_instr_dump(b->instr[i], ind, oprintf);
3218     ind[strlen(ind)-1] = 0;
3219 }
3220
3221 void dump_phi(ir_instr *in, char *ind,
3222               int (*oprintf)(const char*, ...))
3223 {
3224     size_t i;
3225     oprintf("%s <- phi ", in->_ops[0]->name);
3226     for (i = 0; i < vec_size(in->phi); ++i)
3227     {
3228         oprintf("([%s] : %s) ", in->phi[i].from->label,
3229                                 in->phi[i].value->name);
3230     }
3231     oprintf("\n");
3232 }
3233
3234 void ir_instr_dump(ir_instr *in, char *ind,
3235                        int (*oprintf)(const char*, ...))
3236 {
3237     size_t i;
3238     const char *comma = NULL;
3239
3240     oprintf("%s (%i) ", ind, (int)in->eid);
3241
3242     if (in->opcode == VINSTR_PHI) {
3243         dump_phi(in, ind, oprintf);
3244         return;
3245     }
3246
3247     strncat(ind, "\t", IND_BUFSZ);
3248
3249     if (in->_ops[0] && (in->_ops[1] || in->_ops[2])) {
3250         ir_value_dump(in->_ops[0], oprintf);
3251         if (in->_ops[1] || in->_ops[2])
3252             oprintf(" <- ");
3253     }
3254     if (in->opcode == INSTR_CALL0) {
3255         oprintf("CALL%i\t", vec_size(in->params));
3256     } else
3257         oprintf("%s\t", qc_opname(in->opcode));
3258
3259     if (in->_ops[0] && !(in->_ops[1] || in->_ops[2])) {
3260         ir_value_dump(in->_ops[0], oprintf);
3261         comma = ",\t";
3262     }
3263     else
3264     {
3265         for (i = 1; i != 3; ++i) {
3266             if (in->_ops[i]) {
3267                 if (comma)
3268                     oprintf(comma);
3269                 ir_value_dump(in->_ops[i], oprintf);
3270                 comma = ",\t";
3271             }
3272         }
3273     }
3274     if (in->bops[0]) {
3275         if (comma)
3276             oprintf(comma);
3277         oprintf("[%s]", in->bops[0]->label);
3278         comma = ",\t";
3279     }
3280     if (in->bops[1])
3281         oprintf("%s[%s]", comma, in->bops[1]->label);
3282     if (vec_size(in->params)) {
3283         oprintf("\tparams: ");
3284         for (i = 0; i != vec_size(in->params); ++i) {
3285             oprintf("%s, ", in->params[i]->name);
3286         }
3287     }
3288     oprintf("\n");
3289     ind[strlen(ind)-1] = 0;
3290 }
3291
3292 void ir_value_dump(ir_value* v, int (*oprintf)(const char*, ...))
3293 {
3294     if (v->isconst) {
3295         switch (v->vtype) {
3296             default:
3297             case TYPE_VOID:
3298                 oprintf("(void)");
3299                 break;
3300             case TYPE_FUNCTION:
3301                 oprintf("fn:%s", v->name);
3302                 break;
3303             case TYPE_FLOAT:
3304                 oprintf("%g", v->constval.vfloat);
3305                 break;
3306             case TYPE_VECTOR:
3307                 oprintf("'%g %g %g'",
3308                         v->constval.vvec.x,
3309                         v->constval.vvec.y,
3310                         v->constval.vvec.z);
3311                 break;
3312             case TYPE_ENTITY:
3313                 oprintf("(entity)");
3314                 break;
3315             case TYPE_STRING:
3316                 oprintf("\"%s\"", v->constval.vstring);
3317                 break;
3318 #if 0
3319             case TYPE_INTEGER:
3320                 oprintf("%i", v->constval.vint);
3321                 break;
3322 #endif
3323             case TYPE_POINTER:
3324                 oprintf("&%s",
3325                     v->constval.vpointer->name);
3326                 break;
3327         }
3328     } else {
3329         oprintf("%s", v->name);
3330     }
3331 }
3332
3333 void ir_value_dump_life(const ir_value *self, int (*oprintf)(const char*,...))
3334 {
3335     size_t i;
3336     oprintf("Life of %12s:", self->name);
3337     for (i = 0; i < vec_size(self->life); ++i)
3338     {
3339         oprintf(" + [%i, %i]\n", self->life[i].start, self->life[i].end);
3340     }
3341 }