]> git.xonotic.org Git - xonotic/gmqcc.git/blobdiff - ir.c
Life Ranges: First deal with all writes, then with all reads, since writes will remov...
[xonotic/gmqcc.git] / ir.c
diff --git a/ir.c b/ir.c
index f858bb6e9a535a63eb6233cbcac334e20af3989c..60d0c44704027de9728d7fac25379aed3c282710 100644 (file)
--- a/ir.c
+++ b/ir.c
@@ -285,6 +285,8 @@ ir_builder* ir_builder_new(const char *modulename)
     self->htfields    = util_htnew(IR_HT_SIZE);
     self->htfunctions = util_htnew(IR_HT_SIZE);
 
+    self->max_locals  = 0;
+
     self->str_immediate = 0;
     self->name = NULL;
     if (!ir_builder_set_name(self, modulename)) {
@@ -433,6 +435,8 @@ ir_function* ir_function_new(ir_builder* owner, int outtype)
         mem_d(self);
         return NULL;
     }
+    self->flags = 0;
+
     self->owner = owner;
     self->context.file = "<@no context>";
     self->context.line = 0;
@@ -605,7 +609,8 @@ bool ir_function_pass_peephole(ir_function *self)
                     if (inot->_ops[0] != value ||
                         inot->opcode < INSTR_NOT_F ||
                         inot->opcode > INSTR_NOT_FNC ||
-                        inot->opcode == INSTR_NOT_V) /* can't do this one */
+                        inot->opcode == INSTR_NOT_V || /* can't do these */
+                        inot->opcode == INSTR_NOT_S)
                     {
                         break;
                     }
@@ -998,16 +1003,22 @@ ir_value* ir_value_vector_member(ir_value *self, unsigned int member)
     if (self->members[member])
         return self->members[member];
 
-    len = strlen(self->name);
-    name = (char*)mem_a(len + 3);
-    memcpy(name, self->name, len);
-    name[len+0] = '_';
-    name[len+1] = 'x' + member;
-    name[len+2] = '\0';
+    if (self->name) {
+        len = strlen(self->name);
+        name = (char*)mem_a(len + 3);
+        memcpy(name, self->name, len);
+        name[len+0] = '_';
+        name[len+1] = 'x' + member;
+        name[len+2] = '\0';
+    }
+    else
+        name = NULL;
+
     if (self->vtype == TYPE_VECTOR)
     {
         m = ir_value_var(name, self->store, TYPE_FLOAT);
-        mem_d(name);
+        if (name)
+            mem_d(name);
         if (!m)
             return NULL;
         m->context = self->context;
@@ -1020,7 +1031,8 @@ ir_value* ir_value_vector_member(ir_value *self, unsigned int member)
         if (self->fieldtype != TYPE_VECTOR)
             return NULL;
         m = ir_value_var(name, self->store, TYPE_FIELD);
-        mem_d(name);
+        if (name)
+            mem_d(name);
         if (!m)
             return NULL;
         m->fieldtype = TYPE_FLOAT;
@@ -1522,20 +1534,8 @@ bool ir_block_create_jump(ir_block *self, lex_ctx ctx, ir_block *to)
 
 bool ir_block_create_goto(ir_block *self, lex_ctx ctx, ir_block *to)
 {
-    ir_instr *in;
-    if (!ir_check_unreachable(self))
-        return false;
-    self->final = true;
-    in = ir_instr_new(ctx, self, INSTR_GOTO);
-    if (!in)
-        return false;
-
-    in->bops[0] = to;
-    vec_push(self->instr, in);
-
-    vec_push(self->exits, to);
-    vec_push(to->entries, self);
-    return true;
+    self->owner->flags |= IR_FLAG_HAS_GOTO;
+    return ir_block_create_jump(self, ctx, to);
 }
 
 ir_instr* ir_block_create_phi(ir_block *self, lex_ctx ctx, const char *label, int ot)
@@ -2225,6 +2225,7 @@ bool ir_function_calculate_liferanges(ir_function *self)
                 if (!vec_ir_value_find(block->living, v->memberof, NULL))
                     continue;
             }
+            self->flags |= IR_FLAG_HAS_UNINITIALIZED;
             if (irwarning(v->context, WARN_USED_UNINITIALIZED,
                           "variable `%s` may be used uninitialized in this function", v->name))
             {
@@ -2291,9 +2292,7 @@ bool ir_function_allocate_locals(ir_function *self)
 
     for (i = 0; i < vec_size(self->locals); ++i)
     {
-#if 0
         if (!OPTS_OPTIMIZATION(OPTIM_LOCALTEMPS))
-#endif
             self->locals[i]->unique_life = true;
         if (!function_allocator_alloc(&alloc, self->locals[i]))
             goto error;
@@ -2499,22 +2498,6 @@ static bool ir_block_life_propagate(ir_block *self, ir_block *prev, bool *change
     { --i;
         instr = self->instr[i];
 
-        /* PHI operands are always read operands */
-        for (p = 0; p < vec_size(instr->phi); ++p)
-        {
-            value = instr->phi[p].value;
-            if (!vec_ir_value_find(self->living, value, NULL))
-                vec_push(self->living, value);
-        }
-
-        /* call params are read operands too */
-        for (p = 0; p < vec_size(instr->params); ++p)
-        {
-            value = instr->params[p];
-            if (!vec_ir_value_find(self->living, value, NULL))
-                vec_push(self->living, value);
-        }
-
         /* See which operands are read and write operands */
         ir_op_read_write(instr->opcode, &read, &write);
 
@@ -2531,7 +2514,9 @@ static bool ir_block_life_propagate(ir_block *self, ir_block *prev, bool *change
             *changed = *changed || tempbool;
         }
 
-        /* Go through the 3 main operands */
+        /* Go through the 3 main operands
+         * writes first, then reads
+         */
         for (o = 0; o < 3; ++o)
         {
             if (!instr->_ops[o]) /* no such operand */
@@ -2547,13 +2532,6 @@ static bool ir_block_life_propagate(ir_block *self, ir_block *prev, bool *change
                 value->store != store_param)
                 continue;
 
-            /* read operands */
-            if (read & (1<<o))
-            {
-                if (!vec_ir_value_find(self->living, value, NULL))
-                    vec_push(self->living, value);
-            }
-
             /* write operands */
             /* When we write to a local, we consider it "dead" for the
              * remaining upper part of the function, since in SSA a value
@@ -2596,6 +2574,45 @@ static bool ir_block_life_propagate(ir_block *self, ir_block *prev, bool *change
                 }
             }
         }
+
+        for (o = 0; o < 3; ++o)
+        {
+            if (!instr->_ops[o]) /* no such operand */
+                continue;
+
+            value = instr->_ops[o];
+
+            /* We only care about locals */
+            /* we also calculate parameter liferanges so that locals
+             * can take up parameter slots */
+            if (value->store != store_value &&
+                value->store != store_local &&
+                value->store != store_param)
+                continue;
+
+            /* read operands */
+            if (read & (1<<o))
+            {
+                if (!vec_ir_value_find(self->living, value, NULL))
+                    vec_push(self->living, value);
+            }
+        }
+        /* PHI operands are always read operands */
+        for (p = 0; p < vec_size(instr->phi); ++p)
+        {
+            value = instr->phi[p].value;
+            if (!vec_ir_value_find(self->living, value, NULL))
+                vec_push(self->living, value);
+        }
+
+        /* call params are read operands too */
+        for (p = 0; p < vec_size(instr->params); ++p)
+        {
+            value = instr->params[p];
+            if (!vec_ir_value_find(self->living, value, NULL))
+                vec_push(self->living, value);
+        }
+
         /* (A) */
         tempbool = ir_block_living_add_instr(self, instr->eid);
         /*con_err( "living added values\n");*/
@@ -2632,7 +2649,7 @@ static bool ir_block_life_propagate(ir_block *self, ir_block *prev, bool *change
  *
  * Breaking conventions is annoying...
  */
-static bool ir_builder_gen_global(ir_builder *self, ir_value *global, bool islocal);
+static bool ir_builder_gen_global(ir_builder *self, ir_value *global, bool islocal, bool defs_only);
 
 static bool gen_global_field(ir_value *global)
 {
@@ -3055,24 +3072,8 @@ static bool gen_global_function(ir_builder *ir, ir_value *global)
             fun.argsize[i] = type_sizeof_[irfun->params[i]];
     }
 
-    fun.firstlocal = vec_size(code_globals);
-
-    fun.locals = irfun->allocated_locals;
-    for (i = 0; i < vec_size(irfun->locals); ++i) {
-        if (!ir_builder_gen_global(ir, irfun->locals[i], true)) {
-            irerror(irfun->locals[i]->context, "Failed to generate local %s", irfun->locals[i]->name);
-            return false;
-        }
-        ir_value_code_setaddr(irfun->locals[i], fun.firstlocal + irfun->locals[i]->code.local);
-    }
-    for (i = 0; i < vec_size(irfun->values); ++i)
-    {
-        /* generate code.globaladdr for ssa values */
-        ir_value *v = irfun->values[i];
-        ir_value_code_setaddr(v, fun.firstlocal + v->code.local);
-    }
-    for (i = vec_size(code_globals); i < fun.firstlocal + irfun->allocated_locals; ++i)
-        vec_push(code_globals, 0);
+    fun.firstlocal = 0;
+    fun.locals     = irfun->allocated_locals;
 
     if (irfun->builtin)
         fun.entry = irfun->builtin+1;
@@ -3142,6 +3143,40 @@ static bool gen_function_extparam_copy(ir_function *self)
     return true;
 }
 
+static bool gen_function_locals(ir_builder *ir, ir_value *global)
+{
+    prog_section_function *def;
+    ir_function           *irfun;
+    size_t                 i;
+    uint32_t               firstlocal;
+
+    irfun = global->constval.vfunc;
+    def   = code_functions + irfun->code_function_def;
+
+    if (opts.g || !OPTS_OPTIMIZATION(OPTIM_OVERLAP_LOCALS) || (irfun->flags & IR_FLAG_MASK_NO_OVERLAP))
+        firstlocal = def->firstlocal = vec_size(code_globals);
+    else {
+        firstlocal = def->firstlocal = ir->first_common_local;
+        ++opts_optimizationcount[OPTIM_OVERLAP_LOCALS];
+    }
+
+    for (i = vec_size(code_globals); i < firstlocal + irfun->allocated_locals; ++i)
+        vec_push(code_globals, 0);
+    for (i = 0; i < vec_size(irfun->locals); ++i) {
+        ir_value_code_setaddr(irfun->locals[i], firstlocal + irfun->locals[i]->code.local);
+        if (!ir_builder_gen_global(ir, irfun->locals[i], true, true)) {
+            irerror(irfun->locals[i]->context, "failed to generate local %s", irfun->locals[i]->name);
+            return false;
+        }
+    }
+    for (i = 0; i < vec_size(irfun->values); ++i)
+    {
+        ir_value *v = irfun->values[i];
+        ir_value_code_setaddr(v, firstlocal + v->code.local);
+    }
+    return true;
+}
+
 static bool gen_global_function_code(ir_builder *ir, ir_value *global)
 {
     prog_section_function *fundef;
@@ -3169,6 +3204,10 @@ static bool gen_global_function_code(ir_builder *ir, ir_value *global)
     fundef = &code_functions[irfun->code_function_def];
 
     fundef->entry = vec_size(code_statements);
+    if (!gen_function_locals(ir, global)) {
+        irerror(irfun->context, "Failed to generate locals for function %s", irfun->name);
+        return false;
+    }
     if (!gen_function_extparam_copy(irfun)) {
         irerror(irfun->context, "Failed to generate extparam-copy code for function %s", irfun->name);
         return false;
@@ -3236,26 +3275,42 @@ static void gen_vector_fields(prog_section_field fld, const char *name)
     }
 }
 
-static bool ir_builder_gen_global(ir_builder *self, ir_value *global, bool islocal)
+static bool ir_builder_gen_global(ir_builder *self, ir_value *global, bool islocal, bool defs_only)
 {
     size_t           i;
     int32_t         *iptr;
     prog_section_def def;
+    bool             pushdef = false;
 
-    def.type   = global->vtype;
-    def.offset = vec_size(code_globals);
-
-    if (global->name) {
-        if (global->name[0] == '#') {
-            if (!self->str_immediate)
-                self->str_immediate = code_genstring("IMMEDIATE");
-            def.name = global->code.name = self->str_immediate;
+    if (opts.g || !islocal)
+    {
+        pushdef = true;
+        def.type   = global->vtype;
+        def.offset = vec_size(code_globals);
+
+        if (global->name) {
+            if (global->name[0] == '#') {
+                if (!self->str_immediate)
+                    self->str_immediate = code_genstring("IMMEDIATE");
+                def.name = global->code.name = self->str_immediate;
+            }
+            else
+                def.name = global->code.name = code_genstring(global->name);
         }
         else
-            def.name = global->code.name = code_genstring(global->name);
+            def.name   = 0;
+        if (defs_only) {
+            def.offset = ir_value_code_addr(global);
+            vec_push(code_defs, def);
+            if (global->vtype == TYPE_VECTOR)
+                gen_vector_defs(def, global->name);
+            else if (global->vtype == TYPE_FIELD && global->fieldtype == TYPE_VECTOR)
+                gen_vector_defs(def, global->name);
+            return true;
+        }
     }
-    else
-        def.name   = 0;
+    if (defs_only)
+        return true;
 
     switch (global->vtype)
     {
@@ -3280,14 +3335,17 @@ static bool ir_builder_gen_global(ir_builder *self, ir_value *global, bool isloc
         ir_value_code_setaddr(global, vec_size(code_globals));
         vec_push(code_globals, 0);
         /* Add the def */
-        vec_push(code_defs, def);
+        if (pushdef) vec_push(code_defs, def);
         return true;
     case TYPE_POINTER:
-        vec_push(code_defs, def);
+        if (pushdef) vec_push(code_defs, def);
         return gen_global_pointer(global);
     case TYPE_FIELD:
-        vec_push(code_defs, def);
-        gen_vector_defs(def, global->name);
+        if (pushdef) {
+            vec_push(code_defs, def);
+            if (global->fieldtype == TYPE_VECTOR)
+                gen_vector_defs(def, global->name);
+        }
         return gen_global_field(global);
     case TYPE_ENTITY:
         /* fall through */
@@ -3302,7 +3360,7 @@ static bool ir_builder_gen_global(ir_builder *self, ir_value *global, bool isloc
         }
         if (!islocal && global->cvq != CV_CONST)
             def.type |= DEF_SAVEGLOBAL;
-        vec_push(code_defs, def);
+        if (pushdef) vec_push(code_defs, def);
 
         return global->code.globaladdr >= 0;
     }
@@ -3316,7 +3374,7 @@ static bool ir_builder_gen_global(ir_builder *self, ir_value *global, bool isloc
         }
         if (!islocal && global->cvq != CV_CONST)
             def.type |= DEF_SAVEGLOBAL;
-        vec_push(code_defs, def);
+        if (pushdef) vec_push(code_defs, def);
         return global->code.globaladdr >= 0;
     }
     case TYPE_VECTOR:
@@ -3342,9 +3400,11 @@ static bool ir_builder_gen_global(ir_builder *self, ir_value *global, bool isloc
         if (!islocal && global->cvq != CV_CONST)
             def.type |= DEF_SAVEGLOBAL;
 
-        vec_push(code_defs, def);
-        def.type &= ~DEF_SAVEGLOBAL;
-        gen_vector_defs(def, global->name);
+        if (pushdef) {
+            vec_push(code_defs, def);
+            def.type &= ~DEF_SAVEGLOBAL;
+            gen_vector_defs(def, global->name);
+        }
         return global->code.globaladdr >= 0;
     }
     case TYPE_FUNCTION:
@@ -3360,7 +3420,7 @@ static bool ir_builder_gen_global(ir_builder *self, ir_value *global, bool isloc
         }
         if (!islocal && global->cvq != CV_CONST)
             def.type |= DEF_SAVEGLOBAL;
-        vec_push(code_defs, def);
+        if (pushdef) vec_push(code_defs, def);
         return true;
     case TYPE_VARIANT:
         /* assume biggest type */
@@ -3456,7 +3516,7 @@ bool ir_builder_generate(ir_builder *self, const char *filename)
 {
     prog_section_statement stmt;
     size_t i;
-    char   *lnofile = NULL;
+    char  *lnofile = NULL;
 
     code_init();
 
@@ -3467,9 +3527,17 @@ bool ir_builder_generate(ir_builder *self, const char *filename)
 
     for (i = 0; i < vec_size(self->globals); ++i)
     {
-        if (!ir_builder_gen_global(self, self->globals[i], false)) {
+        if (!ir_builder_gen_global(self, self->globals[i], false, false)) {
             return false;
         }
+        if (self->globals[i]->vtype == TYPE_FUNCTION) {
+            ir_function *func = self->globals[i]->constval.vfunc;
+            if (func && self->max_locals < func->allocated_locals &&
+                !(func->flags & IR_FLAG_MASK_NO_OVERLAP))
+            {
+                self->max_locals = func->allocated_locals;
+            }
+        }
     }
 
     for (i = 0; i < vec_size(self->fields); ++i)
@@ -3479,6 +3547,12 @@ bool ir_builder_generate(ir_builder *self, const char *filename)
         }
     }
 
+    /* generate common locals */
+    self->first_common_local = vec_size(code_globals);
+    for (i = 0; i < self->max_locals; ++i) {
+        vec_push(code_globals, 0);
+    }
+
     /* generate function code */
     for (i = 0; i < vec_size(self->globals); ++i)
     {