Add source locations to ARTIQ IR instructions.

This commit is contained in:
whitequark 2015-07-18 07:49:42 +03:00
parent 255ffec483
commit dde2e67c3f
2 changed files with 49 additions and 4 deletions

View File

@ -133,6 +133,7 @@ class Instruction(User):
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 @@ class BasicBlock(NamedValue):
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):

View File

@ -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 @@ class IRGenerator(algorithm.Visitor):
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 @@ class IRGenerator(algorithm.Visitor):
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 @@ class IRGenerator(algorithm.Visitor):
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__']), [])