compiler: get rid of the GetConstructor opcode.

This commit is contained in:
whitequark 2016-03-24 17:56:44 +00:00
parent 8a9c1d3043
commit 39599d4508
4 changed files with 70 additions and 82 deletions

View File

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

View File

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

View File

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

View File

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