def function_limit_bound (fname, split): p = functions[fname].as_problem (problem.Problem) p.do_loop_analysis (skipInnerLoopCheck = True) [p_split] = [n for n in p.loop_heads () if split in p.loop_body (n)] splits = [n for n in p.loop_body (p_split) if p.loop_splittables[n]] # doesn't cover a really odd case, but I think it's good enough for n in splits: if p.nodes[n].kind == 'Call': if function_limit (p.nodes[n].fname) != None: return (function_limit (p.nodes[n].fname), 'FunctionLimit') return None
def function_limit_bound(fname, split): p = functions[fname].as_problem(problem.Problem) p.do_analysis() cuts = [n for n in p.loop_body(split) if p.nodes[n].kind == "Call" if function_limit(p.nodes[n].fname) != None] if not cuts: return None graph = p.mk_node_graph(p.loop_body(split)) # it is not possible to iterate the loop without visiting a bounded # function. naively, this sets the limit to the sum of all the possible # bounds, plus one because we can enter the loop a final time without # visiting any function call site yet. if logic.divides_loop(graph, set(cuts)): fnames = set([p.nodes[n].fname for n in cuts]) return (sum([function_limit(f) for f in fnames]) + 1, "FunctionLimit")
def function_limit_bound(fname, split): p = functions[fname].as_problem(problem.Problem) p.do_analysis() cuts = [ n for n in p.loop_body(split) if p.nodes[n].kind == 'Call' if function_limit(p.nodes[n].fname) != None ] if not cuts: return None graph = p.mk_node_graph(p.loop_body(split)) # it is not possible to iterate the loop without visiting a bounded # function. naively, this sets the limit to the sum of all the possible # bounds, plus one because we can enter the loop a final time without # visiting any function call site yet. if logic.divides_loop(graph, set(cuts)): fnames = set([p.nodes[n].fname for n in cuts]) return (sum([function_limit(f) for f in fnames]) + 1, 'FunctionLimit')
def get_bound_super_ctxt_inner(split, call_ctxt, no_splitting=(False, None)): first_f = trace_refute.identify_function([], (call_ctxt + [split])[:1]) call_sites = all_call_sites(first_f) if function_limit(first_f) == 0: return (0, "FunctionLimit") safe_call_sites = [cs for cs in call_sites if ctxt_within_function_limits([cs] + call_ctxt)] if call_sites and not safe_call_sites: return (0, "FunctionLimit") if len(call_ctxt) < 3 and len(safe_call_sites) == 1: call_ctxt2 = list(safe_call_sites) + call_ctxt if call_ctxt_computable(split, call_ctxt2): return get_bound_super_ctxt(split, call_ctxt2) fname = trace_refute.identify_function(call_ctxt, [split]) bound = function_limit_bound(fname, split) if bound: return bound bound = get_bound_ctxt(split, call_ctxt) if bound: return bound if no_splitting[0]: assert no_splitting[1], no_splitting no_splitting[1][0] = True return None # try to split over potential call sites if len(call_ctxt) >= 3: return None if len(call_sites) == 0: # either entry point or nonsense return None if [call_site for call_site in safe_call_sites if not call_ctxt_computable(split, [call_site] + call_ctxt)]: return None anc_bounds = [ get_bound_super_ctxt(split, [call_site] + call_ctxt, no_splitting=True) for call_site in safe_call_sites ] if None in anc_bounds: return None (bound, kind) = max(anc_bounds) return (bound, "MergedBound")
def get_bound_super_ctxt_inner(split, call_ctxt, no_splitting=(False, None)): first_f = trace_refute.identify_function([], (call_ctxt + [split])[:1]) call_sites = all_call_sites(first_f) if function_limit(first_f) == 0: return (0, 'FunctionLimit') safe_call_sites = [ cs for cs in call_sites if ctxt_within_function_limits([cs] + call_ctxt) ] if call_sites and not safe_call_sites: return (0, 'FunctionLimit') if len(call_ctxt) < 3 and len(safe_call_sites) == 1: call_ctxt2 = list(safe_call_sites) + call_ctxt if call_ctxt_computable(split, call_ctxt2): trace('using unique calling context %s' % str((split, call_ctxt2))) return get_bound_super_ctxt(split, call_ctxt2) fname = trace_refute.identify_function(call_ctxt, [split]) bound = function_limit_bound(fname, split) if bound: return bound bound = get_bound_ctxt(split, call_ctxt) if bound: return bound trace('no bound found immediately.') if no_splitting[0]: assert no_splitting[1], no_splitting no_splitting[1][0] = True trace('cannot split by context (recursion).') return None # try to split over potential call sites if len(call_ctxt) >= 3: trace('cannot split by context (context depth).') return None if len(call_sites) == 0: # either entry point or nonsense trace('cannot split by context (reached top level).') return None problem_sites = [ call_site for call_site in safe_call_sites if not call_ctxt_computable(split, [call_site] + call_ctxt) ] if problem_sites: trace('cannot split by context (issues in %s).' % problem_sites) return None anc_bounds = [ get_bound_super_ctxt(split, [call_site] + call_ctxt, no_splitting=True) for call_site in safe_call_sites ] if None in anc_bounds: return None (bound, kind) = max(anc_bounds) return (bound, 'MergedBound')