diff --git a/loopy/check.py b/loopy/check.py index 9115d740e8c2b6b3f721706306f2ad673ec745ed..a8ec1ad35e42410454b36fa38ef5f0a2fbefc0d6 100644 --- a/loopy/check.py +++ b/loopy/check.py @@ -96,6 +96,17 @@ def check_insn_attributes(kernel): ", ".join(no_sync_with_scopes - VALID_NOSYNC_SCOPES))) +def check_for_duplicate_insn_ids(knl): + insn_ids = set() + + for insn in knl.instructions: + if not isinstance(insn.id, str): + raise LoopyError("instruction id %r is not a string" % insn.id) + if insn.id in insn_ids: + raise LoopyError("duplicate instruction id: '%s'" % insn.id) + insn_ids.add(insn.id) + + def check_loop_priority_inames_known(kernel): for prio in kernel.loop_priority: for iname in prio: @@ -375,6 +386,7 @@ def pre_schedule_checks(kernel): try: logger.debug("%s: pre-schedule check: start" % kernel.name) + check_for_duplicate_insn_ids(kernel) check_for_orphaned_user_hardware_axes(kernel) check_for_double_use_of_hw_axes(kernel) check_insn_attributes(kernel) diff --git a/loopy/kernel/__init__.py b/loopy/kernel/__init__.py index ad86436682af93af7871c86091f74bdf00d31a8d..084c37b45cc4af25689ae3e121f170382c4e8d16 100644 --- a/loopy/kernel/__init__.py +++ b/loopy/kernel/__init__.py @@ -212,54 +212,17 @@ class LoopKernel(ImmutableRecordWithoutPickling): state=kernel_state.INITIAL, target=None, - overridden_get_grid_sizes_for_insn_ids=None, - uniquify_instruction_ids=True): + overridden_get_grid_sizes_for_insn_ids=None): """ :arg overridden_get_grid_sizes_for_insn_ids: A callable. When kernels get intersected in slab decomposition, their grid sizes shouldn't change. This provides a way to forward sub-kernel grid size requests. - - :arg uniquify_instruction_ids: Ensure all instruction IDs are unique and - convert any IDs that are :class:`loopy.kernel.creation.UniqueName` or - *None* into appropriate strings. If *False*, does not look at - `instructions`. """ if cache_manager is None: from loopy.kernel.tools import SetOperationCacheManager cache_manager = SetOperationCacheManager() - # {{{ make instruction ids unique - - if uniquify_instruction_ids: - from loopy.kernel.creation import UniqueName - - insn_ids = set() - for insn in instructions: - if insn.id is not None and not isinstance(insn.id, UniqueName): - if insn.id in insn_ids: - raise RuntimeError("duplicate instruction id: %s" % insn.id) - insn_ids.add(insn.id) - - insn_id_gen = UniqueNameGenerator(insn_ids) - - new_instructions = [] - - for insn in instructions: - if insn.id is None: - new_instructions.append( - insn.copy(id=insn_id_gen("insn"))) - elif isinstance(insn.id, UniqueName): - new_instructions.append( - insn.copy(id=insn_id_gen(insn.id.name))) - else: - new_instructions.append(insn) - - instructions = new_instructions - del new_instructions - - # }}} - # {{{ process assumptions if assumptions is None: diff --git a/loopy/kernel/creation.py b/loopy/kernel/creation.py index aacd76c09d42717cbb2701ee63edae2ea728f568..c6618d62f7543fd2bc5461762ed19714e998fc14 100644 --- a/loopy/kernel/creation.py +++ b/loopy/kernel/creation.py @@ -1984,6 +1984,11 @@ def make_kernel(domains, instructions, kernel_data=["..."], **kwargs): target=target, **kwargs) + from loopy.transform.instruction import uniquify_instruction_ids + knl = uniquify_instruction_ids(knl) + from loopy.check import check_for_duplicate_insn_ids + check_for_duplicate_insn_ids(knl) + if seq_dependencies: knl = add_sequential_dependencies(knl) diff --git a/loopy/transform/instruction.py b/loopy/transform/instruction.py index 2be78f8e5c25a3b48c195f52715f9d6453100e3b..37c5d85a1ade5c8f7fadb2c6a785cf7cea3dde40 100644 --- a/loopy/transform/instruction.py +++ b/loopy/transform/instruction.py @@ -301,4 +301,39 @@ def add_nosync(kernel, scope, source, sink, bidirectional=False, force=False): # }}} +# {{{ uniquify_instruction_ids + +def uniquify_instruction_ids(kernel): + """Converts any ids that are :class:`loopy.UniqueName` or *None* into unique + strings. + + This function does *not* deduplicate existing instruction ids. + """ + + from loopy.kernel.creation import UniqueName + + insn_ids = set( + insn.id for insn in kernel.instructions + if insn.id is not None and not isinstance(insn.id, UniqueName)) + + from pytools import UniqueNameGenerator + insn_id_gen = UniqueNameGenerator(insn_ids) + + new_instructions = [] + + for insn in kernel.instructions: + if insn.id is None: + new_instructions.append( + insn.copy(id=insn_id_gen("insn"))) + elif isinstance(insn.id, UniqueName): + new_instructions.append( + insn.copy(id=insn_id_gen(insn.id.name))) + else: + new_instructions.append(insn) + + return kernel.copy(instructions=new_instructions) + +# }}} + + # vim: foldmethod=marker diff --git a/test/test_transform.py b/test/test_transform.py index b5fcdf04c4781c5f370c911ceb7efcb4042f6b4e..d17f6c707d36214f0f6713da25c8be0691b58d2c 100644 --- a/test/test_transform.py +++ b/test/test_transform.py @@ -438,6 +438,23 @@ def test_add_nosync(): assert frozenset([("insn5", "local")]) == knl.id_to_insn["insn6"].no_sync_with +def test_uniquify_instruction_ids(): + i1 = lp.Assignment("b", 1, id=None) + i2 = lp.Assignment("b", 1, id=None) + i3 = lp.Assignment("b", 1, id=lp.UniqueName("b")) + i4 = lp.Assignment("b", 1, id=lp.UniqueName("b")) + + knl = lp.make_kernel("{[i]: i = 1}", []).copy(instructions=[i1, i2, i3, i4]) + + from loopy.transform.instruction import uniquify_instruction_ids + knl = uniquify_instruction_ids(knl) + + insn_ids = set(insn.id for insn in knl.instructions) + + assert len(insn_ids) == 4 + assert all(isinstance(id, str) for id in insn_ids) + + if __name__ == "__main__": if len(sys.argv) > 1: exec(sys.argv[1])