Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: m-labs/artiq
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: a4525b21cf4e
Choose a base ref
...
head repository: m-labs/artiq
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 02f2763ea849
Choose a head ref
  • 3 commits
  • 4 files changed
  • 1 contributor

Commits on Nov 23, 2015

  1. compiler.algorithms.inline: implement.

    whitequark committed Nov 23, 2015
    Copy the full SHA
    f0fd6cd View commit details
  2. Copy the full SHA
    f3da227 View commit details
  3. compiler.iodelay: always fully fold SToMU and MUToS.

    whitequark committed Nov 23, 2015
    Copy the full SHA
    02f2763 View commit details
Showing with 168 additions and 12 deletions.
  1. +1 −0 artiq/compiler/algorithms/__init__.py
  2. +80 −0 artiq/compiler/algorithms/inline.py
  3. +8 −10 artiq/compiler/iodelay.py
  4. +79 −2 artiq/compiler/ir.py
1 change: 1 addition & 0 deletions artiq/compiler/algorithms/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from .inline import inline
80 changes: 80 additions & 0 deletions artiq/compiler/algorithms/inline.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
"""
:func:`inline` inlines a call instruction in ARTIQ IR.
The call instruction must have a statically known callee,
it must be second to last in the basic block, and the basic
block must have exactly one successor.
"""

from .. import types, builtins, iodelay, ir

def inline(call_insn):
assert isinstance(call_insn, ir.Call)
assert call_insn.static_target_function is not None
assert len(call_insn.basic_block.successors()) == 1
assert call_insn.basic_block.index(call_insn) == \
len(call_insn.basic_block.instructions) - 2

value_map = {}
source_function = call_insn.static_target_function
target_function = call_insn.basic_block.function
target_predecessor = call_insn.basic_block
target_successor = call_insn.basic_block.successors()[0]

if builtins.is_none(source_function.type.ret):
target_return_phi = None
else:
target_return_phi = target_successor.prepend(ir.Phi(source_function.type.ret))

closure = target_predecessor.insert(ir.GetAttr(call_insn.target_function(), '__closure__'),
before=call_insn)
for actual_arg, formal_arg in zip([closure] + call_insn.arguments(),
source_function.arguments):
value_map[formal_arg] = actual_arg

for source_block in source_function.basic_blocks:
target_block = ir.BasicBlock([], "i." + source_block.name)
target_function.add(target_block)
value_map[source_block] = target_block

def mapper(value):
if isinstance(value, ir.Constant):
return value
else:
return value_map[value]

for source_insn in source_function.instructions():
target_block = value_map[source_insn.basic_block]
if isinstance(source_insn, ir.Return):
if target_return_phi is not None:
target_return_phi.add_incoming(mapper(source_insn.value()), target_block)
target_insn = ir.Branch(target_successor)
elif isinstance(source_insn, ir.Phi):
target_insn = ir.Phi()
elif isinstance(source_insn, ir.Delay):
substs = source_insn.substs()
mapped_substs = {var: value_map[substs[var]] for var in substs}
const_substs = {var: iodelay.Const(mapped_substs[var].value)
for var in mapped_substs
if isinstance(mapped_substs[var], ir.Constant)}
other_substs = {var: mapped_substs[var]
for var in mapped_substs
if not isinstance(mapped_substs[var], ir.Constant)}
target_insn = ir.Delay(source_insn.expr.fold(const_substs), other_substs,
value_map[source_insn.decomposition()],
value_map[source_insn.target()])
else:
target_insn = source_insn.copy(mapper)
target_insn.name = "i." + source_insn.name
value_map[source_insn] = target_insn
target_block.append(target_insn)

for source_insn in source_function.instructions():
if isinstance(source_insn, ir.Phi):
target_insn = value_map[source_insn]
for block, value in source_insn.incoming():
target_insn.add_incoming(value_map[value], value_map[block])

target_predecessor.terminator().replace_with(ir.Branch(value_map[source_function.entry()]))
if target_return_phi is not None:
call_insn.replace_all_uses_with(target_return_phi)
call_insn.erase()
18 changes: 8 additions & 10 deletions artiq/compiler/iodelay.py
Original file line number Diff line number Diff line change
@@ -95,10 +95,6 @@ def __eq__(lhs, rhs):
def free_vars(self):
return self.operand.free_vars()

def fold(self, vars=None):
return self.__class__(self.operand.fold(vars),
ref_period=self.ref_period)

class MUToS(Conv):
def __str__(self):
return "mu->s({})".format(self.operand)
@@ -107,10 +103,11 @@ def eval(self, env):
return self.operand.eval(env) * self.ref_period

def fold(self, vars=None):
if isinstance(self.operand, Const):
return Const(self.operand.value * self.ref_period)
operand = self.operand.fold(vars)
if isinstance(operand, Const):
return Const(operand.value * self.ref_period)
else:
return super().fold(vars)
return MUToS(operand, ref_period=self.ref_period)

class SToMU(Conv):
def __str__(self):
@@ -120,10 +117,11 @@ def eval(self, env):
return self.operand.eval(env) / self.ref_period

def fold(self, vars=None):
if isinstance(self.operand, Const):
return Const(self.operand.value / self.ref_period)
operand = self.operand.fold(vars)
if isinstance(operand, Const):
return Const(operand.value / self.ref_period)
else:
return super().fold(vars)
return SToMU(operand, ref_period=self.ref_period)

class BinOp(Expr):
def __init__(self, lhs, rhs):
81 changes: 79 additions & 2 deletions artiq/compiler/ir.py
Original file line number Diff line number Diff line change
@@ -163,6 +163,12 @@ def __init__(self, operands, typ, name=""):
self.basic_block = None
self.loc = None

def copy(self, mapper):
self_copy = self.__class__.__new__(self.__class__)
Instruction.__init__(self_copy, list(map(mapper, self.operands)),
self.type, self.name)
return self_copy

def set_basic_block(self, new_basic_block):
self.basic_block = new_basic_block
if self.basic_block is not None:
@@ -332,7 +338,7 @@ def append(self, insn):
def index(self, insn):
return self.instructions.index(insn)

def insert(self, before, insn):
def insert(self, insn, before):
assert isinstance(insn, Instruction)
insn.set_basic_block(self)
self.instructions.insert(self.index(before), insn)
@@ -345,7 +351,7 @@ def remove(self, insn):
return insn

def replace(self, insn, replacement):
self.insert(insn, replacement)
self.insert(replacement, before=insn)
self.remove(insn)

def is_terminated(self):
@@ -585,6 +591,11 @@ def __init__(self, env, var_name, name=""):
super().__init__([env], env.type.type_of(var_name), name)
self.var_name = var_name

def copy(self, mapper):
self_copy = super().copy(mapper)
self_copy.var_name = self.var_name
return self_copy

def opcode(self):
return "getlocal({})".format(repr(self.var_name))

@@ -613,6 +624,11 @@ def __init__(self, env, var_name, value, name=""):
super().__init__([env, value], builtins.TNone(), name)
self.var_name = var_name

def copy(self, mapper):
self_copy = super().copy(mapper)
self_copy.var_name = self.var_name
return self_copy

def opcode(self):
return "setlocal({})".format(repr(self.var_name))

@@ -643,6 +659,11 @@ def __init__(self, env, var_name, var_type, name=""):
super().__init__([env], var_type, name)
self.var_name = var_name

def copy(self, mapper):
self_copy = super().copy(mapper)
self_copy.var_name = self.var_name
return self_copy

def opcode(self):
return "getconstructor({})".format(repr(self.var_name))

@@ -672,6 +693,11 @@ def __init__(self, obj, attr, name=""):
super().__init__([obj], typ, name)
self.attr = attr

def copy(self, mapper):
self_copy = super().copy(mapper)
self_copy.attr = self.attr
return self_copy

def opcode(self):
return "getattr({})".format(repr(self.attr))

@@ -701,6 +727,11 @@ def __init__(self, obj, attr, value, name=""):
super().__init__([obj, value], builtins.TNone(), name)
self.attr = attr

def copy(self, mapper):
self_copy = super().copy(mapper)
self_copy.attr = self.attr
return self_copy

def opcode(self):
return "setattr({})".format(repr(self.attr))

@@ -798,6 +829,11 @@ def __init__(self, op, lhs, rhs, name=""):
super().__init__([lhs, rhs], lhs.type, name)
self.op = op

def copy(self, mapper):
self_copy = super().copy(mapper)
self_copy.op = self.op
return self_copy

def opcode(self):
return "arith({})".format(type(self.op).__name__)

@@ -827,6 +863,11 @@ def __init__(self, op, lhs, rhs, name=""):
super().__init__([lhs, rhs], builtins.TBool(), name)
self.op = op

def copy(self, mapper):
self_copy = super().copy(mapper)
self_copy.op = self.op
return self_copy

def opcode(self):
return "compare({})".format(type(self.op).__name__)

@@ -853,6 +894,11 @@ def __init__(self, op, operands, typ, name=""):
super().__init__(operands, typ, name)
self.op = op

def copy(self, mapper):
self_copy = super().copy(mapper)
self_copy.op = self.op
return self_copy

def opcode(self):
return "builtin({})".format(self.op)

@@ -874,6 +920,11 @@ def __init__(self, func, env, name=""):
super().__init__([env], func.type, name)
self.target_function = func

def copy(self, mapper):
self_copy = super().copy(mapper)
self_copy.target_function = self.target_function
return self_copy

def opcode(self):
return "closure({})".format(self.target_function.name)

@@ -898,6 +949,11 @@ def __init__(self, func, args, name=""):
super().__init__([func] + args, func.type.ret, name)
self.static_target_function = None

def copy(self, mapper):
self_copy = super().copy(mapper)
self_copy.static_target_function = self.static_target_function
return self_copy

def opcode(self):
return "call"

@@ -957,6 +1013,11 @@ def __init__(self, value, typ, name=""):
super().__init__([], typ, name)
self.value = value

def copy(self, mapper):
self_copy = super().copy(mapper)
self_copy.value = self.value
return self_copy

def opcode(self):
return "quote({})".format(repr(self.value))

@@ -1148,6 +1209,11 @@ def __init__(self, func, args, normal, exn, name=""):
super().__init__([func] + args + [normal, exn], func.type.ret, name)
self.static_target_function = None

def copy(self, mapper):
self_copy = super().copy(mapper)
self_copy.static_target_function = self.static_target_function
return self_copy

def opcode(self):
return "invoke"

@@ -1191,6 +1257,11 @@ def __init__(self, cleanup, name=""):
super().__init__([cleanup], builtins.TException(), name)
self.types = []

def copy(self, mapper):
self_copy = super().copy(mapper)
self_copy.types = list(self.types)
return self_copy

def opcode(self):
return "landingpad"

@@ -1245,6 +1316,12 @@ def __init__(self, expr, substs, decomposition, target, name=""):
self.expr = expr
self.var_names = list(substs.keys())

def copy(self, mapper):
self_copy = super().copy(mapper)
self_copy.expr = self.expr
self_copy.var_names = list(self.var_names)
return self_copy

def decomposition(self):
return self.operands[0]