From db7b9a4f962e871823ad39f3a4132bd3e5e5e20f Mon Sep 17 00:00:00 2001
From: "Wolfgang (Blub) Bumiller" <blub@speed.at>
Date: Mon, 25 Jun 2012 14:51:31 +0200
Subject: [PATCH] ir_value_life_merge_into, to merge the liferange of one value
 into the range of another, testing in test_ir

---
 ir.c           | 79 +++++++++++++++++++++++++++++++++++++++++++++++++-
 ir.h           |  1 +
 test/ir-test.c | 35 ++++++++++++++++++++++
 3 files changed, 114 insertions(+), 1 deletion(-)

diff --git a/ir.c b/ir.c
index 4c03899..398744e 100644
--- a/ir.c
+++ b/ir.c
@@ -584,6 +584,83 @@ bool ir_value_life_merge(ir_value *self, size_t s)
     return ir_value_life_insert(self, i, new_entry);
 }
 
+bool ir_value_life_merge_into(ir_value *self, const ir_value *other)
+{
+    size_t i, myi;
+
+    if (!other->life_count)
+        return true;
+
+    if (!self->life_count) {
+        for (i = 0; i < other->life_count; ++i) {
+            if (!ir_value_life_add(self, other->life[i]))
+                return false;
+        }
+        return true;
+    }
+
+    myi = 0;
+    for (i = 0; i < other->life_count; ++i)
+    {
+        const ir_life_entry_t *life = &other->life[i];
+        while (true)
+        {
+            ir_life_entry_t *entry = &self->life[myi];
+
+            if (life->end+1 < entry->start)
+            {
+                /* adding an interval before entry */
+                if (!ir_value_life_insert(self, myi, *life))
+                    return false;
+                ++myi;
+                break;
+            }
+
+            if (life->start <  entry->start &&
+                life->end   >= entry->start)
+            {
+                /* starts earlier and overlaps */
+                entry->start = life->start;
+            }
+
+            if (life->end     >  entry->end &&
+                life->start-1 <= entry->end)
+            {
+                /* ends later and overlaps */
+                entry->end = life->end;
+            }
+
+            /* see if our change combines it with the next ranges */
+            while (myi+1 < self->life_count &&
+                   entry->end+1 >= self->life[1+myi].start)
+            {
+                /* overlaps with (myi+1) */
+                if (entry->end < self->life[1+myi].end)
+                    entry->end = self->life[1+myi].end;
+                if (!ir_value_life_remove(self, myi+1))
+                    return false;
+                entry = &self->life[myi];
+            }
+
+            /* see if we're after the entry */
+            if (life->start > entry->end)
+            {
+                ++myi;
+                /* append if we're at the end */
+                if (myi >= self->life_count) {
+                    if (!ir_value_life_add(self, *life))
+                        return false;
+                    break;
+                }
+                /* otherweise check the next range */
+                continue;
+            }
+            break;
+        }
+    }
+    return true;
+}
+
 bool ir_values_overlap(ir_value *a, ir_value *b)
 {
     /* For any life entry in A see if it overlaps with
@@ -1425,7 +1502,7 @@ bool ir_function_calculate_liferanges(ir_function *self)
  */
 bool ir_function_allocate_locals(ir_function *self)
 {
-    return false;
+    return true;
 }
 
 /* Get information about which operand
diff --git a/ir.h b/ir.h
index 3881c30..a7f0076 100644
--- a/ir.h
+++ b/ir.h
@@ -89,6 +89,7 @@ MEM_VECTOR_PROTO(ir_value, ir_life_entry_t, life);
 /* merge an instruction into the life-range */
 /* returns false if the lifepoint was already known */
 bool ir_value_life_merge(ir_value*, size_t);
+bool ir_value_life_merge_into(ir_value*, const ir_value*);
 /* check if a value lives at a specific point */
 bool ir_value_lives(ir_value*, size_t);
 /* check if the life-range of 2 values overlaps */
diff --git a/test/ir-test.c b/test/ir-test.c
index f21ce45..38fa764 100644
--- a/test/ir-test.c
+++ b/test/ir-test.c
@@ -9,6 +9,8 @@
 
 int main()
 {
+    int lf;
+
 	ir_builder *b  = ir_builder_new("test");
 	ir_value   *va = ir_builder_create_global(b, "a", TYPE_FLOAT);
 	ir_value   *v3 = ir_builder_create_global(b, "const_f_3", TYPE_FLOAT);
@@ -16,6 +18,10 @@ int main()
 	ir_value   *vc = ir_builder_create_global(b, "c", TYPE_FLOAT);
 	ir_value   *vd = ir_builder_create_global(b, "d", TYPE_FLOAT);
 
+	ir_value   *life1  = ir_builder_create_global(b, "life1", TYPE_FLOAT);
+	ir_value   *life2  = ir_builder_create_global(b, "life2", TYPE_FLOAT);
+	ir_value   *life3  = ir_builder_create_global(b, "life3", TYPE_FLOAT);
+
 	ir_function *fmain  = NULL;
 	ir_value    *la     = NULL;
 	ir_block    *bmain  = NULL;
@@ -110,6 +116,35 @@ int main()
 	ir_value_dump_life(vig, printf);
 	ir_value_dump_life(la, printf);
 
+	ir_value_life_merge_into(retval, vig);
+	ir_value_dump_life(retval, printf);
+	ir_value_life_merge(x1, 12);
+	ir_value_life_merge(x1, 13);
+	ir_value_life_merge(x1, 14);
+	ir_value_life_merge_into(retval, x1);
+	ir_value_dump_life(retval, printf);
+	ir_value_life_merge(x1, 20);
+	ir_value_life_merge(x1, 21);
+	ir_value_life_merge(x1, 22);
+	ir_value_life_merge_into(retval, x1);
+	ir_value_dump_life(retval, printf);
+	ir_value_life_merge(x2, 1);
+	ir_value_life_merge(x2, 2);
+	ir_value_life_merge_into(retval, x2);
+	ir_value_dump_life(retval, printf);
+	for (lf = 4; lf <= 15; ++lf)
+	    ir_value_life_merge(life1, lf);
+	ir_value_life_merge_into(retval, life1);
+	ir_value_dump_life(retval, printf);
+	for (lf = 17; lf <= 18; ++lf)
+	    ir_value_life_merge(life2, lf);
+	ir_value_life_merge_into(retval, life2);
+	ir_value_dump_life(retval, printf);
+	for (lf = 2; lf <= 29; ++lf)
+	    ir_value_life_merge(life3, lf);
+	ir_value_life_merge_into(retval, life3);
+	ir_value_dump_life(retval, printf);
+
 	ir_builder_delete(b);
 	return 0;
 }
-- 
2.39.5