transforms.llvm_ir_generator: implement instrumentation for attribute writeback.

This commit is contained in:
whitequark 2016-01-02 06:50:43 +08:00
parent 5f68cc6a21
commit 2e33084a5f
4 changed files with 131 additions and 12 deletions

View File

@ -41,6 +41,9 @@ class ObjectMap:
return any(filter(lambda x: inspect.isfunction(x) or inspect.ismethod(x), return any(filter(lambda x: inspect.isfunction(x) or inspect.ismethod(x),
self.forward_map.values())) self.forward_map.values()))
def __iter__(self):
return iter(self.forward_map.keys())
class ASTSynthesizer: class ASTSynthesizer:
def __init__(self, object_map, type_map, value_map, quote_function=None, expanded_from=None): def __init__(self, object_map, type_map, value_map, quote_function=None, expanded_from=None):
self.source = "" self.source = ""

View File

@ -20,6 +20,7 @@ class Source:
self.engine = engine self.engine = engine
self.object_map = None self.object_map = None
self.type_map = {}
self.name, _ = os.path.splitext(os.path.basename(source_buffer.name)) self.name, _ = os.path.splitext(os.path.basename(source_buffer.name))
@ -45,6 +46,7 @@ class Module:
def __init__(self, src, ref_period=1e-6): def __init__(self, src, ref_period=1e-6):
self.engine = src.engine self.engine = src.engine
self.object_map = src.object_map self.object_map = src.object_map
self.type_map = src.type_map
int_monomorphizer = transforms.IntMonomorphizer(engine=self.engine) int_monomorphizer = transforms.IntMonomorphizer(engine=self.engine)
inferencer = transforms.Inferencer(engine=self.engine) inferencer = transforms.Inferencer(engine=self.engine)
@ -76,10 +78,10 @@ class Module:
def build_llvm_ir(self, target): def build_llvm_ir(self, target):
"""Compile the module to LLVM IR for the specified target.""" """Compile the module to LLVM IR for the specified target."""
llvm_ir_generator = transforms.LLVMIRGenerator(engine=self.engine, llvm_ir_generator = transforms.LLVMIRGenerator(
module_name=self.name, target=target, engine=self.engine, module_name=self.name, target=target,
object_map=self.object_map) object_map=self.object_map, type_map=self.type_map)
return llvm_ir_generator.process(self.artiq_ir) return llvm_ir_generator.process(self.artiq_ir, attribute_writeback=True)
def entry_point(self): def entry_point(self):
"""Return the name of the function that is the entry point of this module.""" """Return the name of the function that is the entry point of this module."""

View File

@ -3,7 +3,8 @@
into LLVM intermediate representation. into LLVM intermediate representation.
""" """
import os import os, re
from collections import defaultdict
from pythonparser import ast, diagnostic from pythonparser import ast, diagnostic
from llvmlite_artiq import ir as ll from llvmlite_artiq import ir as ll
from ...language import core as language_core from ...language import core as language_core
@ -161,10 +162,11 @@ class DebugInfoEmitter:
class LLVMIRGenerator: class LLVMIRGenerator:
def __init__(self, engine, module_name, target, object_map): def __init__(self, engine, module_name, target, object_map, type_map):
self.engine = engine self.engine = engine
self.target = target self.target = target
self.object_map = object_map self.object_map = object_map
self.type_map = type_map
self.llcontext = target.llcontext self.llcontext = target.llcontext
self.llmodule = ll.Module(context=self.llcontext, name=module_name) self.llmodule = ll.Module(context=self.llcontext, name=module_name)
self.llmodule.triple = target.triple self.llmodule.triple = target.triple
@ -285,8 +287,7 @@ class LLVMIRGenerator:
else: else:
return llty.as_pointer() return llty.as_pointer()
def llstr_of_str(self, value, name=None, def llstr_of_str(self, value, name=None, linkage="private", unnamed_addr=True):
linkage="private", unnamed_addr=True):
if isinstance(value, str): if isinstance(value, str):
assert "\0" not in value assert "\0" not in value
as_bytes = (value + "\0").encode("utf-8") as_bytes = (value + "\0").encode("utf-8")
@ -294,7 +295,8 @@ class LLVMIRGenerator:
as_bytes = value as_bytes = value
if name is None: if name is None:
name = self.llmodule.get_unique_name("str") sanitized_str = re.sub(rb"[^a-zA-Z0-9_.]", b"", as_bytes[:20]).decode('ascii')
name = self.llmodule.get_unique_name("str.{}".format(sanitized_str))
llstr = self.llmodule.get_global(name) llstr = self.llmodule.get_global(name)
if llstr is None: if llstr is None:
@ -403,15 +405,95 @@ class LLVMIRGenerator:
else: else:
assert False assert False
def process(self, functions): def process(self, functions, attribute_writeback):
for func in functions: for func in functions:
self.process_function(func) self.process_function(func)
if any(functions): if any(functions):
self.debug_info_emitter.finalize(functions[0].loc.source_buffer) self.debug_info_emitter.finalize(functions[0].loc.source_buffer)
if attribute_writeback:
self.emit_attribute_writeback()
return self.llmodule return self.llmodule
def emit_attribute_writeback(self):
shadow_memory_dim = defaultdict(lambda: 0)
for obj_id in self.object_map:
obj_ref = self.object_map.retrieve(obj_id)
if isinstance(obj_ref, type):
_, typ = self.type_map[obj_ref]
else:
typ, _ = self.type_map[type(obj_ref)]
if shadow_memory_dim[typ] <= obj_id:
shadow_memory_dim[typ] = obj_id + 1
lldescty = self.llcontext.get_identified_type("shadow.desc")
lldescty.elements = [llptr.as_pointer(), llptr, lli32, llptr]
lldescs = []
for typ in shadow_memory_dim:
if "__objectid__" not in typ.attributes:
continue
assert list(typ.attributes.keys())[0] == "__objectid__"
if types.is_constructor(typ):
type_name = "class.{}".format(typ.name)
else:
type_name = "instance.{}".format(typ.name)
shadowname = "shadow.{}".format(type_name)
llshadow = self.llmodule.get_global(shadowname)
if llshadow is None:
continue
llshadowlen = shadow_memory_dim[typ] * len(typ.attributes)
llshadowty = ll.ArrayType(lli8, llshadowlen)
llshadow.gtype = llshadowty
llshadow.type = llshadowty.as_pointer()
llshadow.initializer = ll.Constant(llshadowty, None)
def rpc_tag_error(typ):
print(typ)
assert False
rpcattrary = list(typ.attributes.keys())[1:]
llrpcattraryty = ll.ArrayType(llptr, len(rpcattrary) + 1)
llrpcattrary = list(map(lambda attr: self.llstr_of_str(attr), rpcattrary))
llrpcattrs = ll.GlobalVariable(self.llmodule, llrpcattraryty,
name="shadow.attrs.{}".format(type_name))
llrpcattrs.initializer = ll.Constant(llrpcattraryty,
llrpcattrary + [ll.Constant(llptr, None)])
llrpcattrs.linkage = 'internal'
rpctag = b""
for attr_type in list(typ.attributes.values())[1:]:
if types.is_function(attr_type) or types.is_method(attr_type):
continue
rpctag += self._rpc_tag(attr_type, error_handler=rpc_tag_error)
rpctag += b"\x00"
llrpctag = self.llstr_of_str(rpctag)
lldesc = ll.GlobalVariable(self.llmodule, lldescty,
name="shadow.desc.{}".format(type_name))
lldesc.initializer = ll.Constant(lldescty, [
llrpcattrs.bitcast(llptr.as_pointer()),
llrpctag,
ll.Constant(lli32, shadow_memory_dim[typ]),
llshadow.bitcast(llptr)])
lldesc.linkage = 'internal'
lldescs.append(lldesc)
llglobaldescty = ll.ArrayType(lldescty.as_pointer(), len(lldescs) + 1)
llglobaldesc = ll.GlobalVariable(self.llmodule, llglobaldescty,
name="shadow.descs")
llglobaldesc.initializer = ll.Constant(llglobaldescty,
lldescs + [ll.Constant(lldescty.as_pointer(), None)])
# llglobaldesc.linkage = 'internal'
def process_function(self, func): def process_function(self, func):
try: try:
self.llfunction = self.llmodule.get_global(func.name) self.llfunction = self.llmodule.get_global(func.name)
@ -571,6 +653,34 @@ class LLVMIRGenerator:
def process_SetAttr(self, insn): def process_SetAttr(self, insn):
assert builtins.is_allocated(insn.object().type) assert builtins.is_allocated(insn.object().type)
object_type = insn.object().type.find()
value_type = insn.value().type.find()
if "__objectid__" in object_type.attributes and \
not (types.is_function(value_type) or types.is_method(value_type)):
llidptr = self.llbuilder.gep(self.map(insn.object()),
[self.llindex(0), self.llindex(0)])
llid = self.llbuilder.load(llidptr, name="shadow.id")
llattrcount = ll.Constant(lli32, len(object_type.attributes) - 1)
llshadowpos = self.llbuilder.add(
self.llbuilder.mul(llid, llattrcount),
ll.Constant(lli32, self.attr_index(insn) - 1))
if types.is_constructor(object_type):
shadowname = "shadow.class.{}".format(object_type.name)
else:
shadowname = "shadow.instance.{}".format(object_type.name)
llshadow = self.llmodule.get_global(shadowname)
if llshadow is None:
llshadowty = ll.ArrayType(lli8, 0)
llshadow = ll.GlobalVariable(self.llmodule, llshadowty, shadowname)
llshadow.linkage = 'internal'
llshadowptr = self.llbuilder.gep(llshadow, [self.llindex(0), llshadowpos],
name="shadow.ptr")
self.llbuilder.store(ll.Constant(lli8, 1), llshadowptr)
llptr = self.llbuilder.gep(self.map(insn.object()), llptr = self.llbuilder.gep(self.map(insn.object()),
[self.llindex(0), self.llindex(self.attr_index(insn))], [self.llindex(0), self.llindex(self.attr_index(insn))],
name=insn.name) name=insn.name)
@ -838,6 +948,7 @@ class LLVMIRGenerator:
# See session.c:{send,receive}_rpc_value and comm_generic.py:_{send,receive}_rpc_value. # See session.c:{send,receive}_rpc_value and comm_generic.py:_{send,receive}_rpc_value.
def _rpc_tag(self, typ, error_handler): def _rpc_tag(self, typ, error_handler):
typ = typ.find()
if types.is_tuple(typ): if types.is_tuple(typ):
assert len(typ.elts) < 256 assert len(typ.elts) < 256
return b"t" + bytes([len(typ.elts)]) + \ return b"t" + bytes([len(typ.elts)]) + \

View File

@ -578,14 +578,17 @@ def is_var(typ):
def is_mono(typ, name=None, **params): def is_mono(typ, name=None, **params):
typ = typ.find() typ = typ.find()
if not isinstance(typ, TMono):
return False
params_match = True params_match = True
for param in params: for param in params:
if param not in typ.params: if param not in typ.params:
return False return False
params_match = params_match and \ params_match = params_match and \
typ.params[param].find() == params[param].find() typ.params[param].find() == params[param].find()
return isinstance(typ, TMono) and \ return name is None or (typ.name == name and params_match)
(name is None or (typ.name == name and params_match))
def is_polymorphic(typ): def is_polymorphic(typ):
return typ.fold(False, lambda accum, typ: accum or is_var(typ)) return typ.fold(False, lambda accum, typ: accum or is_var(typ))