]> git.xonotic.org Git - xonotic/gmqcc.git/blob - ir.c
ir_function_allocate_locals prototype
[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  *IR Builder
30  */
31
32 ir_builder* ir_builder_new(const char *modulename)
33 {
34     ir_builder* self;
35
36     self = (ir_builder*)mem_a(sizeof(*self));
37     if (!self)
38         return NULL;
39
40     MEM_VECTOR_INIT(self, functions);
41     MEM_VECTOR_INIT(self, globals);
42     self->name = NULL;
43     if (!ir_builder_set_name(self, modulename)) {
44         mem_d(self);
45         return NULL;
46     }
47
48     /* globals which always exist */
49
50     /* for now we give it a vector size */
51     ir_builder_create_global(self, "OFS_RETURN", TYPE_VARIANT);
52
53     return self;
54 }
55
56 MEM_VEC_FUNCTIONS(ir_builder, ir_value*, globals)
57 MEM_VEC_FUNCTIONS(ir_builder, ir_function*, functions)
58
59 void ir_builder_delete(ir_builder* self)
60 {
61     size_t i;
62     mem_d((void*)self->name);
63     for (i = 0; i != self->functions_count; ++i) {
64         ir_function_delete(self->functions[i]);
65     }
66     MEM_VECTOR_CLEAR(self, functions);
67     for (i = 0; i != self->globals_count; ++i) {
68         ir_value_delete(self->globals[i]);
69     }
70     MEM_VECTOR_CLEAR(self, globals);
71     mem_d(self);
72 }
73
74 bool ir_builder_set_name(ir_builder *self, const char *name)
75 {
76     if (self->name)
77         mem_d((void*)self->name);
78     self->name = util_strdup(name);
79     return !!self->name;
80 }
81
82 ir_function* ir_builder_get_function(ir_builder *self, const char *name)
83 {
84     size_t i;
85     for (i = 0; i < self->functions_count; ++i) {
86         if (!strcmp(name, self->functions[i]->name))
87             return self->functions[i];
88     }
89     return NULL;
90 }
91
92 ir_function* ir_builder_create_function(ir_builder *self, const char *name)
93 {
94     ir_function *fn = ir_builder_get_function(self, name);
95     if (fn) {
96         return NULL;
97     }
98
99     fn = ir_function_new(self);
100     if (!ir_function_set_name(fn, name) ||
101         !ir_builder_functions_add(self, fn) )
102     {
103         ir_function_delete(fn);
104         return NULL;
105     }
106     return fn;
107 }
108
109 ir_value* ir_builder_get_global(ir_builder *self, const char *name)
110 {
111     size_t i;
112     for (i = 0; i < self->globals_count; ++i) {
113         if (!strcmp(self->globals[i]->name, name))
114             return self->globals[i];
115     }
116     return NULL;
117 }
118
119 ir_value* ir_builder_create_global(ir_builder *self, const char *name, int vtype)
120 {
121     ir_value *ve = ir_builder_get_global(self, name);
122     if (ve) {
123         return NULL;
124     }
125
126     ve = ir_value_var(name, store_global, vtype);
127     if (!ir_builder_globals_add(self, ve)) {
128         ir_value_delete(ve);
129         return NULL;
130     }
131     return ve;
132 }
133
134 /***********************************************************************
135  *IR Function
136  */
137
138 bool ir_function_naive_phi(ir_function*);
139 void ir_function_enumerate(ir_function*);
140 bool ir_function_calculate_liferanges(ir_function*);
141 bool ir_function_allocate_locals(ir_function*);
142
143 ir_function* ir_function_new(ir_builder* owner)
144 {
145     ir_function *self;
146     self = (ir_function*)mem_a(sizeof(*self));
147
148     if (!self)
149         return NULL;
150
151     self->name = NULL;
152     if (!ir_function_set_name(self, "<@unnamed>")) {
153         mem_d(self);
154         return NULL;
155     }
156     self->owner = owner;
157     self->context.file = "<@no context>";
158     self->context.line = 0;
159     self->retype = TYPE_VOID;
160     MEM_VECTOR_INIT(self, params);
161     MEM_VECTOR_INIT(self, blocks);
162     MEM_VECTOR_INIT(self, values);
163     MEM_VECTOR_INIT(self, locals);
164
165     self->run_id = 0;
166     return self;
167 }
168 MEM_VEC_FUNCTIONS(ir_function, ir_value*, values)
169 MEM_VEC_FUNCTIONS(ir_function, ir_block*, blocks)
170 MEM_VEC_FUNCTIONS(ir_function, ir_value*, locals)
171
172 bool ir_function_set_name(ir_function *self, const char *name)
173 {
174     if (self->name)
175         mem_d((void*)self->name);
176     self->name = util_strdup(name);
177     return !!self->name;
178 }
179
180 void ir_function_delete(ir_function *self)
181 {
182     size_t i;
183     mem_d((void*)self->name);
184
185     for (i = 0; i != self->blocks_count; ++i)
186         ir_block_delete(self->blocks[i]);
187     MEM_VECTOR_CLEAR(self, blocks);
188
189     MEM_VECTOR_CLEAR(self, params);
190
191     for (i = 0; i != self->values_count; ++i)
192         ir_value_delete(self->values[i]);
193     MEM_VECTOR_CLEAR(self, values);
194
195     for (i = 0; i != self->locals_count; ++i)
196         ir_value_delete(self->locals[i]);
197     MEM_VECTOR_CLEAR(self, locals);
198
199     mem_d(self);
200 }
201
202 bool GMQCC_WARN ir_function_collect_value(ir_function *self, ir_value *v)
203 {
204     return ir_function_values_add(self, v);
205 }
206
207 ir_block* ir_function_create_block(ir_function *self, const char *label)
208 {
209     ir_block* bn = ir_block_new(self, label);
210     memcpy(&bn->context, &self->context, sizeof(self->context));
211     if (!ir_function_blocks_add(self, bn)) {
212         ir_block_delete(bn);
213         return NULL;
214     }
215     return bn;
216 }
217
218 bool ir_function_finalize(ir_function *self)
219 {
220     if (!ir_function_naive_phi(self))
221         return false;
222
223     ir_function_enumerate(self);
224
225     if (!ir_function_calculate_liferanges(self))
226         return false;
227
228     if (!ir_function_allocate_locals(self))
229         return false;
230     return true;
231 }
232
233 ir_value* ir_function_get_local(ir_function *self, const char *name)
234 {
235     size_t i;
236     for (i = 0; i < self->locals_count; ++i) {
237         if (!strcmp(self->locals[i]->name, name))
238             return self->locals[i];
239     }
240     return NULL;
241 }
242
243 ir_value* ir_function_create_local(ir_function *self, const char *name, int vtype)
244 {
245     ir_value *ve = ir_function_get_local(self, name);
246     if (ve) {
247         return NULL;
248     }
249
250     ve = ir_value_var(name, store_local, vtype);
251     if (!ir_function_locals_add(self, ve)) {
252         ir_value_delete(ve);
253         return NULL;
254     }
255     return ve;
256 }
257
258 /***********************************************************************
259  *IR Block
260  */
261
262 ir_block* ir_block_new(ir_function* owner, const char *name)
263 {
264     ir_block *self;
265     self = (ir_block*)mem_a(sizeof(*self));
266     if (!self)
267         return NULL;
268
269     memset(self, 0, sizeof(*self));
270
271     self->label = NULL;
272     if (!ir_block_set_label(self, name)) {
273         mem_d(self);
274         return NULL;
275     }
276     self->owner = owner;
277     self->context.file = "<@no context>";
278     self->context.line = 0;
279     self->final = false;
280     MEM_VECTOR_INIT(self, instr);
281     MEM_VECTOR_INIT(self, entries);
282     MEM_VECTOR_INIT(self, exits);
283
284     self->eid = 0;
285     self->is_return = false;
286     self->run_id = 0;
287     MEM_VECTOR_INIT(self, living);
288
289     self->generated = false;
290
291     return self;
292 }
293 MEM_VEC_FUNCTIONS(ir_block, ir_instr*, instr)
294 MEM_VEC_FUNCTIONS_ALL(ir_block, ir_block*, entries)
295 MEM_VEC_FUNCTIONS_ALL(ir_block, ir_block*, exits)
296 MEM_VEC_FUNCTIONS_ALL(ir_block, ir_value*, living)
297
298 void ir_block_delete(ir_block* self)
299 {
300     size_t i;
301     mem_d(self->label);
302     for (i = 0; i != self->instr_count; ++i)
303         ir_instr_delete(self->instr[i]);
304     MEM_VECTOR_CLEAR(self, instr);
305     MEM_VECTOR_CLEAR(self, entries);
306     MEM_VECTOR_CLEAR(self, exits);
307     MEM_VECTOR_CLEAR(self, living);
308     mem_d(self);
309 }
310
311 bool ir_block_set_label(ir_block *self, const char *name)
312 {
313     if (self->label)
314         mem_d((void*)self->label);
315     self->label = util_strdup(name);
316     return !!self->label;
317 }
318
319 /***********************************************************************
320  *IR Instructions
321  */
322
323 ir_instr* ir_instr_new(ir_block* owner, int op)
324 {
325     ir_instr *self;
326     self = (ir_instr*)mem_a(sizeof(*self));
327     if (!self)
328         return NULL;
329
330     self->owner = owner;
331     self->context.file = "<@no context>";
332     self->context.line = 0;
333     self->opcode = op;
334     self->_ops[0] = NULL;
335     self->_ops[1] = NULL;
336     self->_ops[2] = NULL;
337     self->bops[0] = NULL;
338     self->bops[1] = NULL;
339     MEM_VECTOR_INIT(self, phi);
340
341     self->eid = 0;
342     return self;
343 }
344 MEM_VEC_FUNCTIONS(ir_instr, ir_phi_entry_t, phi)
345
346 void ir_instr_delete(ir_instr *self)
347 {
348     size_t i;
349     /* The following calls can only delete from
350      * vectors, we still want to delete this instruction
351      * so ignore the return value. Since with the warn_unused_result attribute
352      * gcc doesn't care about an explicit: (void)foo(); to ignore the result,
353      * I have to improvise here and use if(foo());
354      */
355     for (i = 0; i < self->phi_count; ++i) {
356         size_t idx;
357         if (ir_value_writes_find(self->phi[i].value, self, &idx))
358             if (ir_value_writes_remove(self->phi[i].value, idx)) GMQCC_SUPRESS_EMPTY_BODY;
359         if (ir_value_reads_find(self->phi[i].value, self, &idx))
360             if (ir_value_reads_remove (self->phi[i].value, idx)) GMQCC_SUPRESS_EMPTY_BODY;
361     }
362     MEM_VECTOR_CLEAR(self, phi);
363     if (ir_instr_op(self, 0, NULL, false)) GMQCC_SUPRESS_EMPTY_BODY;
364     if (ir_instr_op(self, 1, NULL, false)) GMQCC_SUPRESS_EMPTY_BODY;
365     if (ir_instr_op(self, 2, NULL, false)) GMQCC_SUPRESS_EMPTY_BODY;
366     mem_d(self);
367 }
368
369 bool ir_instr_op(ir_instr *self, int op, ir_value *v, bool writing)
370 {
371     if (self->_ops[op]) {
372         size_t idx;
373         if (writing && ir_value_writes_find(self->_ops[op], self, &idx))
374         {
375             if (!ir_value_writes_remove(self->_ops[op], idx))
376                 return false;
377         }
378         else if (ir_value_reads_find(self->_ops[op], self, &idx))
379         {
380             if (!ir_value_reads_remove(self->_ops[op], idx))
381                 return false;
382         }
383     }
384     if (v) {
385         if (writing) {
386             if (!ir_value_writes_add(v, self))
387                 return false;
388         } else {
389             if (!ir_value_reads_add(v, self))
390                 return false;
391         }
392     }
393     self->_ops[op] = v;
394     return true;
395 }
396
397 /***********************************************************************
398  *IR Value
399  */
400
401 ir_value* ir_value_var(const char *name, int storetype, int vtype)
402 {
403     ir_value *self;
404     self = (ir_value*)mem_a(sizeof(*self));
405     self->vtype = vtype;
406     self->fieldtype = TYPE_VOID;
407     self->store = storetype;
408     MEM_VECTOR_INIT(self, reads);
409     MEM_VECTOR_INIT(self, writes);
410     self->isconst = false;
411     self->context.file = "<@no context>";
412     self->context.line = 0;
413     self->name = NULL;
414     ir_value_set_name(self, name);
415
416     memset(&self->constval, 0, sizeof(self->constval));
417     memset(&self->code,     0, sizeof(self->code));
418
419     MEM_VECTOR_INIT(self, life);
420     return self;
421 }
422 MEM_VEC_FUNCTIONS(ir_value, ir_life_entry_t, life)
423 MEM_VEC_FUNCTIONS_ALL(ir_value, ir_instr*, reads)
424 MEM_VEC_FUNCTIONS_ALL(ir_value, ir_instr*, writes)
425
426 ir_value* ir_value_out(ir_function *owner, const char *name, int storetype, int vtype)
427 {
428     ir_value *v = ir_value_var(name, storetype, vtype);
429     if (!v)
430         return NULL;
431     if (!ir_function_collect_value(owner, v))
432     {
433         ir_value_delete(v);
434         return NULL;
435     }
436     return v;
437 }
438
439 void ir_value_delete(ir_value* self)
440 {
441     mem_d((void*)self->name);
442     if (self->isconst)
443     {
444         if (self->vtype == TYPE_STRING)
445             mem_d((void*)self->constval.vstring);
446     }
447     MEM_VECTOR_CLEAR(self, reads);
448     MEM_VECTOR_CLEAR(self, writes);
449     MEM_VECTOR_CLEAR(self, life);
450     mem_d(self);
451 }
452
453 void ir_value_set_name(ir_value *self, const char *name)
454 {
455     if (self->name)
456         mem_d((void*)self->name);
457     self->name = util_strdup(name);
458 }
459
460 bool ir_value_set_float(ir_value *self, float f)
461 {
462     if (self->vtype != TYPE_FLOAT)
463         return false;
464     self->constval.vfloat = f;
465     self->isconst = true;
466     return true;
467 }
468
469 bool ir_value_set_vector(ir_value *self, vector v)
470 {
471     if (self->vtype != TYPE_VECTOR)
472         return false;
473     self->constval.vvec = v;
474     self->isconst = true;
475     return true;
476 }
477
478 bool ir_value_set_string(ir_value *self, const char *str)
479 {
480     if (self->vtype != TYPE_STRING)
481         return false;
482     self->constval.vstring = util_strdup(str);
483     self->isconst = true;
484     return true;
485 }
486
487 #if 0
488 bool ir_value_set_int(ir_value *self, int i)
489 {
490     if (self->vtype != TYPE_INTEGER)
491         return false;
492     self->constval.vint = i;
493     self->isconst = true;
494     return true;
495 }
496 #endif
497
498 bool ir_value_lives(ir_value *self, size_t at)
499 {
500     size_t i;
501     for (i = 0; i < self->life_count; ++i)
502     {
503         ir_life_entry_t *life = &self->life[i];
504         if (life->start <= at && at <= life->end)
505             return true;
506         if (life->start > at) /* since it's ordered */
507             return false;
508     }
509     return false;
510 }
511
512 bool ir_value_life_insert(ir_value *self, size_t idx, ir_life_entry_t e)
513 {
514     size_t k;
515     if (!ir_value_life_add(self, e)) /* naive... */
516         return false;
517     for (k = self->life_count-1; k > idx; --k)
518         self->life[k] = self->life[k-1];
519     self->life[idx] = e;
520     return true;
521 }
522
523 bool ir_value_life_merge(ir_value *self, size_t s)
524 {
525     size_t i;
526     ir_life_entry_t *life = NULL;
527     ir_life_entry_t *before = NULL;
528     ir_life_entry_t new_entry;
529
530     /* Find the first range >= s */
531     for (i = 0; i < self->life_count; ++i)
532     {
533         before = life;
534         life = &self->life[i];
535         if (life->start > s)
536             break;
537     }
538     /* nothing found? append */
539     if (i == self->life_count) {
540         ir_life_entry_t e;
541         if (life && life->end+1 == s)
542         {
543             /* previous life range can be merged in */
544             life->end++;
545             return true;
546         }
547         if (life && life->end >= s)
548             return false;
549         e.start = e.end = s;
550         if (!ir_value_life_add(self, e))
551             return false; /* failing */
552         return true;
553     }
554     /* found */
555     if (before)
556     {
557         if (before->end + 1 == s &&
558             life->start - 1 == s)
559         {
560             /* merge */
561             before->end = life->end;
562             if (!ir_value_life_remove(self, i))
563                 return false; /* failing */
564             return true;
565         }
566         if (before->end + 1 == s)
567         {
568             /* extend before */
569             before->end++;
570             return true;
571         }
572         /* already contained */
573         if (before->end >= s)
574             return false;
575     }
576     /* extend */
577     if (life->start - 1 == s)
578     {
579         life->start--;
580         return true;
581     }
582     /* insert a new entry */
583     new_entry.start = new_entry.end = s;
584     return ir_value_life_insert(self, i, new_entry);
585 }
586
587 bool ir_values_overlap(ir_value *a, ir_value *b)
588 {
589     /* For any life entry in A see if it overlaps with
590      * any life entry in B.
591      * Note that the life entries are orderes, so we can make a
592      * more efficient algorithm there than naively translating the
593      * statement above.
594      */
595
596     ir_life_entry_t *la, *lb, *enda, *endb;
597
598     /* first of all, if either has no life range, they cannot clash */
599     if (!a->life_count || !b->life_count)
600         return false;
601
602     la = a->life;
603     lb = b->life;
604     enda = la + a->life_count;
605     endb = lb + b->life_count;
606     while (true)
607     {
608         /* check if the entries overlap, for that,
609          * both must start before the other one ends.
610          */
611 #if defined(LIFE_RANGE_WITHOUT_LAST_READ)
612         if (la->start <= lb->end &&
613             lb->start <= la->end)
614 #else
615         if (la->start <  lb->end &&
616             lb->start <  la->end)
617 #endif
618         {
619             return true;
620         }
621
622         /* entries are ordered
623          * one entry is earlier than the other
624          * that earlier entry will be moved forward
625          */
626         if (la->end < lb->end)
627         {
628             /* order: A B, move A forward
629              * check if we hit the end with A
630              */
631             if (++la == enda)
632                 break;
633         }
634         else if (lb->end < la->end)
635         {
636             /* order: B A, move B forward
637              * check if we hit the end with B
638              */
639             if (++lb == endb)
640                 break;
641         }
642     }
643     return false;
644 }
645
646 /***********************************************************************
647  *IR main operations
648  */
649
650 bool ir_block_create_store_op(ir_block *self, int op, ir_value *target, ir_value *what)
651 {
652     if (target->store == store_value) {
653         fprintf(stderr, "cannot store to an SSA value\n");
654         fprintf(stderr, "trying to store: %s <- %s\n", target->name, what->name);
655         return false;
656     } else {
657         ir_instr *in = ir_instr_new(self, op);
658         if (!in)
659             return false;
660         if (!ir_instr_op(in, 0, target, true) ||
661             !ir_instr_op(in, 1, what, false)  ||
662             !ir_block_instr_add(self, in) )
663         {
664             return false;
665         }
666         return true;
667     }
668 }
669
670 bool ir_block_create_store(ir_block *self, ir_value *target, ir_value *what)
671 {
672     int op = 0;
673     int vtype;
674     if (target->vtype == TYPE_VARIANT)
675         vtype = what->vtype;
676     else
677         vtype = target->vtype;
678
679     switch (vtype) {
680         case TYPE_FLOAT:
681 #if 0
682             if (what->vtype == TYPE_INTEGER)
683                 op = INSTR_CONV_ITOF;
684             else
685 #endif
686                 op = INSTR_STORE_F;
687             break;
688         case TYPE_VECTOR:
689             op = INSTR_STORE_V;
690             break;
691         case TYPE_ENTITY:
692             op = INSTR_STORE_ENT;
693             break;
694         case TYPE_STRING:
695             op = INSTR_STORE_S;
696             break;
697         case TYPE_FIELD:
698             op = INSTR_STORE_FLD;
699             break;
700 #if 0
701         case TYPE_INTEGER:
702             if (what->vtype == TYPE_INTEGER)
703                 op = INSTR_CONV_FTOI;
704             else
705                 op = INSTR_STORE_I;
706             break;
707 #endif
708         case TYPE_POINTER:
709 #if 0
710             op = INSTR_STORE_I;
711 #else
712             op = INSTR_STORE_ENT;
713 #endif
714             break;
715         default:
716             /* Unknown type */
717             return false;
718     }
719     return ir_block_create_store_op(self, op, target, what);
720 }
721
722 bool ir_block_create_storep(ir_block *self, ir_value *target, ir_value *what)
723 {
724     int op = 0;
725     int vtype;
726
727     if (target->vtype != TYPE_POINTER)
728         return false;
729
730     /* storing using pointer - target is a pointer, type must be
731      * inferred from source
732      */
733     vtype = what->vtype;
734
735     switch (vtype) {
736         case TYPE_FLOAT:
737             op = INSTR_STOREP_F;
738             break;
739         case TYPE_VECTOR:
740             op = INSTR_STOREP_V;
741             break;
742         case TYPE_ENTITY:
743             op = INSTR_STOREP_ENT;
744             break;
745         case TYPE_STRING:
746             op = INSTR_STOREP_S;
747             break;
748         case TYPE_FIELD:
749             op = INSTR_STOREP_FLD;
750             break;
751 #if 0
752         case TYPE_INTEGER:
753             op = INSTR_STOREP_I;
754             break;
755 #endif
756         case TYPE_POINTER:
757 #if 0
758             op = INSTR_STOREP_I;
759 #else
760             op = INSTR_STOREP_ENT;
761 #endif
762             break;
763         default:
764             /* Unknown type */
765             return false;
766     }
767     return ir_block_create_store_op(self, op, target, what);
768 }
769
770 bool ir_block_create_return(ir_block *self, ir_value *v)
771 {
772     ir_instr *in;
773     if (self->final) {
774         fprintf(stderr, "block already ended (%s)\n", self->label);
775         return false;
776     }
777     self->final = true;
778     self->is_return = true;
779     in = ir_instr_new(self, INSTR_RETURN);
780     if (!in)
781         return false;
782
783     if (!ir_instr_op(in, 0, v, false) ||
784         !ir_block_instr_add(self, in) )
785     {
786         return false;
787     }
788     return true;
789 }
790
791 bool ir_block_create_if(ir_block *self, ir_value *v,
792                         ir_block *ontrue, ir_block *onfalse)
793 {
794     ir_instr *in;
795     if (self->final) {
796         fprintf(stderr, "block already ended (%s)\n", self->label);
797         return false;
798     }
799     self->final = true;
800     /*in = ir_instr_new(self, (v->vtype == TYPE_STRING ? INSTR_IF_S : INSTR_IF_F));*/
801     in = ir_instr_new(self, VINSTR_COND);
802     if (!in)
803         return false;
804
805     if (!ir_instr_op(in, 0, v, false)) {
806         ir_instr_delete(in);
807         return false;
808     }
809
810     in->bops[0] = ontrue;
811     in->bops[1] = onfalse;
812
813     if (!ir_block_instr_add(self, in))
814         return false;
815
816     if (!ir_block_exits_add(self, ontrue)    ||
817         !ir_block_exits_add(self, onfalse)   ||
818         !ir_block_entries_add(ontrue, self)  ||
819         !ir_block_entries_add(onfalse, self) )
820     {
821         return false;
822     }
823     return true;
824 }
825
826 bool ir_block_create_jump(ir_block *self, ir_block *to)
827 {
828     ir_instr *in;
829     if (self->final) {
830         fprintf(stderr, "block already ended (%s)\n", self->label);
831         return false;
832     }
833     self->final = true;
834     in = ir_instr_new(self, VINSTR_JUMP);
835     if (!in)
836         return false;
837
838     in->bops[0] = to;
839     if (!ir_block_instr_add(self, in))
840         return false;
841
842     if (!ir_block_exits_add(self, to) ||
843         !ir_block_entries_add(to, self) )
844     {
845         return false;
846     }
847     return true;
848 }
849
850 bool ir_block_create_goto(ir_block *self, ir_block *to)
851 {
852     ir_instr *in;
853     if (self->final) {
854         fprintf(stderr, "block already ended (%s)\n", self->label);
855         return false;
856     }
857     self->final = true;
858     in = ir_instr_new(self, INSTR_GOTO);
859     if (!in)
860         return false;
861
862     in->bops[0] = to;
863     if (!ir_block_instr_add(self, in))
864         return false;
865
866     if (!ir_block_exits_add(self, to) ||
867         !ir_block_entries_add(to, self) )
868     {
869         return false;
870     }
871     return true;
872 }
873
874 ir_instr* ir_block_create_phi(ir_block *self, const char *label, int ot)
875 {
876     ir_value *out;
877     ir_instr *in;
878     in = ir_instr_new(self, VINSTR_PHI);
879     if (!in)
880         return NULL;
881     out = ir_value_out(self->owner, label, store_value, ot);
882     if (!out) {
883         ir_instr_delete(in);
884         return NULL;
885     }
886     if (!ir_instr_op(in, 0, out, true)) {
887         ir_instr_delete(in);
888         ir_value_delete(out);
889         return NULL;
890     }
891     if (!ir_block_instr_add(self, in)) {
892         ir_instr_delete(in);
893         ir_value_delete(out);
894         return NULL;
895     }
896     return in;
897 }
898
899 ir_value* ir_phi_value(ir_instr *self)
900 {
901     return self->_ops[0];
902 }
903
904 bool ir_phi_add(ir_instr* self, ir_block *b, ir_value *v)
905 {
906     ir_phi_entry_t pe;
907
908     if (!ir_block_entries_find(self->owner, b, NULL)) {
909         /* Must not be possible to cause this, otherwise the AST
910          * is doing something wrong.
911          */
912         fprintf(stderr, "Invalid entry block for PHI\n");
913         abort();
914     }
915
916     pe.value = v;
917     pe.from = b;
918     if (!ir_value_reads_add(v, self))
919         return false;
920     return ir_instr_phi_add(self, pe);
921 }
922
923 /* binary op related code */
924
925 ir_value* ir_block_create_binop(ir_block *self,
926                                 const char *label, int opcode,
927                                 ir_value *left, ir_value *right)
928 {
929     int ot = TYPE_VOID;
930     switch (opcode) {
931         case INSTR_ADD_F:
932         case INSTR_SUB_F:
933         case INSTR_DIV_F:
934         case INSTR_MUL_F:
935         case INSTR_MUL_V:
936         case INSTR_AND:
937         case INSTR_OR:
938 #if 0
939         case INSTR_AND_I:
940         case INSTR_AND_IF:
941         case INSTR_AND_FI:
942         case INSTR_OR_I:
943         case INSTR_OR_IF:
944         case INSTR_OR_FI:
945 #endif
946         case INSTR_BITAND:
947         case INSTR_BITOR:
948 #if 0
949         case INSTR_SUB_S: /* -- offset of string as float */
950         case INSTR_MUL_IF:
951         case INSTR_MUL_FI:
952         case INSTR_DIV_IF:
953         case INSTR_DIV_FI:
954         case INSTR_BITOR_IF:
955         case INSTR_BITOR_FI:
956         case INSTR_BITAND_FI:
957         case INSTR_BITAND_IF:
958         case INSTR_EQ_I:
959         case INSTR_NE_I:
960 #endif
961             ot = TYPE_FLOAT;
962             break;
963 #if 0
964         case INSTR_ADD_I:
965         case INSTR_ADD_IF:
966         case INSTR_ADD_FI:
967         case INSTR_SUB_I:
968         case INSTR_SUB_FI:
969         case INSTR_SUB_IF:
970         case INSTR_MUL_I:
971         case INSTR_DIV_I:
972         case INSTR_BITAND_I:
973         case INSTR_BITOR_I:
974         case INSTR_XOR_I:
975         case INSTR_RSHIFT_I:
976         case INSTR_LSHIFT_I:
977             ot = TYPE_INTEGER;
978             break;
979 #endif
980         case INSTR_ADD_V:
981         case INSTR_SUB_V:
982         case INSTR_MUL_VF:
983         case INSTR_MUL_FV:
984 #if 0
985         case INSTR_DIV_VF:
986         case INSTR_MUL_IV:
987         case INSTR_MUL_VI:
988 #endif
989             ot = TYPE_VECTOR;
990             break;
991 #if 0
992         case INSTR_ADD_SF:
993             ot = TYPE_POINTER;
994             break;
995 #endif
996         default:
997             /* ranges: */
998             /* boolean operations result in floats */
999             if (opcode >= INSTR_EQ_F && opcode <= INSTR_GT)
1000                 ot = TYPE_FLOAT;
1001             else if (opcode >= INSTR_LE && opcode <= INSTR_GT)
1002                 ot = TYPE_FLOAT;
1003 #if 0
1004             else if (opcode >= INSTR_LE_I && opcode <= INSTR_EQ_FI)
1005                 ot = TYPE_FLOAT;
1006 #endif
1007             break;
1008     };
1009     if (ot == TYPE_VOID) {
1010         /* The AST or parser were supposed to check this! */
1011         return NULL;
1012     }
1013
1014     return ir_block_create_general_instr(self, label, opcode, left, right, ot);
1015 }
1016
1017 ir_value* ir_block_create_general_instr(ir_block *self, const char *label,
1018                                         int op, ir_value *a, ir_value *b, int outype)
1019 {
1020     ir_instr *instr;
1021     ir_value *out;
1022
1023     out = ir_value_out(self->owner, label, store_value, outype);
1024     if (!out)
1025         return NULL;
1026
1027     instr = ir_instr_new(self, op);
1028     if (!instr) {
1029         ir_value_delete(out);
1030         return NULL;
1031     }
1032
1033     if (!ir_instr_op(instr, 0, out, true) ||
1034         !ir_instr_op(instr, 1, a, false) ||
1035         !ir_instr_op(instr, 2, b, false) )
1036     {
1037         goto on_error;
1038     }
1039
1040     if (!ir_block_instr_add(self, instr))
1041         goto on_error;
1042
1043     return out;
1044 on_error:
1045     ir_instr_delete(instr);
1046     ir_value_delete(out);
1047     return NULL;
1048 }
1049
1050 ir_value* ir_block_create_fieldaddress(ir_block *self, const char *label, ir_value *ent, ir_value *field)
1051 {
1052     /* Support for various pointer types todo if so desired */
1053     if (ent->vtype != TYPE_ENTITY)
1054         return NULL;
1055
1056     if (field->vtype != TYPE_FIELD)
1057         return NULL;
1058
1059     return ir_block_create_general_instr(self, label, INSTR_ADDRESS, ent, field, TYPE_POINTER);
1060 }
1061
1062 ir_value* ir_block_create_load_from_ent(ir_block *self, const char *label, ir_value *ent, ir_value *field, int outype)
1063 {
1064     int op;
1065     if (ent->vtype != TYPE_ENTITY)
1066         return NULL;
1067
1068     /* at some point we could redirect for TYPE_POINTER... but that could lead to carelessness */
1069     if (field->vtype != TYPE_FIELD)
1070         return NULL;
1071
1072     switch (outype)
1073     {
1074         case TYPE_FLOAT:   op = INSTR_LOAD_F;   break;
1075         case TYPE_VECTOR:  op = INSTR_LOAD_V;   break;
1076         case TYPE_STRING:  op = INSTR_LOAD_S;   break;
1077         case TYPE_FIELD:   op = INSTR_LOAD_FLD; break;
1078         case TYPE_ENTITY:  op = INSTR_LOAD_ENT; break;
1079 #if 0
1080         case TYPE_POINTER: op = INSTR_LOAD_I;   break;
1081         case TYPE_INTEGER: op = INSTR_LOAD_I;   break;
1082 #endif
1083         default:
1084             return NULL;
1085     }
1086
1087     return ir_block_create_general_instr(self, label, op, ent, field, outype);
1088 }
1089
1090 ir_value* ir_block_create_add(ir_block *self,
1091                               const char *label,
1092                               ir_value *left, ir_value *right)
1093 {
1094     int op = 0;
1095     int l = left->vtype;
1096     int r = right->vtype;
1097     if (l == r) {
1098         switch (l) {
1099             default:
1100                 return NULL;
1101             case TYPE_FLOAT:
1102                 op = INSTR_ADD_F;
1103                 break;
1104 #if 0
1105             case TYPE_INTEGER:
1106                 op = INSTR_ADD_I;
1107                 break;
1108 #endif
1109             case TYPE_VECTOR:
1110                 op = INSTR_ADD_V;
1111                 break;
1112         }
1113     } else {
1114 #if 0
1115         if ( (l == TYPE_FLOAT && r == TYPE_INTEGER) )
1116             op = INSTR_ADD_FI;
1117         else if ( (l == TYPE_INTEGER && r == TYPE_FLOAT) )
1118             op = INSTR_ADD_IF;
1119         else
1120 #endif
1121             return NULL;
1122     }
1123     return ir_block_create_binop(self, label, op, left, right);
1124 }
1125
1126 ir_value* ir_block_create_sub(ir_block *self,
1127                               const char *label,
1128                               ir_value *left, ir_value *right)
1129 {
1130     int op = 0;
1131     int l = left->vtype;
1132     int r = right->vtype;
1133     if (l == r) {
1134
1135         switch (l) {
1136             default:
1137                 return NULL;
1138             case TYPE_FLOAT:
1139                 op = INSTR_SUB_F;
1140                 break;
1141 #if 0
1142             case TYPE_INTEGER:
1143                 op = INSTR_SUB_I;
1144                 break;
1145 #endif
1146             case TYPE_VECTOR:
1147                 op = INSTR_SUB_V;
1148                 break;
1149         }
1150     } else {
1151 #if 0
1152         if ( (l == TYPE_FLOAT && r == TYPE_INTEGER) )
1153             op = INSTR_SUB_FI;
1154         else if ( (l == TYPE_INTEGER && r == TYPE_FLOAT) )
1155             op = INSTR_SUB_IF;
1156         else
1157 #endif
1158             return NULL;
1159     }
1160     return ir_block_create_binop(self, label, op, left, right);
1161 }
1162
1163 ir_value* ir_block_create_mul(ir_block *self,
1164                               const char *label,
1165                               ir_value *left, ir_value *right)
1166 {
1167     int op = 0;
1168     int l = left->vtype;
1169     int r = right->vtype;
1170     if (l == r) {
1171
1172         switch (l) {
1173             default:
1174                 return NULL;
1175             case TYPE_FLOAT:
1176                 op = INSTR_MUL_F;
1177                 break;
1178 #if 0
1179             case TYPE_INTEGER:
1180                 op = INSTR_MUL_I;
1181                 break;
1182 #endif
1183             case TYPE_VECTOR:
1184                 op = INSTR_MUL_V;
1185                 break;
1186         }
1187     } else {
1188         if ( (l == TYPE_VECTOR && r == TYPE_FLOAT) )
1189             op = INSTR_MUL_VF;
1190         else if ( (l == TYPE_FLOAT && r == TYPE_VECTOR) )
1191             op = INSTR_MUL_FV;
1192 #if 0
1193         else if ( (l == TYPE_VECTOR && r == TYPE_INTEGER) )
1194             op = INSTR_MUL_VI;
1195         else if ( (l == TYPE_INTEGER && r == TYPE_VECTOR) )
1196             op = INSTR_MUL_IV;
1197         else if ( (l == TYPE_FLOAT && r == TYPE_INTEGER) )
1198             op = INSTR_MUL_FI;
1199         else if ( (l == TYPE_INTEGER && r == TYPE_FLOAT) )
1200             op = INSTR_MUL_IF;
1201 #endif
1202         else
1203             return NULL;
1204     }
1205     return ir_block_create_binop(self, label, op, left, right);
1206 }
1207
1208 ir_value* ir_block_create_div(ir_block *self,
1209                               const char *label,
1210                               ir_value *left, ir_value *right)
1211 {
1212     int op = 0;
1213     int l = left->vtype;
1214     int r = right->vtype;
1215     if (l == r) {
1216
1217         switch (l) {
1218             default:
1219                 return NULL;
1220             case TYPE_FLOAT:
1221                 op = INSTR_DIV_F;
1222                 break;
1223 #if 0
1224             case TYPE_INTEGER:
1225                 op = INSTR_DIV_I;
1226                 break;
1227 #endif
1228         }
1229     } else {
1230 #if 0
1231         if ( (l == TYPE_VECTOR && r == TYPE_FLOAT) )
1232             op = INSTR_DIV_VF;
1233         else if ( (l == TYPE_FLOAT && r == TYPE_INTEGER) )
1234             op = INSTR_DIV_FI;
1235         else if ( (l == TYPE_INTEGER && r == TYPE_FLOAT) )
1236             op = INSTR_DIV_IF;
1237         else
1238 #endif
1239             return NULL;
1240     }
1241     return ir_block_create_binop(self, label, op, left, right);
1242 }
1243
1244 /* PHI resolving breaks the SSA, and must thus be the last
1245  * step before life-range calculation.
1246  */
1247
1248 static bool ir_block_naive_phi(ir_block *self);
1249 bool ir_function_naive_phi(ir_function *self)
1250 {
1251     size_t i;
1252
1253     for (i = 0; i < self->blocks_count; ++i)
1254     {
1255         if (!ir_block_naive_phi(self->blocks[i]))
1256             return false;
1257     }
1258     return true;
1259 }
1260
1261 static bool ir_naive_phi_emit_store(ir_block *block, size_t iid, ir_value *old, ir_value *what)
1262 {
1263     ir_instr *instr;
1264     size_t i;
1265
1266     /* create a store */
1267     if (!ir_block_create_store(block, old, what))
1268         return false;
1269
1270     /* we now move it up */
1271     instr = block->instr[block->instr_count-1];
1272     for (i = block->instr_count; i > iid; --i)
1273         block->instr[i] = block->instr[i-1];
1274     block->instr[i] = instr;
1275
1276     return true;
1277 }
1278
1279 static bool ir_block_naive_phi(ir_block *self)
1280 {
1281     size_t i, p, w;
1282     /* FIXME: optionally, create_phi can add the phis
1283      * to a list so we don't need to loop through blocks
1284      * - anyway: "don't optimize YET"
1285      */
1286     for (i = 0; i < self->instr_count; ++i)
1287     {
1288         ir_instr *instr = self->instr[i];
1289         if (instr->opcode != VINSTR_PHI)
1290             continue;
1291
1292         if (!ir_block_instr_remove(self, i))
1293             return false;
1294         --i; /* NOTE: i+1 below */
1295
1296         for (p = 0; p < instr->phi_count; ++p)
1297         {
1298             ir_value *v = instr->phi[p].value;
1299             for (w = 0; w < v->writes_count; ++w) {
1300                 ir_value *old;
1301
1302                 if (!v->writes[w]->_ops[0])
1303                     continue;
1304
1305                 /* When the write was to a global, we have to emit a mov */
1306                 old = v->writes[w]->_ops[0];
1307
1308                 /* The original instruction now writes to the PHI target local */
1309                 if (v->writes[w]->_ops[0] == v)
1310                     v->writes[w]->_ops[0] = instr->_ops[0];
1311
1312                 if (old->store != store_value && old->store != store_local)
1313                 {
1314                     /* If it originally wrote to a global we need to store the value
1315                      * there as welli
1316                      */
1317                     if (!ir_naive_phi_emit_store(self, i+1, old, v))
1318                         return false;
1319                     if (i+1 < self->instr_count)
1320                         instr = self->instr[i+1];
1321                     else
1322                         instr = NULL;
1323                     /* In case I forget and access instr later, it'll be NULL
1324                      * when it's a problem, to make sure we crash, rather than accessing
1325                      * invalid data.
1326                      */
1327                 }
1328                 else
1329                 {
1330                     /* If it didn't, we can replace all reads by the phi target now. */
1331                     size_t r;
1332                     for (r = 0; r < old->reads_count; ++r)
1333                     {
1334                         size_t op;
1335                         ir_instr *ri = old->reads[r];
1336                         for (op = 0; op < ri->phi_count; ++op) {
1337                             if (ri->phi[op].value == old)
1338                                 ri->phi[op].value = v;
1339                         }
1340                         for (op = 0; op < 3; ++op) {
1341                             if (ri->_ops[op] == old)
1342                                 ri->_ops[op] = v;
1343                         }
1344                     }
1345                 }
1346             }
1347         }
1348         ir_instr_delete(instr);
1349     }
1350     return true;
1351 }
1352
1353 /***********************************************************************
1354  *IR Temp allocation code
1355  * Propagating value life ranges by walking through the function backwards
1356  * until no more changes are made.
1357  * In theory this should happen once more than once for every nested loop
1358  * level.
1359  * Though this implementation might run an additional time for if nests.
1360  */
1361
1362 typedef struct
1363 {
1364     ir_value* *v;
1365     size_t    v_count;
1366     size_t    v_alloc;
1367 } new_reads_t;
1368 MEM_VEC_FUNCTIONS_ALL(new_reads_t, ir_value*, v)
1369
1370 /* Enumerate instructions used by value's life-ranges
1371  */
1372 static void ir_block_enumerate(ir_block *self, size_t *_eid)
1373 {
1374     size_t i;
1375     size_t eid = *_eid;
1376     for (i = 0; i < self->instr_count; ++i)
1377     {
1378         self->instr[i]->eid = eid++;
1379     }
1380     *_eid = eid;
1381 }
1382
1383 /* Enumerate blocks and instructions.
1384  * The block-enumeration is unordered!
1385  * We do not really use the block enumreation, however
1386  * the instruction enumeration is important for life-ranges.
1387  */
1388 void ir_function_enumerate(ir_function *self)
1389 {
1390     size_t i;
1391     size_t instruction_id = 0;
1392     for (i = 0; i < self->blocks_count; ++i)
1393     {
1394         self->blocks[i]->eid = i;
1395         self->blocks[i]->run_id = 0;
1396         ir_block_enumerate(self->blocks[i], &instruction_id);
1397     }
1398 }
1399
1400 static bool ir_block_life_propagate(ir_block *b, ir_block *prev, bool *changed);
1401 bool ir_function_calculate_liferanges(ir_function *self)
1402 {
1403     size_t i;
1404     bool changed;
1405
1406     do {
1407         self->run_id++;
1408         changed = false;
1409         for (i = 0; i != self->blocks_count; ++i)
1410         {
1411             if (self->blocks[i]->is_return)
1412             {
1413                 if (!ir_block_life_propagate(self->blocks[i], NULL, &changed))
1414                     return false;
1415             }
1416         }
1417     } while (changed);
1418     return true;
1419 }
1420
1421 /* Local-value allocator
1422  * After finishing creating the liferange of all values used in a function
1423  * we can allocate their global-positions.
1424  * This is the counterpart to register-allocation in register machines.
1425  */
1426 bool ir_function_allocate_locals(ir_function *self)
1427 {
1428     return false;
1429 }
1430
1431 /* Get information about which operand
1432  * is read from, or written to.
1433  */
1434 static void ir_op_read_write(int op, size_t *read, size_t *write)
1435 {
1436     switch (op)
1437     {
1438     case VINSTR_JUMP:
1439     case INSTR_GOTO:
1440         *write = 0;
1441         *read = 0;
1442         break;
1443     case INSTR_IF:
1444     case INSTR_IFNOT:
1445 #if 0
1446     case INSTR_IF_S:
1447     case INSTR_IFNOT_S:
1448 #endif
1449     case INSTR_RETURN:
1450     case VINSTR_COND:
1451         *write = 0;
1452         *read = 1;
1453         break;
1454     default:
1455         *write = 1;
1456         *read = 6;
1457         break;
1458     };
1459 }
1460
1461 static bool ir_block_living_add_instr(ir_block *self, size_t eid)
1462 {
1463     size_t i;
1464     bool changed = false;
1465     bool tempbool;
1466     for (i = 0; i != self->living_count; ++i)
1467     {
1468         tempbool = ir_value_life_merge(self->living[i], eid);
1469         /* debug
1470         if (tempbool)
1471             fprintf(stderr, "block_living_add_instr() value instruction added %s: %i\n", self->living[i]->_name, (int)eid);
1472         */
1473         changed = changed || tempbool;
1474     }
1475     return changed;
1476 }
1477
1478 static bool ir_block_life_prop_previous(ir_block* self, ir_block *prev, bool *changed)
1479 {
1480     size_t i;
1481     /* values which have been read in a previous iteration are now
1482      * in the "living" array even if the previous block doesn't use them.
1483      * So we have to remove whatever does not exist in the previous block.
1484      * They will be re-added on-read, but the liferange merge won't cause
1485      * a change.
1486      */
1487     for (i = 0; i < self->living_count; ++i)
1488     {
1489         if (!ir_block_living_find(prev, self->living[i], NULL)) {
1490             if (!ir_block_living_remove(self, i))
1491                 return false;
1492             --i;
1493         }
1494     }
1495
1496     /* Whatever the previous block still has in its living set
1497      * must now be added to ours as well.
1498      */
1499     for (i = 0; i < prev->living_count; ++i)
1500     {
1501         if (ir_block_living_find(self, prev->living[i], NULL))
1502             continue;
1503         if (!ir_block_living_add(self, prev->living[i]))
1504             return false;
1505         /*
1506         printf("%s got from prev: %s\n", self->label, prev->living[i]->_name);
1507         */
1508     }
1509     return true;
1510 }
1511
1512 static bool ir_block_life_propagate(ir_block *self, ir_block *prev, bool *changed)
1513 {
1514     ir_instr *instr;
1515     ir_value *value;
1516     bool  tempbool;
1517     size_t i, o, p;
1518     /* bitmasks which operands are read from or written to */
1519     size_t read, write;
1520 #if defined(LIFE_RANGE_WITHOUT_LAST_READ)
1521     size_t rd;
1522     new_reads_t new_reads;
1523 #endif
1524     char dbg_ind[16] = { '#', '0' };
1525     (void)dbg_ind;
1526
1527 #if defined(LIFE_RANGE_WITHOUT_LAST_READ)
1528     MEM_VECTOR_INIT(&new_reads, v);
1529 #endif
1530
1531     if (prev)
1532     {
1533         if (!ir_block_life_prop_previous(self, prev, changed))
1534             return false;
1535     }
1536
1537     i = self->instr_count;
1538     while (i)
1539     { --i;
1540         instr = self->instr[i];
1541
1542         /* PHI operands are always read operands */
1543         for (p = 0; p < instr->phi_count; ++p)
1544         {
1545             value = instr->phi[p].value;
1546 #if ! defined(LIFE_RANGE_WITHOUT_LAST_READ)
1547             if (!ir_block_living_find(self, value, NULL) &&
1548                 !ir_block_living_add(self, value))
1549             {
1550                 goto on_error;
1551             }
1552 #else
1553             if (!new_reads_t_v_find(&new_reads, value, NULL))
1554             {
1555                 if (!new_reads_t_v_add(&new_reads, value))
1556                     goto on_error;
1557             }
1558 #endif
1559         }
1560
1561         /* See which operands are read and write operands */
1562         ir_op_read_write(instr->opcode, &read, &write);
1563
1564         /* Go through the 3 main operands */
1565         for (o = 0; o < 3; ++o)
1566         {
1567             if (!instr->_ops[o]) /* no such operand */
1568                 continue;
1569
1570             value = instr->_ops[o];
1571
1572             /* We only care about locals */
1573             if (value->store != store_value &&
1574                 value->store != store_local)
1575                 continue;
1576
1577             /* read operands */
1578             if (read & (1<<o))
1579             {
1580 #if ! defined(LIFE_RANGE_WITHOUT_LAST_READ)
1581                 if (!ir_block_living_find(self, value, NULL) &&
1582                     !ir_block_living_add(self, value))
1583                 {
1584                     goto on_error;
1585                 }
1586 #else
1587                 /* fprintf(stderr, "read: %s\n", value->_name); */
1588                 if (!new_reads_t_v_find(&new_reads, value, NULL))
1589                 {
1590                     if (!new_reads_t_v_add(&new_reads, value))
1591                         goto on_error;
1592                 }
1593 #endif
1594             }
1595
1596             /* write operands */
1597             /* When we write to a local, we consider it "dead" for the
1598              * remaining upper part of the function, since in SSA a value
1599              * can only be written once (== created)
1600              */
1601             if (write & (1<<o))
1602             {
1603                 size_t idx;
1604                 bool in_living = ir_block_living_find(self, value, &idx);
1605 #if defined(LIFE_RANGE_WITHOUT_LAST_READ)
1606                 size_t readidx;
1607                 bool in_reads = new_reads_t_v_find(&new_reads, value, &readidx);
1608                 if (!in_living && !in_reads)
1609 #else
1610                 if (!in_living)
1611 #endif
1612                 {
1613                     /* If the value isn't alive it hasn't been read before... */
1614                     /* TODO: See if the warning can be emitted during parsing or AST processing
1615                      * otherwise have warning printed here.
1616                      * IF printing a warning here: include filecontext_t,
1617                      * and make sure it's only printed once
1618                      * since this function is run multiple times.
1619                      */
1620                     /* For now: debug info: */
1621                     fprintf(stderr, "Value only written %s\n", value->name);
1622                     tempbool = ir_value_life_merge(value, instr->eid);
1623                     *changed = *changed || tempbool;
1624                     /*
1625                     ir_instr_dump(instr, dbg_ind, printf);
1626                     abort();
1627                     */
1628                 } else {
1629                     /* since 'living' won't contain it
1630                      * anymore, merge the value, since
1631                      * (A) doesn't.
1632                      */
1633                     tempbool = ir_value_life_merge(value, instr->eid);
1634                     /*
1635                     if (tempbool)
1636                         fprintf(stderr, "value added id %s %i\n", value->name, (int)instr->eid);
1637                     */
1638                     *changed = *changed || tempbool;
1639                     /* Then remove */
1640 #if ! defined(LIFE_RANGE_WITHOUT_LAST_READ)
1641                     if (!ir_block_living_remove(self, idx))
1642                         goto on_error;
1643 #else
1644                     if (in_reads)
1645                     {
1646                         if (!new_reads_t_v_remove(&new_reads, readidx))
1647                             goto on_error;
1648                     }
1649 #endif
1650                 }
1651             }
1652         }
1653         /* (A) */
1654         tempbool = ir_block_living_add_instr(self, instr->eid);
1655         /*fprintf(stderr, "living added values\n");*/
1656         *changed = *changed || tempbool;
1657
1658 #if defined(LIFE_RANGE_WITHOUT_LAST_READ)
1659         /* new reads: */
1660         for (rd = 0; rd < new_reads.v_count; ++rd)
1661         {
1662             if (!ir_block_living_find(self, new_reads.v[rd], NULL)) {
1663                 if (!ir_block_living_add(self, new_reads.v[rd]))
1664                     goto on_error;
1665             }
1666             if (!i && !self->entries_count) {
1667                 /* fix the top */
1668                 *changed = *changed || ir_value_life_merge(new_reads.v[rd], instr->eid);
1669             }
1670         }
1671         MEM_VECTOR_CLEAR(&new_reads, v);
1672 #endif
1673     }
1674
1675     if (self->run_id == self->owner->run_id)
1676         return true;
1677
1678     self->run_id = self->owner->run_id;
1679
1680     for (i = 0; i < self->entries_count; ++i)
1681     {
1682         ir_block *entry = self->entries[i];
1683         ir_block_life_propagate(entry, self, changed);
1684     }
1685
1686     return true;
1687 on_error:
1688 #if defined(LIFE_RANGE_WITHOUT_LAST_READ)
1689     MEM_VECTOR_CLEAR(&new_reads, v);
1690 #endif
1691     return false;
1692 }
1693
1694 /***********************************************************************
1695  *IR Code-Generation
1696  *
1697  * Since the IR has the convention of putting 'write' operands
1698  * at the beginning, we have to rotate the operands of instructions
1699  * properly in order to generate valid QCVM code.
1700  *
1701  * Having destinations at a fixed position is more convenient. In QC
1702  * this is *mostly* OPC,  but FTE adds at least 2 instructions which
1703  * read from from OPA,  and store to OPB rather than OPC.   Which is
1704  * partially the reason why the implementation of these instructions
1705  * in darkplaces has been delayed for so long.
1706  *
1707  * Breaking conventions is annoying...
1708  */
1709 static bool ir_builder_gen_global(ir_builder *self, ir_value *global);
1710
1711 static bool gen_global_field(ir_value *global)
1712 {
1713     if (global->isconst)
1714     {
1715         ir_value *fld = global->constval.vpointer;
1716         if (!fld) {
1717             printf("Invalid field constant with no field: %s\n", global->name);
1718             return false;
1719         }
1720
1721         /* Now, in this case, a relocation would be impossible to code
1722          * since it looks like this:
1723          * .vector v = origin;     <- parse error, wtf is 'origin'?
1724          * .vector origin;
1725          *
1726          * But we will need a general relocation support later anyway
1727          * for functions... might as well support that here.
1728          */
1729         if (!fld->code.globaladdr) {
1730             printf("FIXME: Relocation support\n");
1731             return false;
1732         }
1733
1734         /* copy the field's value */
1735         global->code.globaladdr = code_globals_add(code_globals_data[fld->code.globaladdr]);
1736     }
1737     else
1738     {
1739         prog_section_field fld;
1740
1741         fld.name = global->code.name;
1742         fld.offset = code_fields_elements;
1743         fld.type = global->fieldtype;
1744
1745         if (fld.type == TYPE_VOID) {
1746             printf("Field is missing a type: %s\n", global->name);
1747             return false;
1748         }
1749
1750         if (code_fields_add(fld) < 0)
1751             return false;
1752
1753         global->code.globaladdr = code_globals_add(fld.offset);
1754     }
1755     if (global->code.globaladdr < 0)
1756         return false;
1757     return true;
1758 }
1759
1760 static bool gen_global_pointer(ir_value *global)
1761 {
1762     if (global->isconst)
1763     {
1764         ir_value *target = global->constval.vpointer;
1765         if (!target) {
1766             printf("Invalid pointer constant: %s\n", global->name);
1767             /* NULL pointers are pointing to the NULL constant, which also
1768              * sits at address 0, but still has an ir_value for itself.
1769              */
1770             return false;
1771         }
1772
1773         /* Here, relocations ARE possible - in fteqcc-enhanced-qc:
1774          * void() foo; <- proto
1775          * void() *fooptr = &foo;
1776          * void() foo = { code }
1777          */
1778         if (!target->code.globaladdr) {
1779             /* FIXME: Check for the constant nullptr ir_value!
1780              * because then code.globaladdr being 0 is valid.
1781              */
1782             printf("FIXME: Relocation support\n");
1783             return false;
1784         }
1785
1786         global->code.globaladdr = code_globals_add(target->code.globaladdr);
1787     }
1788     else
1789     {
1790         global->code.globaladdr = code_globals_add(0);
1791     }
1792     if (global->code.globaladdr < 0)
1793         return false;
1794     return true;
1795 }
1796
1797 static bool gen_blocks_recursive(ir_function *func, ir_block *block)
1798 {
1799     prog_section_statement stmt;
1800     prog_section_statement *stptr;
1801     ir_instr *instr;
1802     ir_block *target;
1803     ir_block *ontrue;
1804     ir_block *onfalse;
1805     size_t    stidx;
1806     size_t    i;
1807
1808 tailcall:
1809     block->generated = true;
1810     block->code_start = code_statements_elements;
1811     for (i = 0; i < block->instr_count; ++i)
1812     {
1813         instr = block->instr[i];
1814
1815         if (instr->opcode == VINSTR_PHI) {
1816             printf("cannot generate virtual instruction (phi)\n");
1817             return false;
1818         }
1819
1820         if (instr->opcode == VINSTR_JUMP) {
1821             target = instr->bops[0];
1822             /* for uncoditional jumps, if the target hasn't been generated
1823              * yet, we generate them right here.
1824              */
1825             if (!target->generated) {
1826                 block = target;
1827                 goto tailcall;
1828             }
1829
1830             /* otherwise we generate a jump instruction */
1831             stmt.opcode = INSTR_GOTO;
1832             stmt.o1.s1 = (target->code_start-1) - code_statements_elements;
1833             stmt.o2.s1 = 0;
1834             stmt.o3.s1 = 0;
1835             if (code_statements_add(stmt) < 0)
1836                 return false;
1837
1838             /* no further instructions can be in this block */
1839             return true;
1840         }
1841
1842         if (instr->opcode == VINSTR_COND) {
1843             ontrue  = instr->bops[0];
1844             onfalse = instr->bops[1];
1845             /* TODO: have the AST signal which block should
1846              * come first: eg. optimize IFs without ELSE...
1847              */
1848
1849             stmt.o1.u1 = instr->_ops[0]->code.globaladdr;
1850
1851             stmt.o3.s1 = 0;
1852             if (ontrue->generated) {
1853                 stmt.opcode = INSTR_IF;
1854                 stmt.o2.s1 = (ontrue->code_start-1) - code_statements_elements;
1855                 if (code_statements_add(stmt) < 0)
1856                     return false;
1857             }
1858             if (onfalse->generated) {
1859                 stmt.opcode = INSTR_IFNOT;
1860                 stmt.o2.s1 = (onfalse->code_start-1) - code_statements_elements;
1861                 if (code_statements_add(stmt) < 0)
1862                     return false;
1863             }
1864             if (!ontrue->generated) {
1865                 if (onfalse->generated) {
1866                     block = ontrue;
1867                     goto tailcall;
1868                 }
1869             }
1870             if (!onfalse->generated) {
1871                 if (ontrue->generated) {
1872                     block = onfalse;
1873                     goto tailcall;
1874                 }
1875             }
1876             /* neither ontrue nor onfalse exist */
1877             stmt.opcode = INSTR_IFNOT;
1878             stidx = code_statements_elements - 1;
1879             if (code_statements_add(stmt) < 0)
1880                 return false;
1881             stptr = &code_statements_data[stidx];
1882             /* on false we jump, so add ontrue-path */
1883             if (!gen_blocks_recursive(func, ontrue))
1884                 return false;
1885             /* fixup the jump address */
1886             stptr->o2.s1 = (ontrue->code_start-1) - (stidx+1);
1887             /* generate onfalse path */
1888             if (onfalse->generated) {
1889                 /* may have been generated in the previous recursive call */
1890                 stmt.opcode = INSTR_GOTO;
1891                 stmt.o2.s1 = 0;
1892                 stmt.o3.s1 = 0;
1893                 stmt.o1.s1 = (onfalse->code_start-1) - code_statements_elements;
1894                 return (code_statements_add(stmt) >= 0);
1895             }
1896             /* if not, generate now */
1897             block = onfalse;
1898             goto tailcall;
1899         }
1900
1901         if (instr->opcode >= INSTR_CALL0 && instr->opcode <= INSTR_CALL8) {
1902             printf("TODO: call instruction\n");
1903             return false;
1904         }
1905
1906         if (instr->opcode == INSTR_STATE) {
1907             printf("TODO: state instruction\n");
1908             return false;
1909         }
1910
1911         stmt.opcode = instr->opcode;
1912         stmt.o1.u1 = 0;
1913         stmt.o2.u1 = 0;
1914         stmt.o3.u1 = 0;
1915
1916         /* This is the general order of operands */
1917         if (instr->_ops[0])
1918             stmt.o3.u1 = instr->_ops[0]->code.globaladdr;
1919
1920         if (instr->_ops[1])
1921             stmt.o1.u1 = instr->_ops[1]->code.globaladdr;
1922
1923         if (instr->_ops[2])
1924             stmt.o2.u1 = instr->_ops[2]->code.globaladdr;
1925
1926         if (stmt.opcode == INSTR_RETURN || stmt.opcode == INSTR_DONE)
1927         {
1928             stmt.o1.u1 = stmt.o3.u1;
1929             stmt.o3.u1 = 0;
1930         }
1931         else if ((stmt.opcode >= INSTR_STORE_F    &&
1932                   stmt.opcode <= INSTR_STORE_FNC)    ||
1933                  (stmt.opcode >= INSTR_NOT_F      &&
1934                   stmt.opcode <= INSTR_NOT_FNC))
1935         {
1936             /* 2-operand instructions with A -> B */
1937             stmt.o2.u1 = stmt.o3.u1;
1938             stmt.o3.u1 = 0;
1939         }
1940
1941         if (code_statements_add(stmt) < 0)
1942             return false;
1943     }
1944     return true;
1945 }
1946
1947 static bool gen_function_code(ir_function *self)
1948 {
1949     ir_block *block;
1950
1951     /* Starting from entry point, we generate blocks "as they come"
1952      * for now. Dead blocks will not be translated obviously.
1953      */
1954     if (!self->blocks_count) {
1955         printf("Function '%s' declared without body.\n", self->name);
1956         return false;
1957     }
1958
1959     block = self->blocks[0];
1960     if (block->generated)
1961         return true;
1962
1963     if (!gen_blocks_recursive(self, block)) {
1964         printf("failed to generate blocks for '%s'\n", self->name);
1965         return false;
1966     }
1967     return true;
1968 }
1969
1970 static bool gen_global_function(ir_builder *ir, ir_value *global)
1971 {
1972     prog_section_function fun;
1973     ir_function          *irfun;
1974
1975     size_t i;
1976
1977     if (!global->isconst ||
1978         !global->constval.vfunc)
1979     {
1980         printf("Invalid state of function-global: not constant: %s\n", global->name);
1981         return false;
1982     }
1983
1984     irfun = global->constval.vfunc;
1985
1986     fun.name    = global->code.name;
1987     fun.file    = code_cachedstring(global->context.file);
1988     fun.profile = 0; /* always 0 */
1989     fun.nargs   = irfun->params_count;
1990
1991     for (i = 0;i < 8; ++i) {
1992         if (i >= fun.nargs)
1993             fun.argsize[i] = 0;
1994         else if (irfun->params[i] == TYPE_VECTOR)
1995             fun.argsize[i] = 3;
1996         else
1997             fun.argsize[i] = 1;
1998     }
1999
2000     fun.firstlocal = code_globals_elements;
2001     fun.locals = irfun->locals_count;
2002     for (i = 0; i < irfun->locals_count; ++i) {
2003         if (!ir_builder_gen_global(ir, irfun->locals[i])) {
2004             printf("Failed to generate global %s\n", irfun->locals[i]->name);
2005             return false;
2006         }
2007     }
2008
2009     fun.entry      = code_statements_elements;
2010     if (!gen_function_code(irfun)) {
2011         printf("Failed to generate code for function %s\n", irfun->name);
2012         return false;
2013     }
2014
2015     return (code_functions_add(fun) >= 0);
2016 }
2017
2018 static bool ir_builder_gen_global(ir_builder *self, ir_value *global)
2019 {
2020     int32_t         *iptr;
2021     prog_section_def def;
2022
2023     def.type   = global->vtype;
2024     def.offset = code_globals_elements;
2025     def.name   = global->code.name       = code_genstring(global->name);
2026
2027     switch (global->vtype)
2028     {
2029     case TYPE_POINTER:
2030         if (code_defs_add(def) < 0)
2031             return false;
2032         return gen_global_pointer(global);
2033     case TYPE_FIELD:
2034         if (code_defs_add(def) < 0)
2035             return false;
2036         return gen_global_field(global);
2037     case TYPE_ENTITY:
2038         /* fall through */
2039     case TYPE_FLOAT:
2040     {
2041         if (code_defs_add(def) < 0)
2042             return false;
2043
2044         if (global->isconst) {
2045             iptr = (int32_t*)&global->constval.vfloat;
2046             global->code.globaladdr = code_globals_add(*iptr);
2047         } else
2048             global->code.globaladdr = code_globals_add(0);
2049
2050         return global->code.globaladdr >= 0;
2051     }
2052     case TYPE_STRING:
2053     {
2054         if (code_defs_add(def) < 0)
2055             return false;
2056         if (global->isconst)
2057             global->code.globaladdr = code_globals_add(code_cachedstring(global->constval.vstring));
2058         else
2059             global->code.globaladdr = code_globals_add(0);
2060         return global->code.globaladdr >= 0;
2061     }
2062     case TYPE_VECTOR:
2063     {
2064         if (code_defs_add(def) < 0)
2065             return false;
2066
2067         if (global->isconst) {
2068             iptr = (int32_t*)&global->constval.vvec;
2069             global->code.globaladdr = code_globals_add(iptr[0]);
2070             if (code_globals_add(iptr[1]) < 0 || code_globals_add(iptr[2]) < 0)
2071                 return false;
2072         } else {
2073             global->code.globaladdr = code_globals_add(0);
2074             if (code_globals_add(0) < 0 || code_globals_add(0) < 0)
2075                 return false;
2076         }
2077         return global->code.globaladdr >= 0;
2078     }
2079     case TYPE_FUNCTION:
2080         if (code_defs_add(def) < 0)
2081             return false;
2082         code_globals_add(code_functions_elements);
2083         return gen_global_function(self, global);
2084     case TYPE_VARIANT:
2085         /* assume biggest type */
2086             global->code.globaladdr = code_globals_add(0);
2087             code_globals_add(0);
2088             code_globals_add(0);
2089             return true;
2090     default:
2091         /* refuse to create 'void' type or any other fancy business. */
2092         printf("Invalid type for global variable %s\n", global->name);
2093         return false;
2094     }
2095 }
2096
2097 bool ir_builder_generate(ir_builder *self, const char *filename)
2098 {
2099     size_t i;
2100
2101     code_init();
2102
2103     /* FIXME: generate TYPE_FUNCTION globals and link them
2104      * to their ir_function.
2105      */
2106
2107     for (i = 0; i < self->functions_count; ++i)
2108     {
2109         ir_value    *funval;
2110         ir_function *fun = self->functions[i];
2111
2112         funval = ir_builder_create_global(self, fun->name, TYPE_FUNCTION);
2113         funval->isconst = true;
2114         funval->constval.vfunc = fun;
2115         funval->context = fun->context;
2116     }
2117
2118     for (i = 0; i < self->globals_count; ++i)
2119     {
2120         if (!ir_builder_gen_global(self, self->globals[i])) {
2121             return false;
2122         }
2123     }
2124
2125     printf("writing '%s'...\n", filename);
2126     return code_write(filename);
2127 }
2128
2129 /***********************************************************************
2130  *IR DEBUG Dump functions...
2131  */
2132
2133 #define IND_BUFSZ 1024
2134
2135 const char *qc_opname(int op)
2136 {
2137     if (op < 0) return "<INVALID>";
2138     if (op < ( sizeof(asm_instr) / sizeof(asm_instr[0]) ))
2139         return asm_instr[op].m;
2140     switch (op) {
2141         case VINSTR_PHI:  return "PHI";
2142         case VINSTR_JUMP: return "JUMP";
2143         case VINSTR_COND: return "COND";
2144         default:          return "<UNK>";
2145     }
2146 }
2147
2148 void ir_builder_dump(ir_builder *b, int (*oprintf)(const char*, ...))
2149 {
2150         size_t i;
2151         char indent[IND_BUFSZ];
2152         indent[0] = '\t';
2153         indent[1] = 0;
2154
2155         oprintf("module %s\n", b->name);
2156         for (i = 0; i < b->globals_count; ++i)
2157         {
2158                 oprintf("global ");
2159                 if (b->globals[i]->isconst)
2160                         oprintf("%s = ", b->globals[i]->name);
2161                 ir_value_dump(b->globals[i], oprintf);
2162                 oprintf("\n");
2163         }
2164         for (i = 0; i < b->functions_count; ++i)
2165                 ir_function_dump(b->functions[i], indent, oprintf);
2166         oprintf("endmodule %s\n", b->name);
2167 }
2168
2169 void ir_function_dump(ir_function *f, char *ind,
2170                       int (*oprintf)(const char*, ...))
2171 {
2172         size_t i;
2173         oprintf("%sfunction %s\n", ind, f->name);
2174         strncat(ind, "\t", IND_BUFSZ);
2175         if (f->locals_count)
2176         {
2177                 oprintf("%s%i locals:\n", ind, (int)f->locals_count);
2178                 for (i = 0; i < f->locals_count; ++i) {
2179                         oprintf("%s\t", ind);
2180                         ir_value_dump(f->locals[i], oprintf);
2181                         oprintf("\n");
2182                 }
2183         }
2184         if (f->blocks_count)
2185         {
2186                 oprintf("%slife passes (check): %i\n", ind, (int)f->run_id);
2187                 for (i = 0; i < f->blocks_count; ++i) {
2188                     if (f->blocks[i]->run_id != f->run_id) {
2189                         oprintf("%slife pass check fail! %i != %i\n", ind, (int)f->blocks[i]->run_id, (int)f->run_id);
2190                     }
2191                         ir_block_dump(f->blocks[i], ind, oprintf);
2192                 }
2193
2194         }
2195         ind[strlen(ind)-1] = 0;
2196         oprintf("%sendfunction %s\n", ind, f->name);
2197 }
2198
2199 void ir_block_dump(ir_block* b, char *ind,
2200                    int (*oprintf)(const char*, ...))
2201 {
2202         size_t i;
2203         oprintf("%s:%s\n", ind, b->label);
2204         strncat(ind, "\t", IND_BUFSZ);
2205
2206         for (i = 0; i < b->instr_count; ++i)
2207                 ir_instr_dump(b->instr[i], ind, oprintf);
2208         ind[strlen(ind)-1] = 0;
2209 }
2210
2211 void dump_phi(ir_instr *in, char *ind,
2212               int (*oprintf)(const char*, ...))
2213 {
2214         size_t i;
2215         oprintf("%s <- phi ", in->_ops[0]->name);
2216         for (i = 0; i < in->phi_count; ++i)
2217         {
2218                 oprintf("([%s] : %s) ", in->phi[i].from->label,
2219                                         in->phi[i].value->name);
2220         }
2221         oprintf("\n");
2222 }
2223
2224 void ir_instr_dump(ir_instr *in, char *ind,
2225                        int (*oprintf)(const char*, ...))
2226 {
2227         size_t i;
2228         const char *comma = NULL;
2229
2230         oprintf("%s (%i) ", ind, (int)in->eid);
2231
2232         if (in->opcode == VINSTR_PHI) {
2233                 dump_phi(in, ind, oprintf);
2234                 return;
2235         }
2236
2237         strncat(ind, "\t", IND_BUFSZ);
2238
2239         if (in->_ops[0] && (in->_ops[1] || in->_ops[2])) {
2240                 ir_value_dump(in->_ops[0], oprintf);
2241                 if (in->_ops[1] || in->_ops[2])
2242                         oprintf(" <- ");
2243         }
2244         oprintf("%s\t", qc_opname(in->opcode));
2245         if (in->_ops[0] && !(in->_ops[1] || in->_ops[2])) {
2246                 ir_value_dump(in->_ops[0], oprintf);
2247                 comma = ",\t";
2248         }
2249         else
2250         {
2251                 for (i = 1; i != 3; ++i) {
2252                         if (in->_ops[i]) {
2253                                 if (comma)
2254                                         oprintf(comma);
2255                                 ir_value_dump(in->_ops[i], oprintf);
2256                                 comma = ",\t";
2257                         }
2258                 }
2259         }
2260         if (in->bops[0]) {
2261                 if (comma)
2262                         oprintf(comma);
2263                 oprintf("[%s]", in->bops[0]->label);
2264                 comma = ",\t";
2265         }
2266         if (in->bops[1])
2267                 oprintf("%s[%s]", comma, in->bops[1]->label);
2268         oprintf("\n");
2269         ind[strlen(ind)-1] = 0;
2270 }
2271
2272 void ir_value_dump(ir_value* v, int (*oprintf)(const char*, ...))
2273 {
2274         if (v->isconst) {
2275                 switch (v->vtype) {
2276                         case TYPE_VOID:
2277                                 oprintf("(void)");
2278                                 break;
2279                         case TYPE_FLOAT:
2280                                 oprintf("%g", v->constval.vfloat);
2281                                 break;
2282                         case TYPE_VECTOR:
2283                                 oprintf("'%g %g %g'",
2284                                         v->constval.vvec.x,
2285                                         v->constval.vvec.y,
2286                                         v->constval.vvec.z);
2287                                 break;
2288                         case TYPE_ENTITY:
2289                                 oprintf("(entity)");
2290                                 break;
2291                         case TYPE_STRING:
2292                                 oprintf("\"%s\"", v->constval.vstring);
2293                                 break;
2294 #if 0
2295                         case TYPE_INTEGER:
2296                                 oprintf("%i", v->constval.vint);
2297                                 break;
2298 #endif
2299                         case TYPE_POINTER:
2300                                 oprintf("&%s",
2301                                         v->constval.vpointer->name);
2302                                 break;
2303                 }
2304         } else {
2305                 oprintf("%s", v->name);
2306         }
2307 }
2308
2309 void ir_value_dump_life(ir_value *self, int (*oprintf)(const char*,...))
2310 {
2311         size_t i;
2312         oprintf("Life of %s:\n", self->name);
2313         for (i = 0; i < self->life_count; ++i)
2314         {
2315                 oprintf(" + [%i, %i]\n", self->life[i].start, self->life[i].end);
2316         }
2317 }