From f5cca6b09ec35e7ac9cd606adf3fd335d120f111 Mon Sep 17 00:00:00 2001 From: whitequark Date: Sun, 20 Nov 2016 12:48:26 +0000 Subject: [PATCH] analyses.invariant_detection: implement (#622). --- artiq/compiler/analyses/__init__.py | 1 + .../compiler/analyses/invariant_detection.py | 49 +++++++++++++++++++ artiq/compiler/module.py | 5 +- .../compiler/transforms/llvm_ir_generator.py | 6 ++- 4 files changed, 59 insertions(+), 2 deletions(-) create mode 100644 artiq/compiler/analyses/invariant_detection.py diff --git a/artiq/compiler/analyses/__init__.py b/artiq/compiler/analyses/__init__.py index f1553fc74..21da39d23 100644 --- a/artiq/compiler/analyses/__init__.py +++ b/artiq/compiler/analyses/__init__.py @@ -1,3 +1,4 @@ from .constness import Constness from .domination import DominatorTree from .devirtualization import Devirtualization +from .invariant_detection import InvariantDetection diff --git a/artiq/compiler/analyses/invariant_detection.py b/artiq/compiler/analyses/invariant_detection.py new file mode 100644 index 000000000..665c7317b --- /dev/null +++ b/artiq/compiler/analyses/invariant_detection.py @@ -0,0 +1,49 @@ +""" +:class:`InvariantDetection` determines which attributes can be safely +marked kernel invariant. +""" + +from pythonparser import diagnostic +from .. import ir, types + +class InvariantDetection: + def __init__(self, engine): + self.engine = engine + + def process(self, functions): + self.attr_locs = dict() + self.attr_written = set() + + for func in functions: + self.process_function(func) + + for key in self.attr_locs: + if key not in self.attr_written: + typ, attr = key + if attr in typ.constant_attributes: + continue + + diag = diagnostic.Diagnostic("note", + "attribute '{attr}' of type '{type}' is never written to; " + + "it could be marked as kernel invariant to potentially increase performance", + {"attr": attr, + "type": typ.name}, + self.attr_locs[key]) + self.engine.process(diag) + + def process_function(self, func): + for block in func.basic_blocks: + for insn in block.instructions: + if not isinstance(insn, (ir.GetAttr, ir.SetAttr)): + continue + if not types.is_instance(insn.object().type): + continue + + key = (insn.object().type, insn.attr) + if isinstance(insn, ir.GetAttr): + if types.is_method(insn.type): + continue + if key not in self.attr_locs and insn.loc is not None: + self.attr_locs[key] = insn.loc + elif isinstance(insn, ir.SetAttr): + self.attr_written.add(key) diff --git a/artiq/compiler/module.py b/artiq/compiler/module.py index e169a656e..d1d2b1efc 100644 --- a/artiq/compiler/module.py +++ b/artiq/compiler/module.py @@ -40,7 +40,7 @@ class Source: return cls(source.Buffer(f.read(), filename, 1), engine=engine) class Module: - def __init__(self, src, ref_period=1e-6, attribute_writeback=True): + def __init__(self, src, ref_period=1e-6, attribute_writeback=True, remarks=True): self.attribute_writeback = attribute_writeback self.engine = src.engine self.embedding_map = src.embedding_map @@ -61,6 +61,7 @@ class Module: local_access_validator = validators.LocalAccessValidator(engine=self.engine) devirtualization = analyses.Devirtualization() interleaver = transforms.Interleaver(engine=self.engine) + invariant_detection = analyses.InvariantDetection(engine=self.engine) int_monomorphizer.visit(src.typedtree) inferencer.visit(src.typedtree) @@ -74,6 +75,8 @@ class Module: dead_code_eliminator.process(self.artiq_ir) interleaver.process(self.artiq_ir) local_access_validator.process(self.artiq_ir) + if remarks: + invariant_detection.process(self.artiq_ir) def build_llvm_ir(self, target): """Compile the module to LLVM IR for the specified target.""" diff --git a/artiq/compiler/transforms/llvm_ir_generator.py b/artiq/compiler/transforms/llvm_ir_generator.py index 0a41479b8..d1dac2810 100644 --- a/artiq/compiler/transforms/llvm_ir_generator.py +++ b/artiq/compiler/transforms/llvm_ir_generator.py @@ -1151,8 +1151,12 @@ class LLVMIRGenerator: byvals = [i + 1 for i in byvals] for i in byvals: llfun.args[i].add_attribute('byval') - if 'nounwind' in insn.target_function().type.flags: + + flags = insn.target_function().type.flags + if 'nounwind' in flags: llfun.attributes.add('nounwind') + if 'nowrite' in flags: + llfun.attributes.add('inaccessiblememonly') return llfun, list(llargs)