Skip to content

Commit

Permalink
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
compiler: significantly increase readability of LLVM and ARTIQ IRs.
Browse files Browse the repository at this point in the history
whitequark committed Mar 26, 2016
1 parent 8d05666 commit 63e367a
Showing 3 changed files with 133 additions and 109 deletions.
6 changes: 4 additions & 2 deletions artiq/compiler/ir.py
Original file line number Diff line number Diff line change
@@ -437,7 +437,7 @@ def _remove_name(self, name):

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

125 changes: 64 additions & 61 deletions artiq/compiler/transforms/artiq_ir_generator.py
Original file line number Diff line number Diff line change
@@ -237,25 +237,25 @@ def visit_function(self, node, is_lambda, is_internal):
for arg_name, default_node in zip(typ.optargs, node.args.defaults):
default = self.visit(default_node)
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))
defaults.append(env_default_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, {}

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
args.append(arg)

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
optargs.append(arg)

@@ -268,7 +268,7 @@ def visit_function(self, node, is_lambda, is_internal):
if not is_lambda:
self.function_map[node] = func

entry = self.add_block()
entry = self.add_block("entry")
old_block, self.current_block = self.current_block, entry

old_globals, self.current_globals = self.current_globals, node.globals_in_scope
@@ -279,13 +279,13 @@ def visit_function(self, node, is_lambda, is_internal):
if var not in node.globals_in_scope}
env_type = ir.TEnvironment(name=func.name,
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

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 })
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

self.append(ir.SetLocal(env, "$outer", env_arg))
@@ -401,18 +401,18 @@ def visit_If(self, node):
cond = self.coerce_to_bool(cond)
head = self.current_block

if_true = self.add_block()
if_true = self.add_block("if.body")
self.current_block = if_true
self.visit(node.body)
post_if_true = self.current_block

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

tail = self.add_block()
tail = self.add_block("if.tail")
self.current_block = tail
if not post_if_true.is_terminated():
post_if_true.append(ir.Branch(tail))
@@ -499,9 +499,9 @@ def visit_ForT(self, node):
head = self.add_block("for.head")
self.append(ir.Branch(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)
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")
old_break, self.break_target = self.break_target, break_block
@@ -510,7 +510,8 @@ def visit_ForT(self, node):
old_continue, self.continue_target = self.continue_target, 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)
self.append(ir.Branch(head))

@@ -597,13 +598,13 @@ def visit_Try(self, node):
# k for continuation
final_suffix = ".try@{}:{}".format(node.loc.line(), node.loc.column())
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_targets = []
final_paths = []

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_paths.append(block)

@@ -696,19 +697,19 @@ def final_branch(target, block):
block.append(ir.Branch(finalizer))

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))

cleanup.append(ir.SetLocal(final_state, "$k", reraise))
cleanup.append(ir.SetLocal(final_state, "$cont", reraise))
cleanup.append(ir.Branch(finalizer))

for handler, post_handler in handlers:
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))

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))
else:
if not body.is_terminated():
@@ -753,15 +754,15 @@ def visit_With(self, node):

heads, tails = [], []
for stmt in node.body:
self.current_block = self.add_block()
self.current_block = self.add_block("interleave.branch")
heads.append(self.current_block)
self.visit(stmt)
tails.append(self.current_block)

for head in heads:
interleave.add_destination(head)

self.current_block = self.add_block()
self.current_block = self.add_block("interleave.tail")
for tail in tails:
if not tail.is_terminated():
tail.append(ir.Branch(self.current_block))
@@ -773,7 +774,7 @@ def visit_With(self, node):
for stmt in node.body:
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():
self.warn_unreachable(stmt[0])
else:
@@ -837,17 +838,17 @@ def visit_IfExpT(self, node):
cond = self.visit(node.test)
head = self.current_block

if_true = self.add_block()
if_true = self.add_block("ifexp.body")
self.current_block = if_true
true_result = self.visit(node.body)
post_if_true = self.current_block

if_false = self.add_block()
if_false = self.add_block("ifexp.else")
self.current_block = if_false
false_result = self.visit(node.orelse)
post_if_false = self.current_block

tail = self.add_block()
tail = self.add_block("ifexp.tail")
self.current_block = tail

if not post_if_true.is_terminated():
@@ -881,10 +882,10 @@ def _get_local(self, name):
if self.current_class is not None and \
name in self.current_class.type.attributes:
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,
name="local." + name))
name="LOC." + name))

def _set_local(self, name, value):
if self.current_class is not None and \
@@ -910,7 +911,7 @@ def visit_AttributeT(self, node):

if self.current_assign is None:
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):
# RPC functions are just type-level markers
return self.append(ir.Builtin("nop", [], builtins.TNone()))
@@ -930,47 +931,47 @@ def _map_index(self, length, index, one_past_the_end=False, loc=None):
ir.Constant(False, builtins.TBool())))
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"),
ir.Constant("index {0} out of bounds 0:{1}", builtins.TStr()),
index, length)
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))

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
# exn_gen: lambda()->exn Value, exception if condition not true
cond_block = self.current_block

self.current_block = body_block = self.add_block()
self.current_block = body_block = self.add_block("{}.body".format(check))
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(check))
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
# cond_gen: lambda('iter Value)->bool Value, loop condition
# body_gen: lambda('iter Value)->'iter Value, loop body,
# returns next loop variable value
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))
phi = self.append(ir.Phi(init.type))
phi.add_incoming(init, init_block)
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)
self.append(ir.Branch(head_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))

return head_block, body_block, tail_block
@@ -1072,7 +1073,7 @@ def visit_SubscriptT(self, node):

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))

index = self.append(ir.Phi(node.slice.type,
@@ -1087,7 +1088,7 @@ def visit_SubscriptT(self, node):
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))

body = self.current_block = self.add_block()
body = self.current_block = self.add_block("slice.body")

if self.current_assign is None:
elem = self.iterable_get(value, index)
@@ -1103,7 +1104,7 @@ def visit_SubscriptT(self, node):
other_index.add_incoming(next_other_index, body)
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))

if self.current_assign is None:
@@ -1197,7 +1198,7 @@ def visit_BoolOpT(self, node):
value_tail = self.current_block

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
phi = self.append(ir.Phi(node.type))
@@ -1366,26 +1367,26 @@ def polymorphic_compare_pair_order(self, op, lhs, rhs):

# If the length is the same, compare element-by-element
# 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
index_phi = self.append(ir.Phi(self._size_type))
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_body = self.add_block()
loop_body = self.add_block("compare.body")
self.current_block = loop_body
lhs_elt = self.append(ir.GetElem(lhs, index_phi))
rhs_elt = self.append(ir.GetElem(rhs, index_phi))
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
index_next = self.append(ir.Arith(ast.Add(loc=None), index_phi,
ir.Constant(1, self._size_type)))
self.append(ir.Branch(loop_head))
index_phi.add_incoming(index_next, loop_body2)

tail = self.add_block()
tail = self.add_block("compare.tail")
self.current_block = tail
phi = self.append(ir.Phi(builtins.TBool()))
head.append(ir.BranchIf(eq_length, loop_head, tail))
@@ -1431,14 +1432,14 @@ def body_gen(index):
elt = self.iterable_get(haystack, index)
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
return self.append(ir.Arith(ast.Add(loc=None), index,
ir.Constant(1, length.type)))
loop_head, loop_body, loop_tail = \
self._make_loop(ir.Constant(0, length.type),
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))
phi = loop_tail.prepend(ir.Phi(builtins.TBool()))
@@ -1479,7 +1480,7 @@ def visit_CompareT(self, node):
result_tail = self.current_block

blocks.append((result, result_head, result_tail))
self.current_block = self.add_block()
self.current_block = self.add_block("compare.seq")
lhs = rhs

tail = self.current_block
@@ -1674,8 +1675,10 @@ def _user_call(self, callee, positional, keywords, arg_exprs={}):
fn_typ = callee.type
offset = 0
elif types.is_method(callee.type):
func = self.append(ir.GetAttr(callee, "__func__"))
self_arg = self.append(ir.GetAttr(callee, "__self__"))
func = self.append(ir.GetAttr(callee, "__func__",
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)
offset = 1
else:
@@ -1719,7 +1722,7 @@ def _user_call(self, callee, positional, keywords, arg_exprs={}):
if self.unwind_target is None:
insn = self.append(ir.Call(func, args, arg_exprs))
else:
after_invoke = self.add_block()
after_invoke = self.add_block("invoke")
insn = self.append(ir.Invoke(func, args, arg_exprs,
after_invoke, self.unwind_target))
self.current_block = after_invoke
@@ -1734,7 +1737,7 @@ def visit_CallT(self, node):

if node.iodelay is not None and not iodelay.is_const(node.iodelay, 0):
before_delay = self.current_block
during_delay = self.add_block()
during_delay = self.add_block("delay.head")
before_delay.append(ir.Branch(during_delay))
self.current_block = during_delay

@@ -1748,7 +1751,7 @@ def visit_CallT(self, node):
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):
after_delay = self.add_block()
after_delay = self.add_block("delay.tail")
self.append(ir.Delay(node.iodelay, insn, after_delay))
self.current_block = after_delay

@@ -1783,7 +1786,7 @@ def visit_Assert(self, node):
assert_subexprs = self.current_assert_subexprs = []
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)
head = self.current_block
finally:
@@ -1795,7 +1798,7 @@ def visit_Assert(self, node):
init.append(ir.SetLocal(assert_env, subexpr_name, empty))
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:
explanation = node.msg.s
@@ -1813,7 +1816,7 @@ def visit_Assert(self, node):
subexpr_cond = self.append(ir.Builtin("is_some", [subexpr_value_opt],
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", [
ir.Constant(" (%s) = ", builtins.TStr()),
ir.Constant(subexpr_node.loc.source(), builtins.TStr())
@@ -1823,14 +1826,14 @@ def visit_Assert(self, node):
self.polymorphic_print([subexpr_value], separator="", suffix="\n")
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.BranchIf(subexpr_cond, subexpr_body, subexpr_tail), block=subexpr_head)

self.append(ir.Builtin("abort", [], builtins.TNone()))
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)

def polymorphic_print(self, values, separator, suffix="", as_repr=False, as_rtio=False):
@@ -1904,10 +1907,10 @@ def body_gen(index):
is_last = self.append(ir.Compare(ast.Lt(loc=None), index, last))
head = self.current_block

if_last = self.current_block = self.add_block()
if_last = self.current_block = self.add_block("print.comma")
printf(", ")

tail = self.current_block = self.add_block()
tail = self.current_block = self.add_block("print.tail")
if_last.append(ir.Branch(tail))
head.append(ir.BranchIf(is_last, if_last, tail))

111 changes: 65 additions & 46 deletions artiq/compiler/transforms/llvm_ir_generator.py
Original file line number Diff line number Diff line change
@@ -269,11 +269,11 @@ def llty_of_type(self, typ, bare=False, for_return=False):
return llty.as_pointer()
else: # Catch-all for exceptions and custom classes
if builtins.is_exception(typ):
name = "class.Exception" # they all share layout
name = "C.Exception" # they all share layout
elif types.is_constructor(typ):
name = "class.{}".format(typ.name)
name = "C.{}".format(typ.name)
else:
name = "instance.{}".format(typ.name)
name = "I.{}".format(typ.name)

llty = self.llcontext.get_identified_type(name)
if llty.elements is None:
@@ -297,7 +297,7 @@ def llstr_of_str(self, value, name=None, linkage="private", unnamed_addr=True):

if name is None:
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)
if llstr is None:
@@ -439,16 +439,16 @@ def emit_attribute_writeback(self):
else:
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:
llobjects[typ].append(llobject.bitcast(llptr))

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]

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()]

lldescs = []
@@ -457,9 +457,9 @@ def emit_attribute_writeback(self):
continue

if types.is_constructor(typ):
type_name = "class.{}".format(typ.name)
type_name = "C.{}".format(typ.name)
else:
type_name = "instance.{}".format(typ.name)
type_name = "I.{}".format(typ.name)

def llrpcattr_of_attr(name, typ):
size = self.llty_of_type(typ). \
@@ -478,14 +478,19 @@ def rpc_tag_error(typ):
else:
llrpctag = ll.Constant(llptr, None)

llrpcattr = ll.GlobalVariable(self.llmodule, llrpcattrty,
name="attr.{}.{}".format(type_name, name))
llrpcattr.initializer = ll.Constant(llrpcattrty, [
llrpcattrinit = ll.Constant(llrpcattrty, [
ll.Constant(lli32, size),
ll.Constant(lli32, alignment),
llrpctag,
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.unnamed_addr = True
llrpcattr.linkage = 'private'
@@ -497,7 +502,7 @@ def rpc_tag_error(typ):

llrpcattraryty = ll.ArrayType(llrpcattrty.as_pointer(), len(llrpcattrs) + 1)
llrpcattrary = ll.GlobalVariable(self.llmodule, llrpcattraryty,
name="attrs.{}".format(type_name))
name="Ax.{}".format(type_name))
llrpcattrary.initializer = ll.Constant(llrpcattraryty,
llrpcattrs + [ll.Constant(llrpcattrty.as_pointer(), None)])
llrpcattrary.global_constant = True
@@ -506,13 +511,13 @@ def rpc_tag_error(typ):

llobjectaryty = ll.ArrayType(llptr, len(llobjects[typ]) + 1)
llobjectary = ll.GlobalVariable(self.llmodule, llobjectaryty,
name="objects.{}".format(type_name))
name="Ox.{}".format(type_name))
llobjectary.initializer = ll.Constant(llobjectaryty,
llobjects[typ] + [ll.Constant(llptr, None)])
llobjectary.linkage = 'private'

lldesc = ll.GlobalVariable(self.llmodule, lldescty,
name="desc.{}".format(type_name))
name="D.{}".format(type_name))
lldesc.initializer = ll.Constant(lldescty, [
llrpcattrary.bitcast(llrpcattrty.as_pointer().as_pointer()),
llobjectary.bitcast(llptr.as_pointer())
@@ -548,6 +553,7 @@ def process_function(self, func):
llactualargs = self.llfunction.args

for arg, llarg in zip(func.arguments, llactualargs):
llarg.name = arg.name
self.llmap[arg] = llarg

# Second, create all basic blocks.
@@ -649,7 +655,8 @@ def llptr_to_var(self, llenv, env_ty, var_name, var_type=None):
def process_GetLocal(self, insn):
env = insn.environment()
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):
env = insn.environment()
@@ -658,6 +665,7 @@ def process_SetLocal(self, insn):
# We store NoneType as {} but return it as void. So, bail out here.
return ll.Constant(ll.LiteralStructType([]), [])
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):
llvalue = ll.BlockAddress(self.llfunction, llvalue)
if llptr.type.pointee != llvalue.type:
@@ -687,13 +695,13 @@ def get_or_define_global(self, name, llty, llvalue=None):
def get_class(self, typ):
assert types.is_constructor(typ)
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):
assert types.is_constructor(typ)
assert types.is_function(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):
typ, attr = insn.object().type, insn.attr
@@ -715,7 +723,9 @@ def process_GetAttr(self, insn):
assert False

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())

llmethodty = self.llty_of_type(insn.type)
@@ -727,11 +737,12 @@ def process_GetAttr(self, insn):
return llmethod
elif types.is_function(insn.type) and attr in typ.attributes and \
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:
llptr = self.llbuilder.gep(obj, [self.llindex(0), self.llindex(index)],
inbounds=True, name=insn.name)
return self.llbuilder.load(llptr)
inbounds=True, name="ptr.{}".format(insn.name))
return self.llbuilder.load(llptr, name="val.{}".format(insn.name))

def process_SetAttr(self, insn):
typ, attr = insn.object().type, insn.attr
@@ -979,8 +990,8 @@ def get_outer(llenv, env_ty):
elif insn.op == "delay_mu":
interval, = insn.operands
llnowptr = self.llbuiltin("now")
llnow = self.llbuilder.load(llnowptr)
lladjusted = self.llbuilder.add(llnow, self.map(interval))
llnow = self.llbuilder.load(llnowptr, name="now.old")
lladjusted = self.llbuilder.add(llnow, self.map(interval), name="now.new")
return self.llbuilder.store(lladjusted, llnowptr)
elif insn.op == "watchdog_set":
interval, = insn.operands
@@ -992,11 +1003,12 @@ def get_outer(llenv, env_ty):
assert False

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 this closure belongs to a quoted function, we assume this is the only
# 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)
self.llbuilder.store(llenv, llenvptr)

@@ -1009,9 +1021,10 @@ def process_Closure(self, insn):
def _prepare_closure_call(self, insn):
llargs = [self.map(arg) for arg in insn.arguments()]
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:
llfun = self.llbuilder.extract_value(llclosure, 1)
llfun = self.llbuilder.extract_value(llclosure, 1,
name="fun.{}".format(llclosure.name))
else:
llfun = self.map(insn.static_target_function)
return llfun, [llenv] + list(llargs)
@@ -1119,15 +1132,18 @@ def ret_error_handler(typ):

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 = []
for arg in args:
for index, arg in enumerate(args):
if builtins.is_none(arg.type):
llargslot = self.llbuilder.alloca(ll.LiteralStructType([]))
llargslot = self.llbuilder.alloca(ll.LiteralStructType([]),
name="rpc.arg{}".format(index))
else:
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)
llargs.append(llargslot)

@@ -1144,36 +1160,39 @@ def ret_error_handler(typ):
# else *(T*)ptr
# }
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:
llheadu = self.llbuilder.append_basic_block(name=llprehead.name + ".rpc.head.unwind")
llalloc = self.llbuilder.append_basic_block(name=llprehead.name + ".rpc.alloc")
lltail = self.llbuilder.append_basic_block(name=llprehead.name + ".rpc.tail")
llheadu = self.llbuilder.append_basic_block(name="rpc.head.unwind")
llalloc = self.llbuilder.append_basic_block(name="rpc.continue")
lltail = self.llbuilder.append_basic_block(name="rpc.tail")

llretty = self.llty_of_type(fun_type.ret)
llslot = self.llbuilder.alloca(llretty)
llslotgen = self.llbuilder.bitcast(llslot, llptr)
llslot = self.llbuilder.alloca(llretty, name="rpc.ret.alloc")
llslotgen = self.llbuilder.bitcast(llslot, llptr, name="rpc.ret.ptr")
self.llbuilder.branch(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)
if llunwindblock:
llsize = self.llbuilder.invoke(self.llbuiltin("recv_rpc"), [llphi],
llheadu, llunwindblock)
llheadu, llunwindblock,
name="rpc.size.next")
self.llbuilder.position_at_end(llheadu)
else:
llsize = self.llbuilder.call(self.llbuiltin("recv_rpc"), [llphi])
lldone = self.llbuilder.icmp_unsigned('==', llsize, ll.Constant(llsize.type, 0))
llsize = self.llbuilder.call(self.llbuiltin("recv_rpc"), [llphi],
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.position_at_end(llalloc)
llalloca = self.llbuilder.alloca(lli8, llsize)
llalloca = self.llbuilder.alloca(lli8, llsize, name="rpc.alloc")
llphi.add_incoming(llalloca, llalloc)
self.llbuilder.branch(llhead)

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):
# We didn't allocate anything except the slot for the value itself.
# Don't waste stack space.
@@ -1243,7 +1262,7 @@ def _quote(self, value, typ, path):
llglobal = self.get_class(typ)
else:
llglobal = ll.GlobalVariable(self.llmodule, llty.pointee,
name="object.{}".format(objectid))
name="O.{}".format(objectid))

self.llobject_map[value_id] = llglobal
else:
@@ -1297,7 +1316,7 @@ def _quote(self, value, typ, path):
def process_Quote(self, insn):
if insn.value in self.function_map:
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)
llfun = self.get_function(insn.type.find(), func_name)

0 comments on commit 63e367a

Please sign in to comment.