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