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: 321ba57e84dd
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: d6510083b747
Choose a head ref

Commits on Apr 14, 2016

  1. compiler: get rid of the GetConstructor opcode.

    whitequark authored and sbourdeauducq committed Apr 14, 2016
    Copy the full SHA
    00facbb View commit details
  2. transforms.llvm_ir_generator: extract class function attributes.

    This should give LLVM more visibility.
    whitequark authored and sbourdeauducq committed Apr 14, 2016
    Copy the full SHA
    f72e050 View commit details
  3. Copy the full SHA
    e534941 View commit details
  4. Copy the full SHA
    8fa4281 View commit details
  5. compiler: tune the LLVM optimizer pipeline (fixes #315).

    whitequark authored and sbourdeauducq committed Apr 14, 2016
    Copy the full SHA
    ccb1d54 View commit details
  6. Copy the full SHA
    f2c92ff View commit details
  7. llvm_ir_generator: generate code more amenable to LLVM's GlobalOpt.

    This exposes almost all embedded methods to inlining, with massive
    gains.
    whitequark authored and sbourdeauducq committed Apr 14, 2016
    Copy the full SHA
    92f3dc7 View commit details
  8. test_pulse_rate: tighten upper bound to 1500ns.

    whitequark authored and sbourdeauducq committed Apr 14, 2016
    Copy the full SHA
    fcf2a73 View commit details
  9. compiler: extract runtime checks into separate cold functions.

    This reduces register pressure as well as function size, which
    favorably affects the inliner.
    whitequark authored and sbourdeauducq committed Apr 14, 2016
    Copy the full SHA
    3fa5762 View commit details
  10. compiler: raise inliner threshold to the equivalent of -O3.

    whitequark authored and sbourdeauducq committed Apr 14, 2016
    Copy the full SHA
    019f528 View commit details
  11. compiler: run IPSCCP.

    This doesn't do much, only frees some registers.
    whitequark authored and sbourdeauducq committed Apr 14, 2016
    Copy the full SHA
    718d411 View commit details
  12. test_pulse_rate_dds: tighten upper bound to 400us.

    whitequark authored and sbourdeauducq committed Apr 14, 2016
    Copy the full SHA
    348e058 View commit details
  13. compiler: implement kernel constant attributes.

    Part of #322.
    whitequark authored and sbourdeauducq committed Apr 14, 2016
    Copy the full SHA
    665e59e View commit details
  14. compiler: do not write back kernel constant attributes.

    Fixes #322.
    whitequark authored and sbourdeauducq committed Apr 14, 2016
    Copy the full SHA
    b5fd257 View commit details
  15. Copy the full SHA
    081edb2 View commit details
  16. compiler: mark loads of kernel constant attributes as load invariant.

    Also, enable LICM, since it can take advantage of this.
    whitequark authored and sbourdeauducq committed Apr 14, 2016
    Copy the full SHA
    0e0f81b View commit details
  17. compiler: mark FFI functions as ModRef=Ref using TBAA metadata.

    Fascinatingly, the fact that you can mark call instructions with
    !tbaa metadata is completely undocumented. Regardless, it is true:
    a !tbaa metadata for an "immutable" type will cause
    AliasAnalysis::getModRefBehavior to return OnlyReadsMemory for that
    call site.
    
    Don't bother marking loads with TBAA yet since we already place
    !load.invariant on them (which is as good as the TBAA "immutable"
    flag) and after that we're limited by lack of !nonnull anyway.
    
    Also, add TBAA analysis passes in our pipeline to actually engage it.
    whitequark authored and sbourdeauducq committed Apr 14, 2016
    Copy the full SHA
    c6b2165 View commit details
  18. compiler: allow flagging syscalls, providing information to optimizer.

    This also fixes a crash in test_cache introduced in 1d8b0d4.
    whitequark authored and sbourdeauducq committed Apr 14, 2016
    Copy the full SHA
    f7d4a37 View commit details
  19. Commit missing parts of 6f5332f.

    whitequark authored and sbourdeauducq committed Apr 14, 2016
    Copy the full SHA
    5fafcc1 View commit details
  20. compiler: allow specifying per-function "fast-math" flags.

    Fixes #351.
    whitequark authored and sbourdeauducq committed Apr 14, 2016
    Copy the full SHA
    ee7e648 View commit details
  21. Commit missing parts of 1d8b0d4.

    whitequark authored and sbourdeauducq committed Apr 14, 2016
    Copy the full SHA
    dcb0ffd View commit details
  22. llvm_ir_generator: don't mark non-constant attribute loads as invariant.

    Oops.
    whitequark authored and sbourdeauducq committed Apr 14, 2016
    Copy the full SHA
    812e79b View commit details
  23. compiler: fix ARTIQ_DUMP_ELF.

    whitequark authored and sbourdeauducq committed Apr 14, 2016
    Copy the full SHA
    f7603dc View commit details
  24. test: relax lit/embedding/syscall_flags.

    We currently have broken debug info. In either case, debug info
    is irrelevant to this test.
    whitequark authored and sbourdeauducq committed Apr 14, 2016
    Copy the full SHA
    50ae176 View commit details
  25. llvm_ir_generator: mark loads as non-null where applicable.

    whitequark authored and sbourdeauducq committed Apr 14, 2016
    Copy the full SHA
    e416246 View commit details
  26. llvm_ir_generator: do not use 'coldcc' calling convention.

    First, this calling convention doesn't actually exist in OR1K
    and trying to use it in Asserts build causes an UNREACHABLE.
    
    Second, I tried to introduce it and it does not appear to produce
    any measurable benefit: not only OR1K has a ton of CSRs but also
    it is quite hard, if not realistically impossible, to produce
    the kind of register pressure that would be relieved by sparing
    a few more CSRs for our exception raising function calls, since
    temporaries don't have to be preserved before a noreturn call
    and spilling over ten registers across an exceptional edge
    is not something that the code we care about would do.
    
    Third, it produces measurable drawbacks: it inflates code size
    of check:* functions by adding spills. Of course, this could be
    alleviated by making __artiq_raise coldcc as well, but what's
    the point anyway?
    whitequark authored and sbourdeauducq committed Apr 14, 2016
    Copy the full SHA
    f59fd8f View commit details
  27. compiler: use correct data layout.

    whitequark authored and sbourdeauducq committed Apr 14, 2016
    Copy the full SHA
    932e680 View commit details
  28. compiler: update for LLVM 3.7.

    whitequark authored and sbourdeauducq committed Apr 14, 2016
    Copy the full SHA
    03b6555 View commit details
  29. compiler: mark loaded pointers as !dereferenceable.

    Also, lower the bound for test_pulse_rate_dds, since we generate
    better code for it now.
    whitequark authored and sbourdeauducq committed Apr 14, 2016
    Copy the full SHA
    1120c26 View commit details
  30. compiler: add analysis passes from TargetMachine.

    This doesn't have any effect right now, but is the right thing to do.
    whitequark authored and sbourdeauducq committed Apr 14, 2016
    Copy the full SHA
    c89c27e View commit details
  31. compiler: emit verbose assembly via ARTIQ_DUMP_ASM.

    whitequark authored and sbourdeauducq committed Apr 14, 2016
    Copy the full SHA
    f26990a View commit details
  32. conda: require llvmlite-artiq built for LLVM 3.8.

    whitequark authored and sbourdeauducq committed Apr 14, 2016
    Copy the full SHA
    66bbee5 View commit details
  33. coredevice: format backtrace RA as +0xN, not 0xN.

    The absolute address is somewhere in the 0x4000000 range; the one
    that is displayed is an offset from the shared object base.
    whitequark authored and sbourdeauducq committed Apr 14, 2016
    Copy the full SHA
    7c520aa View commit details
  34. llvm_ir_generator: update debug info emission for LLVM 3.8.

    whitequark authored and sbourdeauducq committed Apr 14, 2016
    Copy the full SHA
    f958cba View commit details
  35. llvm_ir_generator: add TBAA metadata for @now.

    whitequark authored and sbourdeauducq committed Apr 14, 2016
    Copy the full SHA
    702e959 View commit details
  36. ttl: mark constant attributes for TTL{In,InOut,ClockGen}.

    whitequark authored and sbourdeauducq committed Apr 14, 2016
    Copy the full SHA
    a2f6e81 View commit details
  37. compiler: purge generated functions from backtraces.

    whitequark authored and sbourdeauducq committed Apr 14, 2016
    Copy the full SHA
    89326fb View commit details
  38. conda: update llvmlite-artiq dependency.

    Build 22 includes debug information support.
    whitequark authored and sbourdeauducq committed Apr 14, 2016
    Copy the full SHA
    31b5154 View commit details
  39. llvm_ir_generator: fix DICompileUnit.language.

    whitequark authored and sbourdeauducq committed Apr 14, 2016
    Copy the full SHA
    75252ca View commit details
  40. llvm_ir_generator: change !{→unconditionally_}dereferenceable.

    Since LLVM 3.8, !dereferenceable is weaker, so we introduce
    !unconditionally_dereferenceable (http://reviews.llvm.org/D18738)
    to regain its functionality.
    whitequark authored and sbourdeauducq committed Apr 14, 2016
    Copy the full SHA
    d4f1614 View commit details
  41. llvm_ir_generator: add fast-math flags to fcmp.

    This is allowed in 3.8.
    whitequark authored and sbourdeauducq committed Apr 14, 2016
    Copy the full SHA
    c6f946a View commit details
  42. conda: update llvmlite-artiq dependency.

    Build 24 includes addc optimizations.
    whitequark authored and sbourdeauducq committed Apr 14, 2016
    Copy the full SHA
    3445462 View commit details
  43. test_pulse_rate_dds: adjust bounds.

    whitequark authored and sbourdeauducq committed Apr 14, 2016
    Copy the full SHA
    e6666ce View commit details
  44. embedding: s/kernel_constant_attributes/kernel_invariants/g

    Requested in #359.
    whitequark authored and sbourdeauducq committed Apr 14, 2016
    Copy the full SHA
    2248a2e View commit details
  45. runtime: add kernel-accessible sqrt.

    Fixes #382.
    whitequark authored and sbourdeauducq committed Apr 14, 2016
    Copy the full SHA
    904379d View commit details
  46. Commit missing parts of bb064c6.

    whitequark authored and sbourdeauducq committed Apr 14, 2016
    Copy the full SHA
    d651008 View commit details
Showing with 1,059 additions and 533 deletions.
  1. +1 −0 artiq/compiler/analyses/__init__.py
  2. +30 −0 artiq/compiler/analyses/constness.py
  3. +4 −0 artiq/compiler/asttyped.py
  4. +72 −66 artiq/compiler/embedding.py
  5. +24 −35 artiq/compiler/ir.py
  6. +5 −1 artiq/compiler/module.py
  7. +50 −15 artiq/compiler/targets.py
  8. +1 −1 artiq/compiler/testbench/jit.py
  9. +153 −118 artiq/compiler/transforms/artiq_ir_generator.py
  10. +8 −6 artiq/compiler/transforms/asttyped_rewriter.py
  11. +2 −3 artiq/compiler/transforms/dead_code_eliminator.py
  12. +9 −1 artiq/compiler/transforms/inferencer.py
  13. +2 −0 artiq/compiler/transforms/iodelay_estimator.py
  14. +410 −226 artiq/compiler/transforms/llvm_ir_generator.py
  15. +10 −1 artiq/compiler/types.py
  16. +2 −0 artiq/compiler/validators/escape.py
  17. +2 −0 artiq/compiler/validators/monomorphism.py
  18. +2 −2 artiq/coredevice/cache.py
  19. +7 −1 artiq/coredevice/core.py
  20. +18 −8 artiq/coredevice/dds.py
  21. +1 −1 artiq/coredevice/exceptions.py
  22. +5 −5 artiq/coredevice/i2c.py
  23. +3 −3 artiq/coredevice/rtio.py
  24. +6 −0 artiq/coredevice/ttl.py
  25. +26 −12 artiq/language/core.py
  26. +105 −9 artiq/runtime/ksupport.c
  27. +18 −0 artiq/test/coredevice/test_portability.py
  28. +24 −18 artiq/test/coredevice/test_rtio.py
  29. +1 −0 artiq/test/lit/devirtualization/function.py
  30. +1 −0 artiq/test/lit/devirtualization/method.py
  31. +18 −0 artiq/test/lit/embedding/error_attr_constant.py
  32. +20 −0 artiq/test/lit/embedding/fast_math_flags.py
  33. +18 −0 artiq/test/lit/embedding/syscall_flags.py
  34. +1 −1 conda/artiq/meta.yaml
1 change: 1 addition & 0 deletions artiq/compiler/analyses/__init__.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
from .constness import Constness
from .domination import DominatorTree
from .devirtualization import Devirtualization
30 changes: 30 additions & 0 deletions artiq/compiler/analyses/constness.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
"""
:class:`Constness` checks that no attribute marked
as constant is ever set.
"""

from pythonparser import algorithm, diagnostic
from .. import types

class Constness(algorithm.Visitor):
def __init__(self, engine):
self.engine = engine
self.in_assign = False

def visit_Assign(self, node):
self.visit(node.value)
self.in_assign = True
self.visit(node.targets)
self.in_assign = False

def visit_AttributeT(self, node):
self.generic_visit(node)
if self.in_assign:
typ = node.value.type.find()
if types.is_instance(typ) and node.attr in typ.constant_attributes:
diag = diagnostic.Diagnostic("error",
"cannot assign to constant attribute '{attr}' of class '{class}'",
{"attr": node.attr, "class": typ.name},
node.loc)
self.engine.process(diag)
return
4 changes: 4 additions & 0 deletions artiq/compiler/asttyped.py
Original file line number Diff line number Diff line change
@@ -29,6 +29,10 @@ class ClassDefT(ast.ClassDef):
_types = ("constructor_type",)
class FunctionDefT(ast.FunctionDef, scoped):
_types = ("signature_type",)
class QuotedFunctionDefT(FunctionDefT):
"""
:ivar flags: (set of str) Code generation flags (see :class:`ir.Function`).
"""
class ModuleT(ast.Module, scoped):
pass

138 changes: 72 additions & 66 deletions artiq/compiler/embedding.py
Original file line number Diff line number Diff line change
@@ -16,6 +16,7 @@
from ..language import core as language_core
from . import types, builtins, asttyped, prelude
from .transforms import ASTTypedRewriter, Inferencer, IntMonomorphizer
from .transforms.asttyped_rewriter import LocalExtractor


def coredevice_print(x): print(x)
@@ -107,11 +108,8 @@ def quote(self, value):
unquote_loc = self._add('`')
loc = quote_loc.join(unquote_loc)

function_name, function_type = self.quote_function(value, self.expanded_from)
if function_name is None:
return asttyped.QuoteT(value=value, type=function_type, loc=loc)
else:
return asttyped.NameT(id=function_name, ctx=None, type=function_type, loc=loc)
function_type = self.quote_function(value, self.expanded_from)
return asttyped.QuoteT(value=value, type=function_type, loc=loc)
else:
quote_loc = self._add('`')
repr_loc = self._add(repr(value))
@@ -139,6 +137,9 @@ def quote(self, value):
instance_type = types.TInstance("{}.{}".format(typ.__module__, typ.__qualname__),
OrderedDict())
instance_type.attributes['__objectid__'] = builtins.TInt32()
if hasattr(typ, 'kernel_invariants'):
assert isinstance(typ.kernel_invariants, set)
instance_type.constant_attributes = typ.kernel_invariants

constructor_type = types.TConstructor(instance_type)
constructor_type.attributes['__objectid__'] = builtins.TInt32()
@@ -155,7 +156,7 @@ def quote(self, value):
return asttyped.QuoteT(value=value, type=instance_type,
loc=loc)

def call(self, function_node, args, kwargs, callback=None):
def call(self, callee, args, kwargs, callback=None):
"""
Construct an AST fragment calling a function specified by
an AST node `function_node`, with given arguments.
@@ -164,11 +165,11 @@ def call(self, function_node, args, kwargs, callback=None):
callback_node = self.quote(callback)
cb_begin_loc = self._add("(")

callee_node = self.quote(callee)
arg_nodes = []
kwarg_nodes = []
kwarg_locs = []

name_loc = self._add(function_node.name)
begin_loc = self._add("(")
for index, arg in enumerate(args):
arg_nodes.append(self.quote(arg))
@@ -189,9 +190,7 @@ def call(self, function_node, args, kwargs, callback=None):
cb_end_loc = self._add(")")

node = asttyped.CallT(
func=asttyped.NameT(id=function_node.name, ctx=None,
type=function_node.signature_type,
loc=name_loc),
func=callee_node,
args=arg_nodes,
keywords=[ast.keyword(arg=kw, value=value,
arg_loc=arg_loc, equals_loc=equals_loc,
@@ -201,7 +200,7 @@ def call(self, function_node, args, kwargs, callback=None):
starargs=None, kwargs=None,
type=types.TVar(), iodelay=None, arg_exprs={},
begin_loc=begin_loc, end_loc=end_loc, star_loc=None, dstar_loc=None,
loc=name_loc.join(end_loc))
loc=callee_node.loc.join(end_loc))

if callback is not None:
node = asttyped.CallT(
@@ -213,19 +212,6 @@ def call(self, function_node, args, kwargs, callback=None):

return node

def assign_local(self, var_name, value):
name_loc = self._add(var_name)
_ = self._add(" ")
equals_loc = self._add("=")
_ = self._add(" ")
value_node = self.quote(value)

var_node = asttyped.NameT(id=var_name, ctx=None, type=value_node.type,
loc=name_loc)

return ast.Assign(targets=[var_node], value=value_node,
op_locs=[equals_loc], loc=name_loc.join(value_node.loc))

def assign_attribute(self, obj, attr_name, value):
obj_node = self.quote(obj)
dot_loc = self._add(".")
@@ -259,6 +245,35 @@ def __init__(self, engine, prelude, globals, host_environment, quote):
self.host_environment = host_environment
self.quote = quote

def visit_quoted_function(self, node, function):
extractor = LocalExtractor(env_stack=self.env_stack, engine=self.engine)
extractor.visit(node)

# We quote the defaults so they end up in the global data in LLVM IR.
# This way there is no "life before main", i.e. they do not have to be
# constructed before the main translated call executes; but the Python
# semantics is kept.
defaults = function.__defaults__ or ()
quoted_defaults = []
for default, default_node in zip(defaults, node.args.defaults):
quoted_defaults.append(self.quote(default, default_node.loc))
node.args.defaults = quoted_defaults

node = asttyped.QuotedFunctionDefT(
typing_env=extractor.typing_env, globals_in_scope=extractor.global_,
signature_type=types.TVar(), return_type=types.TVar(),
name=node.name, args=node.args, returns=node.returns,
body=node.body, decorator_list=node.decorator_list,
keyword_loc=node.keyword_loc, name_loc=node.name_loc,
arrow_loc=node.arrow_loc, colon_loc=node.colon_loc, at_locs=node.at_locs,
loc=node.loc)

try:
self.env_stack.append(node.typing_env)
return self.generic_visit(node)
finally:
self.env_stack.pop()

def visit_Name(self, node):
typ = super()._try_find_name(node.id)
if typ is not None:
@@ -465,18 +480,16 @@ def __init__(self, core, dmgr, engine=None):

self.functions = {}

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

def stitch_call(self, function, args, kwargs, callback=None):
function_node = self._quote_embedded_function(function)
self.typedtree.append(function_node)

# We synthesize source code for the initial call so that
# diagnostics would have something meaningful to display to the user.
synthesizer = self._synthesizer(self._function_loc(function.artiq_embedded.function))
call_node = synthesizer.call(function_node, args, kwargs, callback)
call_node = synthesizer.call(function, args, kwargs, callback)
synthesizer.finalize()
self.typedtree.append(call_node)

@@ -496,9 +509,8 @@ def finalize(self):
break
old_typedtree_hash = typedtree_hash

# For every host class we embed, add an appropriate constructor
# as a global. This is necessary for method lookup, which uses
# the getconstructor instruction.
# 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()):
# Do we have any direct reference to a constructor?
if len(self.value_map[constructor_type]) > 0:
@@ -509,13 +521,6 @@ def finalize(self):
instance, _instance_loc = self.value_map[instance_type][0]
constructor = type(instance)

self.globals[constructor_type.name] = constructor_type

synthesizer = self._synthesizer()
ast = synthesizer.assign_local(constructor_type.name, constructor)
synthesizer.finalize()
self._inject(ast)

for attr in constructor_type.attributes:
if types.is_function(constructor_type.attributes[attr]):
synthesizer = self._synthesizer()
@@ -541,7 +546,7 @@ def _synthesizer(self, expanded_from=None):
value_map=self.value_map,
quote_function=self._quote_function)

def _quote_embedded_function(self, function):
def _quote_embedded_function(self, function, flags):
if not hasattr(function, "artiq_embedded"):
raise ValueError("{} is not an embedded function".format(repr(function)))

@@ -577,23 +582,29 @@ def _quote_embedded_function(self, function):
# Mangle the name, since we put everything into a single module.
function_node.name = "{}.{}".format(module_name, function.__qualname__)

# Normally, LocalExtractor would populate the typing environment
# of the module with the function name. However, since we run
# ASTTypedRewriter on the function node directly, we need to do it
# explicitly.
function_type = types.TVar()
self.globals[function_node.name] = function_type
# Record the function in the function map so that LLVM IR generator
# can handle quoting it.
self.function_map[function] = function_node.name

# Memoize the function before typing it to handle recursive
# Memoize the function type before typing it to handle recursive
# invocations.
self.functions[function] = function_node.name, function_type
self.functions[function] = types.TVar()

# Rewrite into typed form.
asttyped_rewriter = StitchingASTTypedRewriter(
engine=self.engine, prelude=self.prelude,
globals=self.globals, host_environment=host_environment,
quote=self._quote)
return asttyped_rewriter.visit(function_node)
function_node = asttyped_rewriter.visit_quoted_function(function_node, embedded_function)
function_node.flags = flags

# Add it into our typedtree so that it gets inferenced and codegen'd.
self._inject(function_node)

# Tie the typing knot.
self.functions[function].unify(function_node.signature_type)

return function_node

def _function_loc(self, function):
filename = function.__code__.co_filename
@@ -683,7 +694,7 @@ def proxy_diagnostic(diag):
# Let the rest of the program decide.
return types.TVar()

def _quote_foreign_function(self, function, loc, syscall):
def _quote_foreign_function(self, function, loc, syscall, flags):
signature = inspect.signature(function)

arg_types = OrderedDict()
@@ -732,16 +743,14 @@ def _quote_foreign_function(self, function, loc, syscall):
service=self.object_map.store(function))
else:
function_type = types.TCFunction(arg_types, ret_type,
name=syscall)
name=syscall, flags=flags)

self.functions[function] = None, function_type
self.functions[function] = function_type

return None, function_type
return function_type

def _quote_function(self, function, loc):
if function in self.functions:
result = self.functions[function]
else:
if function not in self.functions:
if hasattr(function, "artiq_embedded"):
if function.artiq_embedded.function is not None:
if function.__name__ == "<lambda>":
@@ -766,17 +775,14 @@ def _quote_function(self, function, loc):
notes=[note])
self.engine.process(diag)

# Insert the typed AST for the new function and restart inference.
# It doesn't really matter where we insert as long as it is before
# the final call.
function_node = self._quote_embedded_function(function)
self._inject(function_node)
result = function_node.name, self.globals[function_node.name]
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.
result = self._quote_foreign_function(function, loc,
syscall=function.artiq_embedded.syscall)
self._quote_foreign_function(function, loc,
syscall=function.artiq_embedded.syscall,
flags=function.artiq_embedded.flags)
elif function.artiq_embedded.forbidden is not None:
diag = diagnostic.Diagnostic("fatal",
"this function cannot be called as an RPC", {},
@@ -788,12 +794,12 @@ def _quote_function(self, function, loc):
else:
# Insert a storage-less global whose type instructs the compiler
# to perform an RPC instead of a regular call.
result = self._quote_foreign_function(function, loc, syscall=None)
self._quote_foreign_function(function, loc, syscall=None, flags=None)

function_name, function_type = result
function_type = self.functions[function]
if types.is_rpc_function(function_type):
function_type = types.instantiate(function_type)
return function_name, function_type
return function_type

def _quote(self, value, loc):
synthesizer = self._synthesizer(loc)
Loading