From d49603cd5f2ca095ed2103c66cb3ae8da524ae57 Mon Sep 17 00:00:00 2001 From: Wolfgang Bumiller Date: Wed, 9 Apr 2014 16:26:02 +0200 Subject: [PATCH] implement bitfield-liferanges --- ast.c | 6 +- include.mk | 2 +- ir.c | 313 ++++++++++------------------------------------------- ir.h | 9 +- liveness.c | 249 ++++++++++++++++++++++++++++++++++++++++++ liveness.h | 66 +++++++++++ 6 files changed, 382 insertions(+), 263 deletions(-) create mode 100644 liveness.c create mode 100644 liveness.h diff --git a/ast.c b/ast.c index 8b3f110..f4df684 100644 --- a/ast.c +++ b/ast.c @@ -27,6 +27,7 @@ #include "gmqcc.h" #include "ast.h" #include "parser.h" +#include "liveness.h" #define ast_instantiate(T, ctx, destroyfn) \ T* self = (T*)mem_a(sizeof(T)); \ @@ -1795,7 +1796,7 @@ bool ast_generate_accessors(ast_value *self, ir_builder *ir) compile_error(ast_ctx(self), "internal error: not all array values have been generated for `%s`", self->name); return false; } - if (self->ir_values[i]->life) { + if (self->ir_values[i]->life.alive->bits) { compile_error(ast_ctx(self), "internal error: function containing `%s` already generated", self->name); return false; } @@ -1823,7 +1824,8 @@ bool ast_generate_accessors(ast_value *self, ir_builder *ir) } } for (i = 0; i < self->expression.count; ++i) { - vec_free(self->ir_values[i]->life); + ir_lifemask_clear(&self->ir_values[i]->life); + ir_lifemask_init (&self->ir_values[i]->life); } opts_set(opts.warn, WARN_USED_UNINITIALIZED, warn); return true; diff --git a/include.mk b/include.mk index 23c3fb9..8fb22a6 100644 --- a/include.mk +++ b/include.mk @@ -20,7 +20,7 @@ OPTIONAL_CFLAGS := OPTIONAL_LDFLAGS := #objects -OBJ_C = $(COMMON) main.o lexer.o parser.o code.o ast.o ir.o ftepp.o utf8.o correct.o fold.o intrin.o +OBJ_C = $(COMMON) main.o lexer.o parser.o code.o ast.o ir.o ftepp.o utf8.o correct.o fold.o intrin.o liveness.o OBJ_P = $(COMMON) pak.o OBJ_T = $(COMMON) test.o OBJ_X = $(COMMON) exec.o diff --git a/ir.c b/ir.c index ef782f9..49460d9 100644 --- a/ir.c +++ b/ir.c @@ -1117,7 +1117,7 @@ ir_value* ir_value_var(const char *name, int storetype, int vtype) self->locked = false; self->callparam = false; - self->life = NULL; + ir_lifemask_init(&self->life); return self; } @@ -1212,7 +1212,7 @@ void ir_value_delete(ir_value* self) } vec_free(self->reads); vec_free(self->writes); - vec_free(self->life); + ir_lifemask_clear(&self->life); mem_d(self); } @@ -1282,217 +1282,30 @@ bool ir_value_set_int(ir_value *self, int i) bool ir_value_lives(ir_value *self, size_t at) { - size_t i; - for (i = 0; i < vec_size(self->life); ++i) - { - ir_life_entry_t *life = &self->life[i]; - if (life->start <= at && at <= life->end) - return true; - if (life->start > at) /* since it's ordered */ - return false; - } - return false; -} - -static bool ir_value_life_insert(ir_value *self, size_t idx, ir_life_entry_t e) -{ - size_t k; - vec_push(self->life, e); - for (k = vec_size(self->life)-1; k > idx; --k) - self->life[k] = self->life[k-1]; - self->life[idx] = e; - return true; + return ir_bitlist_getbit(self->life.alive, at); } -static bool ir_value_life_merge(ir_value *self, size_t s) +GMQCC_INLINE static bool ir_value_life_merge(ir_value *self, size_t s, bool wr) { - size_t i; - const size_t vs = vec_size(self->life); - ir_life_entry_t *life = NULL; - ir_life_entry_t *before = NULL; - ir_life_entry_t new_entry; - - /* Find the first range >= s */ - for (i = 0; i < vs; ++i) - { - before = life; - life = &self->life[i]; - if (life->start > s) - break; - } - /* nothing found? append */ - if (i == vs) { - ir_life_entry_t e; - if (life && life->end+1 == s) - { - /* previous life range can be merged in */ - life->end++; - return true; - } - if (life && life->end >= s) - return false; - e.start = e.end = s; - vec_push(self->life, e); - return true; - } - /* found */ - if (before) - { - if (before->end + 1 == s && - life->start - 1 == s) - { - /* merge */ - before->end = life->end; - vec_remove(self->life, i, 1); - return true; - } - if (before->end + 1 == s) - { - /* extend before */ - before->end++; - return true; - } - /* already contained */ - if (before->end >= s) - return false; - } - /* extend */ - if (life->start - 1 == s) - { - life->start--; - return true; - } - /* insert a new entry */ - new_entry.start = new_entry.end = s; - return ir_value_life_insert(self, i, new_entry); -} - -static bool ir_value_life_merge_into(ir_value *self, const ir_value *other) -{ - size_t i, myi; - - if (!vec_size(other->life)) - return true; - - if (!vec_size(self->life)) { - size_t count = vec_size(other->life); - ir_life_entry_t *life = vec_add(self->life, count); - memcpy(life, other->life, count * sizeof(*life)); - return true; - } - - myi = 0; - for (i = 0; i < vec_size(other->life); ++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+1 >= entry->start) - { - /* starts earlier and overlaps */ - entry->start = life->start; - } - - if (life->end > entry->end && - life->start <= entry->end+1) - { - /* ends later and overlaps */ - entry->end = life->end; - } - - /* see if our change combines it with the next ranges */ - while (myi+1 < vec_size(self->life) && - 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; - vec_remove(self->life, myi+1, 1); - 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 >= vec_size(self->life)) { - vec_push(self->life, *life); - break; - } - /* otherweise check the next range */ - continue; - } - break; - } + bool was_set = ir_bitlist_getbit(self->life.alive, s); + ir_bitlist_setbit(self->life.alive, s); + if (wr) { + /* avoid pointlife issues by not marking a write-only assignment as + * dying here. + */ + if (ir_bitlist_getbit(self->life.alive, s+1)) + ir_bitlist_setbit (self->life.dies, s); + else /* still need to perform the write to cause an allocation */ + ir_bitlist_unsetbit(self->life.dies, s); } - return true; + else + ir_bitlist_unsetbit(self->life.dies, s); + return !was_set; } static bool ir_values_overlap(const ir_value *a, const 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 (!vec_size(a->life) || !vec_size(b->life)) - return false; - - la = a->life; - lb = b->life; - enda = la + vec_size(a->life); - endb = lb + vec_size(b->life); - 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->start < lb->start) - { - /* order: A B, move A forward - * check if we hit the end with A - */ - if (++la == enda) - break; - } - else /* if (lb->start < la->start) actually <= */ - { - /* order: B A, move B forward - * check if we hit the end with B - */ - if (++lb == endb) - break; - } - } - return false; + return ir_lifemask_overlaps(&a->life, &b->life); } /*********************************************************************** @@ -2143,18 +1956,13 @@ static bool function_allocator_alloc(function_allocator *alloc, ir_value *var) if (!slot) return false; - if (!ir_value_life_merge_into(slot, var)) - goto localerror; + ir_lifemask_merge(&slot->life, &var->life); vec_push(alloc->locals, slot); vec_push(alloc->sizes, vsize); vec_push(alloc->unique, var->unique_life); return true; - -localerror: - ir_value_delete(slot); - return false; } static bool ir_function_allocator_assign(ir_function *self, function_allocator *alloc, ir_value *v) @@ -2185,8 +1993,7 @@ static bool ir_function_allocator_assign(ir_function *self, function_allocator * if (ir_values_overlap(v, slot)) continue; - if (!ir_value_life_merge_into(slot, v)) - return false; + ir_lifemask_merge(&slot->life, &v->life); /* adjust size for this slot */ if (alloc->sizes[a] < ir_value_sizeof(v)) @@ -2242,7 +2049,7 @@ bool ir_function_allocate_locals(ir_function *self) for (; i < vec_size(self->locals); ++i) { v = self->locals[i]; - if (!vec_size(v->life)) + if (!vec_size(v->life.alive->bits)) continue; if (!ir_function_allocator_assign(self, (v->locked || !opt_gt ? &lockalloc : &globalloc), v)) goto error; @@ -2253,7 +2060,7 @@ bool ir_function_allocate_locals(ir_function *self) { v = self->values[i]; - if (!vec_size(v->life)) + if (!vec_size(v->life.alive->bits)) continue; /* CALL optimization: @@ -2418,7 +2225,7 @@ static bool ir_block_living_add_instr(ir_block *self, size_t eid) bool changed = false; for (i = 0; i != vs; ++i) { - if (ir_value_life_merge(self->living[i], eid)) + if (ir_value_life_merge(self->living[i], eid, false)) changed = true; } return changed; @@ -2507,14 +2314,14 @@ static bool ir_block_life_propagate(ir_block *self, bool *changed) * since this function is run multiple times. */ /* con_err( "Value only written %s\n", value->name); */ - if (ir_value_life_merge(value, instr->eid)) + if (ir_value_life_merge(value, instr->eid, true)) *changed = true; } else { /* since 'living' won't contain it * anymore, merge the value, since * (A) doesn't. */ - if (ir_value_life_merge(value, instr->eid)) + if (ir_value_life_merge(value, instr->eid, true)) *changed = true; /* Then remove */ vec_remove(self->living, idx, 1); @@ -2522,7 +2329,7 @@ static bool ir_block_life_propagate(ir_block *self, bool *changed) /* Removing a vector removes all members */ for (mem = 0; mem < 3; ++mem) { if (value->members[mem] && vec_ir_value_find(self->living, value->members[mem], &idx)) { - if (ir_value_life_merge(value->members[mem], instr->eid)) + if (ir_value_life_merge(value->members[mem], instr->eid, true)) *changed = true; vec_remove(self->living, idx, 1); } @@ -2535,7 +2342,7 @@ static bool ir_block_life_propagate(ir_block *self, bool *changed) break; } if (mem == 3 && vec_ir_value_find(self->living, value, &idx)) { - if (ir_value_life_merge(value, instr->eid)) + if (ir_value_life_merge(value, instr->eid, true)) *changed = true; vec_remove(self->living, idx, 1); } @@ -2556,9 +2363,9 @@ static bool ir_block_life_propagate(ir_block *self, bool *changed) { value = instr->_ops[2]; /* the float source will get an additional lifetime */ - if (ir_value_life_merge(value, instr->eid+1)) + if (ir_value_life_merge(value, instr->eid+1, false)) *changed = true; - if (value->memberof && ir_value_life_merge(value->memberof, instr->eid+1)) + if (value->memberof && ir_value_life_merge(value->memberof, instr->eid+1, false)) *changed = true; } @@ -2571,9 +2378,9 @@ static bool ir_block_life_propagate(ir_block *self, bool *changed) { value = instr->_ops[1]; /* the float source will get an additional lifetime */ - if (ir_value_life_merge(value, instr->eid+1)) + if (ir_value_life_merge(value, instr->eid+1, false)) *changed = true; - if (value->memberof && ir_value_life_merge(value->memberof, instr->eid+1)) + if (value->memberof && ir_value_life_merge(value->memberof, instr->eid+1, false)) *changed = true; } @@ -2652,14 +2459,28 @@ static bool ir_block_life_propagate(ir_block *self, bool *changed) return true; } +static GMQCC_INLINE size_t ir_bitlist_find_first(const ir_bitlist_t *self) +{ + size_t i, size = vec_size(self->bits); + /* FIXME: optimize? only executed when a warning is issued though... */ + for (i = 0; i != size; ++i) { + size_t bit; + for (bit = 0; bit != GMQCC_BL_BITS; ++bit) { + if (self->bits[i] & (1<params); ++i) - if (!ir_value_life_merge(self->locals[i], 0)) + if (!ir_value_life_merge(self->locals[i], 0, true)) compile_error(self->context, "internal error: failed value-life merging"); do { @@ -2681,8 +2502,9 @@ bool ir_function_calculate_liferanges(ir_function *self) continue; self->flags |= IR_FLAG_HAS_UNINITIALIZED; /* find the instruction reading from it */ + firstinstr = ir_bitlist_find_first(v->life.alive); /* used here and later at (FI) */ for (s = 0; s < vec_size(v->reads); ++s) { - if (v->reads[s]->eid == v->life[0].end) + if (v->reads[s]->eid == firstinstr) break; } if (s < vec_size(v->reads)) { @@ -2700,7 +2522,7 @@ bool ir_function_calculate_liferanges(ir_function *self) if (v->memberof) { ir_value *vec = v->memberof; for (s = 0; s < vec_size(vec->reads); ++s) { - if (vec->reads[s]->eid == v->life[0].end) + if (vec->reads[s]->eid == firstinstr) /* (FI) */ break; } if (s < vec_size(vec->reads)) { @@ -3171,7 +2993,7 @@ static bool gen_blocks_recursive(code_t *code, ir_function *func, ir_block *bloc retvalue = instr->_ops[0]; if (retvalue && retvalue->store != store_return && - (retvalue->store == store_global || vec_size(retvalue->life))) + (retvalue->store == store_global || vec_size(retvalue->life.alive->bits))) { /* not to be kept in OFS_RETURN */ if (retvalue->vtype == TYPE_FIELD && OPTS_FLAG(ADJUST_VECTOR_FIELDS)) @@ -4082,7 +3904,7 @@ void ir_function_dump(ir_function *f, char *ind, oprintf("%sliferanges:\n", ind); for (i = 0; i < vec_size(f->locals); ++i) { const char *attr = ""; - size_t l, m; + size_t m; ir_value *v = f->locals[i]; if (v->unique_life && v->locked) attr = "unique,locked "; @@ -4094,26 +3916,20 @@ void ir_function_dump(ir_function *f, char *ind, storenames[v->store], attr, (v->callparam ? "callparam " : ""), (int)v->code.local); - if (!v->life) + if (!v->life.alive->bits) oprintf("[null]"); - for (l = 0; l < vec_size(v->life); ++l) { - oprintf("[%i,%i] ", v->life[l].start, v->life[l].end); - } - oprintf("\n"); + ir_lifemask_dump(&v->life, ind, oprintf); for (m = 0; m < 3; ++m) { ir_value *vm = v->members[m]; if (!vm) continue; oprintf("%s\t%s: @%i ", ind, vm->name, (int)vm->code.local); - for (l = 0; l < vec_size(vm->life); ++l) { - oprintf("[%i,%i] ", vm->life[l].start, vm->life[l].end); - } - oprintf("\n"); + ir_lifemask_dump(&vm->life, ind, oprintf); } } for (i = 0; i < vec_size(f->values); ++i) { const char *attr = ""; - size_t l, m; + size_t m; ir_value *v = f->values[i]; if (v->unique_life && v->locked) attr = "unique,locked "; @@ -4125,11 +3941,9 @@ void ir_function_dump(ir_function *f, char *ind, storenames[v->store], attr, (v->callparam ? "callparam " : ""), (int)v->code.local); - if (!v->life) + if (!v->life.alive->bits) oprintf("[null]"); - for (l = 0; l < vec_size(v->life); ++l) { - oprintf("[%i,%i] ", v->life[l].start, v->life[l].end); - } + ir_lifemask_dump(&v->life, ind, oprintf); oprintf("\n"); for (m = 0; m < 3; ++m) { ir_value *vm = v->members[m]; @@ -4142,10 +3956,7 @@ void ir_function_dump(ir_function *f, char *ind, else if (vm->locked) attr = "locked "; oprintf("%s\t%s: %s@%i ", ind, vm->name, attr, (int)vm->code.local); - for (l = 0; l < vec_size(vm->life); ++l) { - oprintf("[%i,%i] ", vm->life[l].start, vm->life[l].end); - } - oprintf("\n"); + ir_lifemask_dump(&vm->life, ind, oprintf); } } if (vec_size(f->blocks)) @@ -4307,10 +4118,6 @@ void ir_value_dump(ir_value* v, int (*oprintf)(const char*, ...)) void ir_value_dump_life(const ir_value *self, int (*oprintf)(const char*,...)) { - size_t i; oprintf("Life of %12s:", self->name); - for (i = 0; i < vec_size(self->life); ++i) - { - oprintf(" + [%i, %i]\n", self->life[i].start, self->life[i].end); - } + ir_lifemask_dump(&self->life, " ", oprintf); } diff --git a/ir.h b/ir.h index d0fd787..7ac02d1 100644 --- a/ir.h +++ b/ir.h @@ -23,6 +23,7 @@ #ifndef GMQCC_IR_HDR #define GMQCC_IR_HDR #include "gmqcc.h" +#include "liveness.h" /* * Type large enough to hold all the possible IR flags. This should be @@ -36,12 +37,6 @@ typedef struct ir_block_s ir_block; typedef struct ir_function_s ir_function; typedef struct ir_builder_s ir_builder; -typedef struct { - /* both inclusive */ - size_t start; - size_t end; -} ir_life_entry_t; - enum { IR_FLAG_HAS_ARRAYS = 1 << 0, IR_FLAG_HAS_UNINITIALIZED = 1 << 1, @@ -99,7 +94,7 @@ struct ir_value_s { bool locked; /* temps living during a CALL must be locked */ bool callparam; - ir_life_entry_t *life; /* For the temp allocator */ + ir_lifemask_t life; /* For the temp allocator */ }; /* diff --git a/liveness.c b/liveness.c new file mode 100644 index 0000000..1f3f7d6 --- /dev/null +++ b/liveness.c @@ -0,0 +1,249 @@ +/* + * Copyright (C) 2012, 2013, 2014 + * Wolfgang Bumiller + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include + +#include "gmqcc.h" +#include "liveness.h" + +ir_bitlist_t *ir_bitlist_new() { + ir_bitlist_t *list = (ir_bitlist_t*)mem_a(sizeof(ir_bitlist_t)); + list->bits = NULL; + return list; +} + +void ir_bitlist_delete(ir_bitlist_t *self) { + if (self->bits) + vec_free(self->bits); + mem_d(self); +} + +static GMQCC_INLINE void ir_bitlist_allocindex(ir_bitlist_t *self, size_t index) { + size_t size = vec_size(self->bits); + while (size++ <= index) + vec_push(self->bits, 0); +} + +void ir_bitlist_setbit(ir_bitlist_t *self, size_t bit) { + size_t index = bit / GMQCC_BL_BITS; + ir_bitlist_allocindex(self, index); + self->bits[index] |= (1 << (bit % GMQCC_BL_BITS)); +} + +void ir_bitlist_unsetbit(ir_bitlist_t *self, size_t bit) { + size_t index = bit / GMQCC_BL_BITS; + ir_bitlist_allocindex(self, index); + self->bits[index] &= ~(1 << (bit % GMQCC_BL_BITS)); +} + +bool ir_bitlist_getbit(const ir_bitlist_t *self, size_t bit) { + size_t index = bit / GMQCC_BL_BITS; + GMQCC_BL_TYPE mask = 1 << (bit % GMQCC_BL_BITS); + if (index >= vec_size(self->bits)) + return false; + return !!(self->bits[index] & mask); +} + +void ir_bitlist_setrange(ir_bitlist_t *self, size_t from, size_t to) { + size_t index_from, bit_from, index_to, bit_to; + GMQCC_BL_TYPE mask; + + if (from > to) { + con_err("ir_bitlist_setrange: bad bits\n"); + abort(); + } + + ++to; + index_from = from / GMQCC_BL_BITS; + bit_from = from % GMQCC_BL_BITS; + index_to = to / GMQCC_BL_BITS; + bit_to = to % GMQCC_BL_BITS; + + ir_bitlist_allocindex(self, index_to); + + mask = GMQCC_BL_FULL; + + if (index_from == index_to) { + mask <<= bit_from; + mask <<= GMQCC_BL_BITS - bit_to; + mask >>= GMQCC_BL_BITS - bit_to; + self->bits[index_from] |= mask; + return; + } + + /* first chunk: */ + self->bits[index_from] |= mask << bit_from; + /* filled with all ones */ + for (++index_from; index_from != index_to; ++index_from) + self->bits[index_from] |= mask; + /* last chunk */ + mask <<= GMQCC_BL_BITS - bit_to; + mask >>= GMQCC_BL_BITS - bit_to; + self->bits[index_to] |= mask; +} + +static void ir_bitlist_dump(const ir_bitlist_t *self, + int (*oprintf)(const char*, ...)) +{ + size_t i; + size_t size = vec_size(self->bits); + if (!size) + oprintf(""); + for (i = 0; i != size; ++i) { + size_t b; + for (b = 0; b != GMQCC_BL_BITS; ++b) + oprintf( (self->bits[i] & (1UL<alive = ir_bitlist_new(); + self->dies = ir_bitlist_new(); + /*self->mask = NULL;*/ +} + +void ir_lifemask_clear(ir_lifemask_t *self) { + ir_bitlist_delete(self->alive); + ir_bitlist_delete(self->dies); + /*if (self->mask) + ir_bitlist_delete(self->mask);*/ +} + +void ir_lifemask_merge(ir_lifemask_t *self, const ir_lifemask_t *other) { + size_t i; + size_t other_alive_size = vec_size(other->alive->bits); + if (!other_alive_size) + return; + + ir_bitlist_allocindex(self->alive, other_alive_size-1); + ir_bitlist_allocindex(self->dies, other_alive_size-1); + /*if (self->mask) + ir_bitlist_allocindex(self->mask, other_alive_size-1);*/ + + for (i = 0; i != other_alive_size; ++i) { + self->alive->bits[i] |= other->alive->bits[i]; + self->dies->bits[i] &= ~self->alive->bits[i]; + self->dies->bits[i] |= ~other->alive->bits[i] & other->dies->bits[i]; + + /*if (self->mask) + self->mask->bits[i] = self->alive->bits[i] & ~self->dies->bits[i];*/ + } +} + +/* +void ir_lifemask_setmask(ir_lifemask_t *self) { + size_t i; + size_t size; + + if (!self->mask) + self->mask = ir_bitlist_new(); + + size = vec_size(self->alive->bits); + if (!size) + return; + + ir_bitlist_allocindex(self->mask, size-1); + for (i = 0; i != size; ++i) + self->mask->bits[i] = self->alive->bits[i] & ~self->dies->bits[i]; +} +*/ + +bool ir_lifemask_overlaps(const ir_lifemask_t *a, const ir_lifemask_t *b) { + size_t i; + size_t size = vec_size(a->alive->bits), + size_b = vec_size(b->alive->bits); + if (size > size_b) + size = size_b; + for (i = 0; i != size; ++i) { + GMQCC_BL_TYPE mask_a = a->alive->bits[i] & ~a->dies->bits[i]; + GMQCC_BL_TYPE mask_b = b->alive->bits[i] & ~b->dies->bits[i]; + if (mask_a & mask_b) + return true; + } + return false; +} + +void ir_lifemask_dump(const ir_lifemask_t *self, const char *ind, + int (*oprintf)(const char*, ...)) +{ + oprintf("{\n%s ", ind); + ir_bitlist_dump(self->alive, oprintf); + oprintf("%s ", ind); + ir_bitlist_dump(self->dies, oprintf); + /*oprintf("%s ", ind); + ir_bitlist_dump(self->mask, oprintf);*/ + oprintf("%s}\n", ind); +} + +#ifdef LIVETEST +#include +void test_liveness() { + con_init(); + ir_bitlist_t *bl = ir_bitlist_new(); + ir_bitlist_dump(bl); + ir_bitlist_setbit(bl, 1); + ir_bitlist_dump(bl); + ir_bitlist_setbit(bl, 2); + ir_bitlist_dump(bl); + ir_bitlist_setrange(bl, 4, 6); + ir_bitlist_dump(bl); + ir_bitlist_setrange(bl, 8, 9); + ir_bitlist_dump(bl); + ir_bitlist_setrange(bl, 15, 17); + ir_bitlist_dump(bl); + ir_bitlist_delete(bl); + + ir_lifemask_t ma, mb; + ir_lifemask_init(&ma); + ir_lifemask_init(&mb); + + ir_bitlist_setrange(ma.alive, 4, 6); + ir_bitlist_setbit(ma.dies, 4); + ir_lifemask_dump(&ma); + + ir_bitlist_setrange(mb.alive, 6, 8); + ir_bitlist_setbit(mb.dies, 6); + ir_lifemask_dump(&mb); + con_out(ir_lifemask_overlaps(&ma, &mb) ? "WRONG OVERLAP\n" : "Ok\n"); + + ir_bitlist_setrange(mb.alive, 9, 12); + ir_bitlist_setbit(mb.dies, 9); + ir_lifemask_dump(&mb); + con_out(ir_lifemask_overlaps(&ma, &mb) ? "WRONG OVERLAP\n" : "Ok\n"); + + ir_bitlist_setrange(mb.alive, 5, 7); + ir_bitlist_unsetbit(mb.dies, 6); + ir_bitlist_setbit(mb.dies, 5); + ir_lifemask_dump(&mb); + con_out(ir_lifemask_overlaps(&ma, &mb) ? "overlap\n" : "WRONG ! OVERLAPPING\n"); + + ir_lifemask_clear(&ma); + ir_lifemask_clear(&mb); +} + +int main() { + test_liveness(); + return 0; +} +#endif diff --git a/liveness.h b/liveness.h new file mode 100644 index 0000000..0b51cf6 --- /dev/null +++ b/liveness.h @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2012, 2013, 2014 + * Wolfgang Bumiller + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#ifndef GMQCC_LIVENESS_HDR +#define GMQCC_LIVENESS_HDR + +#define GMQCC_BL_BITS 8 +#define GMQCC_BL_FULL 0xF +#define GMQCC_BL_MAKETYPE1(TY) uint##TY##_t +#define GMQCC_BL_MAKETYPE(TY) GMQCC_BL_MAKETYPE1(TY) +#define GMQCC_BL_TYPE GMQCC_BL_MAKETYPE(GMQCC_BL_BITS) +typedef struct { + GMQCC_BL_TYPE *bits; /* vector */ +} ir_bitlist_t; + +ir_bitlist_t *ir_bitlist_new (void); +void ir_bitlist_delete (ir_bitlist_t*); +void ir_bitlist_setbit (ir_bitlist_t*, size_t bit); +void ir_bitlist_unsetbit(ir_bitlist_t*, size_t bit); +bool ir_bitlist_getbit (const ir_bitlist_t*, size_t bit); +/* precondition: from <= to */ +void ir_bitlist_setrange(ir_bitlist_t*, size_t from, size_t to); + +typedef struct { + /* note that the following two lists always have the same size */ + + ir_bitlist_t *alive; /* read or generally alive */ + ir_bitlist_t *dies; /* instructions which only WRITE to this value */ + + /* When a value is written to without being read from it dies. This is + * used to mask out that specific instruction before checking whether + * a value's lifetime overlaps with another's. + */ +} ir_lifemask_t; + +void ir_lifemask_init (ir_lifemask_t*); +void ir_lifemask_clear (ir_lifemask_t*); +void ir_lifemask_merge (ir_lifemask_t*, const ir_lifemask_t*); + +/*void ir_lifemask_setmask (ir_lifemask_t*);*/ +bool ir_lifemask_overlaps(const ir_lifemask_t*, const ir_lifemask_t*); + +/* debug */ +void ir_lifemask_dump(const ir_lifemask_t *self, const char *ind, + int (*oprintf)(const char*, ...)); + +#endif -- 2.39.2