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