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