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: e96bc3c36c91
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: dde2e67c3f46
Choose a head ref
  • 2 commits
  • 2 files changed
  • 1 contributor

Commits on Jul 18, 2015

  1. Generate more compact ARTIQ IR for else-less if.

    whitequark committed Jul 18, 2015
    Copy the full SHA
    255ffec View commit details
  2. Add source locations to ARTIQ IR instructions.

    whitequark committed Jul 18, 2015
    Copy the full SHA
    dde2e67 View commit details
Showing with 60 additions and 10 deletions.
  1. +22 −0 artiq/compiler/ir.py
  2. +38 −10 artiq/compiler/transforms/ir_generator.py
22 changes: 22 additions & 0 deletions artiq/compiler/ir.py
Original file line number Diff line number Diff line change
@@ -133,6 +133,7 @@ def __init__(self, operands, typ, name=""):
assert isinstance(typ, types.Type)
super().__init__(operands, typ, name)
self.basic_block = None
self.loc = None

def set_basic_block(self, new_basic_block):
self.basic_block = new_basic_block
@@ -306,12 +307,33 @@ def predecessors(self):
return self.function.predecessors_of(self)

def __str__(self):
# Header
lines = ["{}:".format(escape_name(self.name))]
if self.function is not None:
lines[0] += " ; predecessors: {}".format(
", ".join([escape_name(pred.name) for pred in self.predecessors()]))

# Annotated instructions
loc = None
for insn in self.instructions:
if loc != insn.loc:
loc = insn.loc

if loc is None:
lines.append("; <synthesized>")
else:
source_lines = loc.source_lines()
beg_col, end_col = loc.column(), loc.end().column()
source_lines[-1] = \
source_lines[-1][:end_col] + "`" + source_lines[-1][end_col:]
source_lines[0] = \
source_lines[0][:beg_col] + "`" + source_lines[0][beg_col:]

line_desc = "{}:{}".format(loc.source_buffer.name, loc.line())
lines += ["; {} {}".format(line_desc, line.rstrip("\n"))
for line in source_lines]
lines.append(" " + str(insn))

return "\n".join(lines)

class Argument(NamedValue):
48 changes: 38 additions & 10 deletions artiq/compiler/transforms/ir_generator.py
Original file line number Diff line number Diff line change
@@ -16,6 +16,12 @@ def _readable_name(insn):
else:
return insn.name

def _extract_loc(node):
if "keyword_loc" in node._locs:
return node.keyword_loc
else:
return node.loc

# We put some effort in keeping generated IR readable,
# i.e. with a more or less linear correspondence to the source.
# This is why basic blocks sometimes seem to be produced in an odd order.
@@ -25,8 +31,10 @@ class IRGenerator(algorithm.Visitor):
which is effectively maintained in a stack--with push/pop
pairs around any state updates. It is comprised of following:
:ivar current_loc: (:class:`pythonparser.source.Range`)
source range of the node being currently visited
:ivar current_function: (:class:`ir.Function` or None)
def or lambda currently being translated
module, def or lambda currently being translated
:ivar current_block: (:class:`ir.BasicBlock`)
basic block to which any new instruction will be appended
:ivar current_env: (:class:`ir.Environment`)
@@ -55,6 +63,7 @@ def __init__(self, module_name, engine):
self.engine = engine
self.functions = []
self.name = [module_name]
self.current_loc = None
self.current_function = None
self.current_block = None
self.current_env = None
@@ -70,8 +79,15 @@ def add_block(self, name=""):
self.current_function.add(block)
return block

def append(self, insn):
return self.current_block.append(insn)
def append(self, insn, block=None, loc=None):
if loc is None:
loc = self.current_loc
if block is None:
block = self.current_block

if insn.loc is None:
insn.loc = self.current_loc
return block.append(insn)

def terminate(self, insn):
if not self.current_block.is_terminated():
@@ -88,11 +104,18 @@ def visit(self, obj):
if self.current_block.is_terminated():
break
elif isinstance(obj, ast.AST):
return self._visit_one(obj)
try:
old_loc, self.current_loc = self.current_loc, _extract_loc(obj)
return self._visit_one(obj)
finally:
self.current_loc = old_loc

# Module visitor

def visit_ModuleT(self, node):
# Treat start of module as synthesized
self.current_loc = None

try:
typ = types.TFunction(OrderedDict(), OrderedDict(), builtins.TNone())
func = ir.Function(typ, ".".join(self.name + ['__modinit__']), [])
@@ -238,17 +261,22 @@ def visit_If(self, node):
self.current_block = if_true
self.visit(node.body)

if_false = self.add_block()
self.current_block = if_false
self.visit(node.orelse)
if any(node.orelse):
if_false = self.add_block()
self.current_block = if_false
self.visit(node.orelse)

tail = self.add_block()
self.current_block = tail
if not if_true.is_terminated():
if_true.append(ir.Branch(tail))
if not if_false.is_terminated():
if_false.append(ir.Branch(tail))
head.append(ir.BranchIf(cond, if_true, if_false))

if any(node.orelse):
if not if_false.is_terminated():
if_false.append(ir.Branch(tail))
head.append(ir.BranchIf(cond, if_true, if_false))
else:
head.append(ir.BranchIf(cond, if_true, tail))

def visit_While(self, node):
try: