compiler: significantly increase readability of LLVM and ARTIQ IRs.

This commit is contained in:
whitequark 2016-03-26 11:38:55 +00:00
parent 8d0566661a
commit 3ee9834197
3 changed files with 133 additions and 109 deletions

View File

@ -437,7 +437,7 @@ class Function:
def _add_name(self, base_name): def _add_name(self, base_name):
if base_name == "": if base_name == "":
name = "v.{}".format(self.next_name) name = "UNN.{}".format(self.next_name)
self.next_name += 1 self.next_name += 1
elif base_name in self.names: elif base_name in self.names:
name = "{}.{}".format(base_name, self.next_name) name = "{}.{}".format(base_name, self.next_name)
@ -869,9 +869,11 @@ class Builtin(Instruction):
""" """
:param op: (string) operation name :param op: (string) operation name
""" """
def __init__(self, op, operands, typ, name=""): def __init__(self, op, operands, typ, name=None):
assert isinstance(op, str) assert isinstance(op, str)
for operand in operands: assert isinstance(operand, Value) for operand in operands: assert isinstance(operand, Value)
if name is None:
name = "BLT.{}".format(op)
super().__init__(operands, typ, name) super().__init__(operands, typ, name)
self.op = op self.op = op

View File

@ -237,25 +237,25 @@ class ARTIQIRGenerator(algorithm.Visitor):
for arg_name, default_node in zip(typ.optargs, node.args.defaults): for arg_name, default_node in zip(typ.optargs, node.args.defaults):
default = self.visit(default_node) default = self.visit(default_node)
env_default_name = \ env_default_name = \
self.current_env.type.add("default$" + arg_name, default.type) self.current_env.type.add("$default." + arg_name, default.type)
self.append(ir.SetLocal(self.current_env, env_default_name, default)) self.append(ir.SetLocal(self.current_env, env_default_name, default))
defaults.append(env_default_name) defaults.append(env_default_name)
old_name, self.name = self.name, self.name + [name] old_name, self.name = self.name, self.name + [name]
env_arg = ir.EnvironmentArgument(self.current_env.type, "outerenv") env_arg = ir.EnvironmentArgument(self.current_env.type, "CLS")
old_args, self.current_args = self.current_args, {} old_args, self.current_args = self.current_args, {}
args = [] args = []
for arg_name in typ.args: for arg_name in typ.args:
arg = ir.Argument(typ.args[arg_name], "arg." + arg_name) arg = ir.Argument(typ.args[arg_name], "ARG." + arg_name)
self.current_args[arg_name] = arg self.current_args[arg_name] = arg
args.append(arg) args.append(arg)
optargs = [] optargs = []
for arg_name in typ.optargs: for arg_name in typ.optargs:
arg = ir.Argument(ir.TOption(typ.optargs[arg_name]), "arg." + arg_name) arg = ir.Argument(ir.TOption(typ.optargs[arg_name]), "ARG." + arg_name)
self.current_args[arg_name] = arg self.current_args[arg_name] = arg
optargs.append(arg) optargs.append(arg)
@ -268,7 +268,7 @@ class ARTIQIRGenerator(algorithm.Visitor):
if not is_lambda: if not is_lambda:
self.function_map[node] = func self.function_map[node] = func
entry = self.add_block() entry = self.add_block("entry")
old_block, self.current_block = self.current_block, entry old_block, self.current_block = self.current_block, entry
old_globals, self.current_globals = self.current_globals, node.globals_in_scope old_globals, self.current_globals = self.current_globals, node.globals_in_scope
@ -279,13 +279,13 @@ class ARTIQIRGenerator(algorithm.Visitor):
if var not in node.globals_in_scope} if var not in node.globals_in_scope}
env_type = ir.TEnvironment(name=func.name, env_type = ir.TEnvironment(name=func.name,
vars=env_without_globals, outer=self.current_env.type) vars=env_without_globals, outer=self.current_env.type)
env = self.append(ir.Alloc([], env_type, name="env")) env = self.append(ir.Alloc([], env_type, name="ENV"))
old_env, self.current_env = self.current_env, env old_env, self.current_env = self.current_env, env
if not is_lambda: if not is_lambda:
priv_env_type = ir.TEnvironment(name=func.name + ".priv", priv_env_type = ir.TEnvironment(name="{}.private".format(func.name),
vars={ "$return": typ.ret }) vars={ "$return": typ.ret })
priv_env = self.append(ir.Alloc([], priv_env_type, name="privenv")) priv_env = self.append(ir.Alloc([], priv_env_type, name="PRV"))
old_priv_env, self.current_private_env = self.current_private_env, priv_env old_priv_env, self.current_private_env = self.current_private_env, priv_env
self.append(ir.SetLocal(env, "$outer", env_arg)) self.append(ir.SetLocal(env, "$outer", env_arg))
@ -401,18 +401,18 @@ class ARTIQIRGenerator(algorithm.Visitor):
cond = self.coerce_to_bool(cond) cond = self.coerce_to_bool(cond)
head = self.current_block head = self.current_block
if_true = self.add_block() if_true = self.add_block("if.body")
self.current_block = if_true self.current_block = if_true
self.visit(node.body) self.visit(node.body)
post_if_true = self.current_block post_if_true = self.current_block
if any(node.orelse): if any(node.orelse):
if_false = self.add_block() if_false = self.add_block("if.else")
self.current_block = if_false self.current_block = if_false
self.visit(node.orelse) self.visit(node.orelse)
post_if_false = self.current_block post_if_false = self.current_block
tail = self.add_block() tail = self.add_block("if.tail")
self.current_block = tail self.current_block = tail
if not post_if_true.is_terminated(): if not post_if_true.is_terminated():
post_if_true.append(ir.Branch(tail)) post_if_true.append(ir.Branch(tail))
@ -499,9 +499,9 @@ class ARTIQIRGenerator(algorithm.Visitor):
head = self.add_block("for.head") head = self.add_block("for.head")
self.append(ir.Branch(head)) self.append(ir.Branch(head))
self.current_block = head self.current_block = head
phi = self.append(ir.Phi(length.type)) phi = self.append(ir.Phi(length.type, name="IND"))
phi.add_incoming(ir.Constant(0, phi.type), prehead) phi.add_incoming(ir.Constant(0, phi.type), prehead)
cond = self.append(ir.Compare(ast.Lt(loc=None), phi, length)) cond = self.append(ir.Compare(ast.Lt(loc=None), phi, length, name="CMP"))
break_block = self.add_block("for.break") break_block = self.add_block("for.break")
old_break, self.break_target = self.break_target, break_block old_break, self.break_target = self.break_target, break_block
@ -510,7 +510,8 @@ class ARTIQIRGenerator(algorithm.Visitor):
old_continue, self.continue_target = self.continue_target, continue_block old_continue, self.continue_target = self.continue_target, continue_block
self.current_block = continue_block self.current_block = continue_block
updated_index = self.append(ir.Arith(ast.Add(loc=None), phi, ir.Constant(1, phi.type))) updated_index = self.append(ir.Arith(ast.Add(loc=None), phi, ir.Constant(1, phi.type),
name="IND.new"))
phi.add_incoming(updated_index, continue_block) phi.add_incoming(updated_index, continue_block)
self.append(ir.Branch(head)) self.append(ir.Branch(head))
@ -597,13 +598,13 @@ class ARTIQIRGenerator(algorithm.Visitor):
# k for continuation # k for continuation
final_suffix = ".try@{}:{}".format(node.loc.line(), node.loc.column()) final_suffix = ".try@{}:{}".format(node.loc.line(), node.loc.column())
final_env_type = ir.TEnvironment(name=self.current_function.name + final_suffix, final_env_type = ir.TEnvironment(name=self.current_function.name + final_suffix,
vars={ "$k": ir.TBasicBlock() }) vars={ "$cont": ir.TBasicBlock() })
final_state = self.append(ir.Alloc([], final_env_type)) final_state = self.append(ir.Alloc([], final_env_type))
final_targets = [] final_targets = []
final_paths = [] final_paths = []
def final_branch(target, block): def final_branch(target, block):
block.append(ir.SetLocal(final_state, "$k", target)) block.append(ir.SetLocal(final_state, "$cont", target))
final_targets.append(target) final_targets.append(target)
final_paths.append(block) final_paths.append(block)
@ -696,19 +697,19 @@ class ARTIQIRGenerator(algorithm.Visitor):
block.append(ir.Branch(finalizer)) block.append(ir.Branch(finalizer))
if not body.is_terminated(): if not body.is_terminated():
body.append(ir.SetLocal(final_state, "$k", tail)) body.append(ir.SetLocal(final_state, "$cont", tail))
body.append(ir.Branch(finalizer)) body.append(ir.Branch(finalizer))
cleanup.append(ir.SetLocal(final_state, "$k", reraise)) cleanup.append(ir.SetLocal(final_state, "$cont", reraise))
cleanup.append(ir.Branch(finalizer)) cleanup.append(ir.Branch(finalizer))
for handler, post_handler in handlers: for handler, post_handler in handlers:
if not post_handler.is_terminated(): if not post_handler.is_terminated():
post_handler.append(ir.SetLocal(final_state, "$k", tail)) post_handler.append(ir.SetLocal(final_state, "$cont", tail))
post_handler.append(ir.Branch(finalizer)) post_handler.append(ir.Branch(finalizer))
if not post_finalizer.is_terminated(): if not post_finalizer.is_terminated():
dest = post_finalizer.append(ir.GetLocal(final_state, "$k")) dest = post_finalizer.append(ir.GetLocal(final_state, "$cont"))
post_finalizer.append(ir.IndirectBranch(dest, final_targets)) post_finalizer.append(ir.IndirectBranch(dest, final_targets))
else: else:
if not body.is_terminated(): if not body.is_terminated():
@ -753,7 +754,7 @@ class ARTIQIRGenerator(algorithm.Visitor):
heads, tails = [], [] heads, tails = [], []
for stmt in node.body: for stmt in node.body:
self.current_block = self.add_block() self.current_block = self.add_block("interleave.branch")
heads.append(self.current_block) heads.append(self.current_block)
self.visit(stmt) self.visit(stmt)
tails.append(self.current_block) tails.append(self.current_block)
@ -761,7 +762,7 @@ class ARTIQIRGenerator(algorithm.Visitor):
for head in heads: for head in heads:
interleave.add_destination(head) interleave.add_destination(head)
self.current_block = self.add_block() self.current_block = self.add_block("interleave.tail")
for tail in tails: for tail in tails:
if not tail.is_terminated(): if not tail.is_terminated():
tail.append(ir.Branch(self.current_block)) tail.append(ir.Branch(self.current_block))
@ -773,7 +774,7 @@ class ARTIQIRGenerator(algorithm.Visitor):
for stmt in node.body: for stmt in node.body:
self.append(ir.Builtin("at_mu", [start_mu], builtins.TNone())) self.append(ir.Builtin("at_mu", [start_mu], builtins.TNone()))
block = self.add_block() block = self.add_block("parallel.branch")
if self.current_block.is_terminated(): if self.current_block.is_terminated():
self.warn_unreachable(stmt[0]) self.warn_unreachable(stmt[0])
else: else:
@ -837,17 +838,17 @@ class ARTIQIRGenerator(algorithm.Visitor):
cond = self.visit(node.test) cond = self.visit(node.test)
head = self.current_block head = self.current_block
if_true = self.add_block() if_true = self.add_block("ifexp.body")
self.current_block = if_true self.current_block = if_true
true_result = self.visit(node.body) true_result = self.visit(node.body)
post_if_true = self.current_block post_if_true = self.current_block
if_false = self.add_block() if_false = self.add_block("ifexp.else")
self.current_block = if_false self.current_block = if_false
false_result = self.visit(node.orelse) false_result = self.visit(node.orelse)
post_if_false = self.current_block post_if_false = self.current_block
tail = self.add_block() tail = self.add_block("ifexp.tail")
self.current_block = tail self.current_block = tail
if not post_if_true.is_terminated(): if not post_if_true.is_terminated():
@ -881,10 +882,10 @@ class ARTIQIRGenerator(algorithm.Visitor):
if self.current_class is not None and \ if self.current_class is not None and \
name in self.current_class.type.attributes: name in self.current_class.type.attributes:
return self.append(ir.GetAttr(self.current_class, name, return self.append(ir.GetAttr(self.current_class, name,
name="local." + name)) name="FLD." + name))
return self.append(ir.GetLocal(self._env_for(name), name, return self.append(ir.GetLocal(self._env_for(name), name,
name="local." + name)) name="LOC." + name))
def _set_local(self, name, value): def _set_local(self, name, value):
if self.current_class is not None and \ if self.current_class is not None and \
@ -910,7 +911,7 @@ class ARTIQIRGenerator(algorithm.Visitor):
if self.current_assign is None: if self.current_assign is None:
return self.append(ir.GetAttr(obj, node.attr, return self.append(ir.GetAttr(obj, node.attr,
name="{}.{}".format(_readable_name(obj), node.attr))) name="{}.FLD.{}".format(_readable_name(obj), node.attr)))
elif types.is_rpc_function(self.current_assign.type): elif types.is_rpc_function(self.current_assign.type):
# RPC functions are just type-level markers # RPC functions are just type-level markers
return self.append(ir.Builtin("nop", [], builtins.TNone())) return self.append(ir.Builtin("nop", [], builtins.TNone()))
@ -930,47 +931,47 @@ class ARTIQIRGenerator(algorithm.Visitor):
ir.Constant(False, builtins.TBool()))) ir.Constant(False, builtins.TBool())))
head = self.current_block head = self.current_block
self.current_block = out_of_bounds_block = self.add_block() self.current_block = out_of_bounds_block = self.add_block("index.outofbounds")
exn = self.alloc_exn(builtins.TException("IndexError"), exn = self.alloc_exn(builtins.TException("IndexError"),
ir.Constant("index {0} out of bounds 0:{1}", builtins.TStr()), ir.Constant("index {0} out of bounds 0:{1}", builtins.TStr()),
index, length) index, length)
self.raise_exn(exn, loc=loc) self.raise_exn(exn, loc=loc)
self.current_block = in_bounds_block = self.add_block() self.current_block = in_bounds_block = self.add_block("index.inbounds")
head.append(ir.BranchIf(in_bounds, in_bounds_block, out_of_bounds_block)) head.append(ir.BranchIf(in_bounds, in_bounds_block, out_of_bounds_block))
return mapped_index return mapped_index
def _make_check(self, cond, exn_gen, loc=None): def _make_check(self, cond, exn_gen, loc=None, name="check"):
# cond: bool Value, condition # cond: bool Value, condition
# exn_gen: lambda()->exn Value, exception if condition not true # exn_gen: lambda()->exn Value, exception if condition not true
cond_block = self.current_block cond_block = self.current_block
self.current_block = body_block = self.add_block() self.current_block = body_block = self.add_block("{}.body".format(name))
self.raise_exn(exn_gen(), loc=loc) self.raise_exn(exn_gen(), loc=loc)
self.current_block = tail_block = self.add_block() self.current_block = tail_block = self.add_block("{}.tail".format(name))
cond_block.append(ir.BranchIf(cond, tail_block, body_block)) cond_block.append(ir.BranchIf(cond, tail_block, body_block))
def _make_loop(self, init, cond_gen, body_gen): def _make_loop(self, init, cond_gen, body_gen, name="loop"):
# init: 'iter Value, initial loop variable value # init: 'iter Value, initial loop variable value
# cond_gen: lambda('iter Value)->bool Value, loop condition # cond_gen: lambda('iter Value)->bool Value, loop condition
# body_gen: lambda('iter Value)->'iter Value, loop body, # body_gen: lambda('iter Value)->'iter Value, loop body,
# returns next loop variable value # returns next loop variable value
init_block = self.current_block init_block = self.current_block
self.current_block = head_block = self.add_block() self.current_block = head_block = self.add_block("{}.head".format(name))
init_block.append(ir.Branch(head_block)) init_block.append(ir.Branch(head_block))
phi = self.append(ir.Phi(init.type)) phi = self.append(ir.Phi(init.type))
phi.add_incoming(init, init_block) phi.add_incoming(init, init_block)
cond = cond_gen(phi) cond = cond_gen(phi)
self.current_block = body_block = self.add_block() self.current_block = body_block = self.add_block("{}.body".format(name))
body = body_gen(phi) body = body_gen(phi)
self.append(ir.Branch(head_block)) self.append(ir.Branch(head_block))
phi.add_incoming(body, self.current_block) phi.add_incoming(body, self.current_block)
self.current_block = tail_block = self.add_block() self.current_block = tail_block = self.add_block("{}.tail".format(name))
head_block.append(ir.BranchIf(cond, body_block, tail_block)) head_block.append(ir.BranchIf(cond, body_block, tail_block))
return head_block, body_block, tail_block return head_block, body_block, tail_block
@ -1072,7 +1073,7 @@ class ARTIQIRGenerator(algorithm.Visitor):
prehead = self.current_block prehead = self.current_block
head = self.current_block = self.add_block() head = self.current_block = self.add_block("slice.head")
prehead.append(ir.Branch(head)) prehead.append(ir.Branch(head))
index = self.append(ir.Phi(node.slice.type, index = self.append(ir.Phi(node.slice.type,
@ -1087,7 +1088,7 @@ class ARTIQIRGenerator(algorithm.Visitor):
bounded_down = self.append(ir.Compare(ast.Gt(loc=None), index, mapped_stop_index)) bounded_down = self.append(ir.Compare(ast.Gt(loc=None), index, mapped_stop_index))
within_bounds = self.append(ir.Select(counting_up, bounded_up, bounded_down)) within_bounds = self.append(ir.Select(counting_up, bounded_up, bounded_down))
body = self.current_block = self.add_block() body = self.current_block = self.add_block("slice.body")
if self.current_assign is None: if self.current_assign is None:
elem = self.iterable_get(value, index) elem = self.iterable_get(value, index)
@ -1103,7 +1104,7 @@ class ARTIQIRGenerator(algorithm.Visitor):
other_index.add_incoming(next_other_index, body) other_index.add_incoming(next_other_index, body)
self.append(ir.Branch(head)) self.append(ir.Branch(head))
tail = self.current_block = self.add_block() tail = self.current_block = self.add_block("slice.tail")
head.append(ir.BranchIf(within_bounds, body, tail)) head.append(ir.BranchIf(within_bounds, body, tail))
if self.current_assign is None: if self.current_assign is None:
@ -1197,7 +1198,7 @@ class ARTIQIRGenerator(algorithm.Visitor):
value_tail = self.current_block value_tail = self.current_block
blocks.append((value, value_head, value_tail)) blocks.append((value, value_head, value_tail))
self.current_block = self.add_block() self.current_block = self.add_block("boolop.seq")
tail = self.current_block tail = self.current_block
phi = self.append(ir.Phi(node.type)) phi = self.append(ir.Phi(node.type))
@ -1366,26 +1367,26 @@ class ARTIQIRGenerator(algorithm.Visitor):
# If the length is the same, compare element-by-element # If the length is the same, compare element-by-element
# and break when the comparison result is false # and break when the comparison result is false
loop_head = self.add_block() loop_head = self.add_block("compare.head")
self.current_block = loop_head self.current_block = loop_head
index_phi = self.append(ir.Phi(self._size_type)) index_phi = self.append(ir.Phi(self._size_type))
index_phi.add_incoming(ir.Constant(0, self._size_type), head) index_phi.add_incoming(ir.Constant(0, self._size_type), head)
loop_cond = self.append(ir.Compare(ast.Lt(loc=None), index_phi, lhs_length)) loop_cond = self.append(ir.Compare(ast.Lt(loc=None), index_phi, lhs_length))
loop_body = self.add_block() loop_body = self.add_block("compare.body")
self.current_block = loop_body self.current_block = loop_body
lhs_elt = self.append(ir.GetElem(lhs, index_phi)) lhs_elt = self.append(ir.GetElem(lhs, index_phi))
rhs_elt = self.append(ir.GetElem(rhs, index_phi)) rhs_elt = self.append(ir.GetElem(rhs, index_phi))
body_result = self.polymorphic_compare_pair(op, lhs_elt, rhs_elt) body_result = self.polymorphic_compare_pair(op, lhs_elt, rhs_elt)
loop_body2 = self.add_block() loop_body2 = self.add_block("compare.body2")
self.current_block = loop_body2 self.current_block = loop_body2
index_next = self.append(ir.Arith(ast.Add(loc=None), index_phi, index_next = self.append(ir.Arith(ast.Add(loc=None), index_phi,
ir.Constant(1, self._size_type))) ir.Constant(1, self._size_type)))
self.append(ir.Branch(loop_head)) self.append(ir.Branch(loop_head))
index_phi.add_incoming(index_next, loop_body2) index_phi.add_incoming(index_next, loop_body2)
tail = self.add_block() tail = self.add_block("compare.tail")
self.current_block = tail self.current_block = tail
phi = self.append(ir.Phi(builtins.TBool())) phi = self.append(ir.Phi(builtins.TBool()))
head.append(ir.BranchIf(eq_length, loop_head, tail)) head.append(ir.BranchIf(eq_length, loop_head, tail))
@ -1431,14 +1432,14 @@ class ARTIQIRGenerator(algorithm.Visitor):
elt = self.iterable_get(haystack, index) elt = self.iterable_get(haystack, index)
cmp_result = self.polymorphic_compare_pair(ast.Eq(loc=None), needle, elt) cmp_result = self.polymorphic_compare_pair(ast.Eq(loc=None), needle, elt)
loop_body2 = self.add_block() loop_body2 = self.add_block("compare.body")
self.current_block = loop_body2 self.current_block = loop_body2
return self.append(ir.Arith(ast.Add(loc=None), index, return self.append(ir.Arith(ast.Add(loc=None), index,
ir.Constant(1, length.type))) ir.Constant(1, length.type)))
loop_head, loop_body, loop_tail = \ loop_head, loop_body, loop_tail = \
self._make_loop(ir.Constant(0, length.type), self._make_loop(ir.Constant(0, length.type),
lambda index: self.append(ir.Compare(ast.Lt(loc=None), index, length)), lambda index: self.append(ir.Compare(ast.Lt(loc=None), index, length)),
body_gen) body_gen, name="compare")
loop_body.append(ir.BranchIf(cmp_result, loop_tail, loop_body2)) loop_body.append(ir.BranchIf(cmp_result, loop_tail, loop_body2))
phi = loop_tail.prepend(ir.Phi(builtins.TBool())) phi = loop_tail.prepend(ir.Phi(builtins.TBool()))
@ -1479,7 +1480,7 @@ class ARTIQIRGenerator(algorithm.Visitor):
result_tail = self.current_block result_tail = self.current_block
blocks.append((result, result_head, result_tail)) blocks.append((result, result_head, result_tail))
self.current_block = self.add_block() self.current_block = self.add_block("compare.seq")
lhs = rhs lhs = rhs
tail = self.current_block tail = self.current_block
@ -1674,8 +1675,10 @@ class ARTIQIRGenerator(algorithm.Visitor):
fn_typ = callee.type fn_typ = callee.type
offset = 0 offset = 0
elif types.is_method(callee.type): elif types.is_method(callee.type):
func = self.append(ir.GetAttr(callee, "__func__")) func = self.append(ir.GetAttr(callee, "__func__",
self_arg = self.append(ir.GetAttr(callee, "__self__")) name="{}.CLS".format(callee.name)))
self_arg = self.append(ir.GetAttr(callee, "__self__",
name="{}.SLF".format(callee.name)))
fn_typ = types.get_method_function(callee.type) fn_typ = types.get_method_function(callee.type)
offset = 1 offset = 1
else: else:
@ -1719,7 +1722,7 @@ class ARTIQIRGenerator(algorithm.Visitor):
if self.unwind_target is None: if self.unwind_target is None:
insn = self.append(ir.Call(func, args, arg_exprs)) insn = self.append(ir.Call(func, args, arg_exprs))
else: else:
after_invoke = self.add_block() after_invoke = self.add_block("invoke")
insn = self.append(ir.Invoke(func, args, arg_exprs, insn = self.append(ir.Invoke(func, args, arg_exprs,
after_invoke, self.unwind_target)) after_invoke, self.unwind_target))
self.current_block = after_invoke self.current_block = after_invoke
@ -1734,7 +1737,7 @@ class ARTIQIRGenerator(algorithm.Visitor):
if node.iodelay is not None and not iodelay.is_const(node.iodelay, 0): if node.iodelay is not None and not iodelay.is_const(node.iodelay, 0):
before_delay = self.current_block before_delay = self.current_block
during_delay = self.add_block() during_delay = self.add_block("delay.head")
before_delay.append(ir.Branch(during_delay)) before_delay.append(ir.Branch(during_delay))
self.current_block = during_delay self.current_block = during_delay
@ -1748,7 +1751,7 @@ class ARTIQIRGenerator(algorithm.Visitor):
self.method_map[(attr_node.value.type.find(), attr_node.attr)].append(insn) self.method_map[(attr_node.value.type.find(), attr_node.attr)].append(insn)
if node.iodelay is not None and not iodelay.is_const(node.iodelay, 0): if node.iodelay is not None and not iodelay.is_const(node.iodelay, 0):
after_delay = self.add_block() after_delay = self.add_block("delay.tail")
self.append(ir.Delay(node.iodelay, insn, after_delay)) self.append(ir.Delay(node.iodelay, insn, after_delay))
self.current_block = after_delay self.current_block = after_delay
@ -1783,7 +1786,7 @@ class ARTIQIRGenerator(algorithm.Visitor):
assert_subexprs = self.current_assert_subexprs = [] assert_subexprs = self.current_assert_subexprs = []
init = self.current_block init = self.current_block
prehead = self.current_block = self.add_block() prehead = self.current_block = self.add_block("assert.prehead")
cond = self.visit(node.test) cond = self.visit(node.test)
head = self.current_block head = self.current_block
finally: finally:
@ -1795,7 +1798,7 @@ class ARTIQIRGenerator(algorithm.Visitor):
init.append(ir.SetLocal(assert_env, subexpr_name, empty)) init.append(ir.SetLocal(assert_env, subexpr_name, empty))
init.append(ir.Branch(prehead)) init.append(ir.Branch(prehead))
if_failed = self.current_block = self.add_block() if_failed = self.current_block = self.add_block("assert.fail")
if node.msg: if node.msg:
explanation = node.msg.s explanation = node.msg.s
@ -1813,7 +1816,7 @@ class ARTIQIRGenerator(algorithm.Visitor):
subexpr_cond = self.append(ir.Builtin("is_some", [subexpr_value_opt], subexpr_cond = self.append(ir.Builtin("is_some", [subexpr_value_opt],
builtins.TBool())) builtins.TBool()))
subexpr_body = self.current_block = self.add_block() subexpr_body = self.current_block = self.add_block("assert.subexpr.body")
self.append(ir.Builtin("printf", [ self.append(ir.Builtin("printf", [
ir.Constant(" (%s) = ", builtins.TStr()), ir.Constant(" (%s) = ", builtins.TStr()),
ir.Constant(subexpr_node.loc.source(), builtins.TStr()) ir.Constant(subexpr_node.loc.source(), builtins.TStr())
@ -1823,14 +1826,14 @@ class ARTIQIRGenerator(algorithm.Visitor):
self.polymorphic_print([subexpr_value], separator="", suffix="\n") self.polymorphic_print([subexpr_value], separator="", suffix="\n")
subexpr_postbody = self.current_block subexpr_postbody = self.current_block
subexpr_tail = self.current_block = self.add_block() subexpr_tail = self.current_block = self.add_block("assert.subexpr.tail")
self.append(ir.Branch(subexpr_tail), block=subexpr_postbody) self.append(ir.Branch(subexpr_tail), block=subexpr_postbody)
self.append(ir.BranchIf(subexpr_cond, subexpr_body, subexpr_tail), block=subexpr_head) self.append(ir.BranchIf(subexpr_cond, subexpr_body, subexpr_tail), block=subexpr_head)
self.append(ir.Builtin("abort", [], builtins.TNone())) self.append(ir.Builtin("abort", [], builtins.TNone()))
self.append(ir.Unreachable()) self.append(ir.Unreachable())
tail = self.current_block = self.add_block() tail = self.current_block = self.add_block("assert.tail")
self.append(ir.BranchIf(cond, tail, if_failed), block=head) self.append(ir.BranchIf(cond, tail, if_failed), block=head)
def polymorphic_print(self, values, separator, suffix="", as_repr=False, as_rtio=False): def polymorphic_print(self, values, separator, suffix="", as_repr=False, as_rtio=False):
@ -1904,10 +1907,10 @@ class ARTIQIRGenerator(algorithm.Visitor):
is_last = self.append(ir.Compare(ast.Lt(loc=None), index, last)) is_last = self.append(ir.Compare(ast.Lt(loc=None), index, last))
head = self.current_block head = self.current_block
if_last = self.current_block = self.add_block() if_last = self.current_block = self.add_block("print.comma")
printf(", ") printf(", ")
tail = self.current_block = self.add_block() tail = self.current_block = self.add_block("print.tail")
if_last.append(ir.Branch(tail)) if_last.append(ir.Branch(tail))
head.append(ir.BranchIf(is_last, if_last, tail)) head.append(ir.BranchIf(is_last, if_last, tail))

View File

@ -269,11 +269,11 @@ class LLVMIRGenerator:
return llty.as_pointer() return llty.as_pointer()
else: # Catch-all for exceptions and custom classes else: # Catch-all for exceptions and custom classes
if builtins.is_exception(typ): if builtins.is_exception(typ):
name = "class.Exception" # they all share layout name = "C.Exception" # they all share layout
elif types.is_constructor(typ): elif types.is_constructor(typ):
name = "class.{}".format(typ.name) name = "C.{}".format(typ.name)
else: else:
name = "instance.{}".format(typ.name) name = "I.{}".format(typ.name)
llty = self.llcontext.get_identified_type(name) llty = self.llcontext.get_identified_type(name)
if llty.elements is None: if llty.elements is None:
@ -297,7 +297,7 @@ class LLVMIRGenerator:
if name is None: if name is None:
sanitized_str = re.sub(rb"[^a-zA-Z0-9_.]", b"", as_bytes[:20]).decode('ascii') sanitized_str = re.sub(rb"[^a-zA-Z0-9_.]", b"", as_bytes[:20]).decode('ascii')
name = self.llmodule.get_unique_name("str.{}".format(sanitized_str)) name = self.llmodule.get_unique_name("S.{}".format(sanitized_str))
llstr = self.llmodule.get_global(name) llstr = self.llmodule.get_global(name)
if llstr is None: if llstr is None:
@ -439,16 +439,16 @@ class LLVMIRGenerator:
else: else:
typ, _ = self.type_map[type(obj_ref)] typ, _ = self.type_map[type(obj_ref)]
llobject = self.llmodule.get_global("object.{}".format(obj_id)) llobject = self.llmodule.get_global("O.{}".format(obj_id))
if llobject is not None: if llobject is not None:
llobjects[typ].append(llobject.bitcast(llptr)) llobjects[typ].append(llobject.bitcast(llptr))
lldatalayout = llvm.create_target_data(self.llmodule.data_layout) lldatalayout = llvm.create_target_data(self.llmodule.data_layout)
llrpcattrty = self.llcontext.get_identified_type("attr_desc") llrpcattrty = self.llcontext.get_identified_type("A")
llrpcattrty.elements = [lli32, lli32, llptr, llptr] llrpcattrty.elements = [lli32, lli32, llptr, llptr]
lldescty = self.llcontext.get_identified_type("type_desc") lldescty = self.llcontext.get_identified_type("D")
lldescty.elements = [llrpcattrty.as_pointer().as_pointer(), llptr.as_pointer()] lldescty.elements = [llrpcattrty.as_pointer().as_pointer(), llptr.as_pointer()]
lldescs = [] lldescs = []
@ -457,9 +457,9 @@ class LLVMIRGenerator:
continue continue
if types.is_constructor(typ): if types.is_constructor(typ):
type_name = "class.{}".format(typ.name) type_name = "C.{}".format(typ.name)
else: else:
type_name = "instance.{}".format(typ.name) type_name = "I.{}".format(typ.name)
def llrpcattr_of_attr(name, typ): def llrpcattr_of_attr(name, typ):
size = self.llty_of_type(typ). \ size = self.llty_of_type(typ). \
@ -478,14 +478,19 @@ class LLVMIRGenerator:
else: else:
llrpctag = ll.Constant(llptr, None) llrpctag = ll.Constant(llptr, None)
llrpcattr = ll.GlobalVariable(self.llmodule, llrpcattrty, llrpcattrinit = ll.Constant(llrpcattrty, [
name="attr.{}.{}".format(type_name, name))
llrpcattr.initializer = ll.Constant(llrpcattrty, [
ll.Constant(lli32, size), ll.Constant(lli32, size),
ll.Constant(lli32, alignment), ll.Constant(lli32, alignment),
llrpctag, llrpctag,
self.llstr_of_str(name) self.llstr_of_str(name)
]) ])
if name == "__objectid__":
return self.get_or_define_global(name, llrpcattrty, llrpcattrinit)
llrpcattr = ll.GlobalVariable(self.llmodule, llrpcattrty,
name="A.{}.{}".format(type_name, name))
llrpcattr.initializer = llrpcattrinit
llrpcattr.global_constant = True llrpcattr.global_constant = True
llrpcattr.unnamed_addr = True llrpcattr.unnamed_addr = True
llrpcattr.linkage = 'private' llrpcattr.linkage = 'private'
@ -497,7 +502,7 @@ class LLVMIRGenerator:
llrpcattraryty = ll.ArrayType(llrpcattrty.as_pointer(), len(llrpcattrs) + 1) llrpcattraryty = ll.ArrayType(llrpcattrty.as_pointer(), len(llrpcattrs) + 1)
llrpcattrary = ll.GlobalVariable(self.llmodule, llrpcattraryty, llrpcattrary = ll.GlobalVariable(self.llmodule, llrpcattraryty,
name="attrs.{}".format(type_name)) name="Ax.{}".format(type_name))
llrpcattrary.initializer = ll.Constant(llrpcattraryty, llrpcattrary.initializer = ll.Constant(llrpcattraryty,
llrpcattrs + [ll.Constant(llrpcattrty.as_pointer(), None)]) llrpcattrs + [ll.Constant(llrpcattrty.as_pointer(), None)])
llrpcattrary.global_constant = True llrpcattrary.global_constant = True
@ -506,13 +511,13 @@ class LLVMIRGenerator:
llobjectaryty = ll.ArrayType(llptr, len(llobjects[typ]) + 1) llobjectaryty = ll.ArrayType(llptr, len(llobjects[typ]) + 1)
llobjectary = ll.GlobalVariable(self.llmodule, llobjectaryty, llobjectary = ll.GlobalVariable(self.llmodule, llobjectaryty,
name="objects.{}".format(type_name)) name="Ox.{}".format(type_name))
llobjectary.initializer = ll.Constant(llobjectaryty, llobjectary.initializer = ll.Constant(llobjectaryty,
llobjects[typ] + [ll.Constant(llptr, None)]) llobjects[typ] + [ll.Constant(llptr, None)])
llobjectary.linkage = 'private' llobjectary.linkage = 'private'
lldesc = ll.GlobalVariable(self.llmodule, lldescty, lldesc = ll.GlobalVariable(self.llmodule, lldescty,
name="desc.{}".format(type_name)) name="D.{}".format(type_name))
lldesc.initializer = ll.Constant(lldescty, [ lldesc.initializer = ll.Constant(lldescty, [
llrpcattrary.bitcast(llrpcattrty.as_pointer().as_pointer()), llrpcattrary.bitcast(llrpcattrty.as_pointer().as_pointer()),
llobjectary.bitcast(llptr.as_pointer()) llobjectary.bitcast(llptr.as_pointer())
@ -548,6 +553,7 @@ class LLVMIRGenerator:
llactualargs = self.llfunction.args llactualargs = self.llfunction.args
for arg, llarg in zip(func.arguments, llactualargs): for arg, llarg in zip(func.arguments, llactualargs):
llarg.name = arg.name
self.llmap[arg] = llarg self.llmap[arg] = llarg
# Second, create all basic blocks. # Second, create all basic blocks.
@ -649,7 +655,8 @@ class LLVMIRGenerator:
def process_GetLocal(self, insn): def process_GetLocal(self, insn):
env = insn.environment() env = insn.environment()
llptr = self.llptr_to_var(self.map(env), env.type, insn.var_name) llptr = self.llptr_to_var(self.map(env), env.type, insn.var_name)
return self.llbuilder.load(llptr) llptr.name = "ptr.{}.{}".format(env.name, insn.var_name)
return self.llbuilder.load(llptr, name="val.{}.{}".format(env.name, insn.var_name))
def process_SetLocal(self, insn): def process_SetLocal(self, insn):
env = insn.environment() env = insn.environment()
@ -658,6 +665,7 @@ class LLVMIRGenerator:
# We store NoneType as {} but return it as void. So, bail out here. # We store NoneType as {} but return it as void. So, bail out here.
return ll.Constant(ll.LiteralStructType([]), []) return ll.Constant(ll.LiteralStructType([]), [])
llptr = self.llptr_to_var(self.map(env), env.type, insn.var_name) llptr = self.llptr_to_var(self.map(env), env.type, insn.var_name)
llptr.name = "ptr.{}.{}".format(env.name, insn.var_name)
if isinstance(llvalue, ll.Block): if isinstance(llvalue, ll.Block):
llvalue = ll.BlockAddress(self.llfunction, llvalue) llvalue = ll.BlockAddress(self.llfunction, llvalue)
if llptr.type.pointee != llvalue.type: if llptr.type.pointee != llvalue.type:
@ -687,13 +695,13 @@ class LLVMIRGenerator:
def get_class(self, typ): def get_class(self, typ):
assert types.is_constructor(typ) assert types.is_constructor(typ)
llty = self.llty_of_type(typ).pointee llty = self.llty_of_type(typ).pointee
return self.get_or_define_global("class.{}".format(typ.name), llty) return self.get_or_define_global("C.{}".format(typ.name), llty)
def get_method(self, typ, attr): def get_method(self, typ, attr):
assert types.is_constructor(typ) assert types.is_constructor(typ)
assert types.is_function(typ.attributes[attr]) assert types.is_function(typ.attributes[attr])
llty = self.llty_of_type(typ.attributes[attr]) llty = self.llty_of_type(typ.attributes[attr])
return self.get_or_define_global("method.{}.{}".format(typ.name, attr), llty) return self.get_or_define_global("M.{}.{}".format(typ.name, attr), llty)
def process_GetAttr(self, insn): def process_GetAttr(self, insn):
typ, attr = insn.object().type, insn.attr typ, attr = insn.object().type, insn.attr
@ -715,7 +723,9 @@ class LLVMIRGenerator:
assert False assert False
if types.is_method(insn.type) and attr not in typ.attributes: if types.is_method(insn.type) and attr not in typ.attributes:
llfun = self.llbuilder.load(self.get_method(typ.constructor, attr)) llmethodptr = self.get_method(typ.constructor, attr)
llfun = self.llbuilder.load(llmethodptr)
llfun.name = "met.{}.{}".format(typ.constructor.name, attr)
llself = self.map(insn.object()) llself = self.map(insn.object())
llmethodty = self.llty_of_type(insn.type) llmethodty = self.llty_of_type(insn.type)
@ -727,11 +737,12 @@ class LLVMIRGenerator:
return llmethod return llmethod
elif types.is_function(insn.type) and attr in typ.attributes and \ elif types.is_function(insn.type) and attr in typ.attributes and \
types.is_constructor(typ): types.is_constructor(typ):
return self.llbuilder.load(self.get_method(typ, attr)) llmethodptr = self.get_method(typ, attr)
return self.llbuilder.load(llmethodptr, name="cls.{}".format(llmethodptr.name))
else: else:
llptr = self.llbuilder.gep(obj, [self.llindex(0), self.llindex(index)], llptr = self.llbuilder.gep(obj, [self.llindex(0), self.llindex(index)],
inbounds=True, name=insn.name) inbounds=True, name="ptr.{}".format(insn.name))
return self.llbuilder.load(llptr) return self.llbuilder.load(llptr, name="val.{}".format(insn.name))
def process_SetAttr(self, insn): def process_SetAttr(self, insn):
typ, attr = insn.object().type, insn.attr typ, attr = insn.object().type, insn.attr
@ -979,8 +990,8 @@ class LLVMIRGenerator:
elif insn.op == "delay_mu": elif insn.op == "delay_mu":
interval, = insn.operands interval, = insn.operands
llnowptr = self.llbuiltin("now") llnowptr = self.llbuiltin("now")
llnow = self.llbuilder.load(llnowptr) llnow = self.llbuilder.load(llnowptr, name="now.old")
lladjusted = self.llbuilder.add(llnow, self.map(interval)) lladjusted = self.llbuilder.add(llnow, self.map(interval), name="now.new")
return self.llbuilder.store(lladjusted, llnowptr) return self.llbuilder.store(lladjusted, llnowptr)
elif insn.op == "watchdog_set": elif insn.op == "watchdog_set":
interval, = insn.operands interval, = insn.operands
@ -992,11 +1003,12 @@ class LLVMIRGenerator:
assert False assert False
def process_Closure(self, insn): def process_Closure(self, insn):
llenv = self.llbuilder.bitcast(self.map(insn.environment()), llptr) llenv = self.map(insn.environment())
llenv = self.llbuilder.bitcast(llenv, llptr, name="ptr.{}".format(llenv.name))
if insn.target_function.name in self.function_map.values(): if insn.target_function.name in self.function_map.values():
# If this closure belongs to a quoted function, we assume this is the only # If this closure belongs to a quoted function, we assume this is the only
# time that the closure is created, and record the environment globally # time that the closure is created, and record the environment globally
llenvptr = self.get_or_define_global("env.{}".format(insn.target_function.name), llenvptr = self.get_or_define_global("E.{}".format(insn.target_function.name),
llptr) llptr)
self.llbuilder.store(llenv, llenvptr) self.llbuilder.store(llenv, llenvptr)
@ -1009,9 +1021,10 @@ class LLVMIRGenerator:
def _prepare_closure_call(self, insn): def _prepare_closure_call(self, insn):
llargs = [self.map(arg) for arg in insn.arguments()] llargs = [self.map(arg) for arg in insn.arguments()]
llclosure = self.map(insn.target_function()) llclosure = self.map(insn.target_function())
llenv = self.llbuilder.extract_value(llclosure, 0) llenv = self.llbuilder.extract_value(llclosure, 0, name="env.call")
if insn.static_target_function is None: if insn.static_target_function is None:
llfun = self.llbuilder.extract_value(llclosure, 1) llfun = self.llbuilder.extract_value(llclosure, 1,
name="fun.{}".format(llclosure.name))
else: else:
llfun = self.map(insn.static_target_function) llfun = self.map(insn.static_target_function)
return llfun, [llenv] + list(llargs) return llfun, [llenv] + list(llargs)
@ -1119,15 +1132,18 @@ class LLVMIRGenerator:
lltag = self.llstr_of_str(tag) lltag = self.llstr_of_str(tag)
llstackptr = self.llbuilder.call(self.llbuiltin("llvm.stacksave"), []) llstackptr = self.llbuilder.call(self.llbuiltin("llvm.stacksave"), [],
name="rpc.stack")
llargs = [] llargs = []
for arg in args: for index, arg in enumerate(args):
if builtins.is_none(arg.type): if builtins.is_none(arg.type):
llargslot = self.llbuilder.alloca(ll.LiteralStructType([])) llargslot = self.llbuilder.alloca(ll.LiteralStructType([]),
name="rpc.arg{}".format(index))
else: else:
llarg = self.map(arg) llarg = self.map(arg)
llargslot = self.llbuilder.alloca(llarg.type) llargslot = self.llbuilder.alloca(llarg.type,
name="rpc.arg{}".format(index))
self.llbuilder.store(llarg, llargslot) self.llbuilder.store(llarg, llargslot)
llargs.append(llargslot) llargs.append(llargslot)
@ -1144,36 +1160,39 @@ class LLVMIRGenerator:
# else *(T*)ptr # else *(T*)ptr
# } # }
llprehead = self.llbuilder.basic_block llprehead = self.llbuilder.basic_block
llhead = self.llbuilder.append_basic_block(name=llprehead.name + ".rpc.head") llhead = self.llbuilder.append_basic_block(name="rpc.head")
if llunwindblock: if llunwindblock:
llheadu = self.llbuilder.append_basic_block(name=llprehead.name + ".rpc.head.unwind") llheadu = self.llbuilder.append_basic_block(name="rpc.head.unwind")
llalloc = self.llbuilder.append_basic_block(name=llprehead.name + ".rpc.alloc") llalloc = self.llbuilder.append_basic_block(name="rpc.continue")
lltail = self.llbuilder.append_basic_block(name=llprehead.name + ".rpc.tail") lltail = self.llbuilder.append_basic_block(name="rpc.tail")
llretty = self.llty_of_type(fun_type.ret) llretty = self.llty_of_type(fun_type.ret)
llslot = self.llbuilder.alloca(llretty) llslot = self.llbuilder.alloca(llretty, name="rpc.ret.alloc")
llslotgen = self.llbuilder.bitcast(llslot, llptr) llslotgen = self.llbuilder.bitcast(llslot, llptr, name="rpc.ret.ptr")
self.llbuilder.branch(llhead) self.llbuilder.branch(llhead)
self.llbuilder.position_at_end(llhead) self.llbuilder.position_at_end(llhead)
llphi = self.llbuilder.phi(llslotgen.type) llphi = self.llbuilder.phi(llslotgen.type, name="rpc.size")
llphi.add_incoming(llslotgen, llprehead) llphi.add_incoming(llslotgen, llprehead)
if llunwindblock: if llunwindblock:
llsize = self.llbuilder.invoke(self.llbuiltin("recv_rpc"), [llphi], llsize = self.llbuilder.invoke(self.llbuiltin("recv_rpc"), [llphi],
llheadu, llunwindblock) llheadu, llunwindblock,
name="rpc.size.next")
self.llbuilder.position_at_end(llheadu) self.llbuilder.position_at_end(llheadu)
else: else:
llsize = self.llbuilder.call(self.llbuiltin("recv_rpc"), [llphi]) llsize = self.llbuilder.call(self.llbuiltin("recv_rpc"), [llphi],
lldone = self.llbuilder.icmp_unsigned('==', llsize, ll.Constant(llsize.type, 0)) name="rpc.size.next")
lldone = self.llbuilder.icmp_unsigned('==', llsize, ll.Constant(llsize.type, 0),
name="rpc.done")
self.llbuilder.cbranch(lldone, lltail, llalloc) self.llbuilder.cbranch(lldone, lltail, llalloc)
self.llbuilder.position_at_end(llalloc) self.llbuilder.position_at_end(llalloc)
llalloca = self.llbuilder.alloca(lli8, llsize) llalloca = self.llbuilder.alloca(lli8, llsize, name="rpc.alloc")
llphi.add_incoming(llalloca, llalloc) llphi.add_incoming(llalloca, llalloc)
self.llbuilder.branch(llhead) self.llbuilder.branch(llhead)
self.llbuilder.position_at_end(lltail) self.llbuilder.position_at_end(lltail)
llret = self.llbuilder.load(llslot) llret = self.llbuilder.load(llslot, name="rpc.ret")
if not builtins.is_allocated(fun_type.ret): if not builtins.is_allocated(fun_type.ret):
# We didn't allocate anything except the slot for the value itself. # We didn't allocate anything except the slot for the value itself.
# Don't waste stack space. # Don't waste stack space.
@ -1243,7 +1262,7 @@ class LLVMIRGenerator:
llglobal = self.get_class(typ) llglobal = self.get_class(typ)
else: else:
llglobal = ll.GlobalVariable(self.llmodule, llty.pointee, llglobal = ll.GlobalVariable(self.llmodule, llty.pointee,
name="object.{}".format(objectid)) name="O.{}".format(objectid))
self.llobject_map[value_id] = llglobal self.llobject_map[value_id] = llglobal
else: else:
@ -1297,7 +1316,7 @@ class LLVMIRGenerator:
def process_Quote(self, insn): def process_Quote(self, insn):
if insn.value in self.function_map: if insn.value in self.function_map:
func_name = self.function_map[insn.value] func_name = self.function_map[insn.value]
llenvptr = self.get_or_define_global("env.{}".format(func_name), llptr) llenvptr = self.get_or_define_global("E.{}".format(func_name), llptr)
llenv = self.llbuilder.load(llenvptr) llenv = self.llbuilder.load(llenvptr)
llfun = self.get_function(insn.type.find(), func_name) llfun = self.get_function(insn.type.find(), func_name)