added -fdefault-eraseable which is the same as adding [[eraseable]] to all definitions
[xonotic/gmqcc.git] / ast.cpp
diff --git a/ast.cpp b/ast.cpp
index 58ed6603b881be4b3c635eac09c31ab3daa1d980..7b444f8a402dfdf18efaab0ae3d171c1174972ae 100644 (file)
--- a/ast.cpp
+++ b/ast.cpp
@@ -24,9 +24,10 @@ ast_node::~ast_node()
 }
 
 /* weight and side effects */
-void ast_node::propagateSideEffects(ast_node *other) const
+void ast_node::propagateSideEffects(const ast_node *other)
 {
-    other->m_side_effects = m_side_effects;
+    if (other->m_side_effects)
+        m_side_effects = true;
 }
 
 /* General expression initialization */
@@ -36,6 +37,8 @@ ast_expression::ast_expression(lex_ctx_t ctx, int nodetype, qc_type type)
 {
     if (OPTS_OPTION_BOOL(OPTION_COVERAGE))
         m_flags |= AST_FLAG_BLOCK_COVERAGE;
+    if (OPTS_FLAG(DEFAULT_ERASEABLE))
+        m_flags |= AST_FLAG_ERASEABLE;
 }
 ast_expression::ast_expression(lex_ctx_t ctx, int nodetype)
     : ast_expression(ctx, nodetype, TYPE_VOID)
@@ -364,16 +367,20 @@ ast_binstore::~ast_binstore()
 
 ast_unary* ast_unary::make(lex_ctx_t ctx, int op, ast_expression *expr)
 {
-    if (ast_istype(expr, ast_unary) && OPTS_OPTIMIZATION(OPTIM_PEEPHOLE)) {
-        ast_unary *prev = (ast_unary*)((ast_unary*)expr)->m_operand;
-
-        /* Handle for double negation */
-        if (((ast_unary*)expr)->m_op == op)
-            prev = (ast_unary*)((ast_unary*)expr)->m_operand;
-
-        if (ast_istype(prev, ast_unary)) {
-            ++opts_optimizationcount[OPTIM_PEEPHOLE];
-            return prev;
+    // handle double negation, double bitwise or logical not
+    if (op == opid2('!','P') ||
+        op == opid2('~','P') ||
+        op == opid2('-','P'))
+    {
+        if (ast_istype(expr, ast_unary) && OPTS_OPTIMIZATION(OPTIM_PEEPHOLE)) {
+            ast_unary *unary = reinterpret_cast<ast_unary*>(expr);
+            if (unary->m_op == op) {
+                auto out = reinterpret_cast<ast_unary*>(unary->m_operand);
+                unary->m_operand = nullptr;
+                delete unary;
+                ++opts_optimizationcount[OPTIM_PEEPHOLE];
+                return out;
+            }
         }
     }
 
@@ -1036,15 +1043,15 @@ bool ast_value::setGlobalArray()
     for (i = 0; i != count; ++i) {
         switch (m_next->m_vtype) {
             case TYPE_FLOAT:
-                if (!ir_value_set_float(m_ir_values[i], m_initlist[i].vfloat))
+                if (!m_ir_values[i]->setFloat(m_initlist[i].vfloat))
                     return false;
                 break;
             case TYPE_VECTOR:
-                if (!ir_value_set_vector(m_ir_values[i], m_initlist[i].vvec))
+                if (!m_ir_values[i]->setVector(m_initlist[i].vvec))
                     return false;
                 break;
             case TYPE_STRING:
-                if (!ir_value_set_string(m_ir_values[i], m_initlist[i].vstring))
+                if (!m_ir_values[i]->setString(m_initlist[i].vstring))
                     return false;
                 break;
             case TYPE_ARRAY:
@@ -1064,7 +1071,7 @@ bool ast_value::setGlobalArray()
                     compile_error(m_context, "field constant generated before its field");
                     return false;
                 }
-                if (!ir_value_set_field(m_ir_values[i], m_initlist[i].vfield->m_ir_v))
+                if (!m_ir_values[i]->setField(m_initlist[i].vfield->m_ir_v))
                     return false;
                 break;
             default:
@@ -1110,9 +1117,9 @@ bool ast_value::generateGlobal(ir_builder *ir, bool isfield)
     } else {
         // Arrays don't do this since there's no "array" value which spans across the
         // whole thing.
-        v = ir_builder_create_global(ir, m_name, m_vtype);
+        v = ir->createGlobal(m_name, m_vtype);
         if (!v) {
-            compile_error(m_context, "ir_builder_create_global failed on `%s`", m_name);
+            compile_error(m_context, "ir_builder::createGlobal failed on `%s`", m_name);
             return false;
         }
         codegen_output_type(this, v);
@@ -1125,23 +1132,25 @@ bool ast_value::generateGlobal(ir_builder *ir, bool isfield)
 
     if (m_flags & AST_FLAG_INCLUDE_DEF)
         m_ir_v->m_flags |= IR_FLAG_INCLUDE_DEF;
-    if (m_flags & AST_FLAG_ERASEABLE)
+    if (m_flags & AST_FLAG_ERASEABLE && !(m_flags & AST_FLAG_NOERASE))
         m_ir_v->m_flags |= IR_FLAG_ERASABLE;
+    if (m_flags & AST_FLAG_NOREF)
+        m_ir_v->m_flags |= IR_FLAG_NOREF;
 
     /* initialize */
     if (m_hasvalue) {
         switch (m_vtype)
         {
             case TYPE_FLOAT:
-                if (!ir_value_set_float(v, m_constval.vfloat))
+                if (!v->setFloat(m_constval.vfloat))
                     return false;
                 break;
             case TYPE_VECTOR:
-                if (!ir_value_set_vector(v, m_constval.vvec))
+                if (!v->setVector(m_constval.vvec))
                     return false;
                 break;
             case TYPE_STRING:
-                if (!ir_value_set_string(v, m_constval.vstring))
+                if (!v->setString(m_constval.vstring))
                     return false;
                 break;
             case TYPE_ARRAY:
@@ -1163,7 +1172,7 @@ bool ast_value::generateGlobal(ir_builder *ir, bool isfield)
                     compile_error(m_context, "field constant generated before its field");
                     return false;
                 }
-                if (!ir_value_set_field(v, m_constval.vfield->m_ir_v))
+                if (!v->setField(m_constval.vfield->m_ir_v))
                     return false;
                 break;
             default:
@@ -1177,7 +1186,7 @@ bool ast_value::generateGlobal(ir_builder *ir, bool isfield)
 
 bool ast_value::generateGlobalFunction(ir_builder *ir)
 {
-    ir_function *func = ir_builder_create_function(ir, m_name, m_next->m_vtype);
+    ir_function *func = ir->createFunction(m_name, m_next->m_vtype);
     if (!func)
         return false;
     func->m_context = m_context;
@@ -1187,7 +1196,7 @@ bool ast_value::generateGlobalFunction(ir_builder *ir)
     m_ir_v = func->m_value;
     if (m_flags & AST_FLAG_INCLUDE_DEF)
         m_ir_v->m_flags |= IR_FLAG_INCLUDE_DEF;
-    if (m_flags & AST_FLAG_ERASEABLE)
+    if (m_flags & AST_FLAG_ERASEABLE && !(m_flags & AST_FLAG_NOERASE))
         m_ir_v->m_flags |= IR_FLAG_ERASABLE;
     if (m_flags & AST_FLAG_BLOCK_COVERAGE)
         func->m_flags |= IR_FLAG_BLOCK_COVERAGE;
@@ -1217,9 +1226,9 @@ bool ast_value::generateGlobalField(ir_builder *ir)
         ast_expression *elemtype = array->m_next;
         qc_type vtype = elemtype->m_vtype;
 
-        ir_value *v = ir_builder_create_field(ir, m_name, vtype);
+        ir_value *v = ir->createField(m_name, vtype);
         if (!v) {
-            compile_error(m_context, "ir_builder_create_global failed on `%s`", m_name);
+            compile_error(m_context, "ir_builder::createGlobal failed on `%s`", m_name);
             return false;
         }
         v->m_context = m_context;
@@ -1229,8 +1238,10 @@ bool ast_value::generateGlobalField(ir_builder *ir)
 
         if (m_flags & AST_FLAG_INCLUDE_DEF)
             m_ir_v->m_flags |= IR_FLAG_INCLUDE_DEF;
-        if (m_flags & AST_FLAG_ERASEABLE)
+        if (m_flags & AST_FLAG_ERASEABLE && !(m_flags & AST_FLAG_NOERASE))
             m_ir_v->m_flags |= IR_FLAG_ERASABLE;
+        if (m_flags & AST_FLAG_NOREF)
+            m_ir_v->m_flags |= IR_FLAG_NOREF;
 
         const size_t namelen = m_name.length();
         std::unique_ptr<char[]> name(new char[namelen+16]);
@@ -1240,30 +1251,33 @@ bool ast_value::generateGlobalField(ir_builder *ir)
         array->m_ir_values[0] = v;
         for (size_t ai = 1; ai < array->m_count; ++ai) {
             util_snprintf(name.get() + namelen, 16, "[%u]", (unsigned int)ai);
-            array->m_ir_values[ai] = ir_builder_create_field(ir, name.get(), vtype);
+            array->m_ir_values[ai] = ir->createField(name.get(), vtype);
             if (!array->m_ir_values[ai]) {
-                compile_error(m_context, "ir_builder_create_global failed on `%s`", name.get());
+                compile_error(m_context, "ir_builder::createGlobal failed on `%s`", name.get());
                 return false;
             }
             array->m_ir_values[ai]->m_context = m_context;
             array->m_ir_values[ai]->m_unique_life = true;
             array->m_ir_values[ai]->m_locked      = true;
             if (m_flags & AST_FLAG_INCLUDE_DEF)
-                m_ir_values[ai]->m_flags |= IR_FLAG_INCLUDE_DEF;
+                array->m_ir_values[ai]->m_flags |= IR_FLAG_INCLUDE_DEF;
+            if (m_flags & AST_FLAG_NOREF)
+                array->m_ir_values[ai]->m_flags |= IR_FLAG_NOREF;
         }
     }
     else
     {
-        ir_value *v = ir_builder_create_field(ir, m_name, m_next->m_vtype);
+        ir_value *v = ir->createField(m_name, m_next->m_vtype);
         if (!v)
             return false;
         v->m_context = m_context;
         m_ir_v = v;
         if (m_flags & AST_FLAG_INCLUDE_DEF)
             m_ir_v->m_flags |= IR_FLAG_INCLUDE_DEF;
-
-        if (m_flags & AST_FLAG_ERASEABLE)
+        if (m_flags & AST_FLAG_ERASEABLE && !(m_flags & AST_FLAG_NOERASE))
             m_ir_v->m_flags |= IR_FLAG_ERASABLE;
+        if (m_flags & AST_FLAG_NOREF)
+            m_ir_v->m_flags |= IR_FLAG_NOREF;
     }
     return true;
 }
@@ -1282,9 +1296,9 @@ ir_value *ast_value::prepareGlobalArray(ir_builder *ir)
     if (!checkArray(*this))
         return nullptr;
 
-    ir_value *v = ir_builder_create_global(ir, m_name, vtype);
+    ir_value *v = ir->createGlobal(m_name, vtype);
     if (!v) {
-        compile_error(m_context, "ir_builder_create_global failed `%s`", m_name);
+        compile_error(m_context, "ir_builder::createGlobal failed `%s`", m_name);
         return nullptr;
     }
     v->m_context = m_context;
@@ -1293,8 +1307,10 @@ ir_value *ast_value::prepareGlobalArray(ir_builder *ir)
 
     if (m_flags & AST_FLAG_INCLUDE_DEF)
         v->m_flags |= IR_FLAG_INCLUDE_DEF;
-    if (m_flags & AST_FLAG_ERASEABLE)
-        m_ir_v->m_flags |= IR_FLAG_ERASABLE;
+    if (m_flags & AST_FLAG_ERASEABLE && !(m_flags & AST_FLAG_NOERASE))
+        v->m_flags |= IR_FLAG_ERASABLE;
+    if (m_flags & AST_FLAG_NOREF)
+        v->m_flags |= IR_FLAG_NOREF;
 
     const size_t namelen = m_name.length();
     std::unique_ptr<char[]> name(new char[namelen+16]);
@@ -1304,9 +1320,9 @@ ir_value *ast_value::prepareGlobalArray(ir_builder *ir)
     m_ir_values[0] = v;
     for (size_t ai = 1; ai < m_count; ++ai) {
         util_snprintf(name.get() + namelen, 16, "[%u]", (unsigned int)ai);
-        m_ir_values[ai] = ir_builder_create_global(ir, name.get(), vtype);
+        m_ir_values[ai] = ir->createGlobal(name.get(), vtype);
         if (!m_ir_values[ai]) {
-            compile_error(m_context, "ir_builder_create_global failed `%s`", name.get());
+            compile_error(m_context, "ir_builder::createGlobal failed `%s`", name.get());
             return nullptr;
         }
         m_ir_values[ai]->m_context = m_context;
@@ -1314,6 +1330,8 @@ ir_value *ast_value::prepareGlobalArray(ir_builder *ir)
         m_ir_values[ai]->m_locked      = true;
         if (m_flags & AST_FLAG_INCLUDE_DEF)
             m_ir_values[ai]->m_flags |= IR_FLAG_INCLUDE_DEF;
+        if (m_flags & AST_FLAG_NOREF)
+            m_ir_values[ai]->m_flags |= IR_FLAG_NOREF;
     }
 
     return v;
@@ -1360,6 +1378,9 @@ bool ast_value::generateLocal(ir_function *func, bool param)
         v->m_unique_life = true;
         v->m_locked      = true;
 
+        if (m_flags & AST_FLAG_NOREF)
+            v->m_flags |= IR_FLAG_NOREF;
+
         const size_t namelen = m_name.length();
         std::unique_ptr<char[]> name(new char[namelen+16]);
         util_strncpy(name.get(), m_name.c_str(), namelen);
@@ -1369,12 +1390,15 @@ bool ast_value::generateLocal(ir_function *func, bool param)
             util_snprintf(name.get() + namelen, 16, "[%u]", (unsigned int)ai);
             m_ir_values[ai] = ir_function_create_local(func, name.get(), vtype, param);
             if (!m_ir_values[ai]) {
-                compile_error(m_context, "internal_error: ir_builder_create_global failed on `%s`", name.get());
+                compile_error(m_context, "internal_error: ir_builder::createGlobal failed on `%s`", name.get());
                 return false;
             }
             m_ir_values[ai]->m_context = m_context;
             m_ir_values[ai]->m_unique_life = true;
-            m_ir_values[ai]->m_locked      = true;
+            m_ir_values[ai]->m_locked = true;
+
+            if (m_flags & AST_FLAG_NOREF)
+                m_ir_values[ai]->m_flags |= IR_FLAG_NOREF;
         }
     }
     else
@@ -1392,15 +1416,15 @@ bool ast_value::generateLocal(ir_function *func, bool param)
         switch (m_vtype)
         {
             case TYPE_FLOAT:
-                if (!ir_value_set_float(v, m_constval.vfloat))
+                if (!v->setFloat(m_constval.vfloat))
                     goto error;
                 break;
             case TYPE_VECTOR:
-                if (!ir_value_set_vector(v, m_constval.vvec))
+                if (!v->setVector(m_constval.vvec))
                     goto error;
                 break;
             case TYPE_STRING:
-                if (!ir_value_set_string(v, m_constval.vstring))
+                if (!v->setString(m_constval.vstring))
                     goto error;
                 break;
             default:
@@ -1413,6 +1437,9 @@ bool ast_value::generateLocal(ir_function *func, bool param)
     v->m_cvq = m_cvq;
     m_ir_v = v;
 
+    if (m_flags & AST_FLAG_NOREF)
+        m_ir_v->m_flags |= IR_FLAG_NOREF;
+
     if (!generateAccessors(func->m_owner))
         return false;
     return true;
@@ -1485,9 +1512,9 @@ bool ast_function::generateFunction(ir_builder *ir)
     /* fill the parameter list */
     for (auto &it : m_function_type->m_type_params) {
         if (it->m_vtype == TYPE_FIELD)
-            vec_push(irf->m_params, it->m_next->m_vtype);
+            irf->m_params.push_back(it->m_next->m_vtype);
         else
-            vec_push(irf->m_params, it->m_vtype);
+            irf->m_params.push_back(it->m_vtype);
         if (!m_builtin) {
             if (!it->generateLocal(m_ir_func, true))
                 return false;
@@ -1534,7 +1561,7 @@ bool ast_function::generateFunction(ir_builder *ir)
             return false;
         sub = ir_block_create_binop(m_curblock, m_context,
                                     makeLabel("va_count"), INSTR_SUB_F,
-                                    ir_builder_get_va_count(ir), fixed);
+                                    ir->get_va_count(), fixed);
         if (!sub)
             return false;
         if (!ir_block_create_store_op(m_curblock, m_context, INSTR_STORE_F,
@@ -1557,7 +1584,7 @@ bool ast_function::generateFunction(ir_builder *ir)
         {
             return ir_block_create_return(m_curblock, m_context, nullptr);
         }
-        else if (vec_size(m_curblock->m_entries) || m_curblock == irf->m_first)
+        else if (m_curblock->m_entries.size() || m_curblock == irf->m_first)
         {
             if (m_return_value) {
                 if (!m_return_value->codegen(this, false, &dummy))
@@ -1779,7 +1806,7 @@ bool ast_binary::codegen(ast_function *func, bool lvalue, ir_value **out)
                 return false;
         }
         /* use the likely flag */
-        vec_last(func->m_curblock->m_instr)->m_likely = true;
+        func->m_curblock->m_instr.back()->m_likely = true;
 
         /* enter the right-expression's block */
         func->m_curblock = other;
@@ -1907,6 +1934,7 @@ bool ast_binstore::codegen(ast_function *func, bool lvalue, ir_value **out)
         if (!idx->codegen(func, false, &iridx))
             return false;
     }
+
     if (!m_dest->codegen(func, false, &leftr))
         return false;
 
@@ -2093,22 +2121,63 @@ bool ast_member::codegen(ast_function *func, bool lvalue, ir_value **out)
         compile_error(m_context, "not an l-value (member access)");
         return false;
     }
-    if (m_outl) {
+    if (lvalue && m_outl) {
         *out = m_outl;
         return true;
     }
+    if (!lvalue && m_outr) {
+        *out = m_outr;
+        return true;
+    }
 
-    if (!m_owner->codegen(func, false, &vec))
+    if (ast_istype(m_owner, ast_entfield)) {
+        ir_value *ent, *field;
+        auto entfield = reinterpret_cast<ast_entfield*>(m_owner);
+        if (!entfield->m_entity->codegen(func, false, &ent))
+            return false;
+        if (!entfield->m_field->codegen(func, false, &vec))
+            return false;
+        field = vec->vectorMember(m_field);
+        if (lvalue) {
+            *out = ir_block_create_fieldaddress(func->m_curblock, m_context, func->makeLabel("mefa"),
+                                                ent, field);
+        } else {
+            *out = ir_block_create_load_from_ent(func->m_curblock, m_context, func->makeLabel("mefv"),
+                                                 ent, field, m_vtype);
+        }
+        if (!*out) {
+            compile_error(m_context, "failed to create %s instruction (output type %s)",
+                     (lvalue ? "ADDRESS" : "FIELD"),
+                     type_name[m_vtype]);
+            return false;
+        }
+        if (lvalue)
+            m_outl = *out;
+        else
+            m_outr = *out;
+        return (*out != nullptr);
+    }
+
+    // Vector member access
+    if (!m_owner->codegen(func, lvalue, &vec))
         return false;
 
     if (vec->m_vtype != TYPE_VECTOR &&
         !(vec->m_vtype == TYPE_FIELD && m_owner->m_next->m_vtype == TYPE_VECTOR))
     {
+        compile_error(m_context, "vector member produced neither vector nor field");
         return false;
     }
 
-    *out = ir_value_vector_member(vec, m_field);
-    m_outl = *out;
+    *out = vec->vectorMember(m_field);
+    if (!*out) {
+        compile_error(m_context, "internal error: failed to create vector member access");
+        return false;
+    }
+    if (lvalue)
+        m_outl = *out;
+    else
+        m_outr = *out;
 
     return (*out != nullptr);
 }
@@ -3022,7 +3091,7 @@ bool ast_call::codegen(ast_function *func, bool lvalue, ir_value **out)
         if (!m_va_count->codegen(func, false, &va_count))
             return false;
         if (!ir_block_create_store_op(func->m_curblock, m_context, INSTR_STORE_F,
-                                      ir_builder_get_va_count(builder), va_count))
+                                      builder->get_va_count(), va_count))
         {
             return false;
         }