From 94eec370c8a479f9471e53756d9f30d26945cc74 Mon Sep 17 00:00:00 2001 From: Andreas Kloeckner <inform@tiker.net> Date: Sat, 29 Oct 2011 14:48:31 -0400 Subject: [PATCH] Rename idempotent->boostable. Be more restrictive in marking insns boostable. In particular, just touching a variable written to by a non-idempotent instruction makes that instruction also not idempotent. --- MEMO | 8 +++++--- loopy/kernel.py | 23 ++++++++++++----------- loopy/preprocess.py | 33 +++++++++++++++++++++++++++------ loopy/schedule.py | 10 +++++----- 4 files changed, 49 insertions(+), 25 deletions(-) diff --git a/MEMO b/MEMO index 148999e6a..dd00893d8 100644 --- a/MEMO +++ b/MEMO @@ -42,9 +42,6 @@ Things to consider To-do ^^^^^ -- Just touching a variable written to by a non-idempotent - instruction makes that instruction also not idempotent - - user interface for dim length prescription - Deal with equality constraints. @@ -89,6 +86,11 @@ Future ideas Dealt with ^^^^^^^^^^ +- Just touching a variable written to by a non-idempotent + instruction makes that instruction also not idempotent + -> Idempotent renamed to boostable. + -> Done. + - Give the user control over which reduction inames are duplicated. diff --git a/loopy/kernel.py b/loopy/kernel.py index 9af083c2e..2eff25538 100644 --- a/loopy/kernel.py +++ b/loopy/kernel.py @@ -223,8 +223,9 @@ class Instruction(Record): :ivar insn_deps: a list of ids of :class:`Instruction` instances that *must* be executed before this one. Note that loop scheduling augments this by adding dependencies on any writes to temporaries read by this instruction. - :ivar idempotent: Whether the instruction may be executed repeatedly (while obeying - dependencies) without changing the meaning of the program. + :ivar boostable: Whether the instruction may safely be executed + inside more loops than advertised without changing the meaning + of the program. Allowed values are *None* (for unknwon), *True*, and *False*. The following two instance variables are only used until :func:`loopy.kernel.make_kernel` is finished: @@ -236,13 +237,13 @@ class Instruction(Record): """ def __init__(self, id, assignee, expression, - forced_iname_deps=[], insn_deps=[], idempotent=None, + forced_iname_deps=[], insn_deps=[], boostable=None, temp_var_type=None, duplicate_inames_and_tags=[]): Record.__init__(self, id=id, assignee=assignee, expression=expression, forced_iname_deps=forced_iname_deps, - insn_deps=insn_deps, idempotent=idempotent, + insn_deps=insn_deps, boostable=boostable, temp_var_type=temp_var_type, duplicate_inames_and_tags=duplicate_inames_and_tags) @memoize_method @@ -268,14 +269,14 @@ class Instruction(Record): result = "%s: %s <- %s\n [%s]" % (self.id, self.assignee, self.expression, ", ".join(sorted(self.all_inames()))) - if self.idempotent == True: - result += " (idempotent)" - elif self.idempotent == False: - result += " (not idempotent)" - elif self.idempotent is None: - result += " (idempotence unknown)" + if self.boostable == True: + result += " (boostable)" + elif self.boostable == False: + result += " (not boostable)" + elif self.boostable is None: + result += " (boostability unknown)" else: - raise RuntimeError("unexpected value for Instruction.idempotent") + raise RuntimeError("unexpected value for Instruction.boostable") if self.insn_deps: result += "\n : " + ", ".join(self.insn_deps) diff --git a/loopy/preprocess.py b/loopy/preprocess.py index 6f02fd2af..a06e28b4e 100644 --- a/loopy/preprocess.py +++ b/loopy/preprocess.py @@ -98,7 +98,7 @@ def realize_reduction(kernel): # }}} -# {{{ automatic dependencies, find idempotent instructions +# {{{ automatic dependencies, find boostability of instructions def find_accessors(kernel, readers): """ @@ -129,7 +129,7 @@ def find_accessors(kernel, readers): -def add_idempotence_and_automatic_dependencies(kernel): +def add_boostability_and_automatic_dependencies(kernel): writer_map = find_accessors(kernel, readers=False) arg_names = set(arg.name for arg in kernel.args) @@ -145,11 +145,14 @@ def add_idempotence_and_automatic_dependencies(kernel): set(var.name for var in dm(insn.expression)) & var_names) + non_boostable_vars = set() + new_insns = [] for insn in kernel.instructions: auto_deps = [] # {{{ add automatic dependencies + all_my_var_writers = set() for var in dep_map[insn.id]: var_writers = writer_map.get(var, set()) @@ -171,7 +174,7 @@ def add_idempotence_and_automatic_dependencies(kernel): # }}} - # {{{ find dependency loops, flag idempotence + # {{{ find dependency loops, flag boostability while True: last_all_my_var_writers = all_my_var_writers @@ -185,12 +188,30 @@ def add_idempotence_and_automatic_dependencies(kernel): # }}} + boostable = insn.id not in all_my_var_writers + + if not boostable: + non_boostable_vars.add(insn.get_assignee_var_name()) + new_insns.append( insn.copy( insn_deps=insn.insn_deps + auto_deps, - idempotent=insn.id not in all_my_var_writers)) + boostable=boostable)) + + # {{{ remove boostability from isns that access non-boostable vars + + new2_insns = [] + for insn in new_insns: + accessed_vars = ( + set([insn.get_assignee_var_name()]) + | insn.get_read_var_names()) + + boostable = insn.boostable and not bool(non_boostable_vars & accessed_vars) + new2_insns.append(insn.copy(boostable=boostable)) + + # }}} - return kernel.copy(instructions=new_insns) + return kernel.copy(instructions=new2_insns) # }}} @@ -480,7 +501,7 @@ def preprocess_kernel(kernel): # }}} kernel = assign_automatic_axes(kernel) - kernel = add_idempotence_and_automatic_dependencies(kernel) + kernel = add_boostability_and_automatic_dependencies(kernel) kernel = adjust_local_temp_var_storage(kernel) import loopy.check as chk diff --git a/loopy/schedule.py b/loopy/schedule.py index d9e52dfa8..d61295676 100644 --- a/loopy/schedule.py +++ b/loopy/schedule.py @@ -191,8 +191,8 @@ def generate_loop_schedules_internal(kernel, loop_priority, schedule=[]): schedule_now = set(insn.insn_deps) <= scheduled_insn_ids - if insn.idempotent == True: - # If insn is idempotent, it may be placed inside a more deeply + if insn.boostable == True: + # If insn is boostable, it may be placed inside a more deeply # nested loop without harm. # But if it can be scheduled on the way *out* of the currently @@ -212,8 +212,8 @@ def generate_loop_schedules_internal(kernel, loop_priority, schedule=[]): if schedulable_at_loop_levels != [len(active_inames)]: schedule_now = False - elif insn.idempotent == False: - # If insn is not idempotent, we must insist that it is placed inside + elif insn.boostable == False: + # If insn is not boostable, we must insist that it is placed inside # the exactly correct set of loops. schedule_now = schedule_now and ( @@ -222,7 +222,7 @@ def generate_loop_schedules_internal(kernel, loop_priority, schedule=[]): active_inames_set - parallel_inames) else: - raise RuntimeError("instruction '%s' has undetermined idempotence" + raise RuntimeError("instruction '%s' has undetermined boostability" % insn.id) if schedule_now: -- GitLab