Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: m-labs/artiq
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 8bff8075de8c
Choose a base ref
...
head repository: m-labs/artiq
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 640022122ba2
Choose a head ref
  • 3 commits
  • 8 files changed
  • 1 contributor

Commits on May 16, 2016

  1. compiler: demangle symbols.

    In future commits we'll add Itanium C++ ABI style mangling to ARTIQ
    emitted function names.
    whitequark committed May 16, 2016
    Copy the full SHA
    c94c411 View commit details
  2. embedding: refactor.

    whitequark committed May 16, 2016
    Copy the full SHA
    d085d5a View commit details
  3. embedding: refactor some more.

    whitequark committed May 16, 2016
    Copy the full SHA
    6400221 View commit details
181 changes: 101 additions & 80 deletions artiq/compiler/embedding.py
Original file line number Diff line number Diff line change
@@ -22,37 +22,61 @@
def coredevice_print(x): print(x)


class ObjectMap:
class EmbeddingMap:
def __init__(self):
self.current_key = 0
self.forward_map = {}
self.reverse_map = {}
self.object_current_key = 0
self.object_forward_map = {}
self.object_reverse_map = {}
self.type_map = {}
self.function_map = {}

# Types
def store_type(self, typ, instance_type, constructor_type):
self.type_map[typ] = (instance_type, constructor_type)

def retrieve_type(self, typ):
return self.type_map[typ]

def has_type(self, typ):
return typ in self.type_map

def iter_types(self):
return self.type_map.values()

# Functions
def store_function(self, function, ir_function_name):
self.function_map[function] = ir_function_name

def retrieve_function(self, function):
return self.function_map[function]

def store(self, obj_ref):
# Objects
def store_object(self, obj_ref):
obj_id = id(obj_ref)
if obj_id in self.reverse_map:
return self.reverse_map[obj_id]
if obj_id in self.object_reverse_map:
return self.object_reverse_map[obj_id]

self.current_key += 1
self.forward_map[self.current_key] = obj_ref
self.reverse_map[obj_id] = self.current_key
return self.current_key
self.object_current_key += 1
self.object_forward_map[self.object_current_key] = obj_ref
self.object_reverse_map[obj_id] = self.object_current_key
return self.object_current_key

def retrieve(self, obj_key):
return self.forward_map[obj_key]
def retrieve_object(self, obj_key):
return self.object_forward_map[obj_key]

def iter_objects(self):
return self.object_forward_map.keys()

def has_rpc(self):
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())
self.object_forward_map.values()))

class ASTSynthesizer:
def __init__(self, object_map, type_map, value_map, quote_function=None, expanded_from=None):
def __init__(self, embedding_map, value_map, quote_function=None, expanded_from=None):
self.source = ""
self.source_buffer = source.Buffer(self.source, "<synthesized>")
self.object_map, self.type_map, self.value_map = object_map, type_map, value_map
self.embedding_map = embedding_map
self.value_map = value_map
self.quote_function = quote_function
self.expanded_from = expanded_from
self.diagnostics = []
@@ -134,8 +158,8 @@ def quote(self, value):
else:
typ = type(value)

if typ in self.type_map:
instance_type, constructor_type = self.type_map[typ]
if self.embedding_map.has_type(typ):
instance_type, constructor_type = self.embedding_map.retrieve_type(typ)

if hasattr(value, 'kernel_invariants') and \
value.kernel_invariants != instance_type.constant_attributes:
@@ -170,7 +194,7 @@ def quote(self, value):
if hasattr(typ, 'artiq_builtin'):
exception_id = 0
else:
exception_id = self.object_map.store(typ)
exception_id = self.embedding_map.store_object(typ)
instance_type = builtins.TException("{}.{}".format(typ.__module__,
typ.__qualname__),
id=exception_id)
@@ -183,7 +207,7 @@ def quote(self, value):
constructor_type.attributes['__objectid__'] = builtins.TInt32()
instance_type.constructor = constructor_type

self.type_map[typ] = instance_type, constructor_type
self.embedding_map.store_type(typ, instance_type, constructor_type)

if hasattr(value, 'kernel_invariants'):
assert isinstance(value.kernel_invariants, set)
@@ -531,9 +555,7 @@ def __init__(self, core, dmgr, engine=None):

self.functions = {}

self.function_map = {}
self.object_map = ObjectMap()
self.type_map = {}
self.embedding_map = EmbeddingMap()
self.value_map = defaultdict(lambda: [])

def stitch_call(self, function, args, kwargs, callback=None):
@@ -562,7 +584,7 @@ def finalize(self):

# For every host class we embed, fill in the function slots
# with their corresponding closures.
for instance_type, constructor_type in list(self.type_map.values()):
for instance_type, constructor_type in self.embedding_map.iter_types():
# Do we have any direct reference to a constructor?
if len(self.value_map[constructor_type]) > 0:
# Yes, use it.
@@ -592,8 +614,7 @@ def _inject(self, node):

def _synthesizer(self, expanded_from=None):
return ASTSynthesizer(expanded_from=expanded_from,
object_map=self.object_map,
type_map=self.type_map,
embedding_map=self.embedding_map,
value_map=self.value_map,
quote_function=self._quote_function)

@@ -635,7 +656,7 @@ def _quote_embedded_function(self, function, flags):

# Record the function in the function map so that LLVM IR generator
# can handle quoting it.
self.function_map[function] = function_node.name
self.embedding_map.store_function(function, function_node.name)

# Memoize the function type before typing it to handle recursive
# invocations.
@@ -786,69 +807,69 @@ def _quote_syscall(self, function, loc):
self.functions[function] = function_type
return function_type

def _quote_rpc(self, callee, loc):
def _quote_rpc(self, function, loc):
ret_type = builtins.TNone()

if isinstance(callee, pytypes.BuiltinFunctionType):
if isinstance(function, pytypes.BuiltinFunctionType):
pass
elif isinstance(callee, pytypes.FunctionType) or isinstance(callee, pytypes.MethodType):
if isinstance(callee, pytypes.FunctionType):
signature = inspect.signature(callee)
elif isinstance(function, pytypes.FunctionType) or isinstance(function, pytypes.MethodType):
if isinstance(function, pytypes.FunctionType):
signature = inspect.signature(function)
else:
# inspect bug?
signature = inspect.signature(callee.__func__)
signature = inspect.signature(function.__func__)
if signature.return_annotation is not inspect.Signature.empty:
ret_type = self._extract_annot(callee, signature.return_annotation,
ret_type = self._extract_annot(function, signature.return_annotation,
"return type", loc, is_syscall=False)
else:
assert False

function_type = types.TRPC(ret_type, service=self.object_map.store(callee))
self.functions[callee] = function_type
function_type = types.TRPC(ret_type, service=self.embedding_map.store_object(function))
self.functions[function] = function_type
return function_type

def _quote_function(self, function, loc):
if function not in self.functions:
if hasattr(function, "artiq_embedded"):
if function.artiq_embedded.function is not None:
if function.__name__ == "<lambda>":
note = diagnostic.Diagnostic("note",
"lambda created here", {},
self._function_loc(function.artiq_embedded.function))
diag = diagnostic.Diagnostic("fatal",
"lambdas cannot be used as kernel functions", {},
loc,
notes=[note])
self.engine.process(diag)

core_name = function.artiq_embedded.core_name
if core_name is not None and self.dmgr.get(core_name) != self.core:
note = diagnostic.Diagnostic("note",
"called from this function", {},
loc)
diag = diagnostic.Diagnostic("fatal",
"this function runs on a different core device '{name}'",
{"name": function.artiq_embedded.core_name},
self._function_loc(function.artiq_embedded.function),
notes=[note])
self.engine.process(diag)

self._quote_embedded_function(function,
flags=function.artiq_embedded.flags)
elif function.artiq_embedded.syscall is not None:
# Insert a storage-less global whose type instructs the compiler
# to perform a system call instead of a regular call.
self._quote_syscall(function, loc)
elif function.artiq_embedded.forbidden is not None:
diag = diagnostic.Diagnostic("fatal",
"this function cannot be called as an RPC", {},
self._function_loc(function),
notes=self._call_site_note(loc, is_syscall=True))
self.engine.process(diag)
else:
assert False
else:
self._quote_rpc(function, loc)
if function in self.functions:
pass
elif not hasattr(function, "artiq_embedded"):
self._quote_rpc(function, loc)
elif function.artiq_embedded.function is not None:
if function.__name__ == "<lambda>":
note = diagnostic.Diagnostic("note",
"lambda created here", {},
self._function_loc(function.artiq_embedded.function))
diag = diagnostic.Diagnostic("fatal",
"lambdas cannot be used as kernel functions", {},
loc,
notes=[note])
self.engine.process(diag)

core_name = function.artiq_embedded.core_name
if core_name is not None and self.dmgr.get(core_name) != self.core:
note = diagnostic.Diagnostic("note",
"called from this function", {},
loc)
diag = diagnostic.Diagnostic("fatal",
"this function runs on a different core device '{name}'",
{"name": function.artiq_embedded.core_name},
self._function_loc(function.artiq_embedded.function),
notes=[note])
self.engine.process(diag)

self._quote_embedded_function(function,
flags=function.artiq_embedded.flags)
elif function.artiq_embedded.syscall is not None:
# Insert a storage-less global whose type instructs the compiler
# to perform a system call instead of a regular call.
self._quote_syscall(function, loc)
elif function.artiq_embedded.forbidden is not None:
diag = diagnostic.Diagnostic("fatal",
"this function cannot be called as an RPC", {},
self._function_loc(function),
notes=self._call_site_note(loc, is_syscall=True))
self.engine.process(diag)
else:
assert False

return self.functions[function]

16 changes: 5 additions & 11 deletions artiq/compiler/module.py
Original file line number Diff line number Diff line change
@@ -18,11 +18,7 @@ def __init__(self, source_buffer, engine=None):
self.engine = diagnostic.Engine(all_errors_are_fatal=True)
else:
self.engine = engine

self.function_map = {}
self.object_map = None
self.type_map = {}

self.embedding_map = None
self.name, _ = os.path.splitext(os.path.basename(source_buffer.name))

asttyped_rewriter = transforms.ASTTypedRewriter(engine=engine,
@@ -46,9 +42,9 @@ def from_filename(cls, filename, engine=None):
class Module:
def __init__(self, src, ref_period=1e-6):
self.engine = src.engine
self.function_map = src.function_map
self.object_map = src.object_map
self.type_map = src.type_map
self.embedding_map = src.embedding_map
self.name = src.name
self.globals = src.globals

int_monomorphizer = transforms.IntMonomorphizer(engine=self.engine)
inferencer = transforms.Inferencer(engine=self.engine)
@@ -65,8 +61,6 @@ def __init__(self, src, ref_period=1e-6):
devirtualization = analyses.Devirtualization()
interleaver = transforms.Interleaver(engine=self.engine)

self.name = src.name
self.globals = src.globals
int_monomorphizer.visit(src.typedtree)
inferencer.visit(src.typedtree)
monomorphism_validator.visit(src.typedtree)
@@ -84,7 +78,7 @@ 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,
function_map=self.function_map, object_map=self.object_map, type_map=self.type_map)
embedding_map=self.embedding_map)
return llvm_ir_generator.process(self.artiq_ir, attribute_writeback=True)

def entry_point(self):
6 changes: 5 additions & 1 deletion artiq/compiler/targets.py
Original file line number Diff line number Diff line change
@@ -196,7 +196,7 @@ def symbolize(self, library, addresses):
# the backtrace entry should point at.
offset_addresses = [hex(addr - 1) for addr in addresses]
with RunTool([self.triple + "-addr2line", "--addresses", "--functions", "--inlines",
"--exe={library}"] + offset_addresses,
"--demangle", "--exe={library}"] + offset_addresses,
library=library) \
as results:
lines = iter(results["__stdout__"].rstrip().split("\n"))
@@ -221,6 +221,10 @@ def symbolize(self, library, addresses):
backtrace.append((filename, int(line), -1, function, address))
return backtrace

def demangle(self, names):
with RunTool([self.triple + "-c++filt"] + names) as results:
return results["__stdout__"].rstrip().split("\n")

class NativeTarget(Target):
def __init__(self):
super().__init__()
Loading