6de9cd9a88
From-SVN: r81764
1142 lines
26 KiB
C
1142 lines
26 KiB
C
/*
|
|
* Copyright (c) 2000-2004
|
|
* 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 <assert.h>
|
|
#include <setjmp.h>
|
|
#include "regions.h"
|
|
#include "bounds.h"
|
|
#include "jcollection.h"
|
|
#include "setif-sort.h"
|
|
#include "util.h"
|
|
|
|
bool flag_eliminate_cycles = TRUE;
|
|
bool flag_merge_projections = TRUE;
|
|
|
|
struct setif_union_ /* extends gen_e */
|
|
{
|
|
#ifdef NONSPEC
|
|
sort_kind sort;
|
|
#endif
|
|
int type;
|
|
stamp st;
|
|
gen_e_list exprs;
|
|
gen_e_list proj_cache;
|
|
};
|
|
|
|
struct setif_inter_ /* extends gen_e */
|
|
{
|
|
#ifdef NONSPEC
|
|
sort_kind sort;
|
|
#endif
|
|
int type;
|
|
stamp st;
|
|
gen_e_list exprs;
|
|
};
|
|
|
|
struct setif_constant_ /* extends gen_e */
|
|
{
|
|
#ifdef NONSPEC
|
|
sort_kind sort;
|
|
#endif
|
|
int type;
|
|
stamp st;
|
|
char *name;
|
|
};
|
|
|
|
typedef struct setif_inter_ *setif_inter_;
|
|
typedef struct setif_union_ *setif_union_;
|
|
typedef struct setif_constant_ *setif_constant_;
|
|
|
|
static setif_var_list setif_vars;
|
|
static region tlb_cache_region;
|
|
static setif_var_list tlb_var_cache;
|
|
static jcoll_dict tlb_dict;
|
|
|
|
|
|
region setif_region;
|
|
term_hash setif_hash;
|
|
struct setif_stats setif_stats;
|
|
|
|
stamp setif_get_stamp(gen_e e)
|
|
{
|
|
#ifdef NONSPEC
|
|
assert(e->sort == setif_sort);
|
|
#endif
|
|
|
|
if ( ((setif_term)e)->type == VAR_TYPE)
|
|
return sv_get_stamp( (setif_var)e );
|
|
|
|
else
|
|
return ((setif_term)e)->st;
|
|
}
|
|
|
|
static void tlv_lower_aux(jmp_buf buf,stamp st, gen_e e)
|
|
{
|
|
if ( setif_is_var(e) && (setif_get_stamp(e) > st) )
|
|
longjmp(buf,1);
|
|
|
|
else if (setif_is_union(e))
|
|
{
|
|
gen_e temp;
|
|
gen_e_list exprs = ((setif_union_)e)->exprs;
|
|
gen_e_list_scanner scan;
|
|
|
|
gen_e_list_scan(exprs,&scan);
|
|
while (gen_e_list_next(&scan,&temp))
|
|
tlv_lower_aux(buf,st,temp);
|
|
}
|
|
}
|
|
|
|
static bool tlv_lower(stamp st, gen_e e)
|
|
{
|
|
jmp_buf buf;
|
|
int higher;
|
|
|
|
higher = setjmp(buf);
|
|
if (higher)
|
|
return FALSE;
|
|
|
|
tlv_lower_aux(buf,st,e);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static void invalidate_tlb_cache(void) deletes
|
|
{
|
|
assert(tlb_cache_region);
|
|
|
|
setif_var_list_app(tlb_var_cache,sv_clear_tlb_cache);
|
|
jcoll_delete_dict(tlb_dict);
|
|
deleteregion_ptr(&tlb_cache_region);
|
|
|
|
tlb_cache_region = newregion();
|
|
tlb_dict = jcoll_create_dict(tlb_cache_region,setif_get_stamp);
|
|
tlb_var_cache = new_setif_var_list(tlb_cache_region);
|
|
}
|
|
|
|
static void set_tlb_cache(setif_var v, jcoll j)
|
|
{
|
|
setif_var_list_cons(v,tlb_var_cache);
|
|
sv_set_tlb_cache(v,j);
|
|
}
|
|
|
|
/*
|
|
A constraint e1 <= e2 is l-inductive iff e2 is a variable x and
|
|
for each y in tlv(e1), stamp(y) < stamp(x)
|
|
*/
|
|
static bool l_inductive(gen_e e1, gen_e e2)
|
|
{
|
|
if (setif_is_var(e2) && tlv_lower(setif_get_stamp(e2), e1))
|
|
return TRUE;
|
|
|
|
else return FALSE;
|
|
}
|
|
|
|
/*
|
|
A constraint e1 <= e2 is r-inductive iff e1 is a variable x and
|
|
for each y in tlv(e2), stamp(y) < stamp(x)
|
|
*/
|
|
static bool r_inductive(gen_e e1, gen_e e2)
|
|
{
|
|
if (setif_is_var(e1) && tlv_lower(setif_get_stamp(e1), e2))
|
|
return TRUE;
|
|
|
|
else return FALSE;
|
|
}
|
|
|
|
static bool eq(gen_e e1, gen_e e2)
|
|
{
|
|
return ( setif_get_stamp(e1) == setif_get_stamp(e2) );
|
|
}
|
|
|
|
gen_e_list setif_get_union(gen_e e)
|
|
{
|
|
assert ( ((setif_term)e)->type == UNION_TYPE);
|
|
|
|
return ( (setif_union_) e)->exprs;
|
|
}
|
|
|
|
gen_e_list setif_get_inter(gen_e e)
|
|
{
|
|
assert ( ((setif_term)e)->type == INTER_TYPE);
|
|
|
|
return ( (setif_inter_) e)->exprs;
|
|
}
|
|
|
|
static setif_var_list search_ubs(region r, setif_var v1, setif_var goal)
|
|
{
|
|
bool found = FALSE;
|
|
setif_var_list cycle;
|
|
|
|
static void search_ubs_aux(setif_var v)
|
|
{
|
|
assert(! found);
|
|
|
|
if (sv_eq (v, goal))
|
|
{
|
|
found = TRUE;
|
|
return;
|
|
}
|
|
else if (sv_lt(v,goal))
|
|
{
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
gen_e_list_scanner scan;
|
|
gen_e ub;
|
|
gen_e_list ubs = sv_get_ubs(v);
|
|
|
|
gen_e_list_scan(ubs,&scan);
|
|
while (gen_e_list_next(&scan,&ub))
|
|
{
|
|
if (setif_is_var(ub))
|
|
{
|
|
search_ubs_aux((setif_var)ub);
|
|
if (found)
|
|
{
|
|
setif_var_list_cons(v,cycle);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
found = FALSE;
|
|
cycle = new_setif_var_list(r);
|
|
search_ubs_aux(v1);
|
|
|
|
return cycle;
|
|
}
|
|
|
|
static setif_var_list search_lbs(region r, setif_var v1, setif_var goal)
|
|
{
|
|
bool found;
|
|
setif_var_list cycle;
|
|
|
|
static void search_lbs_aux(setif_var v)
|
|
{
|
|
assert (! found);
|
|
if (sv_eq(v,goal))
|
|
{
|
|
found = TRUE;
|
|
return;
|
|
}
|
|
else if (sv_lt(v,goal))
|
|
{
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
gen_e_list_scanner scan;
|
|
gen_e lb;
|
|
gen_e_list lbs = sv_get_lbs(v);
|
|
|
|
gen_e_list_scan(lbs,&scan);
|
|
while (gen_e_list_next(&scan,&lb))
|
|
{
|
|
if (setif_is_var(lb))
|
|
{
|
|
search_lbs_aux((setif_var)lb);
|
|
if (found)
|
|
{
|
|
setif_var_list_cons(v,cycle);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
found = FALSE;
|
|
cycle = new_setif_var_list(r);
|
|
search_lbs_aux(v1);
|
|
|
|
return cycle;
|
|
}
|
|
|
|
static setif_var_list cycle_detect(region r,setif_var v1,setif_var v2)
|
|
{
|
|
if (sv_union_component(v1,v2))
|
|
return new_setif_var_list(r);
|
|
|
|
else
|
|
{
|
|
setif_stats.cycles_searched_forward++;
|
|
return search_ubs(r, v2, v1);
|
|
}
|
|
}
|
|
|
|
|
|
static setif_var_list cycle_detect_rev(region r, setif_var v1, setif_var v2)
|
|
{
|
|
if (sv_union_component(v1,v2))
|
|
return new_setif_var_list(r);
|
|
|
|
else
|
|
{
|
|
setif_stats.cycles_searched_backward++;
|
|
return search_lbs(r, v1, v2);
|
|
}
|
|
}
|
|
|
|
void setif_inclusion(con_match_fn_ptr con_match, res_proj_fn_ptr res_proj,
|
|
gen_e e1, gen_e e2) deletes
|
|
{
|
|
|
|
static void collapse_cycle_lower(region r, setif_var witness,
|
|
setif_var_list cycle) deletes
|
|
{
|
|
gen_e lb;
|
|
gen_e_list_scanner scan_bounds;
|
|
setif_var_list_scanner scan_cycle;
|
|
setif_var var;
|
|
|
|
#ifndef NDEBUG
|
|
stamp lowest = sv_get_stamp(witness);
|
|
#endif
|
|
bounds b = bounds_create(r);
|
|
|
|
/* Collect all lower bounds in the cycle, and add transitive edges */
|
|
setif_var_list_scan(cycle,&scan_cycle);
|
|
while(setif_var_list_next(&scan_cycle,&var))
|
|
{
|
|
assert( sv_get_stamp(var) > lowest);
|
|
gen_e_list_scan(sv_get_lbs(var),&scan_bounds);
|
|
while(gen_e_list_next(&scan_bounds,&lb))
|
|
bounds_add(b,lb,setif_get_stamp(lb));
|
|
}
|
|
|
|
sv_unify(witness,cycle);
|
|
assert(sv_get_stamp(witness) == lowest);
|
|
|
|
gen_e_list_scan(bounds_exprs(b),&scan_bounds);
|
|
while (gen_e_list_next(&scan_bounds,&lb))
|
|
setif_inclusion(con_match,res_proj,lb, (gen_e) witness);
|
|
|
|
bounds_delete(b);
|
|
invalidate_tlb_cache();
|
|
|
|
setif_stats.cycles_collapsed_backward++;
|
|
setif_stats.cycles_length_backward += setif_var_list_length(cycle);
|
|
}
|
|
|
|
static void collapse_cycle_upper(region r, setif_var witness,
|
|
setif_var_list cycle) deletes
|
|
{
|
|
gen_e ub;
|
|
gen_e_list_scanner scan_bounds;
|
|
setif_var_list_scanner scan_cycle;
|
|
setif_var var;
|
|
|
|
#ifndef NDEBUG
|
|
stamp lowest = sv_get_stamp(witness);
|
|
#endif
|
|
bounds b = bounds_create(r);
|
|
|
|
/* Collect all upper bounds in the cycle, and add transitive edges */
|
|
setif_var_list_scan(cycle,&scan_cycle);
|
|
while(setif_var_list_next(&scan_cycle,&var))
|
|
{
|
|
assert( sv_get_stamp(var) > lowest);
|
|
|
|
gen_e_list_scan(sv_get_ubs(var),&scan_bounds);
|
|
while(gen_e_list_next(&scan_bounds,&ub))
|
|
bounds_add(b,ub,setif_get_stamp(ub));
|
|
|
|
gen_e_list_scan(sv_get_ub_projs(var),&scan_bounds);
|
|
while(gen_e_list_next(&scan_bounds,&ub))
|
|
bounds_add(b,ub,setif_get_stamp(ub));
|
|
}
|
|
|
|
sv_unify(witness,cycle);
|
|
assert(sv_get_stamp(witness) == lowest);
|
|
|
|
gen_e_list_scan(bounds_exprs(b),&scan_bounds);
|
|
while (gen_e_list_next(&scan_bounds,&ub))
|
|
setif_inclusion(con_match,res_proj,(gen_e) witness, ub);
|
|
|
|
bounds_delete(b);
|
|
invalidate_tlb_cache();
|
|
|
|
setif_stats.cycles_collapsed_forward++;
|
|
setif_stats.cycles_length_backward += setif_var_list_length(cycle);
|
|
}
|
|
|
|
static void update_lower_bound(setif_var v, gen_e e) deletes
|
|
{
|
|
if (sv_add_lb(v,e,setif_get_stamp(e)))
|
|
{
|
|
if (setif_is_var(e))
|
|
setif_stats.redundant_succ++;
|
|
|
|
else
|
|
setif_stats.redundant_source++;
|
|
}
|
|
|
|
else
|
|
{
|
|
gen_e_list_scanner scan;
|
|
gen_e ub;
|
|
|
|
if (setif_is_var(e))
|
|
setif_stats.added_succ++;
|
|
else
|
|
setif_stats.added_source++;
|
|
|
|
invalidate_tlb_cache();
|
|
|
|
gen_e_list_scan(sv_get_ubs(v),&scan);
|
|
while(gen_e_list_next(&scan,&ub))
|
|
setif_inclusion(con_match,res_proj,e,ub);
|
|
|
|
gen_e_list_scan(sv_get_ub_projs(v),&scan);
|
|
while (gen_e_list_next(&scan,&ub))
|
|
setif_inclusion(con_match,res_proj,e,ub);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
static void update_upper_bound(setif_var v, gen_e e) deletes
|
|
{
|
|
if (sv_add_ub(v,e,setif_get_stamp(e)))
|
|
{
|
|
if (setif_is_var(e))
|
|
setif_stats.redundant_pred++;
|
|
|
|
else
|
|
setif_stats.redundant_sink++;
|
|
}
|
|
|
|
else
|
|
{
|
|
gen_e_list_scanner scan;
|
|
gen_e lb;
|
|
|
|
if (setif_is_var(e))
|
|
setif_stats.added_pred++;
|
|
else
|
|
setif_stats.added_sink++;
|
|
|
|
invalidate_tlb_cache();
|
|
|
|
gen_e_list_scan(sv_get_lbs(v),&scan);
|
|
while (gen_e_list_next(&scan,&lb))
|
|
setif_inclusion(con_match,res_proj,lb,e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
if (eq(e1,e2))
|
|
return;
|
|
|
|
else if ( setif_is_zero(e1) || setif_is_one(e2) )
|
|
return;
|
|
|
|
/* c <= d */
|
|
else if ( setif_is_constant(e1) && setif_is_constant(e2) )
|
|
{
|
|
|
|
failure("Inconsistent system of constraints\n");
|
|
return;
|
|
}
|
|
|
|
else if ( setif_is_union(e1) )
|
|
{
|
|
gen_e_list_scanner scan;
|
|
gen_e temp;
|
|
|
|
gen_e_list exprs = setif_get_union(e1);
|
|
|
|
gen_e_list_scan(exprs,&scan);
|
|
while (gen_e_list_next(&scan,&temp))
|
|
{
|
|
setif_inclusion(con_match,res_proj,temp,e2);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
else if ( setif_is_inter(e2) )
|
|
{
|
|
gen_e_list_scanner scan;
|
|
gen_e temp;
|
|
|
|
gen_e_list exprs = setif_get_inter(e2);
|
|
|
|
gen_e_list_scan(exprs,&scan);
|
|
while (gen_e_list_next(&scan,&temp))
|
|
{
|
|
setif_inclusion(con_match,res_proj,e1,temp);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
else if ( l_inductive(e1,e2) ) /* _ <= 'x */
|
|
{
|
|
setif_var v2 = ((setif_var)e2);
|
|
|
|
if (setif_is_var(e1))
|
|
{
|
|
setif_var v1 = ((setif_var)e1);
|
|
|
|
if (flag_eliminate_cycles)
|
|
{
|
|
region scratch = newregion();
|
|
setif_var_list cycle = cycle_detect(scratch,v1,v2);
|
|
|
|
if (! setif_var_list_empty(cycle))
|
|
collapse_cycle_upper(scratch,v1,cycle);
|
|
else
|
|
update_lower_bound(v2,e1);
|
|
|
|
deleteregion(scratch);
|
|
}
|
|
|
|
else
|
|
update_lower_bound(v2,e1);
|
|
}
|
|
else /* e1 is a source */
|
|
update_lower_bound(v2,e1);
|
|
}
|
|
|
|
else if ( r_inductive(e1,e2) ) /* 'x <= _ */
|
|
{
|
|
setif_var v1 = ((setif_var)e1);
|
|
|
|
if (setif_is_var(e2))
|
|
{
|
|
setif_var v2 = ((setif_var)e2);
|
|
|
|
if (flag_eliminate_cycles)
|
|
{
|
|
region scratch = newregion();
|
|
setif_var_list cycle = cycle_detect_rev(scratch,v1,v2);
|
|
|
|
if (! setif_var_list_empty(cycle))
|
|
collapse_cycle_lower(scratch,v2,cycle);
|
|
else
|
|
update_upper_bound(v1,e2);
|
|
|
|
deleteregion(scratch);
|
|
}
|
|
|
|
else
|
|
update_upper_bound(v1,e2);
|
|
}
|
|
else /* e2 is a sink */
|
|
{
|
|
if (flag_merge_projections && res_proj(v1,e2))
|
|
return;
|
|
else
|
|
update_upper_bound(v1,e2);
|
|
}
|
|
}
|
|
|
|
else /* c(...) <= c(...) or c(...) <= projpat(c,i,e) */
|
|
{
|
|
con_match(e1,e2);
|
|
return;
|
|
}
|
|
|
|
}
|
|
|
|
#ifdef NONSPEC
|
|
static struct setif_term zero = {setif_sort,ZERO_TYPE,ZERO_TYPE};
|
|
static struct setif_term one = {setif_sort,ONE_TYPE,ONE_TYPE};
|
|
#else
|
|
static struct setif_term zero = {ZERO_TYPE,ZERO_TYPE};
|
|
static struct setif_term one = {ONE_TYPE,ONE_TYPE};
|
|
#endif /* NONSPEC */
|
|
|
|
gen_e setif_zero(void)
|
|
{
|
|
return (gen_e)&zero;
|
|
}
|
|
|
|
gen_e setif_one(void)
|
|
{
|
|
return (gen_e)&one;
|
|
}
|
|
|
|
gen_e setif_fresh(const char *name)
|
|
{
|
|
setif_var result = sv_fresh(setif_region,name);
|
|
setif_var_list_cons(result,setif_vars);
|
|
|
|
setif_stats.fresh++;
|
|
return (gen_e)result;
|
|
}
|
|
|
|
gen_e setif_fresh_large(const char *name)
|
|
{
|
|
setif_var result = sv_fresh_large(setif_region,name);
|
|
setif_var_list_cons(result,setif_vars);
|
|
|
|
setif_stats.fresh_large++;
|
|
return (gen_e)result;
|
|
}
|
|
|
|
gen_e setif_fresh_small(const char *name)
|
|
{
|
|
setif_var result = sv_fresh_small(setif_region,name);
|
|
setif_var_list_cons(result,setif_vars);
|
|
|
|
setif_stats.fresh_small++;
|
|
return (gen_e)result;
|
|
}
|
|
|
|
gen_e setif_constant(const char *str) deletes
|
|
{
|
|
stamp st[2];
|
|
gen_e result;
|
|
char *name = rstrdup(setif_region,str);
|
|
|
|
assert (str != NULL);
|
|
|
|
st[0] = CONSTANT_TYPE;
|
|
st[1] = stamp_string(name);
|
|
|
|
if ( (result = term_hash_find(setif_hash,st,2)) == NULL)
|
|
{
|
|
setif_constant_ c = ralloc(setif_region, struct setif_constant_);
|
|
#ifdef NONSPEC
|
|
c->sort = setif_sort;
|
|
#endif
|
|
c->type = CONSTANT_TYPE;
|
|
c->st = stamp_fresh();
|
|
c->name = name;
|
|
|
|
result = (gen_e) c;
|
|
term_hash_insert(setif_hash,result,st,2);
|
|
|
|
setif_stats.distinct_constants++;
|
|
|
|
return result;
|
|
}
|
|
|
|
else
|
|
{
|
|
setif_stats.hashed_constants++;
|
|
return result;
|
|
}
|
|
}
|
|
|
|
static bool filter_zero(const gen_e e)
|
|
{
|
|
return (!setif_is_zero(e));
|
|
}
|
|
|
|
|
|
static bool filter_one(const gen_e e)
|
|
{
|
|
return (!setif_is_one(e));
|
|
}
|
|
|
|
gen_e setif_union(gen_e_list exprs) deletes
|
|
{
|
|
gen_e_list filtered = gen_e_list_filter(setif_region,exprs,filter_zero);
|
|
|
|
if ( gen_e_list_empty(filtered) )
|
|
{
|
|
setif_stats.filtered_unions++;
|
|
return setif_zero();
|
|
}
|
|
else if (gen_e_list_length(filtered) == 1)
|
|
{
|
|
setif_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] = setif_get_stamp(temp);
|
|
}
|
|
|
|
if ( (result =
|
|
term_hash_find(setif_hash,st,gen_e_list_length(filtered)+1))
|
|
== NULL )
|
|
{
|
|
struct setif_union_ *u = ralloc(setif_region,struct setif_union_);
|
|
|
|
u->type = UNION_TYPE;
|
|
u->st = stamp_fresh();
|
|
u->proj_cache = new_gen_e_list(setif_region);
|
|
u->exprs = filtered;
|
|
|
|
result = (gen_e)u;
|
|
term_hash_insert(setif_hash,result,st,gen_e_list_length(filtered)+1);
|
|
|
|
setif_stats.distinct_unions++;
|
|
return result;
|
|
}
|
|
else
|
|
{
|
|
setif_stats.hashed_unions++;
|
|
return result;
|
|
}
|
|
}
|
|
}
|
|
|
|
gen_e setif_inter(gen_e_list exprs) deletes
|
|
{
|
|
gen_e_list filtered = gen_e_list_filter(setif_region,exprs,filter_one);
|
|
|
|
if ( gen_e_list_empty(filtered) )
|
|
{
|
|
setif_stats.filtered_intersections++;
|
|
return setif_one();
|
|
}
|
|
else if (gen_e_list_length(filtered) == 1)
|
|
{
|
|
setif_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] = setif_get_stamp(temp);
|
|
}
|
|
|
|
if ( (result =
|
|
term_hash_find(setif_hash,st,gen_e_list_length(filtered)+1))
|
|
== NULL )
|
|
{
|
|
struct setif_inter_ *u = ralloc(setif_region,struct setif_inter_);
|
|
|
|
u->type = UNION_TYPE;
|
|
u->st = stamp_fresh();
|
|
u->exprs = filtered;
|
|
|
|
result = (gen_e)u;
|
|
term_hash_insert(setif_hash,result,st,gen_e_list_length(filtered)+1);
|
|
|
|
setif_stats.distinct_intersections++;
|
|
|
|
return result;
|
|
}
|
|
else
|
|
{
|
|
setif_stats.hashed_intersections++;
|
|
return result;
|
|
}
|
|
}
|
|
}
|
|
|
|
bool setif_is_zero(gen_e e)
|
|
{
|
|
return ((setif_term)e)->type == ZERO_TYPE;
|
|
}
|
|
|
|
bool setif_is_one(gen_e e)
|
|
{
|
|
return ((setif_term)e)->type == ONE_TYPE;
|
|
}
|
|
|
|
bool setif_is_var(gen_e e)
|
|
{
|
|
return ((setif_term)e)->type == VAR_TYPE;
|
|
}
|
|
|
|
bool setif_is_union(gen_e e)
|
|
{
|
|
return ((setif_term)e)->type == UNION_TYPE;
|
|
}
|
|
|
|
bool setif_is_inter(gen_e e)
|
|
{
|
|
return ((setif_term)e)->type == INTER_TYPE;
|
|
}
|
|
|
|
bool setif_is_constant(gen_e e)
|
|
{
|
|
return ((setif_term)e)->type == CONSTANT_TYPE;
|
|
}
|
|
|
|
char *setif_get_constant_name(gen_e e)
|
|
{
|
|
assert( ((setif_term)e)->type == CONSTANT_TYPE );
|
|
|
|
return ((setif_constant_)e)->name;
|
|
}
|
|
|
|
void setif_init(void)
|
|
{
|
|
setif_region = newregion();
|
|
tlb_cache_region = newregion();
|
|
setif_vars = new_setif_var_list(setif_region);
|
|
tlb_var_cache = new_setif_var_list(tlb_cache_region);
|
|
setif_hash = make_term_hash(setif_region);
|
|
tlb_dict = jcoll_create_dict(tlb_cache_region,setif_get_stamp);
|
|
}
|
|
|
|
|
|
|
|
static void setif_reset_stats(void)
|
|
{
|
|
setif_stats.fresh = 0;
|
|
setif_stats.fresh_small = 0;
|
|
setif_stats.fresh_large = 0;
|
|
|
|
setif_stats.distinct_constructors = 0;
|
|
setif_stats.hashed_constructors = 0;
|
|
setif_stats.distinct_constants = 0;
|
|
setif_stats.hashed_constants = 0;
|
|
setif_stats.distinct_unions = 0;
|
|
setif_stats.filtered_unions = 0;
|
|
setif_stats.hashed_unions = 0;
|
|
setif_stats.distinct_intersections = 0;
|
|
setif_stats.filtered_intersections = 0;
|
|
setif_stats.hashed_intersections = 0;
|
|
|
|
setif_stats.redundant_pred = 0;
|
|
setif_stats.redundant_succ = 0;
|
|
setif_stats.redundant_source = 0;
|
|
setif_stats.redundant_sink = 0;
|
|
|
|
setif_stats.added_pred = 0;
|
|
setif_stats.added_succ = 0;
|
|
setif_stats.added_source = 0;
|
|
setif_stats.added_sink = 0;
|
|
|
|
setif_stats.cycles_searched_forward = 0;
|
|
setif_stats.cycles_searched_backward = 0;
|
|
|
|
setif_stats.cycles_collapsed_forward = 0;
|
|
setif_stats.cycles_collapsed_backward = 0;
|
|
|
|
setif_stats.cycles_length_forward = 0;
|
|
setif_stats.cycles_length_backward = 0;
|
|
}
|
|
|
|
void setif_reset(void) deletes
|
|
{
|
|
term_hash_delete(setif_hash);
|
|
invalidate_tlb_cache();
|
|
deleteregion_ptr(&setif_region);
|
|
deleteregion_ptr(&tlb_cache_region);
|
|
|
|
setif_reset_stats();
|
|
|
|
setif_region = newregion();
|
|
tlb_cache_region = newregion();
|
|
setif_vars = new_setif_var_list(setif_region);
|
|
tlb_var_cache = new_setif_var_list(tlb_cache_region);
|
|
setif_hash = make_term_hash(setif_region);
|
|
}
|
|
|
|
static jcoll tlb_aux(gen_e e)
|
|
{
|
|
if (setif_is_var(e))
|
|
{
|
|
setif_var v = (setif_var)e;
|
|
|
|
if ( sv_get_tlb_cache(v) != NULL)
|
|
return sv_get_tlb_cache(v);
|
|
|
|
else
|
|
{
|
|
jcoll result;
|
|
gen_e_list sources = new_gen_e_list(tlb_cache_region);
|
|
jcoll_list jvars = new_jcoll_list(tlb_cache_region);
|
|
gen_e_list_scanner scan;
|
|
gen_e lb;
|
|
|
|
gen_e_list_scan(sv_get_lbs(v),&scan);
|
|
while (gen_e_list_next(&scan,&lb))
|
|
{
|
|
if (setif_is_var(lb))
|
|
jcoll_list_cons(tlb_aux(lb),jvars);
|
|
else
|
|
gen_e_list_cons(lb,sources);
|
|
/* jsources = jcoll_jcons(tlb_cache_region,lb,jsources); */
|
|
}
|
|
|
|
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);
|
|
return result;
|
|
}
|
|
}
|
|
else if (setif_is_union(e))
|
|
{
|
|
gen_e_list_scanner scan;
|
|
gen_e temp;
|
|
jcoll_list jexprs = new_jcoll_list(tlb_cache_region);
|
|
|
|
gen_e_list_scan(setif_get_union(e),&scan);
|
|
while (gen_e_list_next(&scan,&temp))
|
|
{
|
|
jcoll_list_cons(tlb_aux(temp),jexprs);
|
|
}
|
|
|
|
return jcoll_jjoin(tlb_dict,jexprs);
|
|
|
|
}
|
|
else
|
|
{
|
|
failure("Unmatched case in setif tlb computation\n");
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
gen_e_list setif_tlb(gen_e e) deletes
|
|
{
|
|
return jcoll_flatten(tlb_dict,tlb_aux(e));
|
|
}
|
|
|
|
void setif_set_proj_cache(gen_e e,gen_e elem)
|
|
{
|
|
if (setif_is_union(e))
|
|
{
|
|
setif_union_ u = (setif_union_)e;
|
|
gen_e_list_cons(elem,u->proj_cache);
|
|
}
|
|
}
|
|
|
|
gen_e_list setif_get_proj_cache(gen_e e)
|
|
{
|
|
if (setif_is_union(e))
|
|
{
|
|
setif_union_ u = (setif_union_)e;
|
|
return u->proj_cache;
|
|
}
|
|
else
|
|
{
|
|
failure("Term does not cache projections\n");
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
|
|
bool setif_proj_merge(setif_var v, gen_e se, get_proj_fn_ptr get_proj,
|
|
proj_con_fn_ptr proj_con,fresh_large_fn_ptr fresh_large,
|
|
incl_fn_ptr sort_incl, incl_fn_ptr set_incl) deletes
|
|
{
|
|
gen_e proj;
|
|
|
|
if ((proj = sv_get_ub_proj(v,get_proj)) != NULL)
|
|
{
|
|
sort_incl(proj, se);
|
|
return TRUE;
|
|
}
|
|
|
|
else
|
|
{
|
|
gen_e_list_scanner scan;
|
|
gen_e lb;
|
|
|
|
gen_e proj_var;
|
|
gen_e proj_cons;
|
|
|
|
/* create a projection variable for this projection */
|
|
proj_var = fresh_large(NULL);
|
|
|
|
assert(setif_is_var(proj_var));
|
|
|
|
proj_cons = proj_con(proj_var);
|
|
|
|
sv_add_ub_proj(v, proj_cons);
|
|
|
|
/* apply the transitive rule to each of v's lower bounds */
|
|
gen_e_list_scan(sv_get_lbs(v),&scan);
|
|
while (gen_e_list_next(&scan,&lb))
|
|
{
|
|
set_incl(lb,proj_cons);
|
|
}
|
|
|
|
sort_incl(proj_var, se);
|
|
return TRUE;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
void setif_print_stats(FILE *f)
|
|
{
|
|
fprintf(f,"\n========== SetIF Var Stats ==========\n");
|
|
fprintf(f,"Fresh : %d\n",setif_stats.fresh);
|
|
fprintf(f,"Fresh Small : %d\n",setif_stats.fresh_small);
|
|
fprintf(f,"Fresh Large : %d\n",setif_stats.fresh_large);
|
|
fprintf(f,"Total : %d\n",setif_stats.fresh + setif_stats.fresh_small
|
|
+ setif_stats.fresh_large);
|
|
fprintf(f,"\n========== SetIF Sort Stats ==========\n");
|
|
fprintf(f,"\n");
|
|
fprintf(f,"\n------------------------------\n");
|
|
fprintf(f,"Additions");
|
|
fprintf(f,"\n------------------------------\n");
|
|
fprintf(f,"Pred: %d\n",setif_stats.added_pred);
|
|
fprintf(f,"Succ: %d\n",setif_stats.added_succ);
|
|
fprintf(f,"Source: %d\n",setif_stats.added_source);
|
|
fprintf(f,"Sink: %d",setif_stats.added_sink);
|
|
fprintf(f,"\n------------------------------\n");
|
|
fprintf(f,"Total: %d",setif_stats.added_pred + setif_stats.added_succ
|
|
+ setif_stats.added_source + setif_stats.added_sink);
|
|
fprintf(f,"\n");
|
|
fprintf(f,"\n------------------------------\n");
|
|
fprintf(f,"Redundant");
|
|
fprintf(f,"\n------------------------------\n");
|
|
fprintf(f,"Pred: %d\n",setif_stats.redundant_pred);
|
|
fprintf(f,"Succ: %d\n",setif_stats.redundant_succ);
|
|
fprintf(f,"Source: %d\n",setif_stats.redundant_source);
|
|
fprintf(f,"Sink: %d",setif_stats.redundant_sink);
|
|
fprintf(f,"\n------------------------------\n");
|
|
fprintf(f,"Total: %d\n",
|
|
setif_stats.redundant_pred+setif_stats.redundant_succ+setif_stats.redundant_source+setif_stats.redundant_sink);
|
|
|
|
fprintf(f,"\n");
|
|
|
|
fprintf(f,"\n------------------------------\n");
|
|
fprintf(f,"Forward Cycles");
|
|
fprintf(f,"\n------------------------------\n");
|
|
fprintf(f,"Collapsed: %d\n",setif_stats.cycles_collapsed_forward);
|
|
fprintf(f,"Searched: %d\n",setif_stats.cycles_searched_forward);
|
|
fprintf(f,"Hit rate: %f\n",
|
|
((float)setif_stats.cycles_collapsed_forward)/((float)setif_stats.cycles_searched_forward));
|
|
fprintf(f,"Average Length: %f\n",
|
|
1+((float)setif_stats.cycles_length_forward) / ((float)setif_stats.cycles_collapsed_forward));
|
|
fprintf(f,"\n");
|
|
fprintf(f,"\n------------------------------\n");
|
|
fprintf(f,"Reverse Cycles");
|
|
fprintf(f,"\n------------------------------\n");
|
|
fprintf(f,"Collapsed: %d\n",setif_stats.cycles_collapsed_backward);
|
|
fprintf(f,"Searched: %d\n",setif_stats.cycles_searched_backward);
|
|
fprintf(f,"Hit rate: %f\n",
|
|
((float)setif_stats.cycles_collapsed_backward)/((float)setif_stats.cycles_searched_backward));
|
|
fprintf(f,"Average Length: %f\n",
|
|
1+((float)setif_stats.cycles_length_backward) / ((float)setif_stats.cycles_collapsed_backward));
|
|
fprintf(f,"=====================================\n");
|
|
}
|
|
|
|
/*
|
|
for now, print stamps and types for sources and sinks.
|
|
must eventually rely on specialized code
|
|
*/
|
|
void setif_print_constraint_graph(FILE *f)
|
|
{
|
|
setif_var_list_scanner scan;
|
|
gen_e_list_scanner scan_edges;
|
|
gen_e edge;
|
|
setif_var v;
|
|
dot_node n1,n2;
|
|
char temp_str[512];
|
|
|
|
graph_attr graph_style[3] = {{g_size,"\"8.5,11\""},
|
|
{g_center,"true"},
|
|
{g_orientation,"portrait"}};
|
|
edge_attr succ_edge[1] = {{e_style,"solid"}};
|
|
edge_attr pred_edge[1] = {{e_style,"dotted"}};
|
|
|
|
dot_start(f,"setif",TRUE,TRUE);
|
|
dot_global_graph_style(graph_style,3);
|
|
|
|
setif_var_list_scan(setif_vars,&scan);
|
|
while(setif_var_list_next(&scan,&v))
|
|
{
|
|
snprintf(temp_str,512,"%s:%ld",sv_get_name(v),sv_get_stamp(v));
|
|
n1 = dot_get_node(temp_str);
|
|
gen_e_list_scan(sv_get_lbs(v),&scan_edges);
|
|
while(gen_e_list_next(&scan_edges,&edge))
|
|
{
|
|
if (setif_is_var(edge))
|
|
{
|
|
snprintf(temp_str,512,"%s:%ld",sv_get_name((setif_var)edge),
|
|
setif_get_stamp(edge));
|
|
n2 = dot_get_node(temp_str);
|
|
}
|
|
else
|
|
{
|
|
snprintf(temp_str,512,"source:%ld",setif_get_stamp(edge));
|
|
n2 = dot_get_node(temp_str);
|
|
}
|
|
dot_styled_edge(n2,n1,pred_edge,1);
|
|
}
|
|
|
|
gen_e_list_scan(sv_get_ubs(v),&scan_edges);
|
|
while(gen_e_list_next(&scan_edges,&edge))
|
|
{
|
|
if (setif_is_var(edge))
|
|
{
|
|
snprintf(temp_str,512,"%s:%ld",sv_get_name((setif_var)edge),
|
|
setif_get_stamp(edge));
|
|
n2 = dot_get_node(temp_str);
|
|
}
|
|
else
|
|
{
|
|
snprintf(temp_str,512,"sink:%ld",setif_get_stamp(edge));
|
|
n2 = dot_get_node(temp_str);
|
|
}
|
|
dot_styled_edge(n1,n2,succ_edge,1);
|
|
}
|
|
|
|
gen_e_list_scan(sv_get_ub_projs(v),&scan_edges);
|
|
while(gen_e_list_next(&scan_edges,&edge))
|
|
{
|
|
snprintf(temp_str,512,"projpat:%ld",setif_get_stamp(edge));
|
|
n2 = dot_get_node(temp_str);
|
|
dot_styled_edge(n1,n2,succ_edge,1);
|
|
}
|
|
|
|
}
|
|
|
|
dot_end();
|
|
}
|
|
|