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:
whitequark 2015-08-22 13:56:17 -07:00
parent 0e26cfb66e
commit a557445e05
5 changed files with 36 additions and 33 deletions

View File

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

View File

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

View File

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

View File

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

View File

@ -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,