diff options
Diffstat (limited to 'libbanshee/engine/setst-sort.c')
-rw-r--r-- | libbanshee/engine/setst-sort.c | 907 |
1 files changed, 907 insertions, 0 deletions
diff --git a/libbanshee/engine/setst-sort.c b/libbanshee/engine/setst-sort.c new file mode 100644 index 00000000000..5d89817ed00 --- /dev/null +++ b/libbanshee/engine/setst-sort.c @@ -0,0 +1,907 @@ +/* + * Copyright (c) 2000-2001 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#include <regions.h> +#include <assert.h> +#include <stdio.h> +#include "bounds.h" +#include "setst-sort.h" + + +struct setst_union_ +{ +#ifdef NONSPEC + sort_kind sort; +#endif + int type; + stamp st; + gen_e_list exprs; + gen_e_list proj_cache; +}; + +struct setst_inter_ +{ +#ifdef NONSPEC + sort_kind sort; +#endif + int type; + stamp st; + gen_e_list exprs; +}; + +struct setst_constant_ +{ +#ifdef NONSPEC + sort_kind sort; +#endif + int type; + stamp st; + char *name; +}; + +typedef struct setst_inter_ *setst_inter_; +typedef struct setst_union_ *setst_union_; +typedef struct setst_constant_ *setst_constant_; + +static region tlb_cache_region; +static jcoll_dict tlb_dict; +static setst_var_list setst_vars; +static bool setst_changed = FALSE; + +region setst_region; +term_hash setst_hash; +struct setst_stats setst_stats; + +stamp setst_get_stamp(gen_e e) +{ +#ifdef NONSPEC + assert(e->sort == setst_sort); +#endif + + if ( ((setst_term)e)->type == VAR_TYPE) + return st_get_stamp( (setst_var)e ); + + else + return ((setst_term)e)->st; +} + +static bool eq(gen_e e1, gen_e e2) +{ + return ( setst_get_stamp(e1) == setst_get_stamp(e2) ); +} + +static gen_e_list get_union(gen_e e) +{ + assert ( ((setst_term)e)->type == UNION_TYPE); + + return ( (setst_union_) e)->exprs; +} + +static gen_e_list get_inter(gen_e e) +{ + assert ( ((setst_term)e)->type == INTER_TYPE); + + return ( (setst_inter_) e)->exprs; +} + +static void update_lower_bound(setst_var v, gen_e e) +{ + if (setst_is_var(e)) + { + if (st_add_lb(v,(setst_var)e)) + { + setst_stats.redundant_var++; + } + else + { + setst_stats.added_var++; + setst_changed = TRUE; + } + } + else + { + if (st_add_source(v, e,setst_get_stamp(e))) + { + setst_stats.redundant_source++; + } + else + { + setst_stats.added_source++; + setst_changed = TRUE; + } + } + +} + +static void update_upper_bound(setst_var v, gen_e e) +{ + assert(! setst_is_var(e)); + + if (st_add_sink(v,e,setst_get_stamp(e))) + { + setst_stats.redundant_sink++; + } + else + { + setst_stats.added_sink++; + setst_changed = TRUE; + } +} + + +void setst_inclusion(con_match_fn_ptr con_match,gen_e e1, gen_e e2) +{ + if (eq(e1,e2)) + return; + + else if ( setst_is_zero(e1) || setst_is_one(e2) ) + return; + + else if (setst_is_union(e1)) + { + gen_e_list_scanner scan; + gen_e temp; + + gen_e_list exprs = get_union(e1); + + gen_e_list_scan(exprs,&scan); + while (gen_e_list_next(&scan,&temp)) + { + setst_inclusion(con_match,temp,e2); + } + + return; + } + + else if (setst_is_inter(e2)) + { + gen_e_list_scanner scan; + gen_e temp; + + gen_e_list exprs = get_inter(e2); + + gen_e_list_scan(exprs,&scan); + while (gen_e_list_next(&scan,&temp)) + { + setst_inclusion(con_match,e1,temp); + } + + return; + } + + else if (setst_is_var(e2)) + { + setst_var v = (setst_var)e2; + + update_lower_bound(v,e1); + } + + else if (setst_is_var(e1)) + { + setst_var v = (setst_var)e1; + + update_upper_bound(v,e2); + } + + else con_match(e1,e2); +} + +#ifdef NONSPEC +static struct setst_term zero = {ZERO_TYPE,setst_sort,ZERO_TYPE}; +static struct setst_term one = {ONE_TYPE,setst_sort,ONE_TYPE}; +#else +static struct setst_term zero = {ZERO_TYPE,ZERO_TYPE}; +static struct setst_term one = {ONE_TYPE,ONE_TYPE}; +#endif /* NONSPEC */ + +gen_e setst_zero(void) +{ + return (gen_e)&zero; +} + +gen_e setst_one(void) +{ + return (gen_e)&one; +} + +gen_e setst_fresh(const char *name) +{ + setst_var v = st_fresh(setst_region,name); + setst_var_list_cons(v,setst_vars); + return (gen_e)v; +} + +gen_e setst_fresh_large(const char *name) +{ + setst_var v = st_fresh_large(setst_region,name); + setst_var_list_cons(v,setst_vars); + return (gen_e)v; +} + +gen_e setst_fresh_small(const char *name) +{ + setst_var v = st_fresh_small(setst_region,name); + setst_var_list_cons(v,setst_vars); + return (gen_e)v; +} + +gen_e setst_constant(const char *str) deletes +{ + stamp st[2]; + gen_e result; + char *name = rstrdup(setst_region,str); + + assert (str != NULL); + + st[0] = CONSTANT_TYPE; + st[1] = stamp_string(name); + + if ( (result = term_hash_find(setst_hash,st,2)) == NULL) + { + setst_constant_ c = ralloc(setst_region, struct setst_constant_); + c->type = CONSTANT_TYPE; + c->st = stamp_fresh(); + c->name = name; + + result = (gen_e) c; + term_hash_insert(setst_hash,result,st,2); + + setst_stats.distinct_constants++; + + return result; + } + + else + { + setst_stats.hashed_constants++; + return result; + } +} + +static bool filter_zero(const gen_e e) +{ + return (!setst_is_zero(e)); +} + + +static bool filter_one(const gen_e e) +{ + return (!setst_is_one(e)); +} + +gen_e setst_union(gen_e_list exprs) deletes +{ + gen_e_list filtered = gen_e_list_filter(setst_region,exprs,filter_zero); + + if ( gen_e_list_empty(filtered) ) + { + setst_stats.filtered_unions++; + return setst_zero(); + } + else if (gen_e_list_length(filtered) == 1) + { + setst_stats.filtered_unions++; + return gen_e_list_head(filtered); + } + + else + { + int i = 0; + gen_e temp,result; + gen_e_list_scanner scan; + stamp st[ gen_e_list_length(filtered) + 1 ]; + + st[0] = UNION_TYPE; + + gen_e_list_scan(filtered,&scan); + while (gen_e_list_next(&scan,&temp)) + { + st[++i] = setst_get_stamp(temp); + } + + if ( (result = + term_hash_find(setst_hash,st,gen_e_list_length(filtered)+1)) + == NULL ) + { + struct setst_union_ *u = ralloc(setst_region,struct setst_union_); + + u->type = UNION_TYPE; + u->st = stamp_fresh(); + u->proj_cache = new_gen_e_list(setst_region); + u->exprs = filtered; + + result = (gen_e)u; + term_hash_insert(setst_hash,result,st,gen_e_list_length(filtered)+1); + + setst_stats.distinct_unions++; + return result; + } + else + { + setst_stats.hashed_unions++; + return result; + } + } +} + +gen_e setst_inter(gen_e_list exprs) deletes +{ + gen_e_list filtered = gen_e_list_filter(setst_region,exprs,filter_one); + + if ( gen_e_list_empty(filtered) ) + { + setst_stats.filtered_intersections++; + return setst_one(); + } + else if (gen_e_list_length(filtered) == 1) + { + setst_stats.filtered_intersections++; + return gen_e_list_head(filtered); + } + + else + { + int i = 0; + gen_e temp,result; + gen_e_list_scanner scan; + stamp st[ gen_e_list_length(filtered) + 1 ]; + + st[0] = INTER_TYPE; + + gen_e_list_scan(filtered,&scan); + while (gen_e_list_next(&scan,&temp)) + { + st[++i] = setst_get_stamp(temp); + } + + if ( (result = + term_hash_find(setst_hash,st,gen_e_list_length(filtered)+1)) + == NULL ) + { + struct setst_inter_ *u = ralloc(setst_region,struct setst_inter_); + + u->type = UNION_TYPE; + u->st = stamp_fresh(); + u->exprs = filtered; + + result = (gen_e)u; + term_hash_insert(setst_hash,result,st,gen_e_list_length(filtered)+1); + + setst_stats.distinct_intersections++; + + return result; + } + else + { + setst_stats.hashed_intersections++; + return result; + } + } +} + + +gen_e_list setst_get_union(gen_e e) +{ + assert (((setst_term)e)->type == UNION_TYPE); + + return ((setst_union_)e)->exprs; +} + + +gen_e_list setst_get_inter(gen_e e) +{ + assert (((setst_term)e)->type == INTER_TYPE); + + return ((setst_inter_)e)->exprs; +} + +static void invalidate_tlb_cache(void) +{ + assert(tlb_cache_region); + + jcoll_delete_dict(tlb_dict); + setst_var_list_app(setst_vars,st_clear_tlb_cache); + deleteregion_ptr(&tlb_cache_region); + + tlb_cache_region = newregion(); + tlb_dict = jcoll_create_dict(tlb_cache_region,setst_get_stamp); +} + +static void set_tlb_cache(setst_var v,jcoll j) +{ + st_set_tlb_cache(v,j); +} + +static void collect_sinks(bounds b,setst_var v) +{ + gen_e sink; + gen_e_list_scanner scan; + + gen_e_list_scan(st_get_sinks(v),&scan); + + while (gen_e_list_next(&scan,&sink)) + { + bounds_add(b,sink,setst_get_stamp(sink)); + } +} + +static void collect_sources(bounds b, setst_var v) +{ + gen_e source; + gen_e_list_scanner scan; + + gen_e_list_scan(st_get_sources(v),&scan); + + while (gen_e_list_next(&scan,&source)) + { + bounds_add(b,source,setst_get_stamp(source)); + } +} + +static void collect_lower_bounds(bounds b, setst_var v) +{ + setst_var lb; + setst_var_list_scanner scan; + + setst_var_list_scan(st_get_lbs(v),&scan); + + while (setst_var_list_next(&scan,&lb)) + { + bounds_add(b,(gen_e)lb,st_get_stamp(lb)); + } +} + +static void apply_sources(setst_var witness, bounds sources) +{ + gen_e source; + gen_e_list_scanner scan; + + gen_e_list_scan(bounds_exprs(sources),&scan); + + while (gen_e_list_next(&scan,&source)) + { + if ( st_add_source(witness,source,setst_get_stamp(source))) + setst_stats.redundant_source++; + + else + setst_stats.added_source++; + } +} + +static void apply_sinks(setst_var witness, bounds sinks) +{ + gen_e sink; + gen_e_list_scanner scan; + + gen_e_list_scan(bounds_exprs(sinks),&scan); + + while (gen_e_list_next(&scan,&sink)) + { + if (st_add_sink(witness,sink,setst_get_stamp(sink))) + setst_stats.redundant_sink++; + + else + setst_stats.added_sink++; + } +} + +static void apply_lower_bounds(setst_var witness,bounds lower) +{ + gen_e lb; + gen_e_list_scanner scan; + + gen_e_list_scan(bounds_exprs(lower),&scan); + + while (gen_e_list_next(&scan,&lb)) + { + if (st_add_lb(witness,(setst_var)lb)) + setst_stats.redundant_var++; + else + setst_stats.added_var++; + } +} + +static void collapse_cycle(setst_var witness, setst_var_list cycle) deletes +{ + setst_var_list_scanner var_scan; + setst_var temp; + region scratch_rgn = newregion(); + + bounds sources = bounds_create(scratch_rgn); + bounds sinks = bounds_create(scratch_rgn); + bounds lower = bounds_create(scratch_rgn); + + + setst_stats.cycles_collapsed++; + + /* force at least another iteration */ + setst_changed = TRUE; + + /* collect all bounds */ + setst_var_list_scan(cycle,&var_scan); + while (setst_var_list_next(&var_scan,&temp)) + { + collect_sources(sources,temp); + collect_sinks(sinks,temp); + collect_lower_bounds(lower,temp); + } + + /* unify all vars */ + st_unify(witness,cycle); + + /* add all bounds back */ + apply_sources(witness,sources); + apply_sinks(witness,sinks); + apply_lower_bounds(witness,lower); + + /* cleanup */ + bounds_delete(sources); + bounds_delete(sinks); + bounds_delete(lower); + deleteregion(scratch_rgn); + + /* remove self edges */ + st_repair_bounds(witness); +} +/* +static bool cycle_detect(setst_var goal, setst_var_list path, + setst_var_list *result) +{ + int pos = st_get_path_pos(goal); + setst_stats.cycles_searched++; + + if (pos) + { + setst_var_list_scanner scan; + setst_var temp; + setst_var_list cycle = new_setst_var_list(tlb_cache_region); + + setst_var_list_scan(path,&scan); + while(setst_var_list_next(&scan,&temp)) + { + if (st_get_path_pos(temp) >= pos) + setst_var_list_cons(temp,cycle); + } + + *result = cycle; + return TRUE; + } + + else + return FALSE; +} + +*/ +static bool cycle_detect(setst_var goal, setst_var_list path, + setst_var_list *result) +{ + setst_var_list cycle = + setst_var_list_reverse(setst_var_list_copy(tlb_cache_region,path)); + + setst_stats.cycles_searched++; + + while (!setst_var_list_empty(cycle) && + !eq((gen_e)setst_var_list_head(cycle),(gen_e)goal)) + { + setst_var_list_tail(cycle); + } + + if (setst_var_list_empty(cycle)) + { + return FALSE; + } + else + { + *result = cycle; + return TRUE; + } +} + +static jcoll tlb_aux(gen_e e,int path_len,setst_var_list path) deletes +{ + if (setst_is_var(e)) + { + setst_var_list cycle; + setst_var v = (setst_var)e; + if ( cycle_detect(v,path,&cycle) ) + { + setst_stats.cycles_length += setst_var_list_length(cycle); + collapse_cycle(v,cycle); + return NULL; + } + else + { + if (st_get_tlb_cache(v) != NULL) + return st_get_tlb_cache(v); + else + { + jcoll result; + setst_var_list_scanner scan; + setst_var lb; + jcoll_list jvars = new_jcoll_list(tlb_cache_region); + + gen_e_list sources = gen_e_list_copy(tlb_cache_region, + st_get_sources(v)); + + st_set_path_pos(v,path_len); + setst_var_list_scan(st_get_lbs(v),&scan); + while (setst_var_list_next(&scan,&lb)) + { + setst_var_list_cons(v,path); + jcoll_list_cons(tlb_aux((gen_e)lb,++path_len,path), + jvars); + setst_var_list_tail(path); + } + + if (! gen_e_list_empty(sources)) + jcoll_list_cons(jcoll_create_chain(tlb_dict,sources), + jvars); + result = jcoll_jjoin(tlb_dict,jvars); + set_tlb_cache(v,result); + st_set_path_pos(v,0); + return result; + } + + } + } + else if (setst_is_union(e)) + { + gen_e_list_scanner scan; + gen_e temp; + jcoll_list jexprs = new_jcoll_list(tlb_cache_region); + + gen_e_list_scan(setst_get_union(e),&scan); + while (gen_e_list_next(&scan,&temp)) + { + jcoll_list_cons(tlb_aux(temp,++path_len,path),jexprs); + } + + return jcoll_jjoin(tlb_dict,jexprs); + } + else + { + fail("Unmatched case in setst tlb computation\n"); + return NULL; + } +} +static gen_e_list tlb(gen_e e) +{ + return jcoll_flatten(tlb_dict, + tlb_aux(e,1,new_setst_var_list(tlb_cache_region)) ); +} +static void match_sinks(incl_fn_ptr setst_incl) +{ + gen_e_list_scanner tlb_scanner, sink_scanner; + setst_var_list_scanner var_scanner; + setst_var v; + gen_e lb, sink; + + setst_var_list_scan(setst_vars,&var_scanner); + + while (setst_var_list_next(&var_scanner,&v)) + { + gen_e_list tlbs = tlb((gen_e)v); + gen_e_list snks = st_get_sinks(v); + + + if(gen_e_list_empty(st_get_sinks(v))) + { + setst_stats.no_sinks++; + continue; + } + else if(st_get_seen(v)) + { + setst_stats.incycle_vars++; + continue; + } + else if (gen_e_list_length(tlbs) == st_get_src_sz(v) + && gen_e_list_length(snks) == st_get_snk_sz(v) ) + { + setst_stats.unchanged_vars++; + continue; + } + st_set_seen(v,TRUE); + + st_set_src_sz(v,gen_e_list_length(tlbs)); + st_set_snk_sz(v,gen_e_list_length(snks)); + + gen_e_list_scan(tlbs,&tlb_scanner); + + while (gen_e_list_next(&tlb_scanner,&lb)) + { + gen_e_list_scan(snks,&sink_scanner); + + while (gen_e_list_next(&sink_scanner,&sink)) + setst_incl(lb,sink); + } + } +} +static void iterate(incl_fn_ptr setst_incl) +{ + setst_var_list_scanner var_scanner; + setst_var v; + /* static int iterations = 0; */ + setst_changed = FALSE; + + setst_var_list_scan(setst_vars,&var_scanner); + while (setst_var_list_next(&var_scanner,&v)) + { + st_set_seen(v,FALSE); + } + + invalidate_tlb_cache(); + match_sinks(setst_incl); + + /* fprintf(stderr,"Iterations : %d\n",++iterations); */ + + if (setst_changed) + iterate(setst_incl); +} +gen_e_list setst_tlb(gen_e e,incl_fn_ptr setst_incl) deletes +{ + if (! setst_changed) + { + return tlb(e); + } + else + { + iterate(setst_incl); + return tlb(e); + } + +} + +void setst_set_proj_cache(gen_e e, gen_e elem) +{ + if (setst_is_union(e)) + { + setst_union_ u = (setst_union_)e; + gen_e_list_cons(elem,u->proj_cache); + } +} + +gen_e_list setst_get_proj_cache(gen_e e) +{ + + if (setst_is_union(e)) + { + setst_union_ u = (setst_union_)e; + return u->proj_cache; + } + else + { + fail("Term does not cache projections\n"); + return NULL; + } +} + +void setst_init(void) +{ + setst_region = newregion(); + tlb_cache_region = newregion(); + setst_hash = make_term_hash(setst_region); + setst_vars = new_setst_var_list(setst_region); + tlb_dict = jcoll_create_dict(tlb_cache_region,setst_get_stamp); +} + +void setst_reset(void) deletes +{ + term_hash_delete(setst_hash); + deleteregion_ptr(&setst_region); + + setst_region = newregion(); + setst_hash = make_term_hash(setst_region); + setst_vars = new_setst_var_list(setst_region); + invalidate_tlb_cache(); + setst_changed = FALSE; +} + +bool setst_is_zero(gen_e e) +{ + return ((setst_term)e)->type == ZERO_TYPE; +} + +bool setst_is_one(gen_e e) +{ + return ((setst_term)e)->type == ONE_TYPE; +} + +bool setst_is_var(gen_e e) +{ + return ((setst_term)e)->type == VAR_TYPE; +} + +bool setst_is_union(gen_e e) +{ + return ((setst_term)e)->type == UNION_TYPE; +} + +bool setst_is_inter(gen_e e) +{ + return ((setst_term)e)->type == INTER_TYPE; +} + +char *setst_get_constant_name(gen_e e) +{ + assert( ((setst_term)e)->type == CONSTANT_TYPE ); + + return ((setst_constant_)e)->name; +} + +void setst_print_stats(FILE *f) +{ + fprintf(f,"\n========== SetST Var Stats ==========\n"); + fprintf(f,"Fresh : %d\n",setst_stats.fresh); + fprintf(f,"Fresh Small : %d\n",setst_stats.fresh_small); + fprintf(f,"Fresh Large : %d\n",setst_stats.fresh_large); + fprintf(f,"Total : %d\n",setst_stats.fresh + setst_stats.fresh_small + + setst_stats.fresh_large); + fprintf(f,"\n========== SetST Sort Stats ==========\n"); + fprintf(f,"\n"); + fprintf(f,"\n------------------------------\n"); + fprintf(f,"Additions"); + fprintf(f,"\n------------------------------\n"); + fprintf(f,"Var: %d\n",setst_stats.added_var); + fprintf(f,"Source: %d\n",setst_stats.added_source); + fprintf(f,"Sink: %d",setst_stats.added_sink); + fprintf(f,"\n------------------------------\n"); + fprintf(f,"Total: %d",setst_stats.added_var + setst_stats.added_source + + setst_stats.added_sink); + fprintf(f,"\n"); + fprintf(f,"\n------------------------------\n"); + fprintf(f,"Redundant"); + fprintf(f,"\n------------------------------\n"); + fprintf(f,"Var: %d\n",setst_stats.redundant_var); + fprintf(f,"Source: %d\n",setst_stats.redundant_source); + fprintf(f,"Sink: %d",setst_stats.redundant_sink); + fprintf(f,"\n------------------------------\n"); + fprintf(f,"Total: %d\n", + setst_stats.redundant_var + setst_stats.redundant_source + + setst_stats.redundant_sink); + + fprintf(f,"\n"); + fprintf(f,"\n------------------------------\n"); + fprintf(f,"Iteration Optimizations"); + fprintf(f,"\n------------------------------\n"); + fprintf(f,"Skipped vars: %d\n",setst_stats.incycle_vars); + fprintf(f,"Unchanged vars: %d\n",setst_stats.unchanged_vars); + fprintf(f,"Vars w/o sinks: %d\n",setst_stats.no_sinks); + fprintf(f,"\n------------------------------\n"); + fprintf(f,"Cycles"); + fprintf(f,"\n------------------------------\n"); + fprintf(f,"Collapsed: %d\n",setst_stats.cycles_collapsed); + fprintf(f,"Searched: %d\n",setst_stats.cycles_searched); + fprintf(f,"Hit rate: %f\n", + ((float)setst_stats.cycles_collapsed)/((float)setst_stats.cycles_searched)); + fprintf(f,"Average Length: %f\n", + ((float)setst_stats.cycles_length) / ((float)setst_stats.cycles_collapsed)); + fprintf(f,"=====================================\n"); +} + |