From c1085c290f3c142f26f46d6bb535b0757c75f427 Mon Sep 17 00:00:00 2001 From: Andreas Kloeckner Date: Wed, 21 Dec 2016 15:08:22 +0100 Subject: [PATCH 1/3] Add test for interaction of variable loop bounds with ILP [ci skip] --- test/test_loopy.py | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/test/test_loopy.py b/test/test_loopy.py index 6b6071096..6d09e0ad4 100644 --- a/test/test_loopy.py +++ b/test/test_loopy.py @@ -1995,6 +1995,31 @@ def test_integer_reduction(ctx_factory): assert function(out) +def test_ilp_modified_var_in_loop_bound(ctx_factory): + # https://github.com/inducer/loopy/issues/77 + + knl = lp.make_kernel([ + "{ [i] : 0 <= i < m }", + "{ [j] : 0 <= j < length }"], + """ + for i + <> rowstart = rowstarts[i] + <> rowend = rowstarts[i] + <> length = rowend - rowstart + y[i] = sum(j, values[rowstart+j] * x[colindices[rowstart + j]]) + end + """) + + knl = lp.add_and_infer_dtypes( + knl, { + 'values,x': np.float64, + 'rowstarts,colindices': knl.index_dtype}) + knl = lp.split_iname(knl, 'i', 2, inner_tag='ilp') + code = lp.generate_code_v2(knl).device_code() + print(code.replace("length[", "LENGTH[")) + assert 'length' not in code.replace("length[", "LENGTH[") + + if __name__ == "__main__": if len(sys.argv) > 1: exec(sys.argv[1]) -- GitLab From 5e3ef098c1a792c0fda317a0d2e2083146f25838 Mon Sep 17 00:00:00 2001 From: Andreas Kloeckner Date: Fri, 30 Dec 2016 10:18:09 -0500 Subject: [PATCH 2/3] Save up ILP rewritings so that they can be applied to loop bounds and bound-like expressions --- loopy/codegen/bounds.py | 7 +++++++ loopy/codegen/control.py | 11 +++++++---- loopy/codegen/loop.py | 12 +++++++++--- loopy/kernel/__init__.py | 10 +++++++++- loopy/transform/ilp.py | 5 ++++- loopy/version.py | 2 +- 6 files changed, 37 insertions(+), 10 deletions(-) diff --git a/loopy/codegen/bounds.py b/loopy/codegen/bounds.py index 7cc381f11..04599d119 100644 --- a/loopy/codegen/bounds.py +++ b/loopy/codegen/bounds.py @@ -27,6 +27,13 @@ import islpy as isl from islpy import dim_type +def rewrite_loop_bound_expression(kernel, expr): + for rewriter in kernel.loop_bound_expression_rewriters: + expr = rewriter(expr) + + return expr + + # {{{ approximate, convex bounds check generator def get_approximate_convex_bounds_checks(domain, check_inames, implemented_domain): diff --git a/loopy/codegen/control.py b/loopy/codegen/control.py index d206faad5..0128f1786 100644 --- a/loopy/codegen/control.py +++ b/loopy/codegen/control.py @@ -1,8 +1,6 @@ """Loop nest build top-level control/hoisting.""" -from __future__ import division -from __future__ import absolute_import -import six +from __future__ import division, absolute_import __copyright__ = "Copyright (C) 2012 Andreas Kloeckner" @@ -27,6 +25,8 @@ THE SOFTWARE. """ +import six + from loopy.codegen.result import merge_codegen_results, wrap_in_if import islpy as isl from loopy.schedule import ( @@ -464,12 +464,15 @@ def build_loop_nest(codegen_state, schedule_index): if bounds_checks or pred_checks: from loopy.symbolic import constraint_to_cond_expr + from loopy.codegen.bounds import rewrite_loop_bound_expression prev_gen_code = gen_code def gen_code(inner_codegen_state): condition_exprs = [ - constraint_to_cond_expr(cns) + rewrite_loop_bound_expression( + kernel, + constraint_to_cond_expr(cns)) for cns in bounds_checks] + [ pred_chk for pred_chk in pred_checks] diff --git a/loopy/codegen/loop.py b/loopy/codegen/loop.py index ad80475c1..e756b1ef8 100644 --- a/loopy/codegen/loop.py +++ b/loopy/codegen/loop.py @@ -349,7 +349,8 @@ def generate_sequential_loop_dim_code(codegen_state, sched_index): slabs = get_slab_decomposition(kernel, loop_iname) - from loopy.codegen.bounds import get_usable_inames_for_conditional + from loopy.codegen.bounds import ( + get_usable_inames_for_conditional, rewrite_loop_bound_expression) # Note: this does not include loop_iname itself! usable_inames = get_usable_inames_for_conditional(kernel, sched_index) @@ -451,7 +452,8 @@ def generate_sequential_loop_dim_code(codegen_state, sched_index): astb.emit_initializer( codegen_state, kernel.index_dtype, loop_iname, - ecm(pw_aff_to_expr(lbound), PREC_NONE, "i"), + ecm(rewrite_loop_bound_expression(kernel, + pw_aff_to_expr(lbound), PREC_NONE, "i")), is_const=True), astb.emit_blank_line(), inner, @@ -469,7 +471,11 @@ def generate_sequential_loop_dim_code(codegen_state, sched_index): codegen_state, astb.emit_sequential_loop( codegen_state, loop_iname, kernel.index_dtype, - pw_aff_to_expr(lbound), pw_aff_to_expr(ubound), inner_ast))) + rewrite_loop_bound_expression(kernel, + pw_aff_to_expr(lbound)), + rewrite_loop_bound_expression(kernel, + pw_aff_to_expr(ubound)), + inner_ast))) return merge_codegen_results(codegen_state, result) diff --git a/loopy/kernel/__init__.py b/loopy/kernel/__init__.py index 5dff5e53c..98a5feb83 100644 --- a/loopy/kernel/__init__.py +++ b/loopy/kernel/__init__.py @@ -147,6 +147,12 @@ class LoopKernel(ImmutableRecordWithoutPickling): .. attribute:: silenced_warnings + .. attribute:: loop_bound_expression_rewriters + + A tuple of expression mappings that need to be applied to loop bound + expressions once generated. This is necessary, for example, to + capture ILP-based rewritings of data-dependent loop bounds. + .. attribute:: applied_iname_rewrites A list of past substitution dictionaries that @@ -189,6 +195,7 @@ class LoopKernel(ImmutableRecordWithoutPickling): silenced_warnings=[], applied_iname_rewrites=[], + loop_bound_expression_rewriters=(), cache_manager=None, index_dtype=np.int32, options=None, @@ -279,7 +286,7 @@ class LoopKernel(ImmutableRecordWithoutPickling): assert all(dom.get_ctx() == isl.DEFAULT_CONTEXT for dom in domains) assert assumptions.get_ctx() == isl.DEFAULT_CONTEXT - ImmutableRecordWithoutPickling.__init__(self, + super(LoopKernel, self).__init__( domains=domains, instructions=instructions, args=args, @@ -297,6 +304,7 @@ class LoopKernel(ImmutableRecordWithoutPickling): substitutions=substitutions, cache_manager=cache_manager, applied_iname_rewrites=applied_iname_rewrites, + loop_bound_expression_rewriters=loop_bound_expression_rewriters, function_manglers=function_manglers, symbol_manglers=symbol_manglers, index_dtype=index_dtype, diff --git a/loopy/transform/ilp.py b/loopy/transform/ilp.py index 778407532..df8240ea3 100644 --- a/loopy/transform/ilp.py +++ b/loopy/transform/ilp.py @@ -170,7 +170,10 @@ def add_axes_to_temporaries_for_ilp_and_vec(kernel, iname=None): return kernel.copy( temporary_variables=new_temp_vars, - instructions=new_insns) + instructions=new_insns, + loop_bound_expression_rewriters=( + kernel.loop_bound_expression_rewriters + + (eiii,))) # }}} diff --git a/loopy/version.py b/loopy/version.py index b3505973b..fd7c66fa2 100644 --- a/loopy/version.py +++ b/loopy/version.py @@ -32,4 +32,4 @@ except ImportError: else: _islpy_version = islpy.version.VERSION_TEXT -DATA_MODEL_VERSION = "v51-islpy%s" % _islpy_version +DATA_MODEL_VERSION = "v54-islpy%s" % _islpy_version -- GitLab From c5e9c7dcc9157c0386856cfd16a8b73e1167ab17 Mon Sep 17 00:00:00 2001 From: Andreas Kloeckner Date: Fri, 30 Dec 2016 19:28:34 -0500 Subject: [PATCH 3/3] Fix rewrite_loop_bound_expression invocation --- loopy/codegen/loop.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/loopy/codegen/loop.py b/loopy/codegen/loop.py index e756b1ef8..516d83858 100644 --- a/loopy/codegen/loop.py +++ b/loopy/codegen/loop.py @@ -452,8 +452,11 @@ def generate_sequential_loop_dim_code(codegen_state, sched_index): astb.emit_initializer( codegen_state, kernel.index_dtype, loop_iname, - ecm(rewrite_loop_bound_expression(kernel, - pw_aff_to_expr(lbound), PREC_NONE, "i")), + ecm( + rewrite_loop_bound_expression( + kernel, + pw_aff_to_expr(lbound)), + PREC_NONE, "i"), is_const=True), astb.emit_blank_line(), inner, -- GitLab