Skip to content

Commit

Permalink
analyses.invariant_detection: implement (#622).
Browse files Browse the repository at this point in the history
whitequark committed Nov 20, 2016
1 parent 3059872 commit f5cca6b
Showing 4 changed files with 59 additions and 2 deletions.
1 change: 1 addition & 0 deletions artiq/compiler/analyses/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from .constness import Constness
from .domination import DominatorTree
from .devirtualization import Devirtualization
from .invariant_detection import InvariantDetection
49 changes: 49 additions & 0 deletions artiq/compiler/analyses/invariant_detection.py
Original file line number Diff line number Diff line change
@@ -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)
5 changes: 4 additions & 1 deletion artiq/compiler/module.py
Original file line number Diff line number Diff line change
@@ -40,7 +40,7 @@ def from_filename(cls, filename, engine=None):
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 @@ def __init__(self, src, ref_period=1e-6, attribute_writeback=True):
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 @@ def __init__(self, src, ref_period=1e-6, attribute_writeback=True):
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."""
6 changes: 5 additions & 1 deletion artiq/compiler/transforms/llvm_ir_generator.py
Original file line number Diff line number Diff line change
@@ -1151,8 +1151,12 @@ def _prepare_ffi_call(self, insn):
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)

0 comments on commit f5cca6b

Please sign in to comment.