]> git.xonotic.org Git - xonotic/gmqcc.git/blobdiff - ir.c
Merge branch 'master' into ast-and-ir
[xonotic/gmqcc.git] / ir.c
diff --git a/ir.c b/ir.c
index f001e278ef5dc7a3772bb341a44e5d1189f1c2dd..a390ad795bde42d965d8dd693b79bc366a98e8fc 100644 (file)
--- a/ir.c
+++ b/ir.c
@@ -558,6 +558,60 @@ bool ir_value_life_merge(ir_value *self, size_t s)
     return ir_value_life_insert(self, i, new_entry);
 }
 
+bool ir_values_overlap(ir_value *a, ir_value *b)
+{
+    /* For any life entry in A see if it overlaps with
+     * any life entry in B.
+     * Note that the life entries are orderes, so we can make a
+     * more efficient algorithm there than naively translating the
+     * statement above.
+     */
+
+    ir_life_entry_t *la, *lb, *enda, *endb;
+
+    /* first of all, if either has no life range, they cannot clash */
+    if (!a->life_count || !b->life_count)
+        return false;
+
+    la = a->life;
+    lb = b->life;
+    enda = la + a->life_count;
+    endb = lb + b->life_count;
+    while (true)
+    {
+        /* check if the entries overlap, for that,
+         * both must start before the other one ends.
+         */
+        if (la->start <= lb->end &&
+            lb->start <= la->end)
+        {
+            return true;
+        }
+
+        /* entries are ordered
+         * one entry is earlier than the other
+         * that earlier entry will be moved forward
+         */
+        if (la->end < lb->end)
+        {
+            /* order: A B, move A forward
+             * check if we hit the end with A
+             */
+            if (++la == enda)
+                break;
+        }
+        else if (lb->end < la->end)
+        {
+            /* order: B A, move B forward
+             * check if we hit the end with B
+             */
+            if (++lb == endb)
+                break;
+        }
+    }
+    return false;
+}
+
 /***********************************************************************
  *IR main operations
  */
@@ -792,7 +846,7 @@ ir_instr* ir_block_create_phi(ir_block *self, const char *label, int ot)
     in = ir_instr_new(self, VINSTR_PHI);
     if (!in)
         return NULL;
-    out = ir_value_out(self->owner, label, store_local, ot);
+    out = ir_value_out(self->owner, label, store_value, ot);
     if (!out) {
         ir_instr_delete(in);
         return NULL;
@@ -840,9 +894,6 @@ ir_value* ir_block_create_binop(ir_block *self,
                                 const char *label, int opcode,
                                 ir_value *left, ir_value *right)
 {
-    ir_value *out = NULL;
-    ir_instr *in  = NULL;
-
     int ot = TYPE_VOID;
     switch (opcode) {
         case INSTR_ADD_F:
@@ -928,33 +979,82 @@ ir_value* ir_block_create_binop(ir_block *self,
         return NULL;
     }
 
-    out = ir_value_out(self->owner, label, store_local, ot);
+    return ir_block_create_general_instr(self, label, opcode, left, right, ot);
+}
+
+ir_value* ir_block_create_general_instr(ir_block *self, const char *label,
+                                        int op, ir_value *a, ir_value *b, int outype)
+{
+    ir_instr *instr;
+    ir_value *out;
+
+    out = ir_value_out(self->owner, label, store_value, outype);
     if (!out)
         return NULL;
 
-    in = ir_instr_new(self, opcode);
-    if (!in) {
+    instr = ir_instr_new(self, op);
+    if (!instr) {
         ir_value_delete(out);
         return NULL;
     }
 
-    if (!ir_instr_op(in, 0, out, true) ||
-        !ir_instr_op(in, 1, left, false) ||
-        !ir_instr_op(in, 2, right, false) )
+    if (!ir_instr_op(instr, 0, out, true) ||
+        !ir_instr_op(instr, 1, a, false) ||
+        !ir_instr_op(instr, 2, b, false) )
     {
         goto on_error;
     }
 
-    if (!ir_block_instr_add(self, in))
+    if (!ir_block_instr_add(self, instr))
         goto on_error;
 
     return out;
 on_error:
+    ir_instr_delete(instr);
     ir_value_delete(out);
-    ir_instr_delete(in);
     return NULL;
 }
 
+ir_value* ir_block_create_fieldaddress(ir_block *self, const char *label, ir_value *ent, ir_value *field)
+{
+    /* Support for various pointer types todo if so desired */
+    if (ent->vtype != TYPE_ENTITY)
+        return NULL;
+
+    if (field->vtype != TYPE_FIELD)
+        return NULL;
+
+    return ir_block_create_general_instr(self, label, INSTR_ADDRESS, ent, field, TYPE_POINTER);
+}
+
+ir_value* ir_block_create_load_from_ent(ir_block *self, const char *label, ir_value *ent, ir_value *field, int outype)
+{
+    int op;
+    if (ent->vtype != TYPE_ENTITY)
+        return NULL;
+
+    /* at some point we could redirect for TYPE_POINTER... but that could lead to carelessness */
+    if (field->vtype != TYPE_FIELD)
+        return NULL;
+
+    switch (outype)
+    {
+        case TYPE_FLOAT:   op = INSTR_LOAD_F;   break;
+        case TYPE_VECTOR:  op = INSTR_LOAD_V;   break;
+        case TYPE_STRING:  op = INSTR_LOAD_S;   break;
+        case TYPE_FIELD:   op = INSTR_LOAD_FLD; break;
+        case TYPE_ENTITY:  op = INSTR_LOAD_ENT; break;
+#if 0
+        case TYPE_POINTER: op = INSTR_LOAD_I;   break;
+        case TYPE_INTEGER: op = INSTR_LOAD_I;   break;
+#endif
+        default:
+            return NULL;
+    }
+
+    return ir_block_create_general_instr(self, label, op, ent, field, outype);
+}
+
 ir_value* ir_block_create_add(ir_block *self,
                               const char *label,
                               ir_value *left, ir_value *right)