]> git.xonotic.org Git - xonotic/gmqcc.git/blob - ir.c
ir_value_life_merge_into, to merge the liferange of one value into the range of anoth...
[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_value_life_merge_into(ir_value *self, const ir_value *other)
588 {
589     size_t i, myi;
590
591     if (!other->life_count)
592         return true;
593
594     if (!self->life_count) {
595         for (i = 0; i < other->life_count; ++i) {
596             if (!ir_value_life_add(self, other->life[i]))
597                 return false;
598         }
599         return true;
600     }
601
602     myi = 0;
603     for (i = 0; i < other->life_count; ++i)
604     {
605         const ir_life_entry_t *life = &other->life[i];
606         while (true)
607         {
608             ir_life_entry_t *entry = &self->life[myi];
609
610             if (life->end+1 < entry->start)
611             {
612                 /* adding an interval before entry */
613                 if (!ir_value_life_insert(self, myi, *life))
614                     return false;
615                 ++myi;
616                 break;
617             }
618
619             if (life->start <  entry->start &&
620                 life->end   >= entry->start)
621             {
622                 /* starts earlier and overlaps */
623                 entry->start = life->start;
624             }
625
626             if (life->end     >  entry->end &&
627                 life->start-1 <= entry->end)
628             {
629                 /* ends later and overlaps */
630                 entry->end = life->end;
631             }
632
633             /* see if our change combines it with the next ranges */
634             while (myi+1 < self->life_count &&
635                    entry->end+1 >= self->life[1+myi].start)
636             {
637                 /* overlaps with (myi+1) */
638                 if (entry->end < self->life[1+myi].end)
639                     entry->end = self->life[1+myi].end;
640                 if (!ir_value_life_remove(self, myi+1))
641                     return false;
642                 entry = &self->life[myi];
643             }
644
645             /* see if we're after the entry */
646             if (life->start > entry->end)
647             {
648                 ++myi;
649                 /* append if we're at the end */
650                 if (myi >= self->life_count) {
651                     if (!ir_value_life_add(self, *life))
652                         return false;
653                     break;
654                 }
655                 /* otherweise check the next range */
656                 continue;
657             }
658             break;
659         }
660     }
661     return true;
662 }
663
664 bool ir_values_overlap(ir_value *a, ir_value *b)
665 {
666     /* For any life entry in A see if it overlaps with
667      * any life entry in B.
668      * Note that the life entries are orderes, so we can make a
669      * more efficient algorithm there than naively translating the
670      * statement above.
671      */
672
673     ir_life_entry_t *la, *lb, *enda, *endb;
674
675     /* first of all, if either has no life range, they cannot clash */
676     if (!a->life_count || !b->life_count)
677         return false;
678
679     la = a->life;
680     lb = b->life;
681     enda = la + a->life_count;
682     endb = lb + b->life_count;
683     while (true)
684     {
685         /* check if the entries overlap, for that,
686          * both must start before the other one ends.
687          */
688 #if defined(LIFE_RANGE_WITHOUT_LAST_READ)
689         if (la->start <= lb->end &&
690             lb->start <= la->end)
691 #else
692         if (la->start <  lb->end &&
693             lb->start <  la->end)
694 #endif
695         {
696             return true;
697         }
698
699         /* entries are ordered
700          * one entry is earlier than the other
701          * that earlier entry will be moved forward
702          */
703         if (la->end < lb->end)
704         {
705             /* order: A B, move A forward
706              * check if we hit the end with A
707              */
708             if (++la == enda)
709                 break;
710         }
711         else if (lb->end < la->end)
712         {
713             /* order: B A, move B forward
714              * check if we hit the end with B
715              */
716             if (++lb == endb)
717                 break;
718         }
719     }
720     return false;
721 }
722
723 /***********************************************************************
724  *IR main operations
725  */
726
727 bool ir_block_create_store_op(ir_block *self, int op, ir_value *target, ir_value *what)
728 {
729     if (target->store == store_value) {
730         fprintf(stderr, "cannot store to an SSA value\n");
731         fprintf(stderr, "trying to store: %s <- %s\n", target->name, what->name);
732         return false;
733     } else {
734         ir_instr *in = ir_instr_new(self, op);
735         if (!in)
736             return false;
737         if (!ir_instr_op(in, 0, target, true) ||
738             !ir_instr_op(in, 1, what, false)  ||
739             !ir_block_instr_add(self, in) )
740         {
741             return false;
742         }
743         return true;
744     }
745 }
746
747 bool ir_block_create_store(ir_block *self, ir_value *target, ir_value *what)
748 {
749     int op = 0;
750     int vtype;
751     if (target->vtype == TYPE_VARIANT)
752         vtype = what->vtype;
753     else
754         vtype = target->vtype;
755
756     switch (vtype) {
757         case TYPE_FLOAT:
758 #if 0
759             if (what->vtype == TYPE_INTEGER)
760                 op = INSTR_CONV_ITOF;
761             else
762 #endif
763                 op = INSTR_STORE_F;
764             break;
765         case TYPE_VECTOR:
766             op = INSTR_STORE_V;
767             break;
768         case TYPE_ENTITY:
769             op = INSTR_STORE_ENT;
770             break;
771         case TYPE_STRING:
772             op = INSTR_STORE_S;
773             break;
774         case TYPE_FIELD:
775             op = INSTR_STORE_FLD;
776             break;
777 #if 0
778         case TYPE_INTEGER:
779             if (what->vtype == TYPE_INTEGER)
780                 op = INSTR_CONV_FTOI;
781             else
782                 op = INSTR_STORE_I;
783             break;
784 #endif
785         case TYPE_POINTER:
786 #if 0
787             op = INSTR_STORE_I;
788 #else
789             op = INSTR_STORE_ENT;
790 #endif
791             break;
792         default:
793             /* Unknown type */
794             return false;
795     }
796     return ir_block_create_store_op(self, op, target, what);
797 }
798
799 bool ir_block_create_storep(ir_block *self, ir_value *target, ir_value *what)
800 {
801     int op = 0;
802     int vtype;
803
804     if (target->vtype != TYPE_POINTER)
805         return false;
806
807     /* storing using pointer - target is a pointer, type must be
808      * inferred from source
809      */
810     vtype = what->vtype;
811
812     switch (vtype) {
813         case TYPE_FLOAT:
814             op = INSTR_STOREP_F;
815             break;
816         case TYPE_VECTOR:
817             op = INSTR_STOREP_V;
818             break;
819         case TYPE_ENTITY:
820             op = INSTR_STOREP_ENT;
821             break;
822         case TYPE_STRING:
823             op = INSTR_STOREP_S;
824             break;
825         case TYPE_FIELD:
826             op = INSTR_STOREP_FLD;
827             break;
828 #if 0
829         case TYPE_INTEGER:
830             op = INSTR_STOREP_I;
831             break;
832 #endif
833         case TYPE_POINTER:
834 #if 0
835             op = INSTR_STOREP_I;
836 #else
837             op = INSTR_STOREP_ENT;
838 #endif
839             break;
840         default:
841             /* Unknown type */
842             return false;
843     }
844     return ir_block_create_store_op(self, op, target, what);
845 }
846
847 bool ir_block_create_return(ir_block *self, ir_value *v)
848 {
849     ir_instr *in;
850     if (self->final) {
851         fprintf(stderr, "block already ended (%s)\n", self->label);
852         return false;
853     }
854     self->final = true;
855     self->is_return = true;
856     in = ir_instr_new(self, INSTR_RETURN);
857     if (!in)
858         return false;
859
860     if (!ir_instr_op(in, 0, v, false) ||
861         !ir_block_instr_add(self, in) )
862     {
863         return false;
864     }
865     return true;
866 }
867
868 bool ir_block_create_if(ir_block *self, ir_value *v,
869                         ir_block *ontrue, ir_block *onfalse)
870 {
871     ir_instr *in;
872     if (self->final) {
873         fprintf(stderr, "block already ended (%s)\n", self->label);
874         return false;
875     }
876     self->final = true;
877     /*in = ir_instr_new(self, (v->vtype == TYPE_STRING ? INSTR_IF_S : INSTR_IF_F));*/
878     in = ir_instr_new(self, VINSTR_COND);
879     if (!in)
880         return false;
881
882     if (!ir_instr_op(in, 0, v, false)) {
883         ir_instr_delete(in);
884         return false;
885     }
886
887     in->bops[0] = ontrue;
888     in->bops[1] = onfalse;
889
890     if (!ir_block_instr_add(self, in))
891         return false;
892
893     if (!ir_block_exits_add(self, ontrue)    ||
894         !ir_block_exits_add(self, onfalse)   ||
895         !ir_block_entries_add(ontrue, self)  ||
896         !ir_block_entries_add(onfalse, self) )
897     {
898         return false;
899     }
900     return true;
901 }
902
903 bool ir_block_create_jump(ir_block *self, ir_block *to)
904 {
905     ir_instr *in;
906     if (self->final) {
907         fprintf(stderr, "block already ended (%s)\n", self->label);
908         return false;
909     }
910     self->final = true;
911     in = ir_instr_new(self, VINSTR_JUMP);
912     if (!in)
913         return false;
914
915     in->bops[0] = to;
916     if (!ir_block_instr_add(self, in))
917         return false;
918
919     if (!ir_block_exits_add(self, to) ||
920         !ir_block_entries_add(to, self) )
921     {
922         return false;
923     }
924     return true;
925 }
926
927 bool ir_block_create_goto(ir_block *self, ir_block *to)
928 {
929     ir_instr *in;
930     if (self->final) {
931         fprintf(stderr, "block already ended (%s)\n", self->label);
932         return false;
933     }
934     self->final = true;
935     in = ir_instr_new(self, INSTR_GOTO);
936     if (!in)
937         return false;
938
939     in->bops[0] = to;
940     if (!ir_block_instr_add(self, in))
941         return false;
942
943     if (!ir_block_exits_add(self, to) ||
944         !ir_block_entries_add(to, self) )
945     {
946         return false;
947     }
948     return true;
949 }
950
951 ir_instr* ir_block_create_phi(ir_block *self, const char *label, int ot)
952 {
953     ir_value *out;
954     ir_instr *in;
955     in = ir_instr_new(self, VINSTR_PHI);
956     if (!in)
957         return NULL;
958     out = ir_value_out(self->owner, label, store_value, ot);
959     if (!out) {
960         ir_instr_delete(in);
961         return NULL;
962     }
963     if (!ir_instr_op(in, 0, out, true)) {
964         ir_instr_delete(in);
965         ir_value_delete(out);
966         return NULL;
967     }
968     if (!ir_block_instr_add(self, in)) {
969         ir_instr_delete(in);
970         ir_value_delete(out);
971         return NULL;
972     }
973     return in;
974 }
975
976 ir_value* ir_phi_value(ir_instr *self)
977 {
978     return self->_ops[0];
979 }
980
981 bool ir_phi_add(ir_instr* self, ir_block *b, ir_value *v)
982 {
983     ir_phi_entry_t pe;
984
985     if (!ir_block_entries_find(self->owner, b, NULL)) {
986         /* Must not be possible to cause this, otherwise the AST
987          * is doing something wrong.
988          */
989         fprintf(stderr, "Invalid entry block for PHI\n");
990         abort();
991     }
992
993     pe.value = v;
994     pe.from = b;
995     if (!ir_value_reads_add(v, self))
996         return false;
997     return ir_instr_phi_add(self, pe);
998 }
999
1000 /* binary op related code */
1001
1002 ir_value* ir_block_create_binop(ir_block *self,
1003                                 const char *label, int opcode,
1004                                 ir_value *left, ir_value *right)
1005 {
1006     int ot = TYPE_VOID;
1007     switch (opcode) {
1008         case INSTR_ADD_F:
1009         case INSTR_SUB_F:
1010         case INSTR_DIV_F:
1011         case INSTR_MUL_F:
1012         case INSTR_MUL_V:
1013         case INSTR_AND:
1014         case INSTR_OR:
1015 #if 0
1016         case INSTR_AND_I:
1017         case INSTR_AND_IF:
1018         case INSTR_AND_FI:
1019         case INSTR_OR_I:
1020         case INSTR_OR_IF:
1021         case INSTR_OR_FI:
1022 #endif
1023         case INSTR_BITAND:
1024         case INSTR_BITOR:
1025 #if 0
1026         case INSTR_SUB_S: /* -- offset of string as float */
1027         case INSTR_MUL_IF:
1028         case INSTR_MUL_FI:
1029         case INSTR_DIV_IF:
1030         case INSTR_DIV_FI:
1031         case INSTR_BITOR_IF:
1032         case INSTR_BITOR_FI:
1033         case INSTR_BITAND_FI:
1034         case INSTR_BITAND_IF:
1035         case INSTR_EQ_I:
1036         case INSTR_NE_I:
1037 #endif
1038             ot = TYPE_FLOAT;
1039             break;
1040 #if 0
1041         case INSTR_ADD_I:
1042         case INSTR_ADD_IF:
1043         case INSTR_ADD_FI:
1044         case INSTR_SUB_I:
1045         case INSTR_SUB_FI:
1046         case INSTR_SUB_IF:
1047         case INSTR_MUL_I:
1048         case INSTR_DIV_I:
1049         case INSTR_BITAND_I:
1050         case INSTR_BITOR_I:
1051         case INSTR_XOR_I:
1052         case INSTR_RSHIFT_I:
1053         case INSTR_LSHIFT_I:
1054             ot = TYPE_INTEGER;
1055             break;
1056 #endif
1057         case INSTR_ADD_V:
1058         case INSTR_SUB_V:
1059         case INSTR_MUL_VF:
1060         case INSTR_MUL_FV:
1061 #if 0
1062         case INSTR_DIV_VF:
1063         case INSTR_MUL_IV:
1064         case INSTR_MUL_VI:
1065 #endif
1066             ot = TYPE_VECTOR;
1067             break;
1068 #if 0
1069         case INSTR_ADD_SF:
1070             ot = TYPE_POINTER;
1071             break;
1072 #endif
1073         default:
1074             /* ranges: */
1075             /* boolean operations result in floats */
1076             if (opcode >= INSTR_EQ_F && opcode <= INSTR_GT)
1077                 ot = TYPE_FLOAT;
1078             else if (opcode >= INSTR_LE && opcode <= INSTR_GT)
1079                 ot = TYPE_FLOAT;
1080 #if 0
1081             else if (opcode >= INSTR_LE_I && opcode <= INSTR_EQ_FI)
1082                 ot = TYPE_FLOAT;
1083 #endif
1084             break;
1085     };
1086     if (ot == TYPE_VOID) {
1087         /* The AST or parser were supposed to check this! */
1088         return NULL;
1089     }
1090
1091     return ir_block_create_general_instr(self, label, opcode, left, right, ot);
1092 }
1093
1094 ir_value* ir_block_create_general_instr(ir_block *self, const char *label,
1095                                         int op, ir_value *a, ir_value *b, int outype)
1096 {
1097     ir_instr *instr;
1098     ir_value *out;
1099
1100     out = ir_value_out(self->owner, label, store_value, outype);
1101     if (!out)
1102         return NULL;
1103
1104     instr = ir_instr_new(self, op);
1105     if (!instr) {
1106         ir_value_delete(out);
1107         return NULL;
1108     }
1109
1110     if (!ir_instr_op(instr, 0, out, true) ||
1111         !ir_instr_op(instr, 1, a, false) ||
1112         !ir_instr_op(instr, 2, b, false) )
1113     {
1114         goto on_error;
1115     }
1116
1117     if (!ir_block_instr_add(self, instr))
1118         goto on_error;
1119
1120     return out;
1121 on_error:
1122     ir_instr_delete(instr);
1123     ir_value_delete(out);
1124     return NULL;
1125 }
1126
1127 ir_value* ir_block_create_fieldaddress(ir_block *self, const char *label, ir_value *ent, ir_value *field)
1128 {
1129     /* Support for various pointer types todo if so desired */
1130     if (ent->vtype != TYPE_ENTITY)
1131         return NULL;
1132
1133     if (field->vtype != TYPE_FIELD)
1134         return NULL;
1135
1136     return ir_block_create_general_instr(self, label, INSTR_ADDRESS, ent, field, TYPE_POINTER);
1137 }
1138
1139 ir_value* ir_block_create_load_from_ent(ir_block *self, const char *label, ir_value *ent, ir_value *field, int outype)
1140 {
1141     int op;
1142     if (ent->vtype != TYPE_ENTITY)
1143         return NULL;
1144
1145     /* at some point we could redirect for TYPE_POINTER... but that could lead to carelessness */
1146     if (field->vtype != TYPE_FIELD)
1147         return NULL;
1148
1149     switch (outype)
1150     {
1151         case TYPE_FLOAT:   op = INSTR_LOAD_F;   break;
1152         case TYPE_VECTOR:  op = INSTR_LOAD_V;   break;
1153         case TYPE_STRING:  op = INSTR_LOAD_S;   break;
1154         case TYPE_FIELD:   op = INSTR_LOAD_FLD; break;
1155         case TYPE_ENTITY:  op = INSTR_LOAD_ENT; break;
1156 #if 0
1157         case TYPE_POINTER: op = INSTR_LOAD_I;   break;
1158         case TYPE_INTEGER: op = INSTR_LOAD_I;   break;
1159 #endif
1160         default:
1161             return NULL;
1162     }
1163
1164     return ir_block_create_general_instr(self, label, op, ent, field, outype);
1165 }
1166
1167 ir_value* ir_block_create_add(ir_block *self,
1168                               const char *label,
1169                               ir_value *left, ir_value *right)
1170 {
1171     int op = 0;
1172     int l = left->vtype;
1173     int r = right->vtype;
1174     if (l == r) {
1175         switch (l) {
1176             default:
1177                 return NULL;
1178             case TYPE_FLOAT:
1179                 op = INSTR_ADD_F;
1180                 break;
1181 #if 0
1182             case TYPE_INTEGER:
1183                 op = INSTR_ADD_I;
1184                 break;
1185 #endif
1186             case TYPE_VECTOR:
1187                 op = INSTR_ADD_V;
1188                 break;
1189         }
1190     } else {
1191 #if 0
1192         if ( (l == TYPE_FLOAT && r == TYPE_INTEGER) )
1193             op = INSTR_ADD_FI;
1194         else if ( (l == TYPE_INTEGER && r == TYPE_FLOAT) )
1195             op = INSTR_ADD_IF;
1196         else
1197 #endif
1198             return NULL;
1199     }
1200     return ir_block_create_binop(self, label, op, left, right);
1201 }
1202
1203 ir_value* ir_block_create_sub(ir_block *self,
1204                               const char *label,
1205                               ir_value *left, ir_value *right)
1206 {
1207     int op = 0;
1208     int l = left->vtype;
1209     int r = right->vtype;
1210     if (l == r) {
1211
1212         switch (l) {
1213             default:
1214                 return NULL;
1215             case TYPE_FLOAT:
1216                 op = INSTR_SUB_F;
1217                 break;
1218 #if 0
1219             case TYPE_INTEGER:
1220                 op = INSTR_SUB_I;
1221                 break;
1222 #endif
1223             case TYPE_VECTOR:
1224                 op = INSTR_SUB_V;
1225                 break;
1226         }
1227     } else {
1228 #if 0
1229         if ( (l == TYPE_FLOAT && r == TYPE_INTEGER) )
1230             op = INSTR_SUB_FI;
1231         else if ( (l == TYPE_INTEGER && r == TYPE_FLOAT) )
1232             op = INSTR_SUB_IF;
1233         else
1234 #endif
1235             return NULL;
1236     }
1237     return ir_block_create_binop(self, label, op, left, right);
1238 }
1239
1240 ir_value* ir_block_create_mul(ir_block *self,
1241                               const char *label,
1242                               ir_value *left, ir_value *right)
1243 {
1244     int op = 0;
1245     int l = left->vtype;
1246     int r = right->vtype;
1247     if (l == r) {
1248
1249         switch (l) {
1250             default:
1251                 return NULL;
1252             case TYPE_FLOAT:
1253                 op = INSTR_MUL_F;
1254                 break;
1255 #if 0
1256             case TYPE_INTEGER:
1257                 op = INSTR_MUL_I;
1258                 break;
1259 #endif
1260             case TYPE_VECTOR:
1261                 op = INSTR_MUL_V;
1262                 break;
1263         }
1264     } else {
1265         if ( (l == TYPE_VECTOR && r == TYPE_FLOAT) )
1266             op = INSTR_MUL_VF;
1267         else if ( (l == TYPE_FLOAT && r == TYPE_VECTOR) )
1268             op = INSTR_MUL_FV;
1269 #if 0
1270         else if ( (l == TYPE_VECTOR && r == TYPE_INTEGER) )
1271             op = INSTR_MUL_VI;
1272         else if ( (l == TYPE_INTEGER && r == TYPE_VECTOR) )
1273             op = INSTR_MUL_IV;
1274         else if ( (l == TYPE_FLOAT && r == TYPE_INTEGER) )
1275             op = INSTR_MUL_FI;
1276         else if ( (l == TYPE_INTEGER && r == TYPE_FLOAT) )
1277             op = INSTR_MUL_IF;
1278 #endif
1279         else
1280             return NULL;
1281     }
1282     return ir_block_create_binop(self, label, op, left, right);
1283 }
1284
1285 ir_value* ir_block_create_div(ir_block *self,
1286                               const char *label,
1287                               ir_value *left, ir_value *right)
1288 {
1289     int op = 0;
1290     int l = left->vtype;
1291     int r = right->vtype;
1292     if (l == r) {
1293
1294         switch (l) {
1295             default:
1296                 return NULL;
1297             case TYPE_FLOAT:
1298                 op = INSTR_DIV_F;
1299                 break;
1300 #if 0
1301             case TYPE_INTEGER:
1302                 op = INSTR_DIV_I;
1303                 break;
1304 #endif
1305         }
1306     } else {
1307 #if 0
1308         if ( (l == TYPE_VECTOR && r == TYPE_FLOAT) )
1309             op = INSTR_DIV_VF;
1310         else if ( (l == TYPE_FLOAT && r == TYPE_INTEGER) )
1311             op = INSTR_DIV_FI;
1312         else if ( (l == TYPE_INTEGER && r == TYPE_FLOAT) )
1313             op = INSTR_DIV_IF;
1314         else
1315 #endif
1316             return NULL;
1317     }
1318     return ir_block_create_binop(self, label, op, left, right);
1319 }
1320
1321 /* PHI resolving breaks the SSA, and must thus be the last
1322  * step before life-range calculation.
1323  */
1324
1325 static bool ir_block_naive_phi(ir_block *self);
1326 bool ir_function_naive_phi(ir_function *self)
1327 {
1328     size_t i;
1329
1330     for (i = 0; i < self->blocks_count; ++i)
1331     {
1332         if (!ir_block_naive_phi(self->blocks[i]))
1333             return false;
1334     }
1335     return true;
1336 }
1337
1338 static bool ir_naive_phi_emit_store(ir_block *block, size_t iid, ir_value *old, ir_value *what)
1339 {
1340     ir_instr *instr;
1341     size_t i;
1342
1343     /* create a store */
1344     if (!ir_block_create_store(block, old, what))
1345         return false;
1346
1347     /* we now move it up */
1348     instr = block->instr[block->instr_count-1];
1349     for (i = block->instr_count; i > iid; --i)
1350         block->instr[i] = block->instr[i-1];
1351     block->instr[i] = instr;
1352
1353     return true;
1354 }
1355
1356 static bool ir_block_naive_phi(ir_block *self)
1357 {
1358     size_t i, p, w;
1359     /* FIXME: optionally, create_phi can add the phis
1360      * to a list so we don't need to loop through blocks
1361      * - anyway: "don't optimize YET"
1362      */
1363     for (i = 0; i < self->instr_count; ++i)
1364     {
1365         ir_instr *instr = self->instr[i];
1366         if (instr->opcode != VINSTR_PHI)
1367             continue;
1368
1369         if (!ir_block_instr_remove(self, i))
1370             return false;
1371         --i; /* NOTE: i+1 below */
1372
1373         for (p = 0; p < instr->phi_count; ++p)
1374         {
1375             ir_value *v = instr->phi[p].value;
1376             for (w = 0; w < v->writes_count; ++w) {
1377                 ir_value *old;
1378
1379                 if (!v->writes[w]->_ops[0])
1380                     continue;
1381
1382                 /* When the write was to a global, we have to emit a mov */
1383                 old = v->writes[w]->_ops[0];
1384
1385                 /* The original instruction now writes to the PHI target local */
1386                 if (v->writes[w]->_ops[0] == v)
1387                     v->writes[w]->_ops[0] = instr->_ops[0];
1388
1389                 if (old->store != store_value && old->store != store_local)
1390                 {
1391                     /* If it originally wrote to a global we need to store the value
1392                      * there as welli
1393                      */
1394                     if (!ir_naive_phi_emit_store(self, i+1, old, v))
1395                         return false;
1396                     if (i+1 < self->instr_count)
1397                         instr = self->instr[i+1];
1398                     else
1399                         instr = NULL;
1400                     /* In case I forget and access instr later, it'll be NULL
1401                      * when it's a problem, to make sure we crash, rather than accessing
1402                      * invalid data.
1403                      */
1404                 }
1405                 else
1406                 {
1407                     /* If it didn't, we can replace all reads by the phi target now. */
1408                     size_t r;
1409                     for (r = 0; r < old->reads_count; ++r)
1410                     {
1411                         size_t op;
1412                         ir_instr *ri = old->reads[r];
1413                         for (op = 0; op < ri->phi_count; ++op) {
1414                             if (ri->phi[op].value == old)
1415                                 ri->phi[op].value = v;
1416                         }
1417                         for (op = 0; op < 3; ++op) {
1418                             if (ri->_ops[op] == old)
1419                                 ri->_ops[op] = v;
1420                         }
1421                     }
1422                 }
1423             }
1424         }
1425         ir_instr_delete(instr);
1426     }
1427     return true;
1428 }
1429
1430 /***********************************************************************
1431  *IR Temp allocation code
1432  * Propagating value life ranges by walking through the function backwards
1433  * until no more changes are made.
1434  * In theory this should happen once more than once for every nested loop
1435  * level.
1436  * Though this implementation might run an additional time for if nests.
1437  */
1438
1439 typedef struct
1440 {
1441     ir_value* *v;
1442     size_t    v_count;
1443     size_t    v_alloc;
1444 } new_reads_t;
1445 MEM_VEC_FUNCTIONS_ALL(new_reads_t, ir_value*, v)
1446
1447 /* Enumerate instructions used by value's life-ranges
1448  */
1449 static void ir_block_enumerate(ir_block *self, size_t *_eid)
1450 {
1451     size_t i;
1452     size_t eid = *_eid;
1453     for (i = 0; i < self->instr_count; ++i)
1454     {
1455         self->instr[i]->eid = eid++;
1456     }
1457     *_eid = eid;
1458 }
1459
1460 /* Enumerate blocks and instructions.
1461  * The block-enumeration is unordered!
1462  * We do not really use the block enumreation, however
1463  * the instruction enumeration is important for life-ranges.
1464  */
1465 void ir_function_enumerate(ir_function *self)
1466 {
1467     size_t i;
1468     size_t instruction_id = 0;
1469     for (i = 0; i < self->blocks_count; ++i)
1470     {
1471         self->blocks[i]->eid = i;
1472         self->blocks[i]->run_id = 0;
1473         ir_block_enumerate(self->blocks[i], &instruction_id);
1474     }
1475 }
1476
1477 static bool ir_block_life_propagate(ir_block *b, ir_block *prev, bool *changed);
1478 bool ir_function_calculate_liferanges(ir_function *self)
1479 {
1480     size_t i;
1481     bool changed;
1482
1483     do {
1484         self->run_id++;
1485         changed = false;
1486         for (i = 0; i != self->blocks_count; ++i)
1487         {
1488             if (self->blocks[i]->is_return)
1489             {
1490                 if (!ir_block_life_propagate(self->blocks[i], NULL, &changed))
1491                     return false;
1492             }
1493         }
1494     } while (changed);
1495     return true;
1496 }
1497
1498 /* Local-value allocator
1499  * After finishing creating the liferange of all values used in a function
1500  * we can allocate their global-positions.
1501  * This is the counterpart to register-allocation in register machines.
1502  */
1503 bool ir_function_allocate_locals(ir_function *self)
1504 {
1505     return true;
1506 }
1507
1508 /* Get information about which operand
1509  * is read from, or written to.
1510  */
1511 static void ir_op_read_write(int op, size_t *read, size_t *write)
1512 {
1513     switch (op)
1514     {
1515     case VINSTR_JUMP:
1516     case INSTR_GOTO:
1517         *write = 0;
1518         *read = 0;
1519         break;
1520     case INSTR_IF:
1521     case INSTR_IFNOT:
1522 #if 0
1523     case INSTR_IF_S:
1524     case INSTR_IFNOT_S:
1525 #endif
1526     case INSTR_RETURN:
1527     case VINSTR_COND:
1528         *write = 0;
1529         *read = 1;
1530         break;
1531     default:
1532         *write = 1;
1533         *read = 6;
1534         break;
1535     };
1536 }
1537
1538 static bool ir_block_living_add_instr(ir_block *self, size_t eid)
1539 {
1540     size_t i;
1541     bool changed = false;
1542     bool tempbool;
1543     for (i = 0; i != self->living_count; ++i)
1544     {
1545         tempbool = ir_value_life_merge(self->living[i], eid);
1546         /* debug
1547         if (tempbool)
1548             fprintf(stderr, "block_living_add_instr() value instruction added %s: %i\n", self->living[i]->_name, (int)eid);
1549         */
1550         changed = changed || tempbool;
1551     }
1552     return changed;
1553 }
1554
1555 static bool ir_block_life_prop_previous(ir_block* self, ir_block *prev, bool *changed)
1556 {
1557     size_t i;
1558     /* values which have been read in a previous iteration are now
1559      * in the "living" array even if the previous block doesn't use them.
1560      * So we have to remove whatever does not exist in the previous block.
1561      * They will be re-added on-read, but the liferange merge won't cause
1562      * a change.
1563      */
1564     for (i = 0; i < self->living_count; ++i)
1565     {
1566         if (!ir_block_living_find(prev, self->living[i], NULL)) {
1567             if (!ir_block_living_remove(self, i))
1568                 return false;
1569             --i;
1570         }
1571     }
1572
1573     /* Whatever the previous block still has in its living set
1574      * must now be added to ours as well.
1575      */
1576     for (i = 0; i < prev->living_count; ++i)
1577     {
1578         if (ir_block_living_find(self, prev->living[i], NULL))
1579             continue;
1580         if (!ir_block_living_add(self, prev->living[i]))
1581             return false;
1582         /*
1583         printf("%s got from prev: %s\n", self->label, prev->living[i]->_name);
1584         */
1585     }
1586     return true;
1587 }
1588
1589 static bool ir_block_life_propagate(ir_block *self, ir_block *prev, bool *changed)
1590 {
1591     ir_instr *instr;
1592     ir_value *value;
1593     bool  tempbool;
1594     size_t i, o, p;
1595     /* bitmasks which operands are read from or written to */
1596     size_t read, write;
1597 #if defined(LIFE_RANGE_WITHOUT_LAST_READ)
1598     size_t rd;
1599     new_reads_t new_reads;
1600 #endif
1601     char dbg_ind[16] = { '#', '0' };
1602     (void)dbg_ind;
1603
1604 #if defined(LIFE_RANGE_WITHOUT_LAST_READ)
1605     MEM_VECTOR_INIT(&new_reads, v);
1606 #endif
1607
1608     if (prev)
1609     {
1610         if (!ir_block_life_prop_previous(self, prev, changed))
1611             return false;
1612     }
1613
1614     i = self->instr_count;
1615     while (i)
1616     { --i;
1617         instr = self->instr[i];
1618
1619         /* PHI operands are always read operands */
1620         for (p = 0; p < instr->phi_count; ++p)
1621         {
1622             value = instr->phi[p].value;
1623 #if ! defined(LIFE_RANGE_WITHOUT_LAST_READ)
1624             if (!ir_block_living_find(self, value, NULL) &&
1625                 !ir_block_living_add(self, value))
1626             {
1627                 goto on_error;
1628             }
1629 #else
1630             if (!new_reads_t_v_find(&new_reads, value, NULL))
1631             {
1632                 if (!new_reads_t_v_add(&new_reads, value))
1633                     goto on_error;
1634             }
1635 #endif
1636         }
1637
1638         /* See which operands are read and write operands */
1639         ir_op_read_write(instr->opcode, &read, &write);
1640
1641         /* Go through the 3 main operands */
1642         for (o = 0; o < 3; ++o)
1643         {
1644             if (!instr->_ops[o]) /* no such operand */
1645                 continue;
1646
1647             value = instr->_ops[o];
1648
1649             /* We only care about locals */
1650             if (value->store != store_value &&
1651                 value->store != store_local)
1652                 continue;
1653
1654             /* read operands */
1655             if (read & (1<<o))
1656             {
1657 #if ! defined(LIFE_RANGE_WITHOUT_LAST_READ)
1658                 if (!ir_block_living_find(self, value, NULL) &&
1659                     !ir_block_living_add(self, value))
1660                 {
1661                     goto on_error;
1662                 }
1663 #else
1664                 /* fprintf(stderr, "read: %s\n", value->_name); */
1665                 if (!new_reads_t_v_find(&new_reads, value, NULL))
1666                 {
1667                     if (!new_reads_t_v_add(&new_reads, value))
1668                         goto on_error;
1669                 }
1670 #endif
1671             }
1672
1673             /* write operands */
1674             /* When we write to a local, we consider it "dead" for the
1675              * remaining upper part of the function, since in SSA a value
1676              * can only be written once (== created)
1677              */
1678             if (write & (1<<o))
1679             {
1680                 size_t idx;
1681                 bool in_living = ir_block_living_find(self, value, &idx);
1682 #if defined(LIFE_RANGE_WITHOUT_LAST_READ)
1683                 size_t readidx;
1684                 bool in_reads = new_reads_t_v_find(&new_reads, value, &readidx);
1685                 if (!in_living && !in_reads)
1686 #else
1687                 if (!in_living)
1688 #endif
1689                 {
1690                     /* If the value isn't alive it hasn't been read before... */
1691                     /* TODO: See if the warning can be emitted during parsing or AST processing
1692                      * otherwise have warning printed here.
1693                      * IF printing a warning here: include filecontext_t,
1694                      * and make sure it's only printed once
1695                      * since this function is run multiple times.
1696                      */
1697                     /* For now: debug info: */
1698                     fprintf(stderr, "Value only written %s\n", value->name);
1699                     tempbool = ir_value_life_merge(value, instr->eid);
1700                     *changed = *changed || tempbool;
1701                     /*
1702                     ir_instr_dump(instr, dbg_ind, printf);
1703                     abort();
1704                     */
1705                 } else {
1706                     /* since 'living' won't contain it
1707                      * anymore, merge the value, since
1708                      * (A) doesn't.
1709                      */
1710                     tempbool = ir_value_life_merge(value, instr->eid);
1711                     /*
1712                     if (tempbool)
1713                         fprintf(stderr, "value added id %s %i\n", value->name, (int)instr->eid);
1714                     */
1715                     *changed = *changed || tempbool;
1716                     /* Then remove */
1717 #if ! defined(LIFE_RANGE_WITHOUT_LAST_READ)
1718                     if (!ir_block_living_remove(self, idx))
1719                         goto on_error;
1720 #else
1721                     if (in_reads)
1722                     {
1723                         if (!new_reads_t_v_remove(&new_reads, readidx))
1724                             goto on_error;
1725                     }
1726 #endif
1727                 }
1728             }
1729         }
1730         /* (A) */
1731         tempbool = ir_block_living_add_instr(self, instr->eid);
1732         /*fprintf(stderr, "living added values\n");*/
1733         *changed = *changed || tempbool;
1734
1735 #if defined(LIFE_RANGE_WITHOUT_LAST_READ)
1736         /* new reads: */
1737         for (rd = 0; rd < new_reads.v_count; ++rd)
1738         {
1739             if (!ir_block_living_find(self, new_reads.v[rd], NULL)) {
1740                 if (!ir_block_living_add(self, new_reads.v[rd]))
1741                     goto on_error;
1742             }
1743             if (!i && !self->entries_count) {
1744                 /* fix the top */
1745                 *changed = *changed || ir_value_life_merge(new_reads.v[rd], instr->eid);
1746             }
1747         }
1748         MEM_VECTOR_CLEAR(&new_reads, v);
1749 #endif
1750     }
1751
1752     if (self->run_id == self->owner->run_id)
1753         return true;
1754
1755     self->run_id = self->owner->run_id;
1756
1757     for (i = 0; i < self->entries_count; ++i)
1758     {
1759         ir_block *entry = self->entries[i];
1760         ir_block_life_propagate(entry, self, changed);
1761     }
1762
1763     return true;
1764 on_error:
1765 #if defined(LIFE_RANGE_WITHOUT_LAST_READ)
1766     MEM_VECTOR_CLEAR(&new_reads, v);
1767 #endif
1768     return false;
1769 }
1770
1771 /***********************************************************************
1772  *IR Code-Generation
1773  *
1774  * Since the IR has the convention of putting 'write' operands
1775  * at the beginning, we have to rotate the operands of instructions
1776  * properly in order to generate valid QCVM code.
1777  *
1778  * Having destinations at a fixed position is more convenient. In QC
1779  * this is *mostly* OPC,  but FTE adds at least 2 instructions which
1780  * read from from OPA,  and store to OPB rather than OPC.   Which is
1781  * partially the reason why the implementation of these instructions
1782  * in darkplaces has been delayed for so long.
1783  *
1784  * Breaking conventions is annoying...
1785  */
1786 static bool ir_builder_gen_global(ir_builder *self, ir_value *global);
1787
1788 static bool gen_global_field(ir_value *global)
1789 {
1790     if (global->isconst)
1791     {
1792         ir_value *fld = global->constval.vpointer;
1793         if (!fld) {
1794             printf("Invalid field constant with no field: %s\n", global->name);
1795             return false;
1796         }
1797
1798         /* Now, in this case, a relocation would be impossible to code
1799          * since it looks like this:
1800          * .vector v = origin;     <- parse error, wtf is 'origin'?
1801          * .vector origin;
1802          *
1803          * But we will need a general relocation support later anyway
1804          * for functions... might as well support that here.
1805          */
1806         if (!fld->code.globaladdr) {
1807             printf("FIXME: Relocation support\n");
1808             return false;
1809         }
1810
1811         /* copy the field's value */
1812         global->code.globaladdr = code_globals_add(code_globals_data[fld->code.globaladdr]);
1813     }
1814     else
1815     {
1816         prog_section_field fld;
1817
1818         fld.name = global->code.name;
1819         fld.offset = code_fields_elements;
1820         fld.type = global->fieldtype;
1821
1822         if (fld.type == TYPE_VOID) {
1823             printf("Field is missing a type: %s\n", global->name);
1824             return false;
1825         }
1826
1827         if (code_fields_add(fld) < 0)
1828             return false;
1829
1830         global->code.globaladdr = code_globals_add(fld.offset);
1831     }
1832     if (global->code.globaladdr < 0)
1833         return false;
1834     return true;
1835 }
1836
1837 static bool gen_global_pointer(ir_value *global)
1838 {
1839     if (global->isconst)
1840     {
1841         ir_value *target = global->constval.vpointer;
1842         if (!target) {
1843             printf("Invalid pointer constant: %s\n", global->name);
1844             /* NULL pointers are pointing to the NULL constant, which also
1845              * sits at address 0, but still has an ir_value for itself.
1846              */
1847             return false;
1848         }
1849
1850         /* Here, relocations ARE possible - in fteqcc-enhanced-qc:
1851          * void() foo; <- proto
1852          * void() *fooptr = &foo;
1853          * void() foo = { code }
1854          */
1855         if (!target->code.globaladdr) {
1856             /* FIXME: Check for the constant nullptr ir_value!
1857              * because then code.globaladdr being 0 is valid.
1858              */
1859             printf("FIXME: Relocation support\n");
1860             return false;
1861         }
1862
1863         global->code.globaladdr = code_globals_add(target->code.globaladdr);
1864     }
1865     else
1866     {
1867         global->code.globaladdr = code_globals_add(0);
1868     }
1869     if (global->code.globaladdr < 0)
1870         return false;
1871     return true;
1872 }
1873
1874 static bool gen_blocks_recursive(ir_function *func, ir_block *block)
1875 {
1876     prog_section_statement stmt;
1877     prog_section_statement *stptr;
1878     ir_instr *instr;
1879     ir_block *target;
1880     ir_block *ontrue;
1881     ir_block *onfalse;
1882     size_t    stidx;
1883     size_t    i;
1884
1885 tailcall:
1886     block->generated = true;
1887     block->code_start = code_statements_elements;
1888     for (i = 0; i < block->instr_count; ++i)
1889     {
1890         instr = block->instr[i];
1891
1892         if (instr->opcode == VINSTR_PHI) {
1893             printf("cannot generate virtual instruction (phi)\n");
1894             return false;
1895         }
1896
1897         if (instr->opcode == VINSTR_JUMP) {
1898             target = instr->bops[0];
1899             /* for uncoditional jumps, if the target hasn't been generated
1900              * yet, we generate them right here.
1901              */
1902             if (!target->generated) {
1903                 block = target;
1904                 goto tailcall;
1905             }
1906
1907             /* otherwise we generate a jump instruction */
1908             stmt.opcode = INSTR_GOTO;
1909             stmt.o1.s1 = (target->code_start-1) - code_statements_elements;
1910             stmt.o2.s1 = 0;
1911             stmt.o3.s1 = 0;
1912             if (code_statements_add(stmt) < 0)
1913                 return false;
1914
1915             /* no further instructions can be in this block */
1916             return true;
1917         }
1918
1919         if (instr->opcode == VINSTR_COND) {
1920             ontrue  = instr->bops[0];
1921             onfalse = instr->bops[1];
1922             /* TODO: have the AST signal which block should
1923              * come first: eg. optimize IFs without ELSE...
1924              */
1925
1926             stmt.o1.u1 = instr->_ops[0]->code.globaladdr;
1927
1928             stmt.o3.s1 = 0;
1929             if (ontrue->generated) {
1930                 stmt.opcode = INSTR_IF;
1931                 stmt.o2.s1 = (ontrue->code_start-1) - code_statements_elements;
1932                 if (code_statements_add(stmt) < 0)
1933                     return false;
1934             }
1935             if (onfalse->generated) {
1936                 stmt.opcode = INSTR_IFNOT;
1937                 stmt.o2.s1 = (onfalse->code_start-1) - code_statements_elements;
1938                 if (code_statements_add(stmt) < 0)
1939                     return false;
1940             }
1941             if (!ontrue->generated) {
1942                 if (onfalse->generated) {
1943                     block = ontrue;
1944                     goto tailcall;
1945                 }
1946             }
1947             if (!onfalse->generated) {
1948                 if (ontrue->generated) {
1949                     block = onfalse;
1950                     goto tailcall;
1951                 }
1952             }
1953             /* neither ontrue nor onfalse exist */
1954             stmt.opcode = INSTR_IFNOT;
1955             stidx = code_statements_elements - 1;
1956             if (code_statements_add(stmt) < 0)
1957                 return false;
1958             stptr = &code_statements_data[stidx];
1959             /* on false we jump, so add ontrue-path */
1960             if (!gen_blocks_recursive(func, ontrue))
1961                 return false;
1962             /* fixup the jump address */
1963             stptr->o2.s1 = (ontrue->code_start-1) - (stidx+1);
1964             /* generate onfalse path */
1965             if (onfalse->generated) {
1966                 /* may have been generated in the previous recursive call */
1967                 stmt.opcode = INSTR_GOTO;
1968                 stmt.o2.s1 = 0;
1969                 stmt.o3.s1 = 0;
1970                 stmt.o1.s1 = (onfalse->code_start-1) - code_statements_elements;
1971                 return (code_statements_add(stmt) >= 0);
1972             }
1973             /* if not, generate now */
1974             block = onfalse;
1975             goto tailcall;
1976         }
1977
1978         if (instr->opcode >= INSTR_CALL0 && instr->opcode <= INSTR_CALL8) {
1979             printf("TODO: call instruction\n");
1980             return false;
1981         }
1982
1983         if (instr->opcode == INSTR_STATE) {
1984             printf("TODO: state instruction\n");
1985             return false;
1986         }
1987
1988         stmt.opcode = instr->opcode;
1989         stmt.o1.u1 = 0;
1990         stmt.o2.u1 = 0;
1991         stmt.o3.u1 = 0;
1992
1993         /* This is the general order of operands */
1994         if (instr->_ops[0])
1995             stmt.o3.u1 = instr->_ops[0]->code.globaladdr;
1996
1997         if (instr->_ops[1])
1998             stmt.o1.u1 = instr->_ops[1]->code.globaladdr;
1999
2000         if (instr->_ops[2])
2001             stmt.o2.u1 = instr->_ops[2]->code.globaladdr;
2002
2003         if (stmt.opcode == INSTR_RETURN || stmt.opcode == INSTR_DONE)
2004         {
2005             stmt.o1.u1 = stmt.o3.u1;
2006             stmt.o3.u1 = 0;
2007         }
2008         else if ((stmt.opcode >= INSTR_STORE_F    &&
2009                   stmt.opcode <= INSTR_STORE_FNC)    ||
2010                  (stmt.opcode >= INSTR_NOT_F      &&
2011                   stmt.opcode <= INSTR_NOT_FNC))
2012         {
2013             /* 2-operand instructions with A -> B */
2014             stmt.o2.u1 = stmt.o3.u1;
2015             stmt.o3.u1 = 0;
2016         }
2017
2018         if (code_statements_add(stmt) < 0)
2019             return false;
2020     }
2021     return true;
2022 }
2023
2024 static bool gen_function_code(ir_function *self)
2025 {
2026     ir_block *block;
2027
2028     /* Starting from entry point, we generate blocks "as they come"
2029      * for now. Dead blocks will not be translated obviously.
2030      */
2031     if (!self->blocks_count) {
2032         printf("Function '%s' declared without body.\n", self->name);
2033         return false;
2034     }
2035
2036     block = self->blocks[0];
2037     if (block->generated)
2038         return true;
2039
2040     if (!gen_blocks_recursive(self, block)) {
2041         printf("failed to generate blocks for '%s'\n", self->name);
2042         return false;
2043     }
2044     return true;
2045 }
2046
2047 static bool gen_global_function(ir_builder *ir, ir_value *global)
2048 {
2049     prog_section_function fun;
2050     ir_function          *irfun;
2051
2052     size_t i;
2053
2054     if (!global->isconst ||
2055         !global->constval.vfunc)
2056     {
2057         printf("Invalid state of function-global: not constant: %s\n", global->name);
2058         return false;
2059     }
2060
2061     irfun = global->constval.vfunc;
2062
2063     fun.name    = global->code.name;
2064     fun.file    = code_cachedstring(global->context.file);
2065     fun.profile = 0; /* always 0 */
2066     fun.nargs   = irfun->params_count;
2067
2068     for (i = 0;i < 8; ++i) {
2069         if (i >= fun.nargs)
2070             fun.argsize[i] = 0;
2071         else if (irfun->params[i] == TYPE_VECTOR)
2072             fun.argsize[i] = 3;
2073         else
2074             fun.argsize[i] = 1;
2075     }
2076
2077     fun.firstlocal = code_globals_elements;
2078     fun.locals = irfun->locals_count;
2079     for (i = 0; i < irfun->locals_count; ++i) {
2080         if (!ir_builder_gen_global(ir, irfun->locals[i])) {
2081             printf("Failed to generate global %s\n", irfun->locals[i]->name);
2082             return false;
2083         }
2084     }
2085
2086     fun.entry      = code_statements_elements;
2087     if (!gen_function_code(irfun)) {
2088         printf("Failed to generate code for function %s\n", irfun->name);
2089         return false;
2090     }
2091
2092     return (code_functions_add(fun) >= 0);
2093 }
2094
2095 static bool ir_builder_gen_global(ir_builder *self, ir_value *global)
2096 {
2097     int32_t         *iptr;
2098     prog_section_def def;
2099
2100     def.type   = global->vtype;
2101     def.offset = code_globals_elements;
2102     def.name   = global->code.name       = code_genstring(global->name);
2103
2104     switch (global->vtype)
2105     {
2106     case TYPE_POINTER:
2107         if (code_defs_add(def) < 0)
2108             return false;
2109         return gen_global_pointer(global);
2110     case TYPE_FIELD:
2111         if (code_defs_add(def) < 0)
2112             return false;
2113         return gen_global_field(global);
2114     case TYPE_ENTITY:
2115         /* fall through */
2116     case TYPE_FLOAT:
2117     {
2118         if (code_defs_add(def) < 0)
2119             return false;
2120
2121         if (global->isconst) {
2122             iptr = (int32_t*)&global->constval.vfloat;
2123             global->code.globaladdr = code_globals_add(*iptr);
2124         } else
2125             global->code.globaladdr = code_globals_add(0);
2126
2127         return global->code.globaladdr >= 0;
2128     }
2129     case TYPE_STRING:
2130     {
2131         if (code_defs_add(def) < 0)
2132             return false;
2133         if (global->isconst)
2134             global->code.globaladdr = code_globals_add(code_cachedstring(global->constval.vstring));
2135         else
2136             global->code.globaladdr = code_globals_add(0);
2137         return global->code.globaladdr >= 0;
2138     }
2139     case TYPE_VECTOR:
2140     {
2141         if (code_defs_add(def) < 0)
2142             return false;
2143
2144         if (global->isconst) {
2145             iptr = (int32_t*)&global->constval.vvec;
2146             global->code.globaladdr = code_globals_add(iptr[0]);
2147             if (code_globals_add(iptr[1]) < 0 || code_globals_add(iptr[2]) < 0)
2148                 return false;
2149         } else {
2150             global->code.globaladdr = code_globals_add(0);
2151             if (code_globals_add(0) < 0 || code_globals_add(0) < 0)
2152                 return false;
2153         }
2154         return global->code.globaladdr >= 0;
2155     }
2156     case TYPE_FUNCTION:
2157         if (code_defs_add(def) < 0)
2158             return false;
2159         code_globals_add(code_functions_elements);
2160         return gen_global_function(self, global);
2161     case TYPE_VARIANT:
2162         /* assume biggest type */
2163             global->code.globaladdr = code_globals_add(0);
2164             code_globals_add(0);
2165             code_globals_add(0);
2166             return true;
2167     default:
2168         /* refuse to create 'void' type or any other fancy business. */
2169         printf("Invalid type for global variable %s\n", global->name);
2170         return false;
2171     }
2172 }
2173
2174 bool ir_builder_generate(ir_builder *self, const char *filename)
2175 {
2176     size_t i;
2177
2178     code_init();
2179
2180     /* FIXME: generate TYPE_FUNCTION globals and link them
2181      * to their ir_function.
2182      */
2183
2184     for (i = 0; i < self->functions_count; ++i)
2185     {
2186         ir_value    *funval;
2187         ir_function *fun = self->functions[i];
2188
2189         funval = ir_builder_create_global(self, fun->name, TYPE_FUNCTION);
2190         funval->isconst = true;
2191         funval->constval.vfunc = fun;
2192         funval->context = fun->context;
2193     }
2194
2195     for (i = 0; i < self->globals_count; ++i)
2196     {
2197         if (!ir_builder_gen_global(self, self->globals[i])) {
2198             return false;
2199         }
2200     }
2201
2202     printf("writing '%s'...\n", filename);
2203     return code_write(filename);
2204 }
2205
2206 /***********************************************************************
2207  *IR DEBUG Dump functions...
2208  */
2209
2210 #define IND_BUFSZ 1024
2211
2212 const char *qc_opname(int op)
2213 {
2214     if (op < 0) return "<INVALID>";
2215     if (op < ( sizeof(asm_instr) / sizeof(asm_instr[0]) ))
2216         return asm_instr[op].m;
2217     switch (op) {
2218         case VINSTR_PHI:  return "PHI";
2219         case VINSTR_JUMP: return "JUMP";
2220         case VINSTR_COND: return "COND";
2221         default:          return "<UNK>";
2222     }
2223 }
2224
2225 void ir_builder_dump(ir_builder *b, int (*oprintf)(const char*, ...))
2226 {
2227         size_t i;
2228         char indent[IND_BUFSZ];
2229         indent[0] = '\t';
2230         indent[1] = 0;
2231
2232         oprintf("module %s\n", b->name);
2233         for (i = 0; i < b->globals_count; ++i)
2234         {
2235                 oprintf("global ");
2236                 if (b->globals[i]->isconst)
2237                         oprintf("%s = ", b->globals[i]->name);
2238                 ir_value_dump(b->globals[i], oprintf);
2239                 oprintf("\n");
2240         }
2241         for (i = 0; i < b->functions_count; ++i)
2242                 ir_function_dump(b->functions[i], indent, oprintf);
2243         oprintf("endmodule %s\n", b->name);
2244 }
2245
2246 void ir_function_dump(ir_function *f, char *ind,
2247                       int (*oprintf)(const char*, ...))
2248 {
2249         size_t i;
2250         oprintf("%sfunction %s\n", ind, f->name);
2251         strncat(ind, "\t", IND_BUFSZ);
2252         if (f->locals_count)
2253         {
2254                 oprintf("%s%i locals:\n", ind, (int)f->locals_count);
2255                 for (i = 0; i < f->locals_count; ++i) {
2256                         oprintf("%s\t", ind);
2257                         ir_value_dump(f->locals[i], oprintf);
2258                         oprintf("\n");
2259                 }
2260         }
2261         if (f->blocks_count)
2262         {
2263                 oprintf("%slife passes (check): %i\n", ind, (int)f->run_id);
2264                 for (i = 0; i < f->blocks_count; ++i) {
2265                     if (f->blocks[i]->run_id != f->run_id) {
2266                         oprintf("%slife pass check fail! %i != %i\n", ind, (int)f->blocks[i]->run_id, (int)f->run_id);
2267                     }
2268                         ir_block_dump(f->blocks[i], ind, oprintf);
2269                 }
2270
2271         }
2272         ind[strlen(ind)-1] = 0;
2273         oprintf("%sendfunction %s\n", ind, f->name);
2274 }
2275
2276 void ir_block_dump(ir_block* b, char *ind,
2277                    int (*oprintf)(const char*, ...))
2278 {
2279         size_t i;
2280         oprintf("%s:%s\n", ind, b->label);
2281         strncat(ind, "\t", IND_BUFSZ);
2282
2283         for (i = 0; i < b->instr_count; ++i)
2284                 ir_instr_dump(b->instr[i], ind, oprintf);
2285         ind[strlen(ind)-1] = 0;
2286 }
2287
2288 void dump_phi(ir_instr *in, char *ind,
2289               int (*oprintf)(const char*, ...))
2290 {
2291         size_t i;
2292         oprintf("%s <- phi ", in->_ops[0]->name);
2293         for (i = 0; i < in->phi_count; ++i)
2294         {
2295                 oprintf("([%s] : %s) ", in->phi[i].from->label,
2296                                         in->phi[i].value->name);
2297         }
2298         oprintf("\n");
2299 }
2300
2301 void ir_instr_dump(ir_instr *in, char *ind,
2302                        int (*oprintf)(const char*, ...))
2303 {
2304         size_t i;
2305         const char *comma = NULL;
2306
2307         oprintf("%s (%i) ", ind, (int)in->eid);
2308
2309         if (in->opcode == VINSTR_PHI) {
2310                 dump_phi(in, ind, oprintf);
2311                 return;
2312         }
2313
2314         strncat(ind, "\t", IND_BUFSZ);
2315
2316         if (in->_ops[0] && (in->_ops[1] || in->_ops[2])) {
2317                 ir_value_dump(in->_ops[0], oprintf);
2318                 if (in->_ops[1] || in->_ops[2])
2319                         oprintf(" <- ");
2320         }
2321         oprintf("%s\t", qc_opname(in->opcode));
2322         if (in->_ops[0] && !(in->_ops[1] || in->_ops[2])) {
2323                 ir_value_dump(in->_ops[0], oprintf);
2324                 comma = ",\t";
2325         }
2326         else
2327         {
2328                 for (i = 1; i != 3; ++i) {
2329                         if (in->_ops[i]) {
2330                                 if (comma)
2331                                         oprintf(comma);
2332                                 ir_value_dump(in->_ops[i], oprintf);
2333                                 comma = ",\t";
2334                         }
2335                 }
2336         }
2337         if (in->bops[0]) {
2338                 if (comma)
2339                         oprintf(comma);
2340                 oprintf("[%s]", in->bops[0]->label);
2341                 comma = ",\t";
2342         }
2343         if (in->bops[1])
2344                 oprintf("%s[%s]", comma, in->bops[1]->label);
2345         oprintf("\n");
2346         ind[strlen(ind)-1] = 0;
2347 }
2348
2349 void ir_value_dump(ir_value* v, int (*oprintf)(const char*, ...))
2350 {
2351         if (v->isconst) {
2352                 switch (v->vtype) {
2353                         case TYPE_VOID:
2354                                 oprintf("(void)");
2355                                 break;
2356                         case TYPE_FLOAT:
2357                                 oprintf("%g", v->constval.vfloat);
2358                                 break;
2359                         case TYPE_VECTOR:
2360                                 oprintf("'%g %g %g'",
2361                                         v->constval.vvec.x,
2362                                         v->constval.vvec.y,
2363                                         v->constval.vvec.z);
2364                                 break;
2365                         case TYPE_ENTITY:
2366                                 oprintf("(entity)");
2367                                 break;
2368                         case TYPE_STRING:
2369                                 oprintf("\"%s\"", v->constval.vstring);
2370                                 break;
2371 #if 0
2372                         case TYPE_INTEGER:
2373                                 oprintf("%i", v->constval.vint);
2374                                 break;
2375 #endif
2376                         case TYPE_POINTER:
2377                                 oprintf("&%s",
2378                                         v->constval.vpointer->name);
2379                                 break;
2380                 }
2381         } else {
2382                 oprintf("%s", v->name);
2383         }
2384 }
2385
2386 void ir_value_dump_life(ir_value *self, int (*oprintf)(const char*,...))
2387 {
2388         size_t i;
2389         oprintf("Life of %s:\n", self->name);
2390         for (i = 0; i < self->life_count; ++i)
2391         {
2392                 oprintf(" + [%i, %i]\n", self->life[i].start, self->life[i].end);
2393         }
2394 }