forked from M-Labs/artiq
LocalAccessValidator: assume variables with "$" in name are internal.
Internal variables are assumed to be scoped correctly (including not being accessed uninitialized). This was changed from "." because artiq.compiler.embedding uses "." in module prefix of function names.
This commit is contained in:
parent
0e26cfb66e
commit
a557445e05
@ -366,11 +366,11 @@ class Stitcher:
|
||||
if syscall is None:
|
||||
function_type = types.TRPCFunction(arg_types, optarg_types, ret_type,
|
||||
service=self._map(function))
|
||||
function_name = "__rpc_{}__".format(function_type.service)
|
||||
function_name = "rpc${}".format(function_type.service)
|
||||
else:
|
||||
function_type = types.TCFunction(arg_types, ret_type,
|
||||
name=syscall)
|
||||
function_name = "__ffi_{}__".format(function_type.name)
|
||||
function_name = "ffi${}".format(function_type.name)
|
||||
|
||||
self.globals[function_name] = function_type
|
||||
self.functions[function] = function_name
|
||||
|
@ -465,7 +465,7 @@ class TEnvironment(types.TMono):
|
||||
def __init__(self, vars, outer=None):
|
||||
if outer is not None:
|
||||
assert isinstance(outer, TEnvironment)
|
||||
env = OrderedDict({".outer": outer})
|
||||
env = OrderedDict({"$outer": outer})
|
||||
env.update(vars)
|
||||
else:
|
||||
env = OrderedDict(vars)
|
||||
@ -475,14 +475,14 @@ class TEnvironment(types.TMono):
|
||||
def type_of(self, name):
|
||||
if name in self.params:
|
||||
return self.params[name].find()
|
||||
elif ".outer" in self.params:
|
||||
return self.params[".outer"].type_of(name)
|
||||
elif "$outer" in self.params:
|
||||
return self.params["$outer"].type_of(name)
|
||||
else:
|
||||
assert False
|
||||
|
||||
def outermost(self):
|
||||
if ".outer" in self.params:
|
||||
return self.params[".outer"].outermost()
|
||||
if "$outer" in self.params:
|
||||
return self.params["$outer"].outermost()
|
||||
else:
|
||||
return self
|
||||
|
||||
|
@ -141,7 +141,7 @@ class ARTIQIRGenerator(algorithm.Visitor):
|
||||
env = self.append(ir.Alloc([], ir.TEnvironment(node.typing_env), name="env"))
|
||||
old_env, self.current_env = self.current_env, env
|
||||
|
||||
priv_env = self.append(ir.Alloc([], ir.TEnvironment({ ".return": typ.ret }),
|
||||
priv_env = self.append(ir.Alloc([], ir.TEnvironment({ "$return": typ.ret }),
|
||||
name="privenv"))
|
||||
old_priv_env, self.current_private_env = self.current_private_env, priv_env
|
||||
|
||||
@ -181,7 +181,7 @@ class ARTIQIRGenerator(algorithm.Visitor):
|
||||
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)
|
||||
|
||||
@ -217,11 +217,11 @@ class ARTIQIRGenerator(algorithm.Visitor):
|
||||
old_env, self.current_env = self.current_env, env
|
||||
|
||||
if not is_lambda:
|
||||
priv_env = self.append(ir.Alloc([], ir.TEnvironment({ ".return": typ.ret }),
|
||||
priv_env = self.append(ir.Alloc([], ir.TEnvironment({ "$return": typ.ret }),
|
||||
name="privenv"))
|
||||
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))
|
||||
for index, arg_name in enumerate(typ.args):
|
||||
self.append(ir.SetLocal(env, arg_name, args[index]))
|
||||
for index, (arg_name, env_default_name) in enumerate(zip(typ.optargs, defaults)):
|
||||
@ -267,7 +267,7 @@ class ARTIQIRGenerator(algorithm.Visitor):
|
||||
if self.return_target is None:
|
||||
self.append(ir.Return(return_value))
|
||||
else:
|
||||
self.append(ir.SetLocal(self.current_private_env, ".return", return_value))
|
||||
self.append(ir.SetLocal(self.current_private_env, "$return", return_value))
|
||||
self.append(ir.Branch(self.return_target))
|
||||
|
||||
def visit_Expr(self, node):
|
||||
@ -516,30 +516,30 @@ class ARTIQIRGenerator(algorithm.Visitor):
|
||||
|
||||
if any(node.finalbody):
|
||||
# k for continuation
|
||||
final_state = self.append(ir.Alloc([], ir.TEnvironment({ ".k": ir.TBasicBlock() })))
|
||||
final_state = self.append(ir.Alloc([], ir.TEnvironment({ "$k": ir.TBasicBlock() })))
|
||||
final_targets = []
|
||||
|
||||
if self.break_target is not None:
|
||||
break_proxy = self.add_block("try.break")
|
||||
old_break, self.break_target = self.break_target, break_proxy
|
||||
break_proxy.append(ir.SetLocal(final_state, ".k", old_break))
|
||||
break_proxy.append(ir.SetLocal(final_state, "$k", old_break))
|
||||
final_targets.append(old_break)
|
||||
if self.continue_target is not None:
|
||||
continue_proxy = self.add_block("try.continue")
|
||||
old_continue, self.continue_target = self.continue_target, continue_proxy
|
||||
continue_proxy.append(ir.SetLocal(final_state, ".k", old_continue))
|
||||
continue_proxy.append(ir.SetLocal(final_state, "$k", old_continue))
|
||||
final_targets.append(old_continue)
|
||||
|
||||
return_proxy = self.add_block("try.return")
|
||||
old_return, self.return_target = self.return_target, return_proxy
|
||||
if old_return is not None:
|
||||
return_proxy.append(ir.SetLocal(final_state, ".k", old_return))
|
||||
return_proxy.append(ir.SetLocal(final_state, "$k", old_return))
|
||||
final_targets.append(old_return)
|
||||
else:
|
||||
return_action = self.add_block("try.doreturn")
|
||||
value = return_action.append(ir.GetLocal(self.current_private_env, ".return"))
|
||||
value = return_action.append(ir.GetLocal(self.current_private_env, "$return"))
|
||||
return_action.append(ir.Return(value))
|
||||
return_proxy.append(ir.SetLocal(final_state, ".k", return_action))
|
||||
return_proxy.append(ir.SetLocal(final_state, "$k", return_action))
|
||||
final_targets.append(return_action)
|
||||
|
||||
body = self.add_block("try.body")
|
||||
@ -607,19 +607,19 @@ class ARTIQIRGenerator(algorithm.Visitor):
|
||||
return_proxy.append(ir.Branch(finalizer))
|
||||
|
||||
if not body.is_terminated():
|
||||
body.append(ir.SetLocal(final_state, ".k", tail))
|
||||
body.append(ir.SetLocal(final_state, "$k", tail))
|
||||
body.append(ir.Branch(finalizer))
|
||||
|
||||
cleanup.append(ir.SetLocal(final_state, ".k", reraise))
|
||||
cleanup.append(ir.SetLocal(final_state, "$k", 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, "$k", 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, "$k"))
|
||||
post_finalizer.append(ir.IndirectBranch(dest, final_targets))
|
||||
else:
|
||||
if not body.is_terminated():
|
||||
@ -961,7 +961,7 @@ class ARTIQIRGenerator(algorithm.Visitor):
|
||||
env = self.append(ir.Alloc([], env_type, name="env.gen"))
|
||||
old_env, self.current_env = self.current_env, env
|
||||
|
||||
self.append(ir.SetLocal(env, ".outer", old_env))
|
||||
self.append(ir.SetLocal(env, "$outer", old_env))
|
||||
|
||||
def body_gen(index):
|
||||
elt = self.iterable_get(iterable, index)
|
||||
@ -1483,7 +1483,7 @@ class ARTIQIRGenerator(algorithm.Visitor):
|
||||
for (subexpr, name) in self.current_assert_subexprs]):
|
||||
return # don't display the same subexpression twice
|
||||
|
||||
name = self.current_assert_env.type.add(".subexpr", ir.TOption(node.type))
|
||||
name = self.current_assert_env.type.add("$subexpr", ir.TOption(node.type))
|
||||
value_opt = self.append(ir.Alloc([value], ir.TOption(node.type)),
|
||||
loc=node.loc)
|
||||
self.append(ir.SetLocal(self.current_assert_env, name, value_opt),
|
||||
|
@ -495,10 +495,10 @@ class LLVMIRGenerator:
|
||||
var_index = list(env_ty.params.keys()).index(var_name)
|
||||
return self.llbuilder.gep(llenv, [self.llindex(0), self.llindex(var_index)])
|
||||
else:
|
||||
outer_index = list(env_ty.params.keys()).index(".outer")
|
||||
outer_index = list(env_ty.params.keys()).index("$outer")
|
||||
llptr = self.llbuilder.gep(llenv, [self.llindex(0), self.llindex(outer_index)])
|
||||
llouterenv = self.llbuilder.load(llptr)
|
||||
return self.llptr_to_var(llouterenv, env_ty.params[".outer"], var_name)
|
||||
return self.llptr_to_var(llouterenv, env_ty.params["$outer"], var_name)
|
||||
|
||||
def process_GetLocal(self, insn):
|
||||
env = insn.environment()
|
||||
@ -519,7 +519,7 @@ class LLVMIRGenerator:
|
||||
if llptr.type.pointee != llvalue.type:
|
||||
# The environment argument is an i8*, so that all closures can
|
||||
# unify with each other regardless of environment type or size.
|
||||
# We fixup the type on assignment into the ".outer" slot.
|
||||
# We fixup the type on assignment into the "$outer" slot.
|
||||
assert isinstance(insn.value(), ir.EnvironmentArgument)
|
||||
llvalue = self.llbuilder.bitcast(llvalue, llptr.type.pointee)
|
||||
return self.llbuilder.store(llvalue, llptr)
|
||||
@ -740,11 +740,11 @@ class LLVMIRGenerator:
|
||||
name=insn.name)
|
||||
elif insn.op == "globalenv":
|
||||
def get_outer(llenv, env_ty):
|
||||
if ".outer" in env_ty.params:
|
||||
outer_index = list(env_ty.params.keys()).index(".outer")
|
||||
if "$outer" in env_ty.params:
|
||||
outer_index = list(env_ty.params.keys()).index("$outer")
|
||||
llptr = self.llbuilder.gep(llenv, [self.llindex(0), self.llindex(outer_index)])
|
||||
llouterenv = self.llbuilder.load(llptr)
|
||||
return self.llptr_to_var(llouterenv, env_ty.params[".outer"], var_name)
|
||||
return self.llptr_to_var(llouterenv, env_ty.params["$outer"], var_name)
|
||||
else:
|
||||
return llenv
|
||||
|
||||
|
@ -7,6 +7,9 @@ from functools import reduce
|
||||
from pythonparser import diagnostic
|
||||
from .. import ir, analyses
|
||||
|
||||
def is_special_variable(name):
|
||||
return "$" in name
|
||||
|
||||
class LocalAccessValidator:
|
||||
def __init__(self, engine):
|
||||
self.engine = engine
|
||||
@ -85,8 +88,8 @@ class LocalAccessValidator:
|
||||
return None
|
||||
|
||||
set_local_in_this_frame = False
|
||||
if isinstance(insn, (ir.SetLocal, ir.GetLocal)) and \
|
||||
"." not in insn.var_name:
|
||||
if (isinstance(insn, (ir.SetLocal, ir.GetLocal)) and
|
||||
not is_special_variable(insn.var_name)):
|
||||
env, var_name = insn.environment(), insn.var_name
|
||||
|
||||
# Make sure that the variable is defined in the scope of this function.
|
||||
@ -124,7 +127,7 @@ class LocalAccessValidator:
|
||||
# Make sure this environment has any interesting variables.
|
||||
if env in block_state:
|
||||
for var_name in block_state[env]:
|
||||
if not block_state[env][var_name]:
|
||||
if not block_state[env][var_name] and not is_special_variable(var_name):
|
||||
# A closure would capture this variable while it is not always
|
||||
# initialized. Note that this check is transitive.
|
||||
self._uninitialized_access(closure, var_name,
|
||||
|
Loading…
Reference in New Issue
Block a user