From f0c17f3a7b105c9e6c32b9c2a46a641e76d2d80c Mon Sep 17 00:00:00 2001 From: arghdos Date: Wed, 19 Oct 2016 10:31:08 -0400 Subject: [PATCH 01/14] ilp in loopy.transform, not loopy. --- loopy/transform/ilp.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/loopy/transform/ilp.py b/loopy/transform/ilp.py index f3b7d3f0e..778407532 100644 --- a/loopy/transform/ilp.py +++ b/loopy/transform/ilp.py @@ -193,7 +193,7 @@ def realize_ilp(kernel, iname): on a per-iname basis (so that, for instance, data layout of the duplicated storage can be controlled explicitly. """ - from loopy.ilp import add_axes_to_temporaries_for_ilp_and_vec + from loopy.transform.ilp import add_axes_to_temporaries_for_ilp_and_vec return add_axes_to_temporaries_for_ilp_and_vec(kernel, iname) # }}} -- GitLab From a7b53abb6b2040aee7f21ed595636a4df37e53c5 Mon Sep 17 00:00:00 2001 From: arghdos Date: Thu, 20 Oct 2016 10:23:40 -0400 Subject: [PATCH 02/14] add unroll / conditional test --- test/test_loopy.py | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/test/test_loopy.py b/test/test_loopy.py index d6907ed22..869d3b2d3 100644 --- a/test/test_loopy.py +++ b/test/test_loopy.py @@ -1436,6 +1436,28 @@ def test_ilp_and_conditionals(ctx_factory): lp.auto_test_vs_ref(ref_knl, ctx, knl) +def test_unr_and_conditionals(ctx_factory): + ctx = ctx_factory() + + knl = lp.make_kernel('{[k]: 0<=k Tcond[k] = T[k] < 0.5 + if Tcond[k] + cp[k] = 2 * T[k] + Tcond[k] + end + end + """) + + knl = lp.fix_parameters(knl, n=200) + knl = lp.add_and_infer_dtypes(knl, {"T": np.float32}) + + ref_knl = knl + + knl = lp.split_iname(knl, 'k', 2, inner_tag='unr') + + lp.auto_test_vs_ref(ref_knl, ctx, knl) + if __name__ == "__main__": if len(sys.argv) > 1: -- GitLab From c88e1685257b7471f0667cfef7d1706cd84d3228 Mon Sep 17 00:00:00 2001 From: Andreas Kloeckner Date: Tue, 15 Nov 2016 18:41:44 -0600 Subject: [PATCH 03/14] Add elif/else --- loopy/kernel/creation.py | 82 ++++++++++++++++++++++++++++++++++++++-- test/test_loopy.py | 32 +++++++++++++++- 2 files changed, 110 insertions(+), 4 deletions(-) diff --git a/loopy/kernel/creation.py b/loopy/kernel/creation.py index ab3035be0..744700502 100644 --- a/loopy/kernel/creation.py +++ b/loopy/kernel/creation.py @@ -270,7 +270,26 @@ def parse_insn_options(opt_dict, options_str, assignee_names=None): opt_value.split(":")) elif opt_key == "if" and opt_value is not None: - result["predicates"] = intern_frozenset_of_ids(opt_value.split(":")) + predicates = opt_value.split(":") + new_predicates = set() + + for pred in predicates: + from pymbolic.primitives import LogicalNot + from loopy.symbolic import parse + if pred.startswith("!"): + from warnings import warn + warn("predicates starting with '!' are deprecated. " + "Simply use 'not' instead") + pred = LogicalNot(parse(pred[1:])) + else: + pred = parse(pred) + + new_predicates.add(pred) + + result["predicates"] = frozenset(new_predicates) + + del predicates + del new_predicates elif opt_key == "tags" and opt_value is not None: result["tags"] = frozenset( @@ -330,9 +349,17 @@ FOR_RE = re.compile( IF_RE = re.compile( "^" "\s*if\s+" - "(?P(?:not\s+)?\w+(?:\[[ ,\w\d]+\])?)" + "(?P.+)" + "\s*$") + +ELIF_RE = re.compile( + "^" + "\s*elif\s+" + "(?P.+)" "\s*$") +ELSE_RE = re.compile("^\s*else\s*$") + INSN_RE = re.compile( "^" "\s*" @@ -579,7 +606,8 @@ def parse_instructions(instructions, defines): new_instructions.append( insn.copy( id=intern(insn.id) if isinstance(insn.id, str) else insn.id, - depends_on=frozenset(intern_if_str(dep) for dep in insn.depends_on), + depends_on=frozenset(intern_if_str(dep) + for dep in insn.depends_on), groups=frozenset(intern(grp) for grp in insn.groups), conflicts_with_groups=frozenset( intern(grp) for grp in insn.conflicts_with_groups), @@ -751,12 +779,60 @@ def parse_instructions(instructions, defines): if not predicate: raise LoopyError("'if' without predicate encountered") + from loopy.symbolic import parse + predicate = parse(predicate) + options["predicates"] = ( options.get("predicates", frozenset()) | frozenset([predicate])) insn_options_stack.append(options) del options + del predicate + continue + + elif_match = ELIF_RE.match(insn) + else_match = ELSE_RE.match(insn) + if elif_match is not None or else_match is not None: + prev_predicates = insn_options_stack[-1].get( + "predicates", frozenset()) + insn_options_stack.pop() + + outer_predicates = insn_options_stack[-1].get( + "predicates", frozenset()) + last_if_predicates = prev_predicates - outer_predicates + + if elif_match is not None: + predicate = elif_match.group("predicate") + if not predicate: + raise LoopyError("'elif' without predicate encountered") + from loopy.symbolic import parse + predicate = parse(predicate) + + additional_preds = frozenset([predicate]) + del predicate + + else: + assert else_match is not None + additional_preds = frozenset() + + options = insn_options_stack[-1].copy() + + from pymbolic.primitives import LogicalNot + options["predicates"] = ( + options.get("predicates", frozenset()) + | outer_predicates + | frozenset( + LogicalNot(pred) for pred in last_if_predicates) + | additional_preds + ) + + insn_options_stack.append(options) + + del options + del additional_preds + del last_if_predicates + continue if insn == "end": diff --git a/test/test_loopy.py b/test/test_loopy.py index 347c08d0d..0eba70940 100644 --- a/test/test_loopy.py +++ b/test/test_loopy.py @@ -1601,6 +1601,36 @@ def test_scalars_with_base_storage(ctx_factory): knl(queue, out_host=True) +def test_if_else(ctx_factory): + ctx = ctx_factory() + queue = cl.CommandQueue(ctx) + + knl = lp.make_kernel( + "{ [i]: 0<=i<50}", + """ + if i % 3 == 0 + a[i] = 15 + elif i % 3 == 1 + a[i] = 11 + else + a[i] = 3 + end + """ + ) + print(knl) + + knl = lp.set_options(knl, write_cl=True) + + evt, (out,) = knl(queue, out_host=True) + + out_ref = np.empty(50) + out_ref[::3] = 15 + out_ref[1::3] = 11 + out_ref[2::3] = 3 + + assert np.array_equal(out_ref, out) + + if __name__ == "__main__": if len(sys.argv) > 1: exec(sys.argv[1]) @@ -1608,4 +1638,4 @@ if __name__ == "__main__": from py.test.cmdline import main main([__file__]) -# vim: foldmethod=marker \ No newline at end of file +# vim: foldmethod=marker -- GitLab From d4efe54e42881db813f93d4f69cbac9d97bde442 Mon Sep 17 00:00:00 2001 From: arghdos Date: Wed, 23 Nov 2016 18:44:07 -0500 Subject: [PATCH 04/14] support for multiple if / elif / else's --- loopy/kernel/creation.py | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/loopy/kernel/creation.py b/loopy/kernel/creation.py index 744700502..2d50a2676 100644 --- a/loopy/kernel/creation.py +++ b/loopy/kernel/creation.py @@ -691,6 +691,7 @@ def parse_instructions(instructions, defines): # {{{ pass 4: parsing insn_options_stack = [get_default_insn_options_dict()] + if_predicates_stack = [{'predicates' : frozenset()}] for insn in instructions: if isinstance(insn, InstructionBase): @@ -787,6 +788,7 @@ def parse_instructions(instructions, defines): | frozenset([predicate])) insn_options_stack.append(options) + if_predicates_stack.append(options) del options del predicate continue @@ -796,11 +798,15 @@ def parse_instructions(instructions, defines): if elif_match is not None or else_match is not None: prev_predicates = insn_options_stack[-1].get( "predicates", frozenset()) + last_if_predicates = if_predicates_stack[-1].get( + "predicates", frozenset()) insn_options_stack.pop() + if_predicates_stack.pop() outer_predicates = insn_options_stack[-1].get( "predicates", frozenset()) - last_if_predicates = prev_predicates - outer_predicates + last_if_predicates = last_if_predicates - outer_predicates + if elif_match is not None: predicate = elif_match.group("predicate") @@ -814,20 +820,26 @@ def parse_instructions(instructions, defines): else: assert else_match is not None + if not last_if_predicates: + raise LoopyError("'else' without 'if'/'elif' encountered") additional_preds = frozenset() options = insn_options_stack[-1].copy() + if_options = insn_options_stack[-1].copy() from pymbolic.primitives import LogicalNot options["predicates"] = ( options.get("predicates", frozenset()) | outer_predicates + | prev_predicates - last_if_predicates | frozenset( LogicalNot(pred) for pred in last_if_predicates) | additional_preds ) + if_options["predicates"] = additional_preds insn_options_stack.append(options) + if_predicates_stack.append(if_options) del options del additional_preds -- GitLab From 35bba45b3a2b872055672957b05d0a1d1330e6ba Mon Sep 17 00:00:00 2001 From: arghdos Date: Wed, 23 Nov 2016 18:47:40 -0500 Subject: [PATCH 05/14] fixup test --- test/test_loopy.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/test/test_loopy.py b/test/test_loopy.py index 654548fce..20d4950ef 100644 --- a/test/test_loopy.py +++ b/test/test_loopy.py @@ -1647,9 +1647,6 @@ def test_if_else(ctx_factory): end """ ) - print(knl) - - knl = lp.set_options(knl, write_cl=True) evt, (out,) = knl(queue, out_host=True) -- GitLab From cf16f0160cd83af2380143d960fc508aa3ac35eb Mon Sep 17 00:00:00 2001 From: arghdos Date: Wed, 23 Nov 2016 18:51:14 -0500 Subject: [PATCH 06/14] add else / elif to documentation --- doc/ref_kernel.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/ref_kernel.rst b/doc/ref_kernel.rst index 97d71f3e0..2d754dec2 100644 --- a/doc/ref_kernel.rst +++ b/doc/ref_kernel.rst @@ -292,6 +292,8 @@ Loopy's expressions are a slight superset of the expressions supported by :mod:`pymbolic`. * ``if`` +* ``elif`` (following an ``if``) +* ``else`` (following an ``if`` / ``elif``) * ``reductions`` * duplication of reduction inames * ``reduce`` vs ``simul_reduce`` -- GitLab From 8e8bd1d096a970cfd79dc1ee3432f5d5df790fb3 Mon Sep 17 00:00:00 2001 From: arghdos Date: Wed, 23 Nov 2016 19:29:57 -0500 Subject: [PATCH 07/14] add test for outer predicates --- test/test_loopy.py | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/test/test_loopy.py b/test/test_loopy.py index 20d4950ef..7208ee502 100644 --- a/test/test_loopy.py +++ b/test/test_loopy.py @@ -1657,6 +1657,33 @@ def test_if_else(ctx_factory): assert np.array_equal(out_ref, out) + knl = lp.make_kernel( + "{ [i]: 0<=i<50}", + """ + for i + if i % 2 == 0 + if i % 3 == 0 + a[i] = 15 + elif i % 3 == 1 + a[i] = 11 + else + a[i] = 3 + end + end + end + """ + ) + print knl + + evt, (out,) = knl(queue, out_host=True) + + out_ref = np.empty(50) + out_ref[::6] = 15 + out_ref[4::6] = 11 + out_ref[2::6] = 3 + + assert np.array_equal(out_ref, out) + def test_tight_loop_bounds(ctx_factory): ctx = ctx_factory() -- GitLab From 3342f85cbd8288a4c9c709f950fc74a476cb42fa Mon Sep 17 00:00:00 2001 From: arghdos Date: Fri, 25 Nov 2016 11:06:05 -0500 Subject: [PATCH 08/14] remove stray print --- test/test_loopy.py | 1 - 1 file changed, 1 deletion(-) diff --git a/test/test_loopy.py b/test/test_loopy.py index 7208ee502..8844003a0 100644 --- a/test/test_loopy.py +++ b/test/test_loopy.py @@ -1673,7 +1673,6 @@ def test_if_else(ctx_factory): end """ ) - print knl evt, (out,) = knl(queue, out_host=True) -- GitLab From cb1fc7b22fa4c60efe9cb7a9d700a5c5efdce3b5 Mon Sep 17 00:00:00 2001 From: arghdos Date: Fri, 2 Dec 2016 09:58:32 -0500 Subject: [PATCH 09/14] correct stack popping behaviour for if predicates --- loopy/kernel/creation.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/loopy/kernel/creation.py b/loopy/kernel/creation.py index 2495e4f3d..5427d96ca 100644 --- a/loopy/kernel/creation.py +++ b/loopy/kernel/creation.py @@ -695,7 +695,7 @@ def parse_instructions(instructions, defines): # {{{ pass 4: parsing insn_options_stack = [get_default_insn_options_dict()] - if_predicates_stack = [{'predicates' : frozenset()}] + if_predicates_stack = [{'predicates' : frozenset(), 'insn_predicates' : frozenset()}] for insn in instructions: if isinstance(insn, InstructionBase): @@ -841,6 +841,8 @@ def parse_instructions(instructions, defines): | additional_preds ) if_options["predicates"] = additional_preds + #hold on to this for comparison / stack popping later + if_options["insn_predicates"] = options["predicates"] insn_options_stack.append(options) if_predicates_stack.append(if_options) @@ -852,7 +854,10 @@ def parse_instructions(instructions, defines): continue if insn == "end": - insn_options_stack.pop() + obj = insn_options_stack.pop() + #if this object is the end of an if statement + if obj['predicates'] == if_predicates_stack[-1]["insn_predicates"]: + if_predicates_stack.pop() continue insn_match = SPECIAL_INSN_RE.match(insn) -- GitLab From e746e12a3df0e39983ba76d2685a642c650bbc01 Mon Sep 17 00:00:00 2001 From: arghdos Date: Fri, 2 Dec 2016 10:03:07 -0500 Subject: [PATCH 10/14] fix inner / outer scope test --- loopy/kernel/creation.py | 1 + test/test_loopy.py | 7 +++++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/loopy/kernel/creation.py b/loopy/kernel/creation.py index 5427d96ca..cdede223d 100644 --- a/loopy/kernel/creation.py +++ b/loopy/kernel/creation.py @@ -825,6 +825,7 @@ def parse_instructions(instructions, defines): else: assert else_match is not None if not last_if_predicates: + import pdb; pdb.set_trace() raise LoopyError("'else' without 'if'/'elif' encountered") additional_preds = frozenset() diff --git a/test/test_loopy.py b/test/test_loopy.py index debfd8051..4221feb79 100644 --- a/test/test_loopy.py +++ b/test/test_loopy.py @@ -1811,6 +1811,8 @@ def test_if_else(ctx_factory): else a[i] = 3 end + else + a[i] = 4 end end """ @@ -1818,8 +1820,9 @@ def test_if_else(ctx_factory): evt, (out,) = knl(queue, out_host=True) - out_ref = np.empty(50) - out_ref[::6] = 15 + out_ref = np.zeros(50) + out_ref[1::2] = 4 + out_ref[0::6] = 15 out_ref[4::6] = 11 out_ref[2::6] = 3 -- GitLab From 367f63f8db270fd367cb7221b5b8730cd0a0acb0 Mon Sep 17 00:00:00 2001 From: arghdos Date: Fri, 2 Dec 2016 19:21:20 -0500 Subject: [PATCH 11/14] add check to make sure we're not removing an empty if-predicate --- loopy/kernel/creation.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/loopy/kernel/creation.py b/loopy/kernel/creation.py index cdede223d..d672991a8 100644 --- a/loopy/kernel/creation.py +++ b/loopy/kernel/creation.py @@ -857,7 +857,8 @@ def parse_instructions(instructions, defines): if insn == "end": obj = insn_options_stack.pop() #if this object is the end of an if statement - if obj['predicates'] == if_predicates_stack[-1]["insn_predicates"]: + if obj['predicates'] == if_predicates_stack[-1]["insn_predicates"] and\ + if_predicates_stack[-1]: if_predicates_stack.pop() continue -- GitLab From 6dc2bbebebe6799abefe3f6cacff305cf0892357 Mon Sep 17 00:00:00 2001 From: arghdos Date: Sat, 3 Dec 2016 12:44:18 -0500 Subject: [PATCH 12/14] oops, actually have to test the truth value of the predicates! --- loopy/kernel/creation.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/loopy/kernel/creation.py b/loopy/kernel/creation.py index d672991a8..97a4771c1 100644 --- a/loopy/kernel/creation.py +++ b/loopy/kernel/creation.py @@ -858,7 +858,7 @@ def parse_instructions(instructions, defines): obj = insn_options_stack.pop() #if this object is the end of an if statement if obj['predicates'] == if_predicates_stack[-1]["insn_predicates"] and\ - if_predicates_stack[-1]: + if_predicates_stack[-1]["insn_predicates"]: if_predicates_stack.pop() continue -- GitLab From 911feb376cac5c82c0b20574136f4269f81c24bf Mon Sep 17 00:00:00 2001 From: arghdos Date: Sat, 3 Dec 2016 13:01:26 -0500 Subject: [PATCH 13/14] initialize first entries on the if_stack to have the correct insn_predicates in case it's immediately popped off --- loopy/kernel/creation.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/loopy/kernel/creation.py b/loopy/kernel/creation.py index 97a4771c1..ba75ac95f 100644 --- a/loopy/kernel/creation.py +++ b/loopy/kernel/creation.py @@ -792,6 +792,10 @@ def parse_instructions(instructions, defines): | frozenset([predicate])) insn_options_stack.append(options) + + #add to the if_stack + if_options = options.copy() + if_options['insn_predicates'] = options["predicates"] if_predicates_stack.append(options) del options del predicate @@ -825,7 +829,6 @@ def parse_instructions(instructions, defines): else: assert else_match is not None if not last_if_predicates: - import pdb; pdb.set_trace() raise LoopyError("'else' without 'if'/'elif' encountered") additional_preds = frozenset() -- GitLab From 264ddadd106a90ccd64fe706d1d06a7d5d1d6855 Mon Sep 17 00:00:00 2001 From: arghdos Date: Sat, 3 Dec 2016 13:05:27 -0500 Subject: [PATCH 14/14] d'oh, append correct object --- loopy/kernel/creation.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/loopy/kernel/creation.py b/loopy/kernel/creation.py index ba75ac95f..024d97c3f 100644 --- a/loopy/kernel/creation.py +++ b/loopy/kernel/creation.py @@ -796,7 +796,7 @@ def parse_instructions(instructions, defines): #add to the if_stack if_options = options.copy() if_options['insn_predicates'] = options["predicates"] - if_predicates_stack.append(options) + if_predicates_stack.append(if_options) del options del predicate continue -- GitLab