forked from M-Labs/artiq
compiler: get rid of the GetConstructor opcode.
This commit is contained in:
parent
321ba57e84
commit
00facbbc78
|
@ -647,38 +647,6 @@ class SetLocal(Instruction):
|
||||||
def value(self):
|
def value(self):
|
||||||
return self.operands[1]
|
return self.operands[1]
|
||||||
|
|
||||||
class GetConstructor(Instruction):
|
|
||||||
"""
|
|
||||||
An intruction that loads a local variable with the given type
|
|
||||||
from an environment, possibly going through multiple levels of indirection.
|
|
||||||
|
|
||||||
:ivar var_name: (string) variable name
|
|
||||||
"""
|
|
||||||
|
|
||||||
"""
|
|
||||||
:param env: (:class:`Value`) local environment
|
|
||||||
:param var_name: (string) local variable name
|
|
||||||
:param var_type: (:class:`types.Type`) local variable type
|
|
||||||
"""
|
|
||||||
def __init__(self, env, var_name, var_type, name=""):
|
|
||||||
assert isinstance(env, Value)
|
|
||||||
assert isinstance(env.type, TEnvironment)
|
|
||||||
assert isinstance(var_name, str)
|
|
||||||
assert isinstance(var_type, types.Type)
|
|
||||||
super().__init__([env], var_type, name)
|
|
||||||
self.var_name = var_name
|
|
||||||
|
|
||||||
def copy(self, mapper):
|
|
||||||
self_copy = super().copy(mapper)
|
|
||||||
self_copy.var_name = self.var_name
|
|
||||||
return self_copy
|
|
||||||
|
|
||||||
def opcode(self):
|
|
||||||
return "getconstructor({})".format(repr(self.var_name))
|
|
||||||
|
|
||||||
def environment(self):
|
|
||||||
return self.operands[0]
|
|
||||||
|
|
||||||
class GetAttr(Instruction):
|
class GetAttr(Instruction):
|
||||||
"""
|
"""
|
||||||
An intruction that loads an attribute from an object,
|
An intruction that loads an attribute from an object,
|
||||||
|
@ -697,8 +665,12 @@ class GetAttr(Instruction):
|
||||||
if isinstance(attr, int):
|
if isinstance(attr, int):
|
||||||
assert isinstance(obj.type, types.TTuple)
|
assert isinstance(obj.type, types.TTuple)
|
||||||
typ = obj.type.elts[attr]
|
typ = obj.type.elts[attr]
|
||||||
else:
|
elif attr in obj.type.attributes:
|
||||||
typ = obj.type.attributes[attr]
|
typ = obj.type.attributes[attr]
|
||||||
|
else:
|
||||||
|
typ = obj.type.constructor.attributes[attr]
|
||||||
|
if types.is_function(typ):
|
||||||
|
typ = types.TMethod(obj.type, typ)
|
||||||
super().__init__([obj], typ, name)
|
super().__init__([obj], typ, name)
|
||||||
self.attr = attr
|
self.attr = attr
|
||||||
|
|
||||||
|
|
|
@ -806,8 +806,8 @@ class ARTIQIRGenerator(algorithm.Visitor):
|
||||||
self.append(ir.Builtin("watchdog_clear", [watchdog_id], builtins.TNone())))
|
self.append(ir.Builtin("watchdog_clear", [watchdog_id], builtins.TNone())))
|
||||||
else: # user-defined context manager
|
else: # user-defined context manager
|
||||||
context_mgr = self.visit(context_expr_node)
|
context_mgr = self.visit(context_expr_node)
|
||||||
enter_fn = self._get_attribute(context_mgr, '__enter__')
|
enter_fn = self.append(ir.GetAttr(context_mgr, '__enter__'))
|
||||||
exit_fn = self._get_attribute(context_mgr, '__exit__')
|
exit_fn = self.append(ir.GetAttr(context_mgr, '__exit__'))
|
||||||
|
|
||||||
try:
|
try:
|
||||||
self.current_assign = self._user_call(enter_fn, [], {})
|
self.current_assign = self._user_call(enter_fn, [], {})
|
||||||
|
@ -900,26 +900,6 @@ class ARTIQIRGenerator(algorithm.Visitor):
|
||||||
else:
|
else:
|
||||||
return self._set_local(node.id, self.current_assign)
|
return self._set_local(node.id, self.current_assign)
|
||||||
|
|
||||||
def _get_attribute(self, obj, attr_name):
|
|
||||||
if attr_name not in obj.type.find().attributes:
|
|
||||||
# A class attribute. Get the constructor (class object) and
|
|
||||||
# extract the attribute from it.
|
|
||||||
constr_type = obj.type.constructor
|
|
||||||
constr = self.append(ir.GetConstructor(self._env_for(constr_type.name),
|
|
||||||
constr_type.name, constr_type,
|
|
||||||
name="constructor." + constr_type.name))
|
|
||||||
|
|
||||||
if types.is_function(constr.type.attributes[attr_name]):
|
|
||||||
# A method. Construct a method object instead.
|
|
||||||
func = self.append(ir.GetAttr(constr, attr_name))
|
|
||||||
return self.append(ir.Alloc([func, obj],
|
|
||||||
types.TMethod(obj.type, func.type)))
|
|
||||||
else:
|
|
||||||
obj = constr
|
|
||||||
|
|
||||||
return self.append(ir.GetAttr(obj, attr_name,
|
|
||||||
name="{}.{}".format(_readable_name(obj), attr_name)))
|
|
||||||
|
|
||||||
def visit_AttributeT(self, node):
|
def visit_AttributeT(self, node):
|
||||||
try:
|
try:
|
||||||
old_assign, self.current_assign = self.current_assign, None
|
old_assign, self.current_assign = self.current_assign, None
|
||||||
|
@ -928,7 +908,8 @@ class ARTIQIRGenerator(algorithm.Visitor):
|
||||||
self.current_assign = old_assign
|
self.current_assign = old_assign
|
||||||
|
|
||||||
if self.current_assign is None:
|
if self.current_assign is None:
|
||||||
return self._get_attribute(obj, node.attr)
|
return self.append(ir.GetAttr(obj, node.attr,
|
||||||
|
name="{}.{}".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()))
|
||||||
|
|
|
@ -32,9 +32,8 @@ class DeadCodeEliminator:
|
||||||
# a diagnostic for reads of uninitialized locals, and
|
# a diagnostic for reads of uninitialized locals, and
|
||||||
# it also has to run after the interleaver, but interleaver
|
# it also has to run after the interleaver, but interleaver
|
||||||
# doesn't like to work with IR before DCE.
|
# doesn't like to work with IR before DCE.
|
||||||
if isinstance(insn, (ir.Phi, ir.Alloc, ir.GetConstructor,
|
if isinstance(insn, (ir.Phi, ir.Alloc, ir.GetAttr, ir.GetElem, ir.Coerce,
|
||||||
ir.GetAttr, ir.GetElem, ir.Coerce, ir.Arith,
|
ir.Arith, ir.Compare, ir.Closure, ir.Select, ir.Quote)) \
|
||||||
ir.Compare, ir.Closure, ir.Select, ir.Quote)) \
|
|
||||||
and not any(insn.uses):
|
and not any(insn.uses):
|
||||||
insn.erase()
|
insn.erase()
|
||||||
modified = True
|
modified = True
|
||||||
|
|
|
@ -646,13 +646,6 @@ class LLVMIRGenerator:
|
||||||
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)
|
return self.llbuilder.load(llptr)
|
||||||
|
|
||||||
def process_GetConstructor(self, insn):
|
|
||||||
env = insn.environment()
|
|
||||||
llptr = self.llptr_to_var(self.map(env), env.type, insn.var_name, insn.type)
|
|
||||||
llconstr = self.llbuilder.load(llptr)
|
|
||||||
llconstr.metadata['invariant.load'] = self.empty_metadata
|
|
||||||
return llconstr
|
|
||||||
|
|
||||||
def process_SetLocal(self, insn):
|
def process_SetLocal(self, insn):
|
||||||
env = insn.environment()
|
env = insn.environment()
|
||||||
llvalue = self.map(insn.value())
|
llvalue = self.map(insn.value())
|
||||||
|
@ -670,26 +663,67 @@ class LLVMIRGenerator:
|
||||||
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)
|
||||||
|
|
||||||
def attr_index(self, insn):
|
def attr_index(self, typ, attr):
|
||||||
return list(insn.object().type.attributes.keys()).index(insn.attr)
|
return list(typ.attributes.keys()).index(attr)
|
||||||
|
|
||||||
|
def get_class(self, typ):
|
||||||
|
assert types.is_constructor(typ)
|
||||||
|
name = "class.{}".format(typ.name)
|
||||||
|
if name in self.llmodule.globals:
|
||||||
|
llglobal = self.llmodule.get_global(name)
|
||||||
|
else:
|
||||||
|
llty = self.llty_of_type(typ)
|
||||||
|
llglobal = ll.GlobalVariable(self.llmodule, llty.pointee, name)
|
||||||
|
return llglobal
|
||||||
|
|
||||||
def process_GetAttr(self, insn):
|
def process_GetAttr(self, insn):
|
||||||
if types.is_tuple(insn.object().type):
|
typ, attr = insn.object().type, insn.attr
|
||||||
return self.llbuilder.extract_value(self.map(insn.object()), insn.attr,
|
if types.is_tuple(typ):
|
||||||
|
return self.llbuilder.extract_value(self.map(insn.object()), attr,
|
||||||
name=insn.name)
|
name=insn.name)
|
||||||
elif not builtins.is_allocated(insn.object().type):
|
elif not builtins.is_allocated(typ):
|
||||||
return self.llbuilder.extract_value(self.map(insn.object()), self.attr_index(insn),
|
return self.llbuilder.extract_value(self.map(insn.object()),
|
||||||
|
self.attr_index(typ, attr),
|
||||||
name=insn.name)
|
name=insn.name)
|
||||||
else:
|
else:
|
||||||
llptr = self.llbuilder.gep(self.map(insn.object()),
|
if attr in typ.attributes:
|
||||||
[self.llindex(0), self.llindex(self.attr_index(insn))],
|
index = self.attr_index(typ, attr)
|
||||||
|
obj = self.map(insn.object())
|
||||||
|
elif attr in typ.constructor.attributes:
|
||||||
|
index = self.attr_index(typ.constructor, attr)
|
||||||
|
obj = self.get_class(typ.constructor)
|
||||||
|
else:
|
||||||
|
assert False
|
||||||
|
|
||||||
|
llptr = self.llbuilder.gep(obj, [self.llindex(0), self.llindex(index)],
|
||||||
inbounds=True, name=insn.name)
|
inbounds=True, name=insn.name)
|
||||||
return self.llbuilder.load(llptr)
|
llclosure = self.llbuilder.load(llptr)
|
||||||
|
|
||||||
|
if types.is_method(insn.type) and attr not in typ.attributes:
|
||||||
|
llmethodty = self.llty_of_type(insn.type)
|
||||||
|
llmethod = ll.Constant(llmethodty, ll.Undefined)
|
||||||
|
llmethod = self.llbuilder.insert_value(llmethod, llclosure,
|
||||||
|
self.attr_index(insn.type, '__func__'))
|
||||||
|
llmethod = self.llbuilder.insert_value(llmethod, self.map(insn.object()),
|
||||||
|
self.attr_index(insn.type, '__self__'))
|
||||||
|
return llmethod
|
||||||
|
else:
|
||||||
|
return llclosure
|
||||||
|
|
||||||
def process_SetAttr(self, insn):
|
def process_SetAttr(self, insn):
|
||||||
assert builtins.is_allocated(insn.object().type)
|
typ, attr = insn.object().type, insn.attr
|
||||||
llptr = self.llbuilder.gep(self.map(insn.object()),
|
assert builtins.is_allocated(typ)
|
||||||
[self.llindex(0), self.llindex(self.attr_index(insn))],
|
|
||||||
|
if attr in typ.attributes:
|
||||||
|
obj = self.map(insn.object())
|
||||||
|
elif attr in typ.constructor.attributes:
|
||||||
|
typ = typ.constructor
|
||||||
|
obj = self.get_class(typ)
|
||||||
|
else:
|
||||||
|
assert False
|
||||||
|
|
||||||
|
llptr = self.llbuilder.gep(obj, [self.llindex(0),
|
||||||
|
self.llindex(self.attr_index(typ, attr))],
|
||||||
inbounds=True, name=insn.name)
|
inbounds=True, name=insn.name)
|
||||||
return self.llbuilder.store(self.map(insn.value()), llptr)
|
return self.llbuilder.store(self.map(insn.value()), llptr)
|
||||||
|
|
||||||
|
@ -1161,9 +1195,7 @@ class LLVMIRGenerator:
|
||||||
if value_id in self.llobject_map:
|
if value_id in self.llobject_map:
|
||||||
return self.llobject_map[value_id]
|
return self.llobject_map[value_id]
|
||||||
|
|
||||||
global_name = ""
|
|
||||||
llty = self.llty_of_type(typ)
|
llty = self.llty_of_type(typ)
|
||||||
|
|
||||||
if types.is_constructor(typ) or types.is_instance(typ):
|
if types.is_constructor(typ) or types.is_instance(typ):
|
||||||
llglobal = None
|
llglobal = None
|
||||||
llfields = []
|
llfields = []
|
||||||
|
@ -1173,8 +1205,12 @@ class LLVMIRGenerator:
|
||||||
llfields.append(ll.Constant(lli32, objectid))
|
llfields.append(ll.Constant(lli32, objectid))
|
||||||
|
|
||||||
assert llglobal is None
|
assert llglobal is None
|
||||||
|
if types.is_constructor(typ):
|
||||||
|
llglobal = self.get_class(typ)
|
||||||
|
else:
|
||||||
llglobal = ll.GlobalVariable(self.llmodule, llty.pointee,
|
llglobal = ll.GlobalVariable(self.llmodule, llty.pointee,
|
||||||
name="object.{}".format(objectid))
|
name="object.{}".format(objectid))
|
||||||
|
|
||||||
self.llobject_map[value_id] = llglobal
|
self.llobject_map[value_id] = llglobal
|
||||||
else:
|
else:
|
||||||
llfields.append(self._quote(getattr(value, attr), typ.attributes[attr],
|
llfields.append(self._quote(getattr(value, attr), typ.attributes[attr],
|
||||||
|
|
Loading…
Reference in New Issue