From fbf2c9a2fba42a48112606a28b196605f9227e04 Mon Sep 17 00:00:00 2001 From: whitequark Date: Fri, 25 May 2018 02:18:13 +0000 Subject: [PATCH] compiler: hoist loads of kernel invariants to function entry block. Addresses intraprocedural cases of #1007. --- artiq/compiler/module.py | 2 + artiq/compiler/transforms/__init__.py | 1 + artiq/compiler/transforms/constant_hoister.py | 44 +++++++++++++++++++ artiq/test/lit/constant_hoisting/device_db.py | 8 ++++ .../lit/constant_hoisting/invariant_load.py | 25 +++++++++++ 5 files changed, 80 insertions(+) create mode 100644 artiq/compiler/transforms/constant_hoister.py create mode 100644 artiq/test/lit/constant_hoisting/device_db.py create mode 100644 artiq/test/lit/constant_hoisting/invariant_load.py diff --git a/artiq/compiler/module.py b/artiq/compiler/module.py index 8e7091b81..cea86cddb 100644 --- a/artiq/compiler/module.py +++ b/artiq/compiler/module.py @@ -61,6 +61,7 @@ class Module: dead_code_eliminator = transforms.DeadCodeEliminator(engine=self.engine) local_access_validator = validators.LocalAccessValidator(engine=self.engine) local_demoter = transforms.LocalDemoter() + constant_hoister = transforms.ConstantHoister() devirtualization = analyses.Devirtualization() interleaver = transforms.Interleaver(engine=self.engine) invariant_detection = analyses.InvariantDetection(engine=self.engine) @@ -79,6 +80,7 @@ class Module: interleaver.process(self.artiq_ir) local_access_validator.process(self.artiq_ir) local_demoter.process(self.artiq_ir) + constant_hoister.process(self.artiq_ir) if remarks: invariant_detection.process(self.artiq_ir) diff --git a/artiq/compiler/transforms/__init__.py b/artiq/compiler/transforms/__init__.py index 64ee25c46..5696be95f 100644 --- a/artiq/compiler/transforms/__init__.py +++ b/artiq/compiler/transforms/__init__.py @@ -6,6 +6,7 @@ from .iodelay_estimator import IODelayEstimator from .artiq_ir_generator import ARTIQIRGenerator from .dead_code_eliminator import DeadCodeEliminator from .local_demoter import LocalDemoter +from .constant_hoister import ConstantHoister from .interleaver import Interleaver from .typedtree_printer import TypedtreePrinter from .llvm_ir_generator import LLVMIRGenerator diff --git a/artiq/compiler/transforms/constant_hoister.py b/artiq/compiler/transforms/constant_hoister.py new file mode 100644 index 000000000..0484b1c39 --- /dev/null +++ b/artiq/compiler/transforms/constant_hoister.py @@ -0,0 +1,44 @@ +""" +:class:`ConstantHoister` is a code motion transform: +it moves any invariant loads to the earliest point where +they may be executed. +""" + +from .. import types, ir + +class ConstantHoister: + def process(self, functions): + for func in functions: + self.process_function(func) + + def process_function(self, func): + entry = func.entry() + worklist = set(func.instructions()) + moved = set() + while len(worklist) > 0: + insn = worklist.pop() + + if (isinstance(insn, ir.GetAttr) and insn not in moved and + types.is_instance(insn.object().type) and + insn.attr in insn.object().type.constant_attributes): + has_variant_operands = False + index_in_entry = 0 + for operand in insn.operands: + if isinstance(operand, ir.Argument): + pass + elif isinstance(operand, ir.Instruction) and operand.basic_block == entry: + index_in_entry = entry.index(operand) + 1 + else: + has_variant_operands = True + break + + if has_variant_operands: + continue + + insn.remove_from_parent() + entry.instructions.insert(index_in_entry, insn) + moved.add(insn) + print(insn) + + for use in insn.uses: + worklist.add(use) diff --git a/artiq/test/lit/constant_hoisting/device_db.py b/artiq/test/lit/constant_hoisting/device_db.py new file mode 100644 index 000000000..e39c83c09 --- /dev/null +++ b/artiq/test/lit/constant_hoisting/device_db.py @@ -0,0 +1,8 @@ +device_db = { + "core": { + "type": "local", + "module": "artiq.coredevice.core", + "class": "Core", + "arguments": {"host": None, "ref_period": 1e-9} + } +} diff --git a/artiq/test/lit/constant_hoisting/invariant_load.py b/artiq/test/lit/constant_hoisting/invariant_load.py new file mode 100644 index 000000000..62fac4202 --- /dev/null +++ b/artiq/test/lit/constant_hoisting/invariant_load.py @@ -0,0 +1,25 @@ +# RUN: env ARTIQ_DUMP_IR=%t ARTIQ_IR_NO_LOC=1 %python -m artiq.compiler.testbench.embedding +compile %s +# RUN: OutputCheck %s --file-to-check=%t.txt + +from artiq.language.core import * +from artiq.language.types import * + +# CHECK-L: %LOC.self.FLD.foo = numpy.int32 getattr('foo') %ARG.self +# CHECK-L: for.head: + +class c: + kernel_invariants = {"foo"} + + def __init__(self): + self.foo = 1 + + @kernel + def run(self): + for _ in range(10): + core_log(1.0 * self.foo) + +i = c() + +@kernel +def entrypoint(): + i.run()