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),
self.forward_map.values()))
def __iter__(self):
return iter(self.forward_map.keys())
class ASTSynthesizer:
def __init__(self, object_map, type_map, value_map, quote_function=None, expanded_from=None):
self.source = ""

View File

@ -20,6 +20,7 @@ class Source:
self.engine = engine
self.object_map = None
self.type_map = {}
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):
self.engine = src.engine
self.object_map = src.object_map
self.type_map = src.type_map
int_monomorphizer = transforms.IntMonomorphizer(engine=self.engine)
inferencer = transforms.Inferencer(engine=self.engine)
@ -76,10 +78,10 @@ class Module:
def build_llvm_ir(self, target):
"""Compile the module to LLVM IR for the specified target."""
llvm_ir_generator = transforms.LLVMIRGenerator(engine=self.engine,
module_name=self.name, target=target,
object_map=self.object_map)
return llvm_ir_generator.process(self.artiq_ir)
llvm_ir_generator = transforms.LLVMIRGenerator(
engine=self.engine, module_name=self.name, target=target,
object_map=self.object_map, type_map=self.type_map)
return llvm_ir_generator.process(self.artiq_ir, attribute_writeback=True)
def entry_point(self):
"""Return the name of the function that is the entry point of this module."""

View File

@ -3,7 +3,8 @@
into LLVM intermediate representation.
"""
import os
import os, re
from collections import defaultdict
from pythonparser import ast, diagnostic
from llvmlite_artiq import ir as ll
from ...language import core as language_core
@ -161,10 +162,11 @@ class DebugInfoEmitter:
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.target = target
self.object_map = object_map
self.type_map = type_map
self.llcontext = target.llcontext
self.llmodule = ll.Module(context=self.llcontext, name=module_name)
self.llmodule.triple = target.triple
@ -285,8 +287,7 @@ class LLVMIRGenerator:
else:
return llty.as_pointer()
def llstr_of_str(self, value, name=None,
linkage="private", unnamed_addr=True):
def llstr_of_str(self, value, name=None, linkage="private", unnamed_addr=True):
if isinstance(value, str):
assert "\0" not in value
as_bytes = (value + "\0").encode("utf-8")
@ -294,7 +295,8 @@ class LLVMIRGenerator:
as_bytes = value
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)
if llstr is None:
@ -403,15 +405,95 @@ class LLVMIRGenerator:
else:
assert False
def process(self, functions):
def process(self, functions, attribute_writeback):
for func in functions:
self.process_function(func)
if any(functions):
self.debug_info_emitter.finalize(functions[0].loc.source_buffer)
if attribute_writeback:
self.emit_attribute_writeback()
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):
try:
self.llfunction = self.llmodule.get_global(func.name)
@ -571,6 +653,34 @@ class LLVMIRGenerator:
def process_SetAttr(self, insn):
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()),
[self.llindex(0), self.llindex(self.attr_index(insn))],
name=insn.name)
@ -838,6 +948,7 @@ class LLVMIRGenerator:
# See session.c:{send,receive}_rpc_value and comm_generic.py:_{send,receive}_rpc_value.
def _rpc_tag(self, typ, error_handler):
typ = typ.find()
if types.is_tuple(typ):
assert len(typ.elts) < 256
return b"t" + bytes([len(typ.elts)]) + \

View File

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