]> git.xonotic.org Git - xonotic/gmqcc.git/blobdiff - ast.c
-Oglobal-temps
[xonotic/gmqcc.git] / ast.c
diff --git a/ast.c b/ast.c
index 5cb8651d6d5b1e9428c5e3824ee26ce631e277ce..b6a8a786c7d76b55a1fb7af884e82958848255af 100644 (file)
--- a/ast.c
+++ b/ast.c
@@ -476,7 +476,7 @@ ast_unary* ast_unary_new(lex_ctx ctx, int op,
 
 void ast_unary_delete(ast_unary *self)
 {
-    ast_unref(self->operand);
+    if (self->operand) ast_unref(self->operand);
     ast_expression_delete((ast_expression*)self);
     mem_d(self);
 }
@@ -596,6 +596,14 @@ void ast_member_delete(ast_member *self)
     mem_d(self);
 }
 
+bool ast_member_set_name(ast_member *self, const char *name)
+{
+    if (self->name)
+        mem_d((void*)self->name);
+    self->name = util_strdup(name);
+    return !!self->name;
+}
+
 ast_array_index* ast_array_index_new(lex_ctx ctx, ast_expression *array, ast_expression *index)
 {
     ast_expression *outtype;
@@ -709,8 +717,8 @@ void ast_ternary_delete(ast_ternary *self)
 
 ast_loop* ast_loop_new(lex_ctx ctx,
                        ast_expression *initexpr,
-                       ast_expression *precond,
-                       ast_expression *postcond,
+                       ast_expression *precond, bool pre_not,
+                       ast_expression *postcond, bool post_not,
                        ast_expression *increment,
                        ast_expression *body)
 {
@@ -723,6 +731,9 @@ ast_loop* ast_loop_new(lex_ctx ctx,
     self->increment = increment;
     self->body      = body;
 
+    self->pre_not   = pre_not;
+    self->post_not  = post_not;
+
     if (initexpr)
         ast_propagate_effects(self, initexpr);
     if (precond)
@@ -1058,10 +1069,10 @@ const char* ast_function_label(ast_function *self, const char *prefix)
     from = self->labelbuf + sizeof(self->labelbuf)-1;
     *from-- = 0;
     do {
-        unsigned int digit = id % 10;
-        *from = digit + '0';
+        *from-- = (id%10) + '0';
         id /= 10;
     } while (id);
+    ++from;
     memcpy(from - len, prefix, len);
     return from - len;
 }
@@ -1082,7 +1093,6 @@ void _ast_codegen_output_type(ast_expression_common *self, ir_value *out)
 }
 
 #define codegen_output_type(a,o) (_ast_codegen_output_type(&((a)->expression),(o)))
-#define codegen_output_type_expr(a,o) (_ast_codegen_output_type(a,(o)))
 
 bool ast_value_codegen(ast_value *self, ast_function *func, bool lvalue, ir_value **out)
 {
@@ -1096,9 +1106,9 @@ bool ast_value_codegen(ast_value *self, ast_function *func, bool lvalue, ir_valu
      * on all the globals.
      */
     if (!self->ir_v) {
-        char typename[1024];
-        ast_type_to_string((ast_expression*)self, typename, sizeof(typename));
-        compile_error(ast_ctx(self), "ast_value used before generated %s %s", typename, self->name);
+        char tname[1024]; /* typename is reserved in C++ */
+        ast_type_to_string((ast_expression*)self, tname, sizeof(tname));
+        compile_error(ast_ctx(self), "ast_value used before generated %s %s", tname, self->name);
         return false;
     }
     *out = self->ir_v;
@@ -1159,6 +1169,7 @@ bool ast_global_codegen(ast_value *self, ir_builder *ir, bool isfield)
             }
             v->context = ast_ctx(self);
             v->unique_life = true;
+            v->locked      = true;
             array->ir_v = self->ir_v = v;
 
             namelen = strlen(self->name);
@@ -1177,6 +1188,7 @@ bool ast_global_codegen(ast_value *self, ir_builder *ir, bool isfield)
                 }
                 array->ir_values[ai]->context = ast_ctx(self);
                 array->ir_values[ai]->unique_life = true;
+                array->ir_values[ai]->locked      = true;
             }
             mem_d(name);
         }
@@ -1210,6 +1222,7 @@ bool ast_global_codegen(ast_value *self, ir_builder *ir, bool isfield)
         }
         v->context = ast_ctx(self);
         v->unique_life = true;
+        v->locked      = true;
 
         namelen = strlen(self->name);
         name    = (char*)mem_a(namelen + 16);
@@ -1227,6 +1240,7 @@ bool ast_global_codegen(ast_value *self, ir_builder *ir, bool isfield)
             }
             self->ir_values[ai]->context = ast_ctx(self);
             self->ir_values[ai]->unique_life = true;
+            self->ir_values[ai]->locked      = true;
         }
         mem_d(name);
     }
@@ -1315,6 +1329,8 @@ bool ast_local_codegen(ast_value *self, ir_function *func, bool param)
         ast_expression_common *elemtype = &self->expression.next->expression;
         int vtype = elemtype->vtype;
 
+        func->flags |= IR_FLAG_HAS_ARRAYS;
+
         if (param) {
             compile_error(ast_ctx(self), "array-parameters are not supported");
             return false;
@@ -1338,6 +1354,7 @@ bool ast_local_codegen(ast_value *self, ir_function *func, bool param)
         }
         v->context = ast_ctx(self);
         v->unique_life = true;
+        v->locked      = true;
 
         namelen = strlen(self->name);
         name    = (char*)mem_a(namelen + 16);
@@ -1353,6 +1370,7 @@ bool ast_local_codegen(ast_value *self, ir_function *func, bool param)
             }
             self->ir_values[ai]->context = ast_ctx(self);
             self->ir_values[ai]->unique_life = true;
+            self->ir_values[ai]->locked      = true;
         }
     }
     else
@@ -1502,7 +1520,7 @@ bool ast_function_codegen(ast_function *self, ir_builder *ir)
     }
 
     /* TODO: check return types */
-    if (!self->curblock->is_return)
+    if (!self->curblock->final)
     {
         if (!self->vtype->expression.next ||
             self->vtype->expression.next->expression.vtype == TYPE_VOID)
@@ -1570,10 +1588,9 @@ bool ast_block_codegen(ast_block *self, ast_function *func, bool lvalue, ir_valu
     {
         ast_expression_codegen *gen;
         if (func->curblock->final && !ast_istype(self->exprs[i], ast_label)) {
-            if (OPTS_FLAG(ALLOW_UNREACHABLE_CODE))
-                continue;
-            compile_error(ast_ctx(self->exprs[i]), "unreachable statement");
-            return false;
+            if (compile_warning(ast_ctx(self->exprs[i]), WARN_UNREACHABLE_CODE, "unreachable statement"))
+                return false;
+            continue;
         }
         gen = self->exprs[i]->expression.codegen;
         if (!(*gen)(self->exprs[i], func, false, out))
@@ -1698,7 +1715,7 @@ bool ast_binary_codegen(ast_binary *self, ast_function *func, bool lvalue, ir_va
         return true;
     }
 
-    if (OPTS_FLAG(SHORT_LOGIC) &&
+    if ((OPTS_FLAG(SHORT_LOGIC) || OPTS_FLAG(PERL_LOGIC)) &&
         (self->op == INSTR_AND || self->op == INSTR_OR))
     {
         /* short circuit evaluation */
@@ -1706,64 +1723,42 @@ bool ast_binary_codegen(ast_binary *self, ast_function *func, bool lvalue, ir_va
         ir_block *from_left, *from_right;
         ir_instr *phi;
         size_t    merge_id;
-        uint16_t  notop;
-
-        /* Note about casting to true boolean values:
-         * We use a single NOT for sub expressions, and an
-         * overall NOT at the end, and for that purpose swap
-         * all the jump conditions in order for the NOT to get
-         * doubled.
-         * ie: (a && b) usually becomes (!!a ? !!b : !!a)
-         * but we translate this to (!(!a ? !a : !b))
-         */
 
+        /* prepare end-block */
         merge_id = vec_size(func->ir_func->blocks);
-        merge = ir_function_create_block(ast_ctx(self), func->ir_func, ast_function_label(func, "sce_merge"));
+        merge    = ir_function_create_block(ast_ctx(self), func->ir_func, ast_function_label(func, "sce_merge"));
 
+        /* generate the left expression */
         cgen = self->left->expression.codegen;
         if (!(*cgen)((ast_expression*)(self->left), func, false, &left))
             return false;
-        if (!OPTS_FLAG(PERL_LOGIC)) {
-            notop = type_not_instr[left->vtype];
-            if (notop == AINSTR_END) {
-                compile_error(ast_ctx(self), "don't know how to cast to bool...");
-                return false;
-            }
-            left = ir_block_create_unary(func->curblock, ast_ctx(self),
-                                         ast_function_label(func, "sce_not"),
-                                         notop,
-                                         left);
-        }
+        /* remember the block */
         from_left = func->curblock;
 
+        /* create a new block for the right expression */
         other = ir_function_create_block(ast_ctx(self), func->ir_func, ast_function_label(func, "sce_other"));
-        if ( !(self->op == INSTR_OR) != !OPTS_FLAG(PERL_LOGIC) ) {
+        if (self->op == INSTR_AND) {
+            /* on AND: left==true -> other */
             if (!ir_block_create_if(func->curblock, ast_ctx(self), left, other, merge))
                 return false;
         } else {
+            /* on OR: left==false -> other */
             if (!ir_block_create_if(func->curblock, ast_ctx(self), left, merge, other))
                 return false;
         }
         /* use the likely flag */
         vec_last(func->curblock->instr)->likely = true;
 
+        /* enter the right-expression's block */
         func->curblock = other;
+        /* generate */
         cgen = self->right->expression.codegen;
         if (!(*cgen)((ast_expression*)(self->right), func, false, &right))
             return false;
-        if (!OPTS_FLAG(PERL_LOGIC)) {
-            notop = type_not_instr[right->vtype];
-            if (notop == AINSTR_END) {
-                compile_error(ast_ctx(self), "don't know how to cast to bool...");
-                return false;
-            }
-            right = ir_block_create_unary(func->curblock, ast_ctx(self),
-                                          ast_function_label(func, "sce_not"),
-                                          notop,
-                                          right);
-        }
+        /* remember block */
         from_right = func->curblock;
 
+        /* jump to the merge block */
         if (!ir_block_create_jump(func->curblock, ast_ctx(self), merge))
             return false;
 
@@ -1771,23 +1766,50 @@ bool ast_binary_codegen(ast_binary *self, ast_function *func, bool lvalue, ir_va
         vec_push(func->ir_func->blocks, merge);
 
         func->curblock = merge;
-        phi = ir_block_create_phi(func->curblock, ast_ctx(self), ast_function_label(func, "sce_value"), TYPE_FLOAT);
+        phi = ir_block_create_phi(func->curblock, ast_ctx(self),
+                                  ast_function_label(func, "sce_value"),
+                                  self->expression.vtype);
         ir_phi_add(phi, from_left, left);
         ir_phi_add(phi, from_right, right);
         *out = ir_phi_value(phi);
+        if (!*out)
+            return false;
+
         if (!OPTS_FLAG(PERL_LOGIC)) {
-            notop = type_not_instr[(*out)->vtype];
-            if (notop == AINSTR_END) {
-                compile_error(ast_ctx(self), "don't know how to cast to bool...");
-                return false;
+            /* cast-to-bool */
+            if (OPTS_FLAG(CORRECT_LOGIC) && (*out)->vtype == TYPE_VECTOR) {
+                *out = ir_block_create_unary(func->curblock, ast_ctx(self),
+                                             ast_function_label(func, "sce_bool_v"),
+                                             INSTR_NOT_V, *out);
+                if (!*out)
+                    return false;
+                *out = ir_block_create_unary(func->curblock, ast_ctx(self),
+                                             ast_function_label(func, "sce_bool"),
+                                             INSTR_NOT_F, *out);
+                if (!*out)
+                    return false;
+            }
+            else if (OPTS_FLAG(FALSE_EMPTY_STRINGS) && (*out)->vtype == TYPE_STRING) {
+                *out = ir_block_create_unary(func->curblock, ast_ctx(self),
+                                             ast_function_label(func, "sce_bool_s"),
+                                             INSTR_NOT_S, *out);
+                if (!*out)
+                    return false;
+                *out = ir_block_create_unary(func->curblock, ast_ctx(self),
+                                             ast_function_label(func, "sce_bool"),
+                                             INSTR_NOT_F, *out);
+                if (!*out)
+                    return false;
+            }
+            else {
+                *out = ir_block_create_binop(func->curblock, ast_ctx(self),
+                                             ast_function_label(func, "sce_bool"),
+                                             INSTR_AND, *out, *out);
+                if (!*out)
+                    return false;
             }
-            *out = ir_block_create_unary(func->curblock, ast_ctx(self),
-                                         ast_function_label(func, "sce_final_not"),
-                                         notop,
-                                         *out);
         }
-        if (!*out)
-            return false;
+
         self->expression.outr = *out;
         return true;
     }
@@ -2547,6 +2569,11 @@ bool ast_loop_codegen(ast_loop *self, ast_function *func, bool lvalue, ir_value
         else if (bpostcond)  ontrue = bpostcond;
         else                 ontrue = bprecond;
         onfalse = bout;
+        if (self->pre_not) {
+            tmpblock = ontrue;
+            ontrue   = onfalse;
+            onfalse  = tmpblock;
+        }
         if (!ir_block_create_if(end_bprecond, ast_ctx(self), precond, ontrue, onfalse))
             return false;
     }
@@ -2582,6 +2609,11 @@ bool ast_loop_codegen(ast_loop *self, ast_function *func, bool lvalue, ir_value
         else if (bincrement) ontrue = bincrement;
         else                 ontrue = bpostcond;
         onfalse = bout;
+        if (self->post_not) {
+            tmpblock = ontrue;
+            ontrue   = onfalse;
+            onfalse  = tmpblock;
+        }
         if (!ir_block_create_if(end_bpostcond, ast_ctx(self), postcond, ontrue, onfalse))
             return false;
     }
@@ -2840,14 +2872,14 @@ bool ast_goto_codegen(ast_goto *self, ast_function *func, bool lvalue, ir_value
         if (self->irblock_from) {
             /* we already tried once, this is the callback */
             self->irblock_from->final = false;
-            if (!ir_block_create_jump(self->irblock_from, ast_ctx(self), self->target->irblock)) {
+            if (!ir_block_create_goto(self->irblock_from, ast_ctx(self), self->target->irblock)) {
                 compile_error(ast_ctx(self), "failed to generate goto to `%s`", self->name);
                 return false;
             }
         }
         else
         {
-            if (!ir_block_create_jump(func->curblock, ast_ctx(self), self->target->irblock)) {
+            if (!ir_block_create_goto(func->curblock, ast_ctx(self), self->target->irblock)) {
                 compile_error(ast_ctx(self), "failed to generate goto to `%s`", self->name);
                 return false;
             }