]> git.xonotic.org Git - xonotic/gmqcc.git/blob - ast.cpp
fix backward propagateSideEffect impl
[xonotic/gmqcc.git] / ast.cpp
1 #include <new>
2
3 #include <stdlib.h>
4 #include <string.h>
5
6 #include "gmqcc.h"
7 #include "ast.h"
8 #include "fold.h"
9 //#include "parser.h"
10
11 #include "algo.h"
12
13 /* Initialize main ast node aprts */
14 ast_node::ast_node(lex_ctx_t ctx, int node_type)
15     : m_context(ctx)
16     , m_node_type(node_type)
17     , m_keep_node(false)
18     , m_side_effects(false)
19 {
20 }
21
22 ast_node::~ast_node()
23 {
24 }
25
26 /* weight and side effects */
27 void ast_node::propagateSideEffects(const ast_node *other)
28 {
29     if (other->m_side_effects)
30         m_side_effects = true;
31 }
32
33 /* General expression initialization */
34 ast_expression::ast_expression(lex_ctx_t ctx, int nodetype, qc_type type)
35     : ast_node(ctx, nodetype)
36     , m_vtype(type)
37 {
38     if (OPTS_OPTION_BOOL(OPTION_COVERAGE))
39         m_flags |= AST_FLAG_BLOCK_COVERAGE;
40 }
41 ast_expression::ast_expression(lex_ctx_t ctx, int nodetype)
42     : ast_expression(ctx, nodetype, TYPE_VOID)
43 {}
44
45 ast_expression::~ast_expression()
46 {
47     if (m_next)
48         delete m_next;
49     if (m_varparam)
50         delete m_varparam;
51 }
52
53 ast_expression::ast_expression(ast_copy_type_t, const ast_expression &other)
54     : ast_expression(ast_copy_type, other.m_context, other)
55 {}
56
57 ast_expression::ast_expression(ast_copy_type_t, lex_ctx_t ctx, const ast_expression &other)
58     : ast_expression(ast_copy_type, TYPE_ast_expression, ctx, other)
59 {}
60
61 ast_expression::ast_expression(ast_copy_type_t, int nodetype, const ast_expression &other)
62     : ast_expression(ast_copy_type, nodetype, other.m_context, other)
63 {}
64
65 ast_expression::ast_expression(ast_copy_type_t, int nodetype, lex_ctx_t ctx, const ast_expression &other)
66     : ast_expression(ctx, nodetype)
67 {
68     m_vtype = other.m_vtype;
69     m_count = other.m_count;
70     m_flags = other.m_flags;
71     if (other.m_next)
72         m_next = new ast_expression(ast_copy_type, *other.m_next);
73     m_type_params.reserve(other.m_type_params.size());
74     for (auto &it : other.m_type_params)
75         m_type_params.emplace_back(new ast_value(ast_copy_type, *it));
76 }
77
78
79 ast_expression *ast_expression::shallowType(lex_ctx_t ctx, qc_type vtype) {
80     auto expr = new ast_expression(ctx, TYPE_ast_expression);
81     expr->m_vtype = vtype;
82     return expr;
83 }
84
85 void ast_expression::adoptType(const ast_expression &other)
86 {
87     m_vtype = other.m_vtype;
88     if (other.m_next)
89         m_next = new ast_expression(ast_copy_type, *other.m_next);
90     m_count = other.m_count;
91     m_flags = other.m_flags;
92     m_type_params.clear();
93     m_type_params.reserve(other.m_type_params.size());
94     for (auto &it : other.m_type_params)
95         m_type_params.emplace_back(new ast_value(ast_copy_type, *it));
96 }
97
98 bool ast_expression::compareType(const ast_expression &other) const
99 {
100     if (m_vtype == TYPE_NIL ||
101         other.m_vtype == TYPE_NIL)
102         return true;
103     if (m_vtype != other.m_vtype)
104         return false;
105     if (!m_next != !other.m_next)
106         return false;
107     if (m_type_params.size() != other.m_type_params.size())
108         return false;
109     if ((m_flags & AST_FLAG_TYPE_MASK) !=
110         (other.m_flags & AST_FLAG_TYPE_MASK) )
111     {
112         return false;
113     }
114     if (m_type_params.size()) {
115         size_t i;
116         for (i = 0; i < m_type_params.size(); ++i) {
117             if (!m_type_params[i]->compareType(*other.m_type_params[i]))
118                 return false;
119         }
120     }
121     if (m_next)
122         return m_next->compareType(*other.m_next);
123     return true;
124 }
125
126 bool ast_expression::codegen(ast_function*, bool, ir_value**) {
127     compile_error(m_context, "ast_expression::codegen called!");
128     abort();
129     return false;
130 }
131
132 ast_value::ast_value(ast_copy_type_t, const ast_value &other, const std::string &name)
133     : ast_value(ast_copy_type, static_cast<const ast_expression&>(other), name)
134 {
135     m_keep_node = true; // keep values, always
136     memset(&m_constval, 0, sizeof(m_constval));
137 }
138
139 ast_value::ast_value(ast_copy_type_t, const ast_value &other)
140     : ast_value(ast_copy_type, static_cast<const ast_expression&>(other), other.m_name)
141 {
142     m_keep_node = true; // keep values, always
143     memset(&m_constval, 0, sizeof(m_constval));
144 }
145
146 ast_value::ast_value(ast_copy_type_t, const ast_expression &other, const std::string &name)
147     : ast_expression(ast_copy_type, TYPE_ast_value, other)
148     , m_name(name)
149 {
150     m_keep_node = true; // keep values, always
151     memset(&m_constval, 0, sizeof(m_constval));
152 }
153
154 ast_value::ast_value(lex_ctx_t ctx, const std::string &name, qc_type t)
155     : ast_expression(ctx, TYPE_ast_value, t)
156     , m_name(name)
157 {
158     m_keep_node = true; // keep values, always
159     memset(&m_constval, 0, sizeof(m_constval));
160 }
161
162 ast_value::~ast_value()
163 {
164     if (m_argcounter)
165         mem_d((void*)m_argcounter);
166     if (m_hasvalue) {
167         switch (m_vtype)
168         {
169         case TYPE_STRING:
170             mem_d((void*)m_constval.vstring);
171             break;
172         case TYPE_FUNCTION:
173             // unlink us from the function node
174             m_constval.vfunc->m_function_type = nullptr;
175             break;
176         // NOTE: delete function? currently collected in
177         // the parser structure
178         default:
179             break;
180         }
181     }
182
183     // initlist imples an array which implies .next in the expression exists.
184     if (m_initlist.size() && m_next->m_vtype == TYPE_STRING) {
185         for (auto &it : m_initlist)
186             if (it.vstring)
187                 mem_d(it.vstring);
188     }
189 }
190
191 static size_t ast_type_to_string_impl(const ast_expression *e, char *buf, size_t bufsize, size_t pos)
192 {
193     const char *typestr;
194     size_t typelen;
195     size_t i;
196
197     if (!e) {
198         if (pos + 6 >= bufsize)
199             goto full;
200         util_strncpy(buf + pos, "(null)", 6);
201         return pos + 6;
202     }
203
204     if (pos + 1 >= bufsize)
205         goto full;
206
207     switch (e->m_vtype) {
208         case TYPE_VARIANT:
209             util_strncpy(buf + pos, "(variant)", 9);
210             return pos + 9;
211
212         case TYPE_FIELD:
213             buf[pos++] = '.';
214             return ast_type_to_string_impl(e->m_next, buf, bufsize, pos);
215
216         case TYPE_POINTER:
217             if (pos + 3 >= bufsize)
218                 goto full;
219             buf[pos++] = '*';
220             buf[pos++] = '(';
221             pos = ast_type_to_string_impl(e->m_next, buf, bufsize, pos);
222             if (pos + 1 >= bufsize)
223                 goto full;
224             buf[pos++] = ')';
225             return pos;
226
227         case TYPE_FUNCTION:
228             pos = ast_type_to_string_impl(e->m_next, buf, bufsize, pos);
229             if (pos + 2 >= bufsize)
230                 goto full;
231             if (e->m_type_params.empty()) {
232                 buf[pos++] = '(';
233                 buf[pos++] = ')';
234                 return pos;
235             }
236             buf[pos++] = '(';
237             pos = ast_type_to_string_impl(e->m_type_params[0].get(), buf, bufsize, pos);
238             for (i = 1; i < e->m_type_params.size(); ++i) {
239                 if (pos + 2 >= bufsize)
240                     goto full;
241                 buf[pos++] = ',';
242                 buf[pos++] = ' ';
243                 pos = ast_type_to_string_impl(e->m_type_params[i].get(), buf, bufsize, pos);
244             }
245             if (pos + 1 >= bufsize)
246                 goto full;
247             buf[pos++] = ')';
248             return pos;
249
250         case TYPE_ARRAY:
251             pos = ast_type_to_string_impl(e->m_next, buf, bufsize, pos);
252             if (pos + 1 >= bufsize)
253                 goto full;
254             buf[pos++] = '[';
255             pos += util_snprintf(buf + pos, bufsize - pos - 1, "%i", (int)e->m_count);
256             if (pos + 1 >= bufsize)
257                 goto full;
258             buf[pos++] = ']';
259             return pos;
260
261         default:
262             typestr = type_name[e->m_vtype];
263             typelen = strlen(typestr);
264             if (pos + typelen >= bufsize)
265                 goto full;
266             util_strncpy(buf + pos, typestr, typelen);
267             return pos + typelen;
268     }
269
270 full:
271     buf[bufsize-3] = '.';
272     buf[bufsize-2] = '.';
273     buf[bufsize-1] = '.';
274     return bufsize;
275 }
276
277 void ast_type_to_string(const ast_expression *e, char *buf, size_t bufsize)
278 {
279     size_t pos = ast_type_to_string_impl(e, buf, bufsize-1, 0);
280     buf[pos] = 0;
281 }
282
283 void ast_value::addParam(ast_value *p)
284 {
285     m_type_params.emplace_back(p);
286 }
287
288 ast_binary::ast_binary(lex_ctx_t ctx, int op,
289                        ast_expression* left, ast_expression* right)
290     : ast_expression(ctx, TYPE_ast_binary)
291     , m_op(op)
292     // m_left/m_right happen after the peephole step right below
293     , m_right_first(false)
294 {
295     if (ast_istype(right, ast_unary) && OPTS_OPTIMIZATION(OPTIM_PEEPHOLE)) {
296         ast_unary      *unary  = ((ast_unary*)right);
297         ast_expression *normal = unary->m_operand;
298
299         /* make a-(-b) => a + b */
300         if (unary->m_op == VINSTR_NEG_F || unary->m_op == VINSTR_NEG_V) {
301             if (op == INSTR_SUB_F) {
302                 op = INSTR_ADD_F;
303                 right = normal;
304                 ++opts_optimizationcount[OPTIM_PEEPHOLE];
305             } else if (op == INSTR_SUB_V) {
306                 op = INSTR_ADD_V;
307                 right = normal;
308                 ++opts_optimizationcount[OPTIM_PEEPHOLE];
309             }
310         }
311     }
312
313     m_left = left;
314     m_right = right;
315
316     propagateSideEffects(left);
317     propagateSideEffects(right);
318
319     if (op >= INSTR_EQ_F && op <= INSTR_GT)
320         m_vtype = TYPE_FLOAT;
321     else if (op == INSTR_AND || op == INSTR_OR) {
322         if (OPTS_FLAG(PERL_LOGIC))
323             adoptType(*right);
324         else
325             m_vtype = TYPE_FLOAT;
326     }
327     else if (op == INSTR_BITAND || op == INSTR_BITOR)
328         m_vtype = TYPE_FLOAT;
329     else if (op == INSTR_MUL_VF || op == INSTR_MUL_FV)
330         m_vtype = TYPE_VECTOR;
331     else if (op == INSTR_MUL_V)
332         m_vtype = TYPE_FLOAT;
333     else
334         m_vtype = left->m_vtype;
335
336     // references all
337     m_refs = AST_REF_ALL;
338 }
339
340 ast_binary::~ast_binary()
341 {
342     if (m_refs & AST_REF_LEFT)  ast_unref(m_left);
343     if (m_refs & AST_REF_RIGHT) ast_unref(m_right);
344 }
345
346 ast_binstore::ast_binstore(lex_ctx_t ctx, int storop, int mathop,
347                            ast_expression* left, ast_expression* right)
348     : ast_expression(ctx, TYPE_ast_binstore)
349     , m_opstore(storop)
350     , m_opbin(mathop)
351     , m_dest(left)
352     , m_source(right)
353     , m_keep_dest(false)
354 {
355     m_side_effects = true;
356     adoptType(*left);
357 }
358
359 ast_binstore::~ast_binstore()
360 {
361     if (!m_keep_dest)
362         ast_unref(m_dest);
363     ast_unref(m_source);
364 }
365
366 ast_unary* ast_unary::make(lex_ctx_t ctx, int op, ast_expression *expr)
367 {
368     if (ast_istype(expr, ast_unary) && OPTS_OPTIMIZATION(OPTIM_PEEPHOLE)) {
369         ast_unary *prev = (ast_unary*)((ast_unary*)expr)->m_operand;
370
371         /* Handle for double negation */
372         if (((ast_unary*)expr)->m_op == op)
373             prev = (ast_unary*)((ast_unary*)expr)->m_operand;
374
375         if (ast_istype(prev, ast_unary)) {
376             ++opts_optimizationcount[OPTIM_PEEPHOLE];
377             return prev;
378         }
379     }
380
381     return new ast_unary(ctx, op, expr);
382 }
383
384 ast_unary::ast_unary(lex_ctx_t ctx, int op, ast_expression *expr)
385     : ast_expression(ctx, TYPE_ast_unary)
386     , m_op(op)
387     , m_operand(expr)
388 {
389     propagateSideEffects(expr);
390     if ((op >= INSTR_NOT_F && op <= INSTR_NOT_FNC) || op == VINSTR_NEG_F) {
391         m_vtype = TYPE_FLOAT;
392     } else if (op == VINSTR_NEG_V) {
393         m_vtype = TYPE_VECTOR;
394     } else {
395         compile_error(ctx, "cannot determine type of unary operation %s", util_instr_str[op]);
396     }
397 }
398
399 ast_unary::~ast_unary()
400 {
401     if (m_operand)
402         ast_unref(m_operand);
403 }
404
405 ast_return::ast_return(lex_ctx_t ctx, ast_expression *expr)
406     : ast_expression(ctx, TYPE_ast_return)
407     , m_operand(expr)
408 {
409     if (expr)
410         propagateSideEffects(expr);
411 }
412
413 ast_return::~ast_return()
414 {
415     if (m_operand)
416         ast_unref(m_operand);
417 }
418
419 ast_entfield::ast_entfield(lex_ctx_t ctx, ast_expression *entity, ast_expression *field)
420     : ast_entfield(ctx, entity, field, field->m_next)
421 {
422     if (field->m_vtype != TYPE_FIELD)
423         compile_error(ctx, "ast_entfield with expression not of type field");
424 }
425
426 ast_entfield::ast_entfield(lex_ctx_t ctx, ast_expression *entity, ast_expression *field, const ast_expression *outtype)
427     : ast_expression(ctx, TYPE_ast_entfield)
428     , m_entity(entity)
429     , m_field(field)
430 {
431     propagateSideEffects(m_entity);
432     propagateSideEffects(m_field);
433
434     if (!outtype) {
435         compile_error(ctx, "ast_entfield: field has no type");
436         m_vtype = TYPE_VOID;
437     }
438     else
439         adoptType(*outtype);
440 }
441
442 ast_entfield::~ast_entfield()
443 {
444     ast_unref(m_entity);
445     ast_unref(m_field);
446 }
447
448 ast_member *ast_member::make(lex_ctx_t ctx, ast_expression *owner, unsigned int field, const std::string &name)
449 {
450     if (field >= 3) {
451         compile_error(ctx, "ast_member: invalid field (>=3): %u", field);
452         return nullptr;
453     }
454     if (owner->m_vtype != TYPE_VECTOR &&
455         owner->m_vtype != TYPE_FIELD)
456     {
457         compile_error(ctx, "member-access on an invalid owner of type %s", type_name[owner->m_vtype]);
458         return nullptr;
459     }
460     return new ast_member(ctx, owner, field, name);
461 }
462
463 ast_member::ast_member(lex_ctx_t ctx, ast_expression *owner, unsigned int field, const std::string &name)
464     : ast_expression(ctx, TYPE_ast_member)
465     , m_owner(owner)
466     , m_field(field)
467     , m_name(name)
468     , m_rvalue(false)
469 {
470     m_keep_node = true;
471
472     if (m_owner->m_vtype == TYPE_VECTOR) {
473         m_vtype = TYPE_FLOAT;
474         m_next  = nullptr;
475     } else {
476         m_vtype = TYPE_FIELD;
477         m_next = ast_expression::shallowType(ctx, TYPE_FLOAT);
478     }
479
480     propagateSideEffects(owner);
481 }
482
483 ast_member::~ast_member()
484 {
485     // The owner is always an ast_value, which has .keep_node=true,
486     // also: ast_members are usually deleted after the owner, thus
487     // this will cause invalid access
488         //ast_unref(self->m_owner);
489     // once we allow (expression).x to access a vector-member, we need
490     // to change this: preferably by creating an alternate ast node for this
491     // purpose that is not garbage-collected.
492 }
493
494 ast_array_index* ast_array_index::make(lex_ctx_t ctx, ast_expression *array, ast_expression *index)
495 {
496     ast_expression *outtype = array->m_next;
497     if (!outtype) {
498         // field has no type
499         return nullptr;
500     }
501
502     return new ast_array_index(ctx, array, index);
503 }
504
505 ast_array_index::ast_array_index(lex_ctx_t ctx, ast_expression *array, ast_expression *index)
506     : ast_expression(ctx, TYPE_ast_array_index)
507     , m_array(array)
508     , m_index(index)
509 {
510     propagateSideEffects(array);
511     propagateSideEffects(index);
512
513     ast_expression *outtype = m_array->m_next;
514     adoptType(*outtype);
515
516     if (array->m_vtype == TYPE_FIELD && outtype->m_vtype == TYPE_ARRAY) {
517         // FIXME: investigate - this is not possible after adoptType
518         //if (m_vtype != TYPE_ARRAY) {
519         //    compile_error(self->m_context, "array_index node on type");
520         //    ast_array_index_delete(self);
521         //    return nullptr;
522         //}
523
524         m_array = outtype;
525         m_vtype = TYPE_FIELD;
526     }
527 }
528
529 ast_array_index::~ast_array_index()
530 {
531     if (m_array)
532         ast_unref(m_array);
533     if (m_index)
534         ast_unref(m_index);
535 }
536
537 ast_argpipe::ast_argpipe(lex_ctx_t ctx, ast_expression *index)
538     : ast_expression(ctx, TYPE_ast_argpipe)
539     , m_index(index)
540 {
541     m_vtype = TYPE_NOEXPR;
542 }
543
544 ast_argpipe::~ast_argpipe()
545 {
546     if (m_index)
547         ast_unref(m_index);
548 }
549
550 ast_store::ast_store(lex_ctx_t ctx, int op, ast_expression *dest, ast_expression *source)
551     : ast_expression(ctx, TYPE_ast_store)
552     , m_op(op)
553     , m_dest(dest)
554     , m_source(source)
555 {
556     m_side_effects = true;
557     adoptType(*dest);
558 }
559
560 ast_store::~ast_store()
561 {
562     ast_unref(m_dest);
563     ast_unref(m_source);
564 }
565
566 ast_ifthen::ast_ifthen(lex_ctx_t ctx, ast_expression *cond, ast_expression *ontrue, ast_expression *onfalse)
567     : ast_expression(ctx, TYPE_ast_ifthen)
568     , m_cond(cond)
569     , m_on_true(ontrue)
570     , m_on_false(onfalse)
571 {
572     propagateSideEffects(cond);
573     if (ontrue)
574         propagateSideEffects(ontrue);
575     if (onfalse)
576         propagateSideEffects(onfalse);
577 }
578
579 ast_ifthen::~ast_ifthen()
580 {
581     ast_unref(m_cond);
582     if (m_on_true)
583         ast_unref(m_on_true);
584     if (m_on_false)
585         ast_unref(m_on_false);
586 }
587
588 ast_ternary::ast_ternary(lex_ctx_t ctx, ast_expression *cond, ast_expression *ontrue, ast_expression *onfalse)
589     : ast_expression(ctx, TYPE_ast_ternary)
590     , m_cond(cond)
591     , m_on_true(ontrue)
592     , m_on_false(onfalse)
593 {
594     propagateSideEffects(cond);
595     propagateSideEffects(ontrue);
596     propagateSideEffects(onfalse);
597
598     if (ontrue->m_vtype == TYPE_NIL)
599         adoptType(*onfalse);
600     else
601         adoptType(*ontrue);
602 }
603
604 ast_ternary::~ast_ternary()
605 {
606     /* the if()s are only there because computed-gotos can set them
607      * to nullptr
608      */
609     if (m_cond)     ast_unref(m_cond);
610     if (m_on_true)  ast_unref(m_on_true);
611     if (m_on_false) ast_unref(m_on_false);
612 }
613
614 ast_loop::ast_loop(lex_ctx_t ctx,
615                    ast_expression *initexpr,
616                    ast_expression *precond, bool pre_not,
617                    ast_expression *postcond, bool post_not,
618                    ast_expression *increment,
619                    ast_expression *body)
620     : ast_expression(ctx, TYPE_ast_loop)
621     , m_initexpr(initexpr)
622     , m_precond(precond)
623     , m_postcond(postcond)
624     , m_increment(increment)
625     , m_body(body)
626     , m_pre_not(pre_not)
627     , m_post_not(post_not)
628 {
629     if (initexpr)
630         propagateSideEffects(initexpr);
631     if (precond)
632         propagateSideEffects(precond);
633     if (postcond)
634         propagateSideEffects(postcond);
635     if (increment)
636         propagateSideEffects(increment);
637     if (body)
638         propagateSideEffects(body);
639 }
640
641 ast_loop::~ast_loop()
642 {
643     if (m_initexpr)
644         ast_unref(m_initexpr);
645     if (m_precond)
646         ast_unref(m_precond);
647     if (m_postcond)
648         ast_unref(m_postcond);
649     if (m_increment)
650         ast_unref(m_increment);
651     if (m_body)
652         ast_unref(m_body);
653 }
654
655 ast_breakcont::ast_breakcont(lex_ctx_t ctx, bool iscont, unsigned int levels)
656     : ast_expression(ctx, TYPE_ast_breakcont)
657     , m_is_continue(iscont)
658     , m_levels(levels)
659 {
660 }
661
662 ast_breakcont::~ast_breakcont()
663 {
664 }
665
666 ast_switch::ast_switch(lex_ctx_t ctx, ast_expression *op)
667     : ast_expression(ctx, TYPE_ast_switch)
668     , m_operand(op)
669 {
670     propagateSideEffects(op);
671 }
672
673 ast_switch::~ast_switch()
674 {
675     ast_unref(m_operand);
676
677     for (auto &it : m_cases) {
678         if (it.m_value)
679             ast_unref(it.m_value);
680         ast_unref(it.m_code);
681     }
682 }
683
684 ast_label::ast_label(lex_ctx_t ctx, const std::string &name, bool undefined)
685     : ast_expression(ctx, TYPE_ast_label)
686     , m_name(name)
687     , m_irblock(nullptr)
688     , m_undefined(undefined)
689 {
690     m_vtype = TYPE_NOEXPR;
691 }
692
693 ast_label::~ast_label()
694 {
695 }
696
697 void ast_label::registerGoto(ast_goto *g)
698 {
699    m_gotos.push_back(g);
700 }
701
702 ast_goto::ast_goto(lex_ctx_t ctx, const std::string &name)
703     : ast_expression(ctx, TYPE_ast_goto)
704     , m_name(name)
705     , m_target(nullptr)
706     , m_irblock_from(nullptr)
707 {
708 }
709
710 ast_goto::~ast_goto()
711 {
712 }
713
714 void ast_goto::setLabel(ast_label *label)
715 {
716     m_target = label;
717 }
718
719 ast_state::ast_state(lex_ctx_t ctx, ast_expression *frame, ast_expression *think)
720     : ast_expression(ctx, TYPE_ast_expression)
721     , m_framenum(frame)
722     , m_nextthink(think)
723 {
724 }
725
726 ast_state::~ast_state()
727 {
728     if (m_framenum)
729         ast_unref(m_framenum);
730     if (m_nextthink)
731         ast_unref(m_nextthink);
732 }
733
734 ast_call *ast_call::make(lex_ctx_t ctx, ast_expression *funcexpr)
735 {
736     if (!funcexpr->m_next) {
737         compile_error(ctx, "not a function");
738         return nullptr;
739     }
740     return new ast_call(ctx, funcexpr);
741 }
742
743 ast_call::ast_call(lex_ctx_t ctx, ast_expression *funcexpr)
744     : ast_expression(ctx, TYPE_ast_call)
745     , m_func(funcexpr)
746     , m_va_count(nullptr)
747 {
748     m_side_effects = true;
749     adoptType(*funcexpr->m_next);
750 }
751
752 ast_call::~ast_call()
753 {
754     for (auto &it : m_params)
755         ast_unref(it);
756
757     if (m_func)
758         ast_unref(m_func);
759
760     if (m_va_count)
761         ast_unref(m_va_count);
762 }
763
764 bool ast_call::checkVararg(ast_expression *va_type, ast_expression *exp_type) const
765 {
766     char texp[1024];
767     char tgot[1024];
768     if (!exp_type)
769         return true;
770     if (!va_type || !va_type->compareType(*exp_type))
771     {
772         if (va_type && exp_type)
773         {
774             ast_type_to_string(va_type,  tgot, sizeof(tgot));
775             ast_type_to_string(exp_type, texp, sizeof(texp));
776             if (OPTS_FLAG(UNSAFE_VARARGS)) {
777                 if (compile_warning(m_context, WARN_UNSAFE_TYPES,
778                                     "piped variadic argument differs in type: constrained to type %s, expected type %s",
779                                     tgot, texp))
780                     return false;
781             } else {
782                 compile_error(m_context,
783                               "piped variadic argument differs in type: constrained to type %s, expected type %s",
784                               tgot, texp);
785                 return false;
786             }
787         }
788         else
789         {
790             ast_type_to_string(exp_type, texp, sizeof(texp));
791             if (OPTS_FLAG(UNSAFE_VARARGS)) {
792                 if (compile_warning(m_context, WARN_UNSAFE_TYPES,
793                                     "piped variadic argument may differ in type: expected type %s",
794                                     texp))
795                     return false;
796             } else {
797                 compile_error(m_context,
798                               "piped variadic argument may differ in type: expected type %s",
799                               texp);
800                 return false;
801             }
802         }
803     }
804     return true;
805 }
806
807 bool ast_call::checkTypes(ast_expression *va_type) const
808 {
809     char texp[1024];
810     char tgot[1024];
811     size_t i;
812     bool retval = true;
813
814     size_t count = m_params.size();
815     if (count > m_func->m_type_params.size())
816         count = m_func->m_type_params.size();
817
818     for (i = 0; i < count; ++i) {
819         if (ast_istype(m_params[i], ast_argpipe)) {
820             /* warn about type safety instead */
821             if (i+1 != count) {
822                 compile_error(m_context, "argpipe must be the last parameter to a function call");
823                 return false;
824             }
825             if (!checkVararg(va_type, m_func->m_type_params[i].get()))
826                 retval = false;
827         }
828         else if (!m_params[i]->compareType(*m_func->m_type_params[i]))
829         {
830             ast_type_to_string(m_params[i], tgot, sizeof(tgot));
831             ast_type_to_string(m_func->m_type_params[i].get(), texp, sizeof(texp));
832             compile_error(m_context, "invalid type for parameter %u in function call: expected %s, got %s",
833                      (unsigned int)(i+1), texp, tgot);
834             /* we don't immediately return */
835             retval = false;
836         }
837     }
838     count = m_params.size();
839     if (count > m_func->m_type_params.size() && m_func->m_varparam) {
840         for (; i < count; ++i) {
841             if (ast_istype(m_params[i], ast_argpipe)) {
842                 /* warn about type safety instead */
843                 if (i+1 != count) {
844                     compile_error(m_context, "argpipe must be the last parameter to a function call");
845                     return false;
846                 }
847                 if (!checkVararg(va_type, m_func->m_varparam))
848                     retval = false;
849             }
850             else if (!m_params[i]->compareType(*m_func->m_varparam))
851             {
852                 ast_type_to_string(m_params[i], tgot, sizeof(tgot));
853                 ast_type_to_string(m_func->m_varparam, texp, sizeof(texp));
854                 compile_error(m_context, "invalid type for variadic parameter %u in function call: expected %s, got %s",
855                          (unsigned int)(i+1), texp, tgot);
856                 /* we don't immediately return */
857                 retval = false;
858             }
859         }
860     }
861     return retval;
862 }
863
864 ast_block::ast_block(lex_ctx_t ctx)
865     : ast_expression(ctx, TYPE_ast_block)
866 {
867 }
868
869 ast_block::~ast_block()
870 {
871     for (auto &it : m_exprs) ast_unref(it);
872     for (auto &it : m_locals) delete it;
873     for (auto &it : m_collect) delete it;
874 }
875
876 void ast_block::setType(const ast_expression &from)
877 {
878     if (m_next)
879         delete m_next;
880     adoptType(from);
881 }
882
883
884 bool ast_block::addExpr(ast_expression *e)
885 {
886     propagateSideEffects(e);
887     m_exprs.push_back(e);
888     if (m_next) {
889         delete m_next;
890         m_next = nullptr;
891     }
892     adoptType(*e);
893     return true;
894 }
895
896 void ast_block::collect(ast_expression *expr)
897 {
898     m_collect.push_back(expr);
899     expr->m_keep_node = true;
900 }
901
902 ast_function *ast_function::make(lex_ctx_t ctx, const std::string &name, ast_value *vtype)
903 {
904     if (!vtype) {
905         compile_error(ctx, "internal error: ast_function_new condition 0");
906         return nullptr;
907     } else if (vtype->m_hasvalue || vtype->m_vtype != TYPE_FUNCTION) {
908         compile_error(ctx, "internal error: ast_function_new condition %i %i type=%i (probably 2 bodies?)",
909                  (int)!vtype,
910                  (int)vtype->m_hasvalue,
911                  vtype->m_vtype);
912         return nullptr;
913     }
914     return new ast_function(ctx, name, vtype);
915 }
916
917 ast_function::ast_function(lex_ctx_t ctx, const std::string &name, ast_value *vtype)
918     : ast_node(ctx, TYPE_ast_function)
919     , m_function_type(vtype)
920     , m_name(name)
921     , m_builtin(0)
922     , m_static_count(0)
923     , m_ir_func(nullptr)
924     , m_curblock(nullptr)
925     , m_labelcount(0)
926     , m_varargs(nullptr)
927     , m_argc(nullptr)
928     , m_fixedparams(nullptr)
929     , m_return_value(nullptr)
930 {
931     vtype->m_hasvalue = true;
932     vtype->m_constval.vfunc = this;
933 }
934
935 ast_function::~ast_function()
936 {
937     if (m_function_type) {
938         // ast_value_delete(m_function_type);
939         m_function_type->m_hasvalue = false;
940         m_function_type->m_constval.vfunc = nullptr;
941         // We use unref - if it was stored in a global table it is supposed
942         // to be deleted from *there*
943         ast_unref(m_function_type);
944     }
945
946     if (m_fixedparams)
947         ast_unref(m_fixedparams);
948     if (m_return_value)
949         ast_unref(m_return_value);
950
951     // force this to be cleared before m_varargs/m_argc as blocks might
952     // try to access them via ast_unref()
953     m_blocks.clear();
954 }
955
956 const char* ast_function::makeLabel(const char *prefix)
957 {
958     size_t id;
959     size_t len;
960     char  *from;
961
962     if (!OPTS_OPTION_BOOL(OPTION_DUMP)    &&
963         !OPTS_OPTION_BOOL(OPTION_DUMPFIN) &&
964         !OPTS_OPTION_BOOL(OPTION_DEBUG))
965     {
966         return nullptr;
967     }
968
969     id  = (m_labelcount++);
970     len = strlen(prefix);
971
972     from = m_labelbuf + sizeof(m_labelbuf)-1;
973     *from-- = 0;
974     do {
975         *from-- = (id%10) + '0';
976         id /= 10;
977     } while (id);
978     ++from;
979     memcpy(from - len, prefix, len);
980     return from - len;
981 }
982
983 /*********************************************************************/
984 /* AST codegen part
985  * by convention you must never pass nullptr to the 'ir_value **out'
986  * parameter. If you really don't care about the output, pass a dummy.
987  * But I can't imagine a pituation where the output is truly unnecessary.
988  */
989
990 static void codegen_output_type(ast_expression *self, ir_value *out)
991 {
992     if (out->m_vtype == TYPE_FIELD)
993         out->m_fieldtype = self->m_next->m_vtype;
994     if (out->m_vtype == TYPE_FUNCTION)
995         out->m_outtype = self->m_next->m_vtype;
996 }
997
998 bool ast_value::codegen(ast_function *func, bool lvalue, ir_value **out)
999 {
1000     (void)func;
1001     (void)lvalue;
1002     if (m_vtype == TYPE_NIL) {
1003         *out = func->m_ir_func->m_owner->m_nil;
1004         return true;
1005     }
1006     // NOTE: This is the codegen for a variable used in an expression.
1007     // It is not the codegen to generate the value storage. For this purpose,
1008     // generateLocal and generateGlobal are to be used before this
1009     // is executed. ast_function::generateFunction should take care of its
1010     // locals, and the ast-user should take care of generateGlobal to be used
1011     // on all the globals.
1012     if (!m_ir_v) {
1013         char tname[1024]; /* typename is reserved in C++ */
1014         ast_type_to_string(this, tname, sizeof(tname));
1015         compile_error(m_context, "ast_value used before generated %s %s", tname, m_name);
1016         return false;
1017     }
1018     *out = m_ir_v;
1019     return true;
1020 }
1021
1022 bool ast_value::setGlobalArray()
1023 {
1024     size_t count = m_initlist.size();
1025     size_t i;
1026
1027     if (count > m_count) {
1028         compile_error(m_context, "too many elements in initializer");
1029         count = m_count;
1030     }
1031     else if (count < m_count) {
1032         /* add this?
1033         compile_warning(m_context, "not all elements are initialized");
1034         */
1035     }
1036
1037     for (i = 0; i != count; ++i) {
1038         switch (m_next->m_vtype) {
1039             case TYPE_FLOAT:
1040                 if (!ir_value_set_float(m_ir_values[i], m_initlist[i].vfloat))
1041                     return false;
1042                 break;
1043             case TYPE_VECTOR:
1044                 if (!ir_value_set_vector(m_ir_values[i], m_initlist[i].vvec))
1045                     return false;
1046                 break;
1047             case TYPE_STRING:
1048                 if (!ir_value_set_string(m_ir_values[i], m_initlist[i].vstring))
1049                     return false;
1050                 break;
1051             case TYPE_ARRAY:
1052                 /* we don't support them in any other place yet either */
1053                 compile_error(m_context, "TODO: nested arrays");
1054                 return false;
1055             case TYPE_FUNCTION:
1056                 /* this requiers a bit more work - similar to the fields I suppose */
1057                 compile_error(m_context, "global of type function not properly generated");
1058                 return false;
1059             case TYPE_FIELD:
1060                 if (!m_initlist[i].vfield) {
1061                     compile_error(m_context, "field constant without vfield set");
1062                     return false;
1063                 }
1064                 if (!m_initlist[i].vfield->m_ir_v) {
1065                     compile_error(m_context, "field constant generated before its field");
1066                     return false;
1067                 }
1068                 if (!ir_value_set_field(m_ir_values[i], m_initlist[i].vfield->m_ir_v))
1069                     return false;
1070                 break;
1071             default:
1072                 compile_error(m_context, "TODO: global constant type %i", m_vtype);
1073                 break;
1074         }
1075     }
1076     return true;
1077 }
1078
1079 bool ast_value::checkArray(const ast_value &array) const
1080 {
1081     if (array.m_flags & AST_FLAG_ARRAY_INIT && array.m_initlist.empty()) {
1082         compile_error(m_context, "array without size: %s", m_name);
1083         return false;
1084     }
1085     // we are lame now - considering the way QC works we won't tolerate arrays > 1024 elements
1086     if (!array.m_count || array.m_count > OPTS_OPTION_U32(OPTION_MAX_ARRAY_SIZE)) {
1087         compile_error(m_context, "Invalid array of size %lu", (unsigned long)array.m_count);
1088         return false;
1089     }
1090     return true;
1091 }
1092
1093 bool ast_value::generateGlobal(ir_builder *ir, bool isfield)
1094 {
1095     if (m_vtype == TYPE_NIL) {
1096         compile_error(m_context, "internal error: trying to generate a variable of TYPE_NIL");
1097         return false;
1098     }
1099
1100     if (m_hasvalue && m_vtype == TYPE_FUNCTION)
1101         return generateGlobalFunction(ir);
1102
1103     if (isfield && m_vtype == TYPE_FIELD)
1104         return generateGlobalField(ir);
1105
1106     ir_value *v = nullptr;
1107     if (m_vtype == TYPE_ARRAY) {
1108         v = prepareGlobalArray(ir);
1109         if (!v)
1110             return false;
1111     } else {
1112         // Arrays don't do this since there's no "array" value which spans across the
1113         // whole thing.
1114         v = ir_builder_create_global(ir, m_name, m_vtype);
1115         if (!v) {
1116             compile_error(m_context, "ir_builder_create_global failed on `%s`", m_name);
1117             return false;
1118         }
1119         codegen_output_type(this, v);
1120         v->m_context = m_context;
1121     }
1122
1123     /* link us to the ir_value */
1124     v->m_cvq = m_cvq;
1125     m_ir_v = v;
1126
1127     if (m_flags & AST_FLAG_INCLUDE_DEF)
1128         m_ir_v->m_flags |= IR_FLAG_INCLUDE_DEF;
1129     if (m_flags & AST_FLAG_ERASEABLE)
1130         m_ir_v->m_flags |= IR_FLAG_ERASABLE;
1131
1132     /* initialize */
1133     if (m_hasvalue) {
1134         switch (m_vtype)
1135         {
1136             case TYPE_FLOAT:
1137                 if (!ir_value_set_float(v, m_constval.vfloat))
1138                     return false;
1139                 break;
1140             case TYPE_VECTOR:
1141                 if (!ir_value_set_vector(v, m_constval.vvec))
1142                     return false;
1143                 break;
1144             case TYPE_STRING:
1145                 if (!ir_value_set_string(v, m_constval.vstring))
1146                     return false;
1147                 break;
1148             case TYPE_ARRAY:
1149                 if (!setGlobalArray())
1150                     return false;
1151                 break;
1152             case TYPE_FUNCTION:
1153                 compile_error(m_context, "global of type function not properly generated");
1154                 return false;
1155                 /* Cannot generate an IR value for a function,
1156                  * need a pointer pointing to a function rather.
1157                  */
1158             case TYPE_FIELD:
1159                 if (!m_constval.vfield) {
1160                     compile_error(m_context, "field constant without vfield set");
1161                     return false;
1162                 }
1163                 if (!m_constval.vfield->m_ir_v) {
1164                     compile_error(m_context, "field constant generated before its field");
1165                     return false;
1166                 }
1167                 if (!ir_value_set_field(v, m_constval.vfield->m_ir_v))
1168                     return false;
1169                 break;
1170             default:
1171                 compile_error(m_context, "TODO: global constant type %i", m_vtype);
1172                 break;
1173         }
1174     }
1175
1176     return true;
1177 }
1178
1179 bool ast_value::generateGlobalFunction(ir_builder *ir)
1180 {
1181     ir_function *func = ir_builder_create_function(ir, m_name, m_next->m_vtype);
1182     if (!func)
1183         return false;
1184     func->m_context = m_context;
1185     func->m_value->m_context = m_context;
1186
1187     m_constval.vfunc->m_ir_func = func;
1188     m_ir_v = func->m_value;
1189     if (m_flags & AST_FLAG_INCLUDE_DEF)
1190         m_ir_v->m_flags |= IR_FLAG_INCLUDE_DEF;
1191     if (m_flags & AST_FLAG_ERASEABLE)
1192         m_ir_v->m_flags |= IR_FLAG_ERASABLE;
1193     if (m_flags & AST_FLAG_BLOCK_COVERAGE)
1194         func->m_flags |= IR_FLAG_BLOCK_COVERAGE;
1195     // The function is filled later on ast_function::generateFunction...
1196     return true;
1197 }
1198
1199 bool ast_value::generateGlobalField(ir_builder *ir)
1200 {
1201     ast_expression *fieldtype = m_next;
1202
1203     if (m_hasvalue) {
1204         compile_error(m_context, "TODO: constant field pointers with value");
1205         return false;
1206     }
1207
1208     if (fieldtype->m_vtype == TYPE_ARRAY) {
1209         if (!ast_istype(fieldtype, ast_value)) {
1210             compile_error(m_context, "internal error: ast_value required");
1211             return false;
1212         }
1213         ast_value      *array = reinterpret_cast<ast_value*>(fieldtype);
1214
1215         if (!checkArray(*array))
1216             return false;
1217
1218         ast_expression *elemtype = array->m_next;
1219         qc_type vtype = elemtype->m_vtype;
1220
1221         ir_value *v = ir_builder_create_field(ir, m_name, vtype);
1222         if (!v) {
1223             compile_error(m_context, "ir_builder_create_global failed on `%s`", m_name);
1224             return false;
1225         }
1226         v->m_context = m_context;
1227         v->m_unique_life = true;
1228         v->m_locked      = true;
1229         array->m_ir_v = m_ir_v = v;
1230
1231         if (m_flags & AST_FLAG_INCLUDE_DEF)
1232             m_ir_v->m_flags |= IR_FLAG_INCLUDE_DEF;
1233         if (m_flags & AST_FLAG_ERASEABLE)
1234             m_ir_v->m_flags |= IR_FLAG_ERASABLE;
1235
1236         const size_t namelen = m_name.length();
1237         std::unique_ptr<char[]> name(new char[namelen+16]);
1238         util_strncpy(name.get(), m_name.c_str(), namelen);
1239
1240         array->m_ir_values.resize(array->m_count);
1241         array->m_ir_values[0] = v;
1242         for (size_t ai = 1; ai < array->m_count; ++ai) {
1243             util_snprintf(name.get() + namelen, 16, "[%u]", (unsigned int)ai);
1244             array->m_ir_values[ai] = ir_builder_create_field(ir, name.get(), vtype);
1245             if (!array->m_ir_values[ai]) {
1246                 compile_error(m_context, "ir_builder_create_global failed on `%s`", name.get());
1247                 return false;
1248             }
1249             array->m_ir_values[ai]->m_context = m_context;
1250             array->m_ir_values[ai]->m_unique_life = true;
1251             array->m_ir_values[ai]->m_locked      = true;
1252             if (m_flags & AST_FLAG_INCLUDE_DEF)
1253                 m_ir_values[ai]->m_flags |= IR_FLAG_INCLUDE_DEF;
1254         }
1255     }
1256     else
1257     {
1258         ir_value *v = ir_builder_create_field(ir, m_name, m_next->m_vtype);
1259         if (!v)
1260             return false;
1261         v->m_context = m_context;
1262         m_ir_v = v;
1263         if (m_flags & AST_FLAG_INCLUDE_DEF)
1264             m_ir_v->m_flags |= IR_FLAG_INCLUDE_DEF;
1265
1266         if (m_flags & AST_FLAG_ERASEABLE)
1267             m_ir_v->m_flags |= IR_FLAG_ERASABLE;
1268     }
1269     return true;
1270 }
1271
1272 ir_value *ast_value::prepareGlobalArray(ir_builder *ir)
1273 {
1274     ast_expression *elemtype = m_next;
1275     qc_type vtype = elemtype->m_vtype;
1276
1277     if (m_flags & AST_FLAG_ARRAY_INIT && !m_count) {
1278         compile_error(m_context, "array `%s' has no size", m_name);
1279         return nullptr;
1280     }
1281
1282     /* same as with field arrays */
1283     if (!checkArray(*this))
1284         return nullptr;
1285
1286     ir_value *v = ir_builder_create_global(ir, m_name, vtype);
1287     if (!v) {
1288         compile_error(m_context, "ir_builder_create_global failed `%s`", m_name);
1289         return nullptr;
1290     }
1291     v->m_context = m_context;
1292     v->m_unique_life = true;
1293     v->m_locked      = true;
1294
1295     if (m_flags & AST_FLAG_INCLUDE_DEF)
1296         v->m_flags |= IR_FLAG_INCLUDE_DEF;
1297     if (m_flags & AST_FLAG_ERASEABLE)
1298         m_ir_v->m_flags |= IR_FLAG_ERASABLE;
1299
1300     const size_t namelen = m_name.length();
1301     std::unique_ptr<char[]> name(new char[namelen+16]);
1302     util_strncpy(name.get(), m_name.c_str(), namelen);
1303
1304     m_ir_values.resize(m_count);
1305     m_ir_values[0] = v;
1306     for (size_t ai = 1; ai < m_count; ++ai) {
1307         util_snprintf(name.get() + namelen, 16, "[%u]", (unsigned int)ai);
1308         m_ir_values[ai] = ir_builder_create_global(ir, name.get(), vtype);
1309         if (!m_ir_values[ai]) {
1310             compile_error(m_context, "ir_builder_create_global failed `%s`", name.get());
1311             return nullptr;
1312         }
1313         m_ir_values[ai]->m_context = m_context;
1314         m_ir_values[ai]->m_unique_life = true;
1315         m_ir_values[ai]->m_locked      = true;
1316         if (m_flags & AST_FLAG_INCLUDE_DEF)
1317             m_ir_values[ai]->m_flags |= IR_FLAG_INCLUDE_DEF;
1318     }
1319
1320     return v;
1321 }
1322
1323 bool ast_value::generateLocal(ir_function *func, bool param)
1324 {
1325     if (m_vtype == TYPE_NIL) {
1326         compile_error(m_context, "internal error: trying to generate a variable of TYPE_NIL");
1327         return false;
1328     }
1329
1330     if (m_hasvalue && m_vtype == TYPE_FUNCTION)
1331     {
1332         /* Do we allow local functions? I think not...
1333          * this is NOT a function pointer atm.
1334          */
1335         return false;
1336     }
1337
1338     ir_value *v = nullptr;
1339     if (m_vtype == TYPE_ARRAY) {
1340         ast_expression *elemtype = m_next;
1341         qc_type vtype = elemtype->m_vtype;
1342
1343         func->m_flags |= IR_FLAG_HAS_ARRAYS;
1344
1345         if (param && !(m_flags & AST_FLAG_IS_VARARG)) {
1346             compile_error(m_context, "array-parameters are not supported");
1347             return false;
1348         }
1349
1350         /* we are lame now - considering the way QC works we won't tolerate arrays > 1024 elements */
1351         if (!checkArray(*this))
1352             return false;
1353
1354         m_ir_values.resize(m_count);
1355         v = ir_function_create_local(func, m_name, vtype, param);
1356         if (!v) {
1357             compile_error(m_context, "internal error: ir_function_create_local failed");
1358             return false;
1359         }
1360         v->m_context = m_context;
1361         v->m_unique_life = true;
1362         v->m_locked      = true;
1363
1364         const size_t namelen = m_name.length();
1365         std::unique_ptr<char[]> name(new char[namelen+16]);
1366         util_strncpy(name.get(), m_name.c_str(), namelen);
1367
1368         m_ir_values[0] = v;
1369         for (size_t ai = 1; ai < m_count; ++ai) {
1370             util_snprintf(name.get() + namelen, 16, "[%u]", (unsigned int)ai);
1371             m_ir_values[ai] = ir_function_create_local(func, name.get(), vtype, param);
1372             if (!m_ir_values[ai]) {
1373                 compile_error(m_context, "internal_error: ir_builder_create_global failed on `%s`", name.get());
1374                 return false;
1375             }
1376             m_ir_values[ai]->m_context = m_context;
1377             m_ir_values[ai]->m_unique_life = true;
1378             m_ir_values[ai]->m_locked      = true;
1379         }
1380     }
1381     else
1382     {
1383         v = ir_function_create_local(func, m_name, m_vtype, param);
1384         if (!v)
1385             return false;
1386         codegen_output_type(this, v);
1387         v->m_context = m_context;
1388     }
1389
1390     // A constant local... hmmm...
1391     // I suppose the IR will have to deal with this
1392     if (m_hasvalue) {
1393         switch (m_vtype)
1394         {
1395             case TYPE_FLOAT:
1396                 if (!ir_value_set_float(v, m_constval.vfloat))
1397                     goto error;
1398                 break;
1399             case TYPE_VECTOR:
1400                 if (!ir_value_set_vector(v, m_constval.vvec))
1401                     goto error;
1402                 break;
1403             case TYPE_STRING:
1404                 if (!ir_value_set_string(v, m_constval.vstring))
1405                     goto error;
1406                 break;
1407             default:
1408                 compile_error(m_context, "TODO: global constant type %i", m_vtype);
1409                 break;
1410         }
1411     }
1412
1413     // link us to the ir_value
1414     v->m_cvq = m_cvq;
1415     m_ir_v = v;
1416
1417     if (!generateAccessors(func->m_owner))
1418         return false;
1419     return true;
1420
1421 error: /* clean up */
1422     delete v;
1423     return false;
1424 }
1425
1426 bool ast_value::generateAccessors(ir_builder *ir)
1427 {
1428     size_t i;
1429     bool warn = OPTS_WARN(WARN_USED_UNINITIALIZED);
1430     if (!m_setter || !m_getter)
1431         return true;
1432     if (m_count && m_ir_values.empty()) {
1433         compile_error(m_context, "internal error: no array values generated for `%s`", m_name);
1434         return false;
1435     }
1436     for (i = 0; i < m_count; ++i) {
1437         if (!m_ir_values[i]) {
1438             compile_error(m_context, "internal error: not all array values have been generated for `%s`", m_name);
1439             return false;
1440         }
1441         if (!m_ir_values[i]->m_life.empty()) {
1442             compile_error(m_context, "internal error: function containing `%s` already generated", m_name);
1443             return false;
1444         }
1445     }
1446
1447     opts_set(opts.warn, WARN_USED_UNINITIALIZED, false);
1448     if (m_setter) {
1449         if (!m_setter->generateGlobal(ir, false) ||
1450             !m_setter->m_constval.vfunc->generateFunction(ir) ||
1451             !ir_function_finalize(m_setter->m_constval.vfunc->m_ir_func))
1452         {
1453             compile_error(m_context, "internal error: failed to generate setter for `%s`", m_name);
1454             opts_set(opts.warn, WARN_USED_UNINITIALIZED, warn);
1455             return false;
1456         }
1457     }
1458     if (m_getter) {
1459         if (!m_getter->generateGlobal(ir, false) ||
1460             !m_getter->m_constval.vfunc->generateFunction(ir) ||
1461             !ir_function_finalize(m_getter->m_constval.vfunc->m_ir_func))
1462         {
1463             compile_error(m_context, "internal error: failed to generate getter for `%s`", m_name);
1464             opts_set(opts.warn, WARN_USED_UNINITIALIZED, warn);
1465             return false;
1466         }
1467     }
1468     for (i = 0; i < m_count; ++i)
1469         m_ir_values[i]->m_life.clear();
1470     opts_set(opts.warn, WARN_USED_UNINITIALIZED, warn);
1471     return true;
1472 }
1473
1474 bool ast_function::generateFunction(ir_builder *ir)
1475 {
1476     (void)ir;
1477
1478     ir_value *dummy;
1479
1480     ir_function *irf = m_ir_func;
1481     if (!irf) {
1482         compile_error(m_context, "internal error: ast_function's related ast_value was not generated yet");
1483         return false;
1484     }
1485
1486     /* fill the parameter list */
1487     for (auto &it : m_function_type->m_type_params) {
1488         if (it->m_vtype == TYPE_FIELD)
1489             vec_push(irf->m_params, it->m_next->m_vtype);
1490         else
1491             vec_push(irf->m_params, it->m_vtype);
1492         if (!m_builtin) {
1493             if (!it->generateLocal(m_ir_func, true))
1494                 return false;
1495         }
1496     }
1497
1498     if (m_varargs) {
1499         if (!m_varargs->generateLocal(m_ir_func, true))
1500             return false;
1501         irf->m_max_varargs = m_varargs->m_count;
1502     }
1503
1504     if (m_builtin) {
1505         irf->m_builtin = m_builtin;
1506         return true;
1507     }
1508
1509     /* have a local return value variable? */
1510     if (m_return_value) {
1511         if (!m_return_value->generateLocal(m_ir_func, false))
1512             return false;
1513     }
1514
1515     if (m_blocks.empty()) {
1516         compile_error(m_context, "function `%s` has no body", m_name);
1517         return false;
1518     }
1519
1520     irf->m_first = m_curblock = ir_function_create_block(m_context, irf, "entry");
1521     if (!m_curblock) {
1522         compile_error(m_context, "failed to allocate entry block for `%s`", m_name);
1523         return false;
1524     }
1525
1526     if (m_argc) {
1527         ir_value *va_count;
1528         ir_value *fixed;
1529         ir_value *sub;
1530         if (!m_argc->generateLocal(m_ir_func, true))
1531             return false;
1532         if (!m_argc->codegen(this, false, &va_count))
1533             return false;
1534         if (!m_fixedparams->codegen(this, false, &fixed))
1535             return false;
1536         sub = ir_block_create_binop(m_curblock, m_context,
1537                                     makeLabel("va_count"), INSTR_SUB_F,
1538                                     ir_builder_get_va_count(ir), fixed);
1539         if (!sub)
1540             return false;
1541         if (!ir_block_create_store_op(m_curblock, m_context, INSTR_STORE_F,
1542                                       va_count, sub))
1543         {
1544             return false;
1545         }
1546     }
1547
1548     for (auto &it : m_blocks) {
1549         if (!it->codegen(this, false, &dummy))
1550           return false;
1551     }
1552
1553     /* TODO: check return types */
1554     if (!m_curblock->m_final)
1555     {
1556         if (!m_function_type->m_next ||
1557             m_function_type->m_next->m_vtype == TYPE_VOID)
1558         {
1559             return ir_block_create_return(m_curblock, m_context, nullptr);
1560         }
1561         else if (vec_size(m_curblock->m_entries) || m_curblock == irf->m_first)
1562         {
1563             if (m_return_value) {
1564                 if (!m_return_value->codegen(this, false, &dummy))
1565                     return false;
1566                 return ir_block_create_return(m_curblock, m_context, dummy);
1567             }
1568             else if (compile_warning(m_context, WARN_MISSING_RETURN_VALUES,
1569                                 "control reaches end of non-void function (`%s`) via %s",
1570                                 m_name.c_str(), m_curblock->m_label.c_str()))
1571             {
1572                 return false;
1573             }
1574             return ir_block_create_return(m_curblock, m_context, nullptr);
1575         }
1576     }
1577     return true;
1578 }
1579
1580 static bool starts_a_label(const ast_expression *ex)
1581 {
1582     while (ex && ast_istype(ex, ast_block)) {
1583         auto b = reinterpret_cast<const ast_block*>(ex);
1584         ex = b->m_exprs[0];
1585     }
1586     if (!ex)
1587         return false;
1588     return ast_istype(ex, ast_label);
1589 }
1590
1591 /* Note, you will not see ast_block_codegen generate ir_blocks.
1592  * To the AST and the IR, blocks are 2 different things.
1593  * In the AST it represents a block of code, usually enclosed in
1594  * curly braces {...}.
1595  * While in the IR it represents a block in terms of control-flow.
1596  */
1597 bool ast_block::codegen(ast_function *func, bool lvalue, ir_value **out)
1598 {
1599     /* We don't use this
1600      * Note: an ast-representation using the comma-operator
1601      * of the form: (a, b, c) = x should not assign to c...
1602      */
1603     if (lvalue) {
1604         compile_error(m_context, "not an l-value (code-block)");
1605         return false;
1606     }
1607
1608     if (m_outr) {
1609         *out = m_outr;
1610         return true;
1611     }
1612
1613     /* output is nullptr at first, we'll have each expression
1614      * assign to out output, thus, a comma-operator represention
1615      * using an ast_block will return the last generated value,
1616      * so: (b, c) + a  executed both b and c, and returns c,
1617      * which is then added to a.
1618      */
1619     *out = nullptr;
1620
1621     /* generate locals */
1622     for (auto &it : m_locals) {
1623         if (!it->generateLocal(func->m_ir_func, false)) {
1624             if (OPTS_OPTION_BOOL(OPTION_DEBUG))
1625                 compile_error(m_context, "failed to generate local `%s`", it->m_name);
1626             return false;
1627         }
1628     }
1629
1630     for (auto &it : m_exprs) {
1631         if (func->m_curblock->m_final && !starts_a_label(it)) {
1632             if (compile_warning(it->m_context, WARN_UNREACHABLE_CODE, "unreachable statement"))
1633                 return false;
1634             continue;
1635         }
1636         if (!it->codegen(func, false, out))
1637             return false;
1638     }
1639
1640     m_outr = *out;
1641
1642     return true;
1643 }
1644
1645 bool ast_store::codegen(ast_function *func, bool lvalue, ir_value **out)
1646 {
1647     ir_value *left  = nullptr;
1648     ir_value *right = nullptr;
1649
1650     ast_value       *idx = 0;
1651     ast_array_index *ai = nullptr;
1652
1653     if (lvalue && m_outl) {
1654         *out = m_outl;
1655         return true;
1656     }
1657
1658     if (!lvalue && m_outr) {
1659         *out = m_outr;
1660         return true;
1661     }
1662
1663     if (ast_istype(m_dest, ast_array_index))
1664     {
1665
1666         ai = (ast_array_index*)m_dest;
1667         idx = (ast_value*)ai->m_index;
1668
1669         if (ast_istype(ai->m_index, ast_value) && idx->m_hasvalue && idx->m_cvq == CV_CONST)
1670             ai = nullptr;
1671     }
1672
1673     if (ai) {
1674         /* we need to call the setter */
1675         ir_value  *iridx, *funval;
1676         ir_instr  *call;
1677
1678         if (lvalue) {
1679             compile_error(m_context, "array-subscript assignment cannot produce lvalues");
1680             return false;
1681         }
1682
1683         auto arr = reinterpret_cast<ast_value*>(ai->m_array);
1684         if (!ast_istype(ai->m_array, ast_value) || !arr->m_setter) {
1685             compile_error(m_context, "value has no setter (%s)", arr->m_name);
1686             return false;
1687         }
1688
1689         if (!idx->codegen(func, false, &iridx))
1690             return false;
1691
1692         if (!arr->m_setter->codegen(func, true, &funval))
1693             return false;
1694
1695         if (!m_source->codegen(func, false, &right))
1696             return false;
1697
1698         call = ir_block_create_call(func->m_curblock, m_context, func->makeLabel("store"), funval, false);
1699         if (!call)
1700             return false;
1701         ir_call_param(call, iridx);
1702         ir_call_param(call, right);
1703         m_outr = right;
1704     }
1705     else
1706     {
1707         // regular code
1708
1709         // lvalue!
1710         if (!m_dest->codegen(func, true, &left))
1711             return false;
1712         m_outl = left;
1713
1714         /* rvalue! */
1715         if (!m_source->codegen(func, false, &right))
1716             return false;
1717
1718         if (!ir_block_create_store_op(func->m_curblock, m_context, m_op, left, right))
1719             return false;
1720         m_outr = right;
1721     }
1722
1723     /* Theoretically, an assinment returns its left side as an
1724      * lvalue, if we don't need an lvalue though, we return
1725      * the right side as an rvalue, otherwise we have to
1726      * somehow know whether or not we need to dereference the pointer
1727      * on the left side - that is: OP_LOAD if it was an address.
1728      * Also: in original QC we cannot OP_LOADP *anyway*.
1729      */
1730     *out = (lvalue ? left : right);
1731
1732     return true;
1733 }
1734
1735 bool ast_binary::codegen(ast_function *func, bool lvalue, ir_value **out)
1736 {
1737     ir_value *left, *right;
1738
1739     /* A binary operation cannot yield an l-value */
1740     if (lvalue) {
1741         compile_error(m_context, "not an l-value (binop)");
1742         return false;
1743     }
1744
1745     if (m_outr) {
1746         *out = m_outr;
1747         return true;
1748     }
1749
1750     if ((OPTS_FLAG(SHORT_LOGIC) || OPTS_FLAG(PERL_LOGIC)) &&
1751         (m_op == INSTR_AND || m_op == INSTR_OR))
1752     {
1753         /* NOTE: The short-logic path will ignore right_first */
1754
1755         /* short circuit evaluation */
1756         ir_block *other, *merge;
1757         ir_block *from_left, *from_right;
1758         ir_instr *phi;
1759         size_t    merge_id;
1760
1761         /* prepare end-block */
1762         merge_id = func->m_ir_func->m_blocks.size();
1763         merge    = ir_function_create_block(m_context, func->m_ir_func, func->makeLabel("sce_merge"));
1764
1765         /* generate the left expression */
1766         if (!m_left->codegen(func, false, &left))
1767             return false;
1768         /* remember the block */
1769         from_left = func->m_curblock;
1770
1771         /* create a new block for the right expression */
1772         other = ir_function_create_block(m_context, func->m_ir_func, func->makeLabel("sce_other"));
1773         if (m_op == INSTR_AND) {
1774             /* on AND: left==true -> other */
1775             if (!ir_block_create_if(func->m_curblock, m_context, left, other, merge))
1776                 return false;
1777         } else {
1778             /* on OR: left==false -> other */
1779             if (!ir_block_create_if(func->m_curblock, m_context, left, merge, other))
1780                 return false;
1781         }
1782         /* use the likely flag */
1783         vec_last(func->m_curblock->m_instr)->m_likely = true;
1784
1785         /* enter the right-expression's block */
1786         func->m_curblock = other;
1787         /* generate */
1788         if (!m_right->codegen(func, false, &right))
1789             return false;
1790         /* remember block */
1791         from_right = func->m_curblock;
1792
1793         /* jump to the merge block */
1794         if (!ir_block_create_jump(func->m_curblock, m_context, merge))
1795             return false;
1796
1797         algo::shiftback(func->m_ir_func->m_blocks.begin() + merge_id,
1798                         func->m_ir_func->m_blocks.end());
1799         // FIXME::DELME::
1800         //func->m_ir_func->m_blocks[merge_id].release();
1801         //func->m_ir_func->m_blocks.erase(func->m_ir_func->m_blocks.begin() + merge_id);
1802         //func->m_ir_func->m_blocks.emplace_back(merge);
1803
1804         func->m_curblock = merge;
1805         phi = ir_block_create_phi(func->m_curblock, m_context,
1806                                   func->makeLabel("sce_value"),
1807                                   m_vtype);
1808         ir_phi_add(phi, from_left, left);
1809         ir_phi_add(phi, from_right, right);
1810         *out = ir_phi_value(phi);
1811         if (!*out)
1812             return false;
1813
1814         if (!OPTS_FLAG(PERL_LOGIC)) {
1815             /* cast-to-bool */
1816             if (OPTS_FLAG(CORRECT_LOGIC) && (*out)->m_vtype == TYPE_VECTOR) {
1817                 *out = ir_block_create_unary(func->m_curblock, m_context,
1818                                              func->makeLabel("sce_bool_v"),
1819                                              INSTR_NOT_V, *out);
1820                 if (!*out)
1821                     return false;
1822                 *out = ir_block_create_unary(func->m_curblock, m_context,
1823                                              func->makeLabel("sce_bool"),
1824                                              INSTR_NOT_F, *out);
1825                 if (!*out)
1826                     return false;
1827             }
1828             else if (OPTS_FLAG(FALSE_EMPTY_STRINGS) && (*out)->m_vtype == TYPE_STRING) {
1829                 *out = ir_block_create_unary(func->m_curblock, m_context,
1830                                              func->makeLabel("sce_bool_s"),
1831                                              INSTR_NOT_S, *out);
1832                 if (!*out)
1833                     return false;
1834                 *out = ir_block_create_unary(func->m_curblock, m_context,
1835                                              func->makeLabel("sce_bool"),
1836                                              INSTR_NOT_F, *out);
1837                 if (!*out)
1838                     return false;
1839             }
1840             else {
1841                 *out = ir_block_create_binop(func->m_curblock, m_context,
1842                                              func->makeLabel("sce_bool"),
1843                                              INSTR_AND, *out, *out);
1844                 if (!*out)
1845                     return false;
1846             }
1847         }
1848
1849         m_outr = *out;
1850         codegen_output_type(this, *out);
1851         return true;
1852     }
1853
1854     if (m_right_first) {
1855         if (!m_right->codegen(func, false, &right))
1856             return false;
1857         if (!m_left->codegen(func, false, &left))
1858             return false;
1859     } else {
1860         if (!m_left->codegen(func, false, &left))
1861             return false;
1862         if (!m_right->codegen(func, false, &right))
1863             return false;
1864     }
1865
1866     *out = ir_block_create_binop(func->m_curblock, m_context, func->makeLabel("bin"),
1867                                  m_op, left, right);
1868     if (!*out)
1869         return false;
1870     m_outr = *out;
1871     codegen_output_type(this, *out);
1872
1873     return true;
1874 }
1875
1876 bool ast_binstore::codegen(ast_function *func, bool lvalue, ir_value **out)
1877 {
1878     ir_value *leftl = nullptr, *leftr, *right, *bin;
1879
1880     ast_value       *arr;
1881     ast_value       *idx = 0;
1882     ast_array_index *ai = nullptr;
1883     ir_value        *iridx = nullptr;
1884
1885     if (lvalue && m_outl) {
1886         *out = m_outl;
1887         return true;
1888     }
1889
1890     if (!lvalue && m_outr) {
1891         *out = m_outr;
1892         return true;
1893     }
1894
1895     if (ast_istype(m_dest, ast_array_index))
1896     {
1897
1898         ai = (ast_array_index*)m_dest;
1899         idx = (ast_value*)ai->m_index;
1900
1901         if (ast_istype(ai->m_index, ast_value) && idx->m_hasvalue && idx->m_cvq == CV_CONST)
1902             ai = nullptr;
1903     }
1904
1905     /* for a binstore we need both an lvalue and an rvalue for the left side */
1906     /* rvalue of destination! */
1907     if (ai) {
1908         if (!idx->codegen(func, false, &iridx))
1909             return false;
1910     }
1911     if (!m_dest->codegen(func, false, &leftr))
1912         return false;
1913
1914     /* source as rvalue only */
1915     if (!m_source->codegen(func, false, &right))
1916         return false;
1917
1918     /* now the binary */
1919     bin = ir_block_create_binop(func->m_curblock, m_context, func->makeLabel("binst"),
1920                                 m_opbin, leftr, right);
1921     m_outr = bin;
1922
1923     if (ai) {
1924         /* we need to call the setter */
1925         ir_value  *funval;
1926         ir_instr  *call;
1927
1928         if (lvalue) {
1929             compile_error(m_context, "array-subscript assignment cannot produce lvalues");
1930             return false;
1931         }
1932
1933         arr = (ast_value*)ai->m_array;
1934         if (!ast_istype(ai->m_array, ast_value) || !arr->m_setter) {
1935             compile_error(m_context, "value has no setter (%s)", arr->m_name);
1936             return false;
1937         }
1938
1939         if (!arr->m_setter->codegen(func, true, &funval))
1940             return false;
1941
1942         call = ir_block_create_call(func->m_curblock, m_context, func->makeLabel("store"), funval, false);
1943         if (!call)
1944             return false;
1945         ir_call_param(call, iridx);
1946         ir_call_param(call, bin);
1947         m_outr = bin;
1948     } else {
1949         // now store them
1950         // lvalue of destination
1951         if (!m_dest->codegen(func, true, &leftl))
1952             return false;
1953         m_outl = leftl;
1954
1955         if (!ir_block_create_store_op(func->m_curblock, m_context, m_opstore, leftl, bin))
1956             return false;
1957         m_outr = bin;
1958     }
1959
1960     /* Theoretically, an assinment returns its left side as an
1961      * lvalue, if we don't need an lvalue though, we return
1962      * the right side as an rvalue, otherwise we have to
1963      * somehow know whether or not we need to dereference the pointer
1964      * on the left side - that is: OP_LOAD if it was an address.
1965      * Also: in original QC we cannot OP_LOADP *anyway*.
1966      */
1967     *out = (lvalue ? leftl : bin);
1968
1969     return true;
1970 }
1971
1972 bool ast_unary::codegen(ast_function *func, bool lvalue, ir_value **out)
1973 {
1974     ir_value *operand;
1975
1976     /* An unary operation cannot yield an l-value */
1977     if (lvalue) {
1978         compile_error(m_context, "not an l-value (binop)");
1979         return false;
1980     }
1981
1982     if (m_outr) {
1983         *out = m_outr;
1984         return true;
1985     }
1986
1987     /* lvalue! */
1988     if (!m_operand->codegen(func, false, &operand))
1989         return false;
1990
1991     *out = ir_block_create_unary(func->m_curblock, m_context, func->makeLabel("unary"),
1992                                  m_op, operand);
1993     if (!*out)
1994         return false;
1995     m_outr = *out;
1996
1997     return true;
1998 }
1999
2000 bool ast_return::codegen(ast_function *func, bool lvalue, ir_value **out)
2001 {
2002     ir_value *operand;
2003
2004     *out = nullptr;
2005
2006     /* In the context of a return operation, we don't actually return
2007      * anything...
2008      */
2009     if (lvalue) {
2010         compile_error(m_context, "return-expression is not an l-value");
2011         return false;
2012     }
2013
2014     if (m_outr) {
2015         compile_error(m_context, "internal error: ast_return cannot be reused, it bears no result!");
2016         return false;
2017     }
2018     m_outr = (ir_value*)1;
2019
2020     if (m_operand) {
2021         /* lvalue! */
2022         if (!m_operand->codegen(func, false, &operand))
2023             return false;
2024
2025         if (!ir_block_create_return(func->m_curblock, m_context, operand))
2026             return false;
2027     } else {
2028         if (!ir_block_create_return(func->m_curblock, m_context, nullptr))
2029             return false;
2030     }
2031
2032     return true;
2033 }
2034
2035 bool ast_entfield::codegen(ast_function *func, bool lvalue, ir_value **out)
2036 {
2037     ir_value *ent, *field;
2038
2039     // This function needs to take the 'lvalue' flag into account!
2040     // As lvalue we provide a field-pointer, as rvalue we provide the
2041     // value in a temp.
2042
2043     if (lvalue && m_outl) {
2044         *out = m_outl;
2045         return true;
2046     }
2047
2048     if (!lvalue && m_outr) {
2049         *out = m_outr;
2050         return true;
2051     }
2052
2053     if (!m_entity->codegen(func, false, &ent))
2054         return false;
2055
2056     if (!m_field->codegen(func, false, &field))
2057         return false;
2058
2059     if (lvalue) {
2060         /* address! */
2061         *out = ir_block_create_fieldaddress(func->m_curblock, m_context, func->makeLabel("efa"),
2062                                             ent, field);
2063     } else {
2064         *out = ir_block_create_load_from_ent(func->m_curblock, m_context, func->makeLabel("efv"),
2065                                              ent, field, m_vtype);
2066         /* Done AFTER error checking:
2067         codegen_output_type(this, *out);
2068         */
2069     }
2070     if (!*out) {
2071         compile_error(m_context, "failed to create %s instruction (output type %s)",
2072                  (lvalue ? "ADDRESS" : "FIELD"),
2073                  type_name[m_vtype]);
2074         return false;
2075     }
2076     if (!lvalue)
2077         codegen_output_type(this, *out);
2078
2079     if (lvalue)
2080         m_outl = *out;
2081     else
2082         m_outr = *out;
2083
2084     // Hm that should be it...
2085     return true;
2086 }
2087
2088 bool ast_member::codegen(ast_function *func, bool lvalue, ir_value **out)
2089 {
2090     ir_value *vec;
2091
2092     /* in QC this is always an lvalue */
2093     if (lvalue && m_rvalue) {
2094         compile_error(m_context, "not an l-value (member access)");
2095         return false;
2096     }
2097     if (m_outl) {
2098         *out = m_outl;
2099         return true;
2100     }
2101
2102     if (!m_owner->codegen(func, false, &vec))
2103         return false;
2104
2105     if (vec->m_vtype != TYPE_VECTOR &&
2106         !(vec->m_vtype == TYPE_FIELD && m_owner->m_next->m_vtype == TYPE_VECTOR))
2107     {
2108         return false;
2109     }
2110
2111     *out = ir_value_vector_member(vec, m_field);
2112     m_outl = *out;
2113
2114     return (*out != nullptr);
2115 }
2116
2117 bool ast_array_index::codegen(ast_function *func, bool lvalue, ir_value **out)
2118 {
2119     ast_value *arr;
2120     ast_value *idx;
2121
2122     if (!lvalue && m_outr) {
2123         *out = m_outr;
2124         return true;
2125     }
2126     if (lvalue && m_outl) {
2127         *out = m_outl;
2128         return true;
2129     }
2130
2131     if (!ast_istype(m_array, ast_value)) {
2132         compile_error(m_context, "array indexing this way is not supported");
2133         /* note this would actually be pointer indexing because the left side is
2134          * not an actual array but (hopefully) an indexable expression.
2135          * Once we get integer arithmetic, and GADDRESS/GSTORE/GLOAD instruction
2136          * support this path will be filled.
2137          */
2138         return false;
2139     }
2140
2141     arr = reinterpret_cast<ast_value*>(m_array);
2142     idx = reinterpret_cast<ast_value*>(m_index);
2143
2144     if (!ast_istype(m_index, ast_value) || !idx->m_hasvalue || idx->m_cvq != CV_CONST) {
2145         /* Time to use accessor functions */
2146         ir_value               *iridx, *funval;
2147         ir_instr               *call;
2148
2149         if (lvalue) {
2150             compile_error(m_context, "(.2) array indexing here needs a compile-time constant");
2151             return false;
2152         }
2153
2154         if (!arr->m_getter) {
2155             compile_error(m_context, "value has no getter, don't know how to index it");
2156             return false;
2157         }
2158
2159         if (!m_index->codegen(func, false, &iridx))
2160             return false;
2161
2162         if (!arr->m_getter->codegen(func, true, &funval))
2163             return false;
2164
2165         call = ir_block_create_call(func->m_curblock, m_context, func->makeLabel("fetch"), funval, false);
2166         if (!call)
2167             return false;
2168         ir_call_param(call, iridx);
2169
2170         *out = ir_call_value(call);
2171         m_outr = *out;
2172         (*out)->m_vtype = m_vtype;
2173         codegen_output_type(this, *out);
2174         return true;
2175     }
2176
2177     if (idx->m_vtype == TYPE_FLOAT) {
2178         unsigned int arridx = idx->m_constval.vfloat;
2179         if (arridx >= m_array->m_count)
2180         {
2181             compile_error(m_context, "array index out of bounds: %i", arridx);
2182             return false;
2183         }
2184         *out = arr->m_ir_values[arridx];
2185     }
2186     else if (idx->m_vtype == TYPE_INTEGER) {
2187         unsigned int arridx = idx->m_constval.vint;
2188         if (arridx >= m_array->m_count)
2189         {
2190             compile_error(m_context, "array index out of bounds: %i", arridx);
2191             return false;
2192         }
2193         *out = arr->m_ir_values[arridx];
2194     }
2195     else {
2196         compile_error(m_context, "array indexing here needs an integer constant");
2197         return false;
2198     }
2199     (*out)->m_vtype = m_vtype;
2200     codegen_output_type(this, *out);
2201     return true;
2202 }
2203
2204 bool ast_argpipe::codegen(ast_function *func, bool lvalue, ir_value **out)
2205 {
2206     *out = nullptr;
2207     if (lvalue) {
2208         compile_error(m_context, "argpipe node: not an lvalue");
2209         return false;
2210     }
2211     (void)func;
2212     (void)out;
2213     compile_error(m_context, "TODO: argpipe codegen not implemented");
2214     return false;
2215 }
2216
2217 bool ast_ifthen::codegen(ast_function *func, bool lvalue, ir_value **out)
2218 {
2219     ir_value *condval;
2220     ir_value *dummy;
2221
2222     ir_block *cond;
2223     ir_block *ontrue;
2224     ir_block *onfalse;
2225     ir_block *ontrue_endblock = nullptr;
2226     ir_block *onfalse_endblock = nullptr;
2227     ir_block *merge = nullptr;
2228     int folded = 0;
2229
2230     /* We don't output any value, thus also don't care about r/lvalue */
2231     (void)out;
2232     (void)lvalue;
2233
2234     if (m_outr) {
2235         compile_error(m_context, "internal error: ast_ifthen cannot be reused, it bears no result!");
2236         return false;
2237     }
2238     m_outr = (ir_value*)1;
2239
2240     /* generate the condition */
2241     if (!m_cond->codegen(func, false, &condval))
2242         return false;
2243     /* update the block which will get the jump - because short-logic or ternaries may have changed this */
2244     cond = func->m_curblock;
2245
2246     /* try constant folding away the condition */
2247     if ((folded = fold::cond_ifthen(condval, func, this)) != -1)
2248         return folded;
2249
2250     if (m_on_true) {
2251         /* create on-true block */
2252         ontrue = ir_function_create_block(m_context, func->m_ir_func, func->makeLabel("ontrue"));
2253         if (!ontrue)
2254             return false;
2255
2256         /* enter the block */
2257         func->m_curblock = ontrue;
2258
2259         /* generate */
2260         if (!m_on_true->codegen(func, false, &dummy))
2261             return false;
2262
2263         /* we now need to work from the current endpoint */
2264         ontrue_endblock = func->m_curblock;
2265     } else
2266         ontrue = nullptr;
2267
2268     /* on-false path */
2269     if (m_on_false) {
2270         /* create on-false block */
2271         onfalse = ir_function_create_block(m_context, func->m_ir_func, func->makeLabel("onfalse"));
2272         if (!onfalse)
2273             return false;
2274
2275         /* enter the block */
2276         func->m_curblock = onfalse;
2277
2278         /* generate */
2279         if (!m_on_false->codegen(func, false, &dummy))
2280             return false;
2281
2282         /* we now need to work from the current endpoint */
2283         onfalse_endblock = func->m_curblock;
2284     } else
2285         onfalse = nullptr;
2286
2287     /* Merge block were they all merge in to */
2288     if (!ontrue || !onfalse || !ontrue_endblock->m_final || !onfalse_endblock->m_final)
2289     {
2290         merge = ir_function_create_block(m_context, func->m_ir_func, func->makeLabel("endif"));
2291         if (!merge)
2292             return false;
2293         /* add jumps ot the merge block */
2294         if (ontrue && !ontrue_endblock->m_final && !ir_block_create_jump(ontrue_endblock, m_context, merge))
2295             return false;
2296         if (onfalse && !onfalse_endblock->m_final && !ir_block_create_jump(onfalse_endblock, m_context, merge))
2297             return false;
2298
2299         /* Now enter the merge block */
2300         func->m_curblock = merge;
2301     }
2302
2303     /* we create the if here, that way all blocks are ordered :)
2304      */
2305     if (!ir_block_create_if(cond, m_context, condval,
2306                             (ontrue  ? ontrue  : merge),
2307                             (onfalse ? onfalse : merge)))
2308     {
2309         return false;
2310     }
2311
2312     return true;
2313 }
2314
2315 bool ast_ternary::codegen(ast_function *func, bool lvalue, ir_value **out)
2316 {
2317     ir_value *condval;
2318     ir_value *trueval, *falseval;
2319     ir_instr *phi;
2320
2321     ir_block *cond = func->m_curblock;
2322     ir_block *cond_out = nullptr;
2323     ir_block *ontrue, *ontrue_out = nullptr;
2324     ir_block *onfalse, *onfalse_out = nullptr;
2325     ir_block *merge;
2326     int folded = 0;
2327
2328     /* Ternary can never create an lvalue... */
2329     if (lvalue)
2330         return false;
2331
2332     /* In theory it shouldn't be possible to pass through a node twice, but
2333      * in case we add any kind of optimization pass for the AST itself, it
2334      * may still happen, thus we remember a created ir_value and simply return one
2335      * if it already exists.
2336      */
2337     if (m_outr) {
2338         *out = m_outr;
2339         return true;
2340     }
2341
2342     /* In the following, contraty to ast_ifthen, we assume both paths exist. */
2343
2344     /* generate the condition */
2345     func->m_curblock = cond;
2346     if (!m_cond->codegen(func, false, &condval))
2347         return false;
2348     cond_out = func->m_curblock;
2349
2350     /* try constant folding away the condition */
2351     if ((folded = fold::cond_ternary(condval, func, this)) != -1)
2352         return folded;
2353
2354     /* create on-true block */
2355     ontrue = ir_function_create_block(m_context, func->m_ir_func, func->makeLabel("tern_T"));
2356     if (!ontrue)
2357         return false;
2358     else
2359     {
2360         /* enter the block */
2361         func->m_curblock = ontrue;
2362
2363         /* generate */
2364         if (!m_on_true->codegen(func, false, &trueval))
2365             return false;
2366
2367         ontrue_out = func->m_curblock;
2368     }
2369
2370     /* create on-false block */
2371     onfalse = ir_function_create_block(m_context, func->m_ir_func, func->makeLabel("tern_F"));
2372     if (!onfalse)
2373         return false;
2374     else
2375     {
2376         /* enter the block */
2377         func->m_curblock = onfalse;
2378
2379         /* generate */
2380         if (!m_on_false->codegen(func, false, &falseval))
2381             return false;
2382
2383         onfalse_out = func->m_curblock;
2384     }
2385
2386     /* create merge block */
2387     merge = ir_function_create_block(m_context, func->m_ir_func, func->makeLabel("tern_out"));
2388     if (!merge)
2389         return false;
2390     /* jump to merge block */
2391     if (!ir_block_create_jump(ontrue_out, m_context, merge))
2392         return false;
2393     if (!ir_block_create_jump(onfalse_out, m_context, merge))
2394         return false;
2395
2396     /* create if instruction */
2397     if (!ir_block_create_if(cond_out, m_context, condval, ontrue, onfalse))
2398         return false;
2399
2400     /* Now enter the merge block */
2401     func->m_curblock = merge;
2402
2403     /* Here, now, we need a PHI node
2404      * but first some sanity checking...
2405      */
2406     if (trueval->m_vtype != falseval->m_vtype && trueval->m_vtype != TYPE_NIL && falseval->m_vtype != TYPE_NIL) {
2407         /* error("ternary with different types on the two sides"); */
2408         compile_error(m_context, "internal error: ternary operand types invalid");
2409         return false;
2410     }
2411
2412     /* create PHI */
2413     phi = ir_block_create_phi(merge, m_context, func->makeLabel("phi"), m_vtype);
2414     if (!phi) {
2415         compile_error(m_context, "internal error: failed to generate phi node");
2416         return false;
2417     }
2418     ir_phi_add(phi, ontrue_out,  trueval);
2419     ir_phi_add(phi, onfalse_out, falseval);
2420
2421     m_outr = ir_phi_value(phi);
2422     *out = m_outr;
2423
2424     codegen_output_type(this, *out);
2425
2426     return true;
2427 }
2428
2429 bool ast_loop::codegen(ast_function *func, bool lvalue, ir_value **out)
2430 {
2431     ir_value *dummy      = nullptr;
2432     ir_value *precond    = nullptr;
2433     ir_value *postcond   = nullptr;
2434
2435     /* Since we insert some jumps "late" so we have blocks
2436      * ordered "nicely", we need to keep track of the actual end-blocks
2437      * of expressions to add the jumps to.
2438      */
2439     ir_block *bbody      = nullptr, *end_bbody      = nullptr;
2440     ir_block *bprecond   = nullptr, *end_bprecond   = nullptr;
2441     ir_block *bpostcond  = nullptr, *end_bpostcond  = nullptr;
2442     ir_block *bincrement = nullptr, *end_bincrement = nullptr;
2443     ir_block *bout       = nullptr, *bin            = nullptr;
2444
2445     /* let's at least move the outgoing block to the end */
2446     size_t    bout_id;
2447
2448     /* 'break' and 'continue' need to be able to find the right blocks */
2449     ir_block *bcontinue     = nullptr;
2450     ir_block *bbreak        = nullptr;
2451
2452     ir_block *tmpblock      = nullptr;
2453
2454     (void)lvalue;
2455     (void)out;
2456
2457     if (m_outr) {
2458         compile_error(m_context, "internal error: ast_loop cannot be reused, it bears no result!");
2459         return false;
2460     }
2461     m_outr = (ir_value*)1;
2462
2463     /* NOTE:
2464      * Should we ever need some kind of block ordering, better make this function
2465      * move blocks around than write a block ordering algorithm later... after all
2466      * the ast and ir should work together, not against each other.
2467      */
2468
2469     /* initexpr doesn't get its own block, it's pointless, it could create more blocks
2470      * anyway if for example it contains a ternary.
2471      */
2472     if (m_initexpr)
2473     {
2474         if (!m_initexpr->codegen(func, false, &dummy))
2475             return false;
2476     }
2477
2478     /* Store the block from which we enter this chaos */
2479     bin = func->m_curblock;
2480
2481     /* The pre-loop condition needs its own block since we
2482      * need to be able to jump to the start of that expression.
2483      */
2484     if (m_precond)
2485     {
2486         bprecond = ir_function_create_block(m_context, func->m_ir_func, func->makeLabel("pre_loop_cond"));
2487         if (!bprecond)
2488             return false;
2489
2490         /* the pre-loop-condition the least important place to 'continue' at */
2491         bcontinue = bprecond;
2492
2493         /* enter */
2494         func->m_curblock = bprecond;
2495
2496         /* generate */
2497         if (!m_precond->codegen(func, false, &precond))
2498             return false;
2499
2500         end_bprecond = func->m_curblock;
2501     } else {
2502         bprecond = end_bprecond = nullptr;
2503     }
2504
2505     /* Now the next blocks won't be ordered nicely, but we need to
2506      * generate them this early for 'break' and 'continue'.
2507      */
2508     if (m_increment) {
2509         bincrement = ir_function_create_block(m_context, func->m_ir_func, func->makeLabel("loop_increment"));
2510         if (!bincrement)
2511             return false;
2512         bcontinue = bincrement; /* increment comes before the pre-loop-condition */
2513     } else {
2514         bincrement = end_bincrement = nullptr;
2515     }
2516
2517     if (m_postcond) {
2518         bpostcond = ir_function_create_block(m_context, func->m_ir_func, func->makeLabel("post_loop_cond"));
2519         if (!bpostcond)
2520             return false;
2521         bcontinue = bpostcond; /* postcond comes before the increment */
2522     } else {
2523         bpostcond = end_bpostcond = nullptr;
2524     }
2525
2526     bout_id = func->m_ir_func->m_blocks.size();
2527     bout = ir_function_create_block(m_context, func->m_ir_func, func->makeLabel("after_loop"));
2528     if (!bout)
2529         return false;
2530     bbreak = bout;
2531
2532     /* The loop body... */
2533     /* if (m_body) */
2534     {
2535         bbody = ir_function_create_block(m_context, func->m_ir_func, func->makeLabel("loop_body"));
2536         if (!bbody)
2537             return false;
2538
2539         /* enter */
2540         func->m_curblock = bbody;
2541
2542         func->m_breakblocks.push_back(bbreak);
2543         if (bcontinue)
2544             func->m_continueblocks.push_back(bcontinue);
2545         else
2546             func->m_continueblocks.push_back(bbody);
2547
2548         /* generate */
2549         if (m_body) {
2550             if (!m_body->codegen(func, false, &dummy))
2551                 return false;
2552         }
2553
2554         end_bbody = func->m_curblock;
2555         func->m_breakblocks.pop_back();
2556         func->m_continueblocks.pop_back();
2557     }
2558
2559     /* post-loop-condition */
2560     if (m_postcond)
2561     {
2562         /* enter */
2563         func->m_curblock = bpostcond;
2564
2565         /* generate */
2566         if (!m_postcond->codegen(func, false, &postcond))
2567             return false;
2568
2569         end_bpostcond = func->m_curblock;
2570     }
2571
2572     /* The incrementor */
2573     if (m_increment)
2574     {
2575         /* enter */
2576         func->m_curblock = bincrement;
2577
2578         /* generate */
2579         if (!m_increment->codegen(func, false, &dummy))
2580             return false;
2581
2582         end_bincrement = func->m_curblock;
2583     }
2584
2585     /* In any case now, we continue from the outgoing block */
2586     func->m_curblock = bout;
2587
2588     /* Now all blocks are in place */
2589     /* From 'bin' we jump to whatever comes first */
2590     if      (bprecond)   tmpblock = bprecond;
2591     else                 tmpblock = bbody;    /* can never be null */
2592
2593     /* DEAD CODE
2594     else if (bpostcond)  tmpblock = bpostcond;
2595     else                 tmpblock = bout;
2596     */
2597
2598     if (!ir_block_create_jump(bin, m_context, tmpblock))
2599         return false;
2600
2601     /* From precond */
2602     if (bprecond)
2603     {
2604         ir_block *ontrue, *onfalse;
2605         ontrue = bbody; /* can never be null */
2606
2607         /* all of this is dead code
2608         else if (bincrement) ontrue = bincrement;
2609         else                 ontrue = bpostcond;
2610         */
2611
2612         onfalse = bout;
2613         if (m_pre_not) {
2614             tmpblock = ontrue;
2615             ontrue   = onfalse;
2616             onfalse  = tmpblock;
2617         }
2618         if (!ir_block_create_if(end_bprecond, m_context, precond, ontrue, onfalse))
2619             return false;
2620     }
2621
2622     /* from body */
2623     if (bbody)
2624     {
2625         if      (bincrement) tmpblock = bincrement;
2626         else if (bpostcond)  tmpblock = bpostcond;
2627         else if (bprecond)   tmpblock = bprecond;
2628         else                 tmpblock = bbody;
2629         if (!end_bbody->m_final && !ir_block_create_jump(end_bbody, m_context, tmpblock))
2630             return false;
2631     }
2632
2633     /* from increment */
2634     if (bincrement)
2635     {
2636         if      (bpostcond)  tmpblock = bpostcond;
2637         else if (bprecond)   tmpblock = bprecond;
2638         else if (bbody)      tmpblock = bbody;
2639         else                 tmpblock = bout;
2640         if (!ir_block_create_jump(end_bincrement, m_context, tmpblock))
2641             return false;
2642     }
2643
2644     /* from postcond */
2645     if (bpostcond)
2646     {
2647         ir_block *ontrue, *onfalse;
2648         if      (bprecond)   ontrue = bprecond;
2649         else                 ontrue = bbody; /* can never be null */
2650
2651         /* all of this is dead code
2652         else if (bincrement) ontrue = bincrement;
2653         else                 ontrue = bpostcond;
2654         */
2655
2656         onfalse = bout;
2657         if (m_post_not) {
2658             tmpblock = ontrue;
2659             ontrue   = onfalse;
2660             onfalse  = tmpblock;
2661         }
2662         if (!ir_block_create_if(end_bpostcond, m_context, postcond, ontrue, onfalse))
2663             return false;
2664     }
2665
2666     /* Move 'bout' to the end */
2667     algo::shiftback(func->m_ir_func->m_blocks.begin() + bout_id,
2668                     func->m_ir_func->m_blocks.end());
2669     // FIXME::DELME::
2670     //func->m_ir_func->m_blocks[bout_id].release(); // it's a vector<std::unique_ptr<>>
2671     //func->m_ir_func->m_blocks.erase(func->m_ir_func->m_blocks.begin() + bout_id);
2672     //func->m_ir_func->m_blocks.emplace_back(bout);
2673
2674     return true;
2675 }
2676
2677 bool ast_breakcont::codegen(ast_function *func, bool lvalue, ir_value **out)
2678 {
2679     ir_block *target;
2680
2681     *out = nullptr;
2682
2683     if (lvalue) {
2684         compile_error(m_context, "break/continue expression is not an l-value");
2685         return false;
2686     }
2687
2688     if (m_outr) {
2689         compile_error(m_context, "internal error: ast_breakcont cannot be reused!");
2690         return false;
2691     }
2692     m_outr = (ir_value*)1;
2693
2694     if (m_is_continue)
2695         target = func->m_continueblocks[func->m_continueblocks.size()-1-m_levels];
2696     else
2697         target = func->m_breakblocks[func->m_breakblocks.size()-1-m_levels];
2698
2699     if (!target) {
2700         compile_error(m_context, "%s is lacking a target block", (m_is_continue ? "continue" : "break"));
2701         return false;
2702     }
2703
2704     if (!ir_block_create_jump(func->m_curblock, m_context, target))
2705         return false;
2706     return true;
2707 }
2708
2709 bool ast_switch::codegen(ast_function *func, bool lvalue, ir_value **out)
2710 {
2711     ast_switch_case *def_case     = nullptr;
2712     ir_block        *def_bfall    = nullptr;
2713     ir_block        *def_bfall_to = nullptr;
2714     bool set_def_bfall_to = false;
2715
2716     ir_value *dummy     = nullptr;
2717     ir_value *irop      = nullptr;
2718     ir_block *bout      = nullptr;
2719     ir_block *bfall     = nullptr;
2720     size_t    bout_id;
2721
2722     char      typestr[1024];
2723     uint16_t  cmpinstr;
2724
2725     if (lvalue) {
2726         compile_error(m_context, "switch expression is not an l-value");
2727         return false;
2728     }
2729
2730     if (m_outr) {
2731         compile_error(m_context, "internal error: ast_switch cannot be reused!");
2732         return false;
2733     }
2734     m_outr = (ir_value*)1;
2735
2736     (void)lvalue;
2737     (void)out;
2738
2739     if (!m_operand->codegen(func, false, &irop))
2740         return false;
2741
2742     if (m_cases.empty())
2743         return true;
2744
2745     cmpinstr = type_eq_instr[irop->m_vtype];
2746     if (cmpinstr >= VINSTR_END) {
2747         ast_type_to_string(m_operand, typestr, sizeof(typestr));
2748         compile_error(m_context, "invalid type to perform a switch on: %s", typestr);
2749         return false;
2750     }
2751
2752     bout_id = func->m_ir_func->m_blocks.size();
2753     bout = ir_function_create_block(m_context, func->m_ir_func, func->makeLabel("after_switch"));
2754     if (!bout)
2755         return false;
2756
2757     /* setup the break block */
2758     func->m_breakblocks.push_back(bout);
2759
2760     /* Now create all cases */
2761     for (auto &it : m_cases) {
2762         ir_value *cond, *val;
2763         ir_block *bcase, *bnot;
2764         size_t bnot_id;
2765
2766         ast_switch_case *swcase = &it;
2767
2768         if (swcase->m_value) {
2769             /* A regular case */
2770             /* generate the condition operand */
2771             if (!swcase->m_value->codegen(func, false, &val))
2772                 return false;
2773             /* generate the condition */
2774             cond = ir_block_create_binop(func->m_curblock, m_context, func->makeLabel("switch_eq"), cmpinstr, irop, val);
2775             if (!cond)
2776                 return false;
2777
2778             bcase = ir_function_create_block(m_context, func->m_ir_func, func->makeLabel("case"));
2779             bnot_id = func->m_ir_func->m_blocks.size();
2780             bnot = ir_function_create_block(m_context, func->m_ir_func, func->makeLabel("not_case"));
2781             if (!bcase || !bnot)
2782                 return false;
2783             if (set_def_bfall_to) {
2784                 set_def_bfall_to = false;
2785                 def_bfall_to = bcase;
2786             }
2787             if (!ir_block_create_if(func->m_curblock, m_context, cond, bcase, bnot))
2788                 return false;
2789
2790             /* Make the previous case-end fall through */
2791             if (bfall && !bfall->m_final) {
2792                 if (!ir_block_create_jump(bfall, m_context, bcase))
2793                     return false;
2794             }
2795
2796             /* enter the case */
2797             func->m_curblock = bcase;
2798             if (!swcase->m_code->codegen(func, false, &dummy))
2799                 return false;
2800
2801             /* remember this block to fall through from */
2802             bfall = func->m_curblock;
2803
2804             /* enter the else and move it down */
2805             func->m_curblock = bnot;
2806             algo::shiftback(func->m_ir_func->m_blocks.begin() + bnot_id,
2807                             func->m_ir_func->m_blocks.end());
2808             // FIXME::DELME::
2809             //func->m_ir_func->m_blocks[bnot_id].release();
2810             //func->m_ir_func->m_blocks.erase(func->m_ir_func->m_blocks.begin() + bnot_id);
2811             //func->m_ir_func->m_blocks.emplace_back(bnot);
2812         } else {
2813             /* The default case */
2814             /* Remember where to fall through from: */
2815             def_bfall = bfall;
2816             bfall     = nullptr;
2817             /* remember which case it was */
2818             def_case  = swcase;
2819             /* And the next case will be remembered */
2820             set_def_bfall_to = true;
2821         }
2822     }
2823
2824     /* Jump from the last bnot to bout */
2825     if (bfall && !bfall->m_final && !ir_block_create_jump(bfall, m_context, bout)) {
2826         /*
2827         astwarning(bfall->m_context, WARN_???, "missing break after last case");
2828         */
2829         return false;
2830     }
2831
2832     /* If there was a default case, put it down here */
2833     if (def_case) {
2834         ir_block *bcase;
2835
2836         /* No need to create an extra block */
2837         bcase = func->m_curblock;
2838
2839         /* Insert the fallthrough jump */
2840         if (def_bfall && !def_bfall->m_final) {
2841             if (!ir_block_create_jump(def_bfall, m_context, bcase))
2842                 return false;
2843         }
2844
2845         /* Now generate the default code */
2846         if (!def_case->m_code->codegen(func, false, &dummy))
2847             return false;
2848
2849         /* see if we need to fall through */
2850         if (def_bfall_to && !func->m_curblock->m_final)
2851         {
2852             if (!ir_block_create_jump(func->m_curblock, m_context, def_bfall_to))
2853                 return false;
2854         }
2855     }
2856
2857     /* Jump from the last bnot to bout */
2858     if (!func->m_curblock->m_final && !ir_block_create_jump(func->m_curblock, m_context, bout))
2859         return false;
2860     /* enter the outgoing block */
2861     func->m_curblock = bout;
2862
2863     /* restore the break block */
2864     func->m_breakblocks.pop_back();
2865
2866     /* Move 'bout' to the end, it's nicer */
2867     algo::shiftback(func->m_ir_func->m_blocks.begin() + bout_id,
2868                     func->m_ir_func->m_blocks.end());
2869     // FIXME::DELME::
2870     //func->m_ir_func->m_blocks[bout_id].release();
2871     //func->m_ir_func->m_blocks.erase(func->m_ir_func->m_blocks.begin() + bout_id);
2872     //func->m_ir_func->m_blocks.emplace_back(bout);
2873
2874     return true;
2875 }
2876
2877 bool ast_label::codegen(ast_function *func, bool lvalue, ir_value **out)
2878 {
2879     ir_value *dummy;
2880
2881     if (m_undefined) {
2882         compile_error(m_context, "internal error: ast_label never defined");
2883         return false;
2884     }
2885
2886     *out = nullptr;
2887     if (lvalue) {
2888         compile_error(m_context, "internal error: ast_label cannot be an lvalue");
2889         return false;
2890     }
2891
2892     /* simply create a new block and jump to it */
2893     m_irblock = ir_function_create_block(m_context, func->m_ir_func, m_name.c_str());
2894     if (!m_irblock) {
2895         compile_error(m_context, "failed to allocate label block `%s`", m_name);
2896         return false;
2897     }
2898     if (!func->m_curblock->m_final) {
2899         if (!ir_block_create_jump(func->m_curblock, m_context, m_irblock))
2900             return false;
2901     }
2902
2903     /* enter the new block */
2904     func->m_curblock = m_irblock;
2905
2906     /* Generate all the leftover gotos */
2907     for (auto &it : m_gotos) {
2908         if (!it->codegen(func, false, &dummy))
2909             return false;
2910     }
2911
2912     return true;
2913 }
2914
2915 bool ast_goto::codegen(ast_function *func, bool lvalue, ir_value **out)
2916 {
2917     *out = nullptr;
2918     if (lvalue) {
2919         compile_error(m_context, "internal error: ast_goto cannot be an lvalue");
2920         return false;
2921     }
2922
2923     if (m_target->m_irblock) {
2924         if (m_irblock_from) {
2925             /* we already tried once, this is the callback */
2926             m_irblock_from->m_final = false;
2927             if (!ir_block_create_goto(m_irblock_from, m_context, m_target->m_irblock)) {
2928                 compile_error(m_context, "failed to generate goto to `%s`", m_name);
2929                 return false;
2930             }
2931         }
2932         else
2933         {
2934             if (!ir_block_create_goto(func->m_curblock, m_context, m_target->m_irblock)) {
2935                 compile_error(m_context, "failed to generate goto to `%s`", m_name);
2936                 return false;
2937             }
2938         }
2939     }
2940     else
2941     {
2942         /* the target has not yet been created...
2943          * close this block in a sneaky way:
2944          */
2945         func->m_curblock->m_final = true;
2946         m_irblock_from = func->m_curblock;
2947         m_target->registerGoto(this);
2948     }
2949
2950     return true;
2951 }
2952
2953 bool ast_state::codegen(ast_function *func, bool lvalue, ir_value **out)
2954 {
2955     ir_value *frameval, *thinkval;
2956
2957     if (lvalue) {
2958         compile_error(m_context, "not an l-value (state operation)");
2959         return false;
2960     }
2961     if (m_outr) {
2962         compile_error(m_context, "internal error: ast_state cannot be reused!");
2963         return false;
2964     }
2965     *out = nullptr;
2966
2967     if (!m_framenum->codegen(func, false, &frameval))
2968         return false;
2969     if (!frameval)
2970         return false;
2971
2972     if (!m_nextthink->codegen(func, false, &thinkval))
2973         return false;
2974     if (!frameval)
2975         return false;
2976
2977     if (!ir_block_create_state_op(func->m_curblock, m_context, frameval, thinkval)) {
2978         compile_error(m_context, "failed to create STATE instruction");
2979         return false;
2980     }
2981
2982     m_outr = (ir_value*)1;
2983     return true;
2984 }
2985
2986 bool ast_call::codegen(ast_function *func, bool lvalue, ir_value **out)
2987 {
2988     std::vector<ir_value*> params;
2989     ir_instr *callinstr;
2990
2991     ir_value *funval = nullptr;
2992
2993     /* return values are never lvalues */
2994     if (lvalue) {
2995         compile_error(m_context, "not an l-value (function call)");
2996         return false;
2997     }
2998
2999     if (m_outr) {
3000         *out = m_outr;
3001         return true;
3002     }
3003
3004     if (!m_func->codegen(func, false, &funval))
3005         return false;
3006     if (!funval)
3007         return false;
3008
3009     /* parameters */
3010     for (auto &it : m_params) {
3011         ir_value *param;
3012         if (!it->codegen(func, false, &param))
3013             return false;
3014         if (!param)
3015             return false;
3016         params.push_back(param);
3017     }
3018
3019     /* varargs counter */
3020     if (m_va_count) {
3021         ir_value   *va_count;
3022         ir_builder *builder = func->m_curblock->m_owner->m_owner;
3023         if (!m_va_count->codegen(func, false, &va_count))
3024             return false;
3025         if (!ir_block_create_store_op(func->m_curblock, m_context, INSTR_STORE_F,
3026                                       ir_builder_get_va_count(builder), va_count))
3027         {
3028             return false;
3029         }
3030     }
3031
3032     callinstr = ir_block_create_call(func->m_curblock, m_context,
3033                                      func->makeLabel("call"),
3034                                      funval, !!(m_func->m_flags & AST_FLAG_NORETURN));
3035     if (!callinstr)
3036         return false;
3037
3038     for (auto &it : params)
3039         ir_call_param(callinstr, it);
3040
3041     *out = ir_call_value(callinstr);
3042     m_outr = *out;
3043
3044     codegen_output_type(this, *out);
3045
3046     return true;
3047 }