]> git.xonotic.org Git - xonotic/gmqcc.git/commitdiff
-Ocall-stores as part of -O1: instead of having CALL instructions issue STOREs for...
authorWolfgang Bumiller <blub@speed.at>
Tue, 25 Dec 2012 22:25:59 +0000 (23:25 +0100)
committerWolfgang Bumiller <blub@speed.at>
Tue, 25 Dec 2012 22:25:59 +0000 (23:25 +0100)
ir.c
ir.h
opts.def

diff --git a/ir.c b/ir.c
index 40f36deaea6e9dbf9ad94f12a052495d1d3fba8c..0189c2e50ad259ec737086a41d1454faa0300a68 100644 (file)
--- a/ir.c
+++ b/ir.c
@@ -194,7 +194,8 @@ uint16_t type_not_instr[TYPE_COUNT] = {
 };
 
 /* protos */
 };
 
 /* protos */
-static void ir_gen_extparam(ir_builder *ir);
+static ir_value* ir_gen_extparam_proto(ir_builder *ir);
+static void      ir_gen_extparam      (ir_builder *ir);
 
 /* error functions */
 
 
 /* error functions */
 
@@ -220,7 +221,7 @@ static bool irwarning(lex_ctx ctx, int warntype, const char *fmt, ...)
  * Vector utility functions
  */
 
  * Vector utility functions
  */
 
-bool GMQCC_WARN vec_ir_value_find(ir_value **vec, ir_value *what, size_t *idx)
+bool GMQCC_WARN vec_ir_value_find(ir_value **vec, const ir_value *what, size_t *idx)
 {
     size_t i;
     size_t len = vec_size(vec);
 {
     size_t i;
     size_t len = vec_size(vec);
@@ -278,13 +279,15 @@ ir_builder* ir_builder_new(const char *modulename)
     self->functions   = NULL;
     self->globals     = NULL;
     self->fields      = NULL;
     self->functions   = NULL;
     self->globals     = NULL;
     self->fields      = NULL;
-    self->extparams   = NULL;
     self->filenames   = NULL;
     self->filestrings = NULL;
     self->htglobals   = util_htnew(IR_HT_SIZE);
     self->htfields    = util_htnew(IR_HT_SIZE);
     self->htfunctions = util_htnew(IR_HT_SIZE);
 
     self->filenames   = NULL;
     self->filestrings = NULL;
     self->htglobals   = util_htnew(IR_HT_SIZE);
     self->htfields    = util_htnew(IR_HT_SIZE);
     self->htfunctions = util_htnew(IR_HT_SIZE);
 
+    self->extparams       = NULL;
+    self->extparam_protos = NULL;
+
     self->max_locals  = 0;
 
     self->str_immediate = 0;
     self->max_locals  = 0;
 
     self->str_immediate = 0;
@@ -988,6 +991,7 @@ ir_value* ir_value_var(const char *name, int storetype, int vtype)
 
     self->unique_life = false;
     self->locked      = false;
 
     self->unique_life = false;
     self->locked      = false;
+    self->callparam   = false;
 
     self->life = NULL;
     return self;
 
     self->life = NULL;
     return self;
@@ -2136,7 +2140,7 @@ bool ir_function_allocate_locals(ir_function *self)
     size_t pos;
 
     ir_value *slot;
     size_t pos;
 
     ir_value *slot;
-    const ir_value *v;
+    ir_value *v;
 
     function_allocator alloc;
 
 
     function_allocator alloc;
 
@@ -2164,6 +2168,41 @@ bool ir_function_allocate_locals(ir_function *self)
         if (!vec_size(v->life))
             continue;
 
         if (!vec_size(v->life))
             continue;
 
+        /* CALL optimization:
+         * If the value is a parameter-temp: 1 write, 1 read from a CALL
+         * and it's not "locked", write it to the OFS_PARM directly.
+         */
+        if (OPTS_OPTIMIZATION(OPTIM_CALL_STORES)) {
+            if (!v->locked && vec_size(v->reads) == 1 && vec_size(v->writes) == 1 &&
+                (v->reads[0]->opcode == VINSTR_NRCALL ||
+                 (v->reads[0]->opcode >= INSTR_CALL0 && v->reads[0]->opcode <= INSTR_CALL8)
+                )
+               )
+            {
+                size_t    param;
+                ir_instr *call = v->reads[0];
+                if (!vec_ir_value_find(call->params, v, &param)) {
+                    irerror(call->context, "internal error: unlocked parameter %s not found", v->name);
+                    goto error;
+                }
+
+                v->callparam = true;
+                if (param < 8)
+                    ir_value_code_setaddr(v, OFS_PARM0 + 3*param);
+                else {
+                    ir_value *ep;
+                    param -= 8;
+                    if (vec_size(self->owner->extparam_protos) <= param)
+                        ep = ir_gen_extparam_proto(self->owner);
+                    else
+                        ep = self->owner->extparam_protos[param];
+                    ir_instr_op(v->writes[0], 0, ep, true);
+                    call->params[param+8] = ep;
+                }
+                continue;
+            }
+        }
+
         for (a = 0; a < vec_size(alloc.locals); ++a)
         {
             /* if it's reserved for a unique liferange: skip */
         for (a = 0; a < vec_size(alloc.locals); ++a)
         {
             /* if it's reserved for a unique liferange: skip */
@@ -2765,19 +2804,6 @@ tailcall:
         if ( (instr->opcode >= INSTR_CALL0 && instr->opcode <= INSTR_CALL8)
            || instr->opcode == VINSTR_NRCALL)
         {
         if ( (instr->opcode >= INSTR_CALL0 && instr->opcode <= INSTR_CALL8)
            || instr->opcode == VINSTR_NRCALL)
         {
-            /* Trivial call translation:
-             * copy all params to OFS_PARM*
-             * if the output's storetype is not store_return,
-             * add append a STORE instruction!
-             *
-             * NOTES on how to do it better without much trouble:
-             * -) The liferanges!
-             *      Simply check the liferange of all parameters for
-             *      other CALLs. For each param with no CALL in its
-             *      liferange, we can store it in an OFS_PARM at
-             *      generation already. This would even include later
-             *      reuse.... probably... :)
-             */
             size_t p, first;
             ir_value *retvalue;
 
             size_t p, first;
             ir_value *retvalue;
 
@@ -2787,6 +2813,8 @@ tailcall:
             for (p = 0; p < first; ++p)
             {
                 ir_value *param = instr->params[p];
             for (p = 0; p < first; ++p)
             {
                 ir_value *param = instr->params[p];
+                if (param->callparam)
+                    continue;
 
                 stmt.opcode = INSTR_STORE_F;
                 stmt.o3.u1 = 0;
 
                 stmt.opcode = INSTR_STORE_F;
                 stmt.o3.u1 = 0;
@@ -2807,6 +2835,9 @@ tailcall:
                 ir_value *param = instr->params[p];
                 ir_value *targetparam;
 
                 ir_value *param = instr->params[p];
                 ir_value *targetparam;
 
+                if (param->callparam)
+                    continue;
+
                 if (p-8 >= vec_size(ir->extparams))
                     ir_gen_extparam(ir);
 
                 if (p-8 >= vec_size(ir->extparams))
                     ir_gen_extparam(ir);
 
@@ -2992,16 +3023,29 @@ static bool gen_global_function(ir_builder *ir, ir_value *global)
     return true;
 }
 
     return true;
 }
 
+static ir_value* ir_gen_extparam_proto(ir_builder *ir)
+{
+    ir_value *global;
+    char      name[128];
+
+    snprintf(name, sizeof(name), "EXTPARM#%i", (int)(vec_size(ir->extparam_protos)+8));
+    global = ir_value_var(name, store_global, TYPE_VECTOR);
+
+    vec_push(ir->extparam_protos, global);
+    return global;
+}
+
 static void ir_gen_extparam(ir_builder *ir)
 {
     prog_section_def def;
     ir_value        *global;
 static void ir_gen_extparam(ir_builder *ir)
 {
     prog_section_def def;
     ir_value        *global;
-    char             name[128];
 
 
-    snprintf(name, sizeof(name), "EXTPARM#%i", (int)(vec_size(ir->extparams)+8));
-    global = ir_value_var(name, store_global, TYPE_VECTOR);
+    if (vec_size(ir->extparam_protos) < vec_size(ir->extparams)+1)
+        global = ir_gen_extparam_proto(ir);
+    else
+        global = ir->extparam_protos[vec_size(ir->extparams)];
 
 
-    def.name = code_genstring(name);
+    def.name = code_genstring(global->name);
     def.type = TYPE_VECTOR;
     def.offset = vec_size(code_globals);
 
     def.type = TYPE_VECTOR;
     def.offset = vec_size(code_globals);
 
@@ -3078,6 +3122,8 @@ static bool gen_function_locals(ir_builder *ir, ir_value *global)
     for (i = 0; i < vec_size(irfun->values); ++i)
     {
         ir_value *v = irfun->values[i];
     for (i = 0; i < vec_size(irfun->values); ++i)
     {
         ir_value *v = irfun->values[i];
+        if (v->callparam)
+            continue;
         ir_value_code_setaddr(v, firstlocal + v->code.local);
     }
     return true;
         ir_value_code_setaddr(v, firstlocal + v->code.local);
     }
     return true;
diff --git a/ir.h b/ir.h
index e85eb45916961440c3015fdb015c018f5d65407f..6eaba3c9fd95b6757f3a638131aa93439aca605b 100644 (file)
--- a/ir.h
+++ b/ir.h
@@ -79,6 +79,7 @@ typedef struct ir_value_s {
     bool unique_life;
     /* temps living during a CALL must be locked */
     bool      locked;
     bool unique_life;
     /* temps living during a CALL must be locked */
     bool      locked;
+    bool      callparam;
 
     /* For the temp allocator */
     ir_life_entry_t *life;
 
     /* For the temp allocator */
     ir_life_entry_t *life;
@@ -96,7 +97,7 @@ void      ir_value_delete(ir_value*);
 bool      ir_value_set_name(ir_value*, const char *name);
 ir_value* ir_value_vector_member(ir_value*, unsigned int member);
 
 bool      ir_value_set_name(ir_value*, const char *name);
 ir_value* ir_value_vector_member(ir_value*, unsigned int member);
 
-bool GMQCC_WARN vec_ir_value_find(ir_value **vec, ir_value *what, size_t *idx);
+bool GMQCC_WARN vec_ir_value_find(ir_value **vec, const ir_value *what, size_t *idx);
 
 bool GMQCC_WARN ir_value_set_float(ir_value*, float f);
 bool GMQCC_WARN ir_value_set_func(ir_value*, int f);
 
 bool GMQCC_WARN ir_value_set_float(ir_value*, float f);
 bool GMQCC_WARN ir_value_set_func(ir_value*, int f);
@@ -153,7 +154,7 @@ void      ir_instr_delete(ir_instr*);
 
 bool GMQCC_WARN vec_ir_instr_find(ir_instr **vec, ir_instr *what, size_t *idx);
 
 
 bool GMQCC_WARN vec_ir_instr_find(ir_instr **vec, ir_instr *what, size_t *idx);
 
-bool GMQCC_WARN ir_instr_op(ir_instr*, int op, ir_value *value, bool writing);
+bool ir_instr_op(ir_instr*, int op, ir_value *value, bool writing);
 
 void ir_instr_dump(ir_instr* in, char *ind, int (*oprintf)(const char*,...));
 
 
 void ir_instr_dump(ir_instr* in, char *ind, int (*oprintf)(const char*,...));
 
@@ -309,6 +310,7 @@ typedef struct ir_builder_s
     ht            htfields;
 
     ir_value    **extparams;
     ht            htfields;
 
     ir_value    **extparams;
+    ir_value    **extparam_protos;
 
     /* the highest func->allocated_locals */
     size_t        max_locals;
 
     /* the highest func->allocated_locals */
     size_t        max_locals;
index f39336a8cae13107b57107cb2bb03cd12c7a6aac..3fbe1041e339b829205093a4877f49449e7e0929 100644 (file)
--- a/opts.def
+++ b/opts.def
@@ -86,6 +86,7 @@
     GMQCC_DEFINE_FLAG(OVERLAP_LOCALS,       3)
     GMQCC_DEFINE_FLAG(STRIP_CONSTANT_NAMES, 1)
     GMQCC_DEFINE_FLAG(OVERLAP_STRINGS,      2)
     GMQCC_DEFINE_FLAG(OVERLAP_LOCALS,       3)
     GMQCC_DEFINE_FLAG(STRIP_CONSTANT_NAMES, 1)
     GMQCC_DEFINE_FLAG(OVERLAP_STRINGS,      2)
+    GMQCC_DEFINE_FLAG(CALL_STORES,          1)
 #endif
 
 /* some cleanup so we don't have to */
 #endif
 
 /* some cleanup so we don't have to */