compiler: hoist loads of kernel invariants to function entry block.

Addresses intraprocedural cases of #1007.
This commit is contained in:
whitequark 2018-05-25 02:18:13 +00:00
parent 12d1b9819c
commit fbf2c9a2fb
5 changed files with 80 additions and 0 deletions

View File

@ -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)

View File

@ -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

View File

@ -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)

View File

@ -0,0 +1,8 @@
device_db = {
"core": {
"type": "local",
"module": "artiq.coredevice.core",
"class": "Core",
"arguments": {"host": None, "ref_period": 1e-9}
}
}

View File

@ -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') <instance testbench.c> %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()