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):
|
||||
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):
|
||||
"""
|
||||
An intruction that loads an attribute from an object,
|
||||
|
@ -697,8 +665,12 @@ class GetAttr(Instruction):
|
|||
if isinstance(attr, int):
|
||||
assert isinstance(obj.type, types.TTuple)
|
||||
typ = obj.type.elts[attr]
|
||||
else:
|
||||
elif attr in obj.type.attributes:
|
||||
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)
|
||||
self.attr = attr
|
||||
|
||||
|
|
|
@ -806,8 +806,8 @@ class ARTIQIRGenerator(algorithm.Visitor):
|
|||
self.append(ir.Builtin("watchdog_clear", [watchdog_id], builtins.TNone())))
|
||||
else: # user-defined context manager
|
||||
context_mgr = self.visit(context_expr_node)
|
||||
enter_fn = self._get_attribute(context_mgr, '__enter__')
|
||||
exit_fn = self._get_attribute(context_mgr, '__exit__')
|
||||
enter_fn = self.append(ir.GetAttr(context_mgr, '__enter__'))
|
||||
exit_fn = self.append(ir.GetAttr(context_mgr, '__exit__'))
|
||||
|
||||
try:
|
||||
self.current_assign = self._user_call(enter_fn, [], {})
|
||||
|
@ -900,26 +900,6 @@ class ARTIQIRGenerator(algorithm.Visitor):
|
|||
else:
|
||||
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):
|
||||
try:
|
||||
old_assign, self.current_assign = self.current_assign, None
|
||||
|
@ -928,7 +908,8 @@ class ARTIQIRGenerator(algorithm.Visitor):
|
|||
self.current_assign = old_assign
|
||||
|
||||
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):
|
||||
# RPC functions are just type-level markers
|
||||
return self.append(ir.Builtin("nop", [], builtins.TNone()))
|
||||
|
|
|
@ -32,9 +32,8 @@ class DeadCodeEliminator:
|
|||
# a diagnostic for reads of uninitialized locals, and
|
||||
# it also has to run after the interleaver, but interleaver
|
||||
# doesn't like to work with IR before DCE.
|
||||
if isinstance(insn, (ir.Phi, ir.Alloc, ir.GetConstructor,
|
||||
ir.GetAttr, ir.GetElem, ir.Coerce, ir.Arith,
|
||||
ir.Compare, ir.Closure, ir.Select, ir.Quote)) \
|
||||
if isinstance(insn, (ir.Phi, ir.Alloc, ir.GetAttr, ir.GetElem, ir.Coerce,
|
||||
ir.Arith, ir.Compare, ir.Closure, ir.Select, ir.Quote)) \
|
||||
and not any(insn.uses):
|
||||
insn.erase()
|
||||
modified = True
|
||||
|
|
|
@ -646,13 +646,6 @@ class LLVMIRGenerator:
|
|||
llptr = self.llptr_to_var(self.map(env), env.type, insn.var_name)
|
||||
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):
|
||||
env = insn.environment()
|
||||
llvalue = self.map(insn.value())
|
||||
|
@ -670,26 +663,67 @@ class LLVMIRGenerator:
|
|||
llvalue = self.llbuilder.bitcast(llvalue, llptr.type.pointee)
|
||||
return self.llbuilder.store(llvalue, llptr)
|
||||
|
||||
def attr_index(self, insn):
|
||||
return list(insn.object().type.attributes.keys()).index(insn.attr)
|
||||
def attr_index(self, typ, 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):
|
||||
if types.is_tuple(insn.object().type):
|
||||
return self.llbuilder.extract_value(self.map(insn.object()), insn.attr,
|
||||
typ, attr = insn.object().type, insn.attr
|
||||
if types.is_tuple(typ):
|
||||
return self.llbuilder.extract_value(self.map(insn.object()), attr,
|
||||
name=insn.name)
|
||||
elif not builtins.is_allocated(insn.object().type):
|
||||
return self.llbuilder.extract_value(self.map(insn.object()), self.attr_index(insn),
|
||||
elif not builtins.is_allocated(typ):
|
||||
return self.llbuilder.extract_value(self.map(insn.object()),
|
||||
self.attr_index(typ, attr),
|
||||
name=insn.name)
|
||||
else:
|
||||
llptr = self.llbuilder.gep(self.map(insn.object()),
|
||||
[self.llindex(0), self.llindex(self.attr_index(insn))],
|
||||
if attr in typ.attributes:
|
||||
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)
|
||||
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):
|
||||
assert builtins.is_allocated(insn.object().type)
|
||||
llptr = self.llbuilder.gep(self.map(insn.object()),
|
||||
[self.llindex(0), self.llindex(self.attr_index(insn))],
|
||||
typ, attr = insn.object().type, insn.attr
|
||||
assert builtins.is_allocated(typ)
|
||||
|
||||
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)
|
||||
return self.llbuilder.store(self.map(insn.value()), llptr)
|
||||
|
||||
|
@ -1161,9 +1195,7 @@ class LLVMIRGenerator:
|
|||
if value_id in self.llobject_map:
|
||||
return self.llobject_map[value_id]
|
||||
|
||||
global_name = ""
|
||||
llty = self.llty_of_type(typ)
|
||||
|
||||
if types.is_constructor(typ) or types.is_instance(typ):
|
||||
llglobal = None
|
||||
llfields = []
|
||||
|
@ -1173,8 +1205,12 @@ class LLVMIRGenerator:
|
|||
llfields.append(ll.Constant(lli32, objectid))
|
||||
|
||||
assert llglobal is None
|
||||
if types.is_constructor(typ):
|
||||
llglobal = self.get_class(typ)
|
||||
else:
|
||||
llglobal = ll.GlobalVariable(self.llmodule, llty.pointee,
|
||||
name="object.{}".format(objectid))
|
||||
|
||||
self.llobject_map[value_id] = llglobal
|
||||
else:
|
||||
llfields.append(self._quote(getattr(value, attr), typ.attributes[attr],
|
||||
|
|
Loading…
Reference in New Issue