gcc/libbanshee/engine/setst-sort.c

908 lines
20 KiB
C

/*
* 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");
}