2015-07-21 09:54:34 +08:00
|
|
|
"""
|
|
|
|
:class:`LLVMIRGenerator` transforms ARTIQ intermediate representation
|
|
|
|
into LLVM intermediate representation.
|
|
|
|
"""
|
|
|
|
|
2015-08-10 20:11:52 +08:00
|
|
|
import os
|
2015-08-09 07:17:19 +08:00
|
|
|
from pythonparser import ast, diagnostic
|
2015-07-29 18:54:00 +08:00
|
|
|
from llvmlite_artiq import ir as ll
|
2015-08-28 16:24:15 +08:00
|
|
|
from ...language import core as language_core
|
2015-11-21 03:22:47 +08:00
|
|
|
from .. import types, builtins, ir
|
2015-07-21 09:54:34 +08:00
|
|
|
|
2015-08-10 14:12:34 +08:00
|
|
|
|
|
|
|
llvoid = ll.VoidType()
|
|
|
|
lli1 = ll.IntType(1)
|
|
|
|
lli8 = ll.IntType(8)
|
|
|
|
lli32 = ll.IntType(32)
|
2015-08-31 23:59:33 +08:00
|
|
|
lli64 = ll.IntType(64)
|
2015-08-10 14:12:34 +08:00
|
|
|
lldouble = ll.DoubleType()
|
|
|
|
llptr = ll.IntType(8).as_pointer()
|
2015-08-10 20:11:52 +08:00
|
|
|
llmetadata = ll.MetaData()
|
|
|
|
|
|
|
|
|
|
|
|
DW_LANG_Python = 0x0014
|
|
|
|
DW_TAG_compile_unit = 17
|
|
|
|
DW_TAG_subroutine_type = 21
|
|
|
|
DW_TAG_file_type = 41
|
|
|
|
DW_TAG_subprogram = 46
|
|
|
|
|
|
|
|
def memoize(generator):
|
|
|
|
def memoized(self, *args):
|
|
|
|
result = self.cache.get((generator,) + args, None)
|
|
|
|
if result is None:
|
|
|
|
return generator(self, *args)
|
|
|
|
else:
|
|
|
|
return result
|
|
|
|
return memoized
|
|
|
|
|
|
|
|
class DebugInfoEmitter:
|
|
|
|
def __init__(self, llmodule):
|
|
|
|
self.llmodule = llmodule
|
|
|
|
self.cache = {}
|
|
|
|
self.subprograms = []
|
|
|
|
|
|
|
|
def emit(self, operands):
|
|
|
|
def map_operand(operand):
|
|
|
|
if operand is None:
|
|
|
|
return ll.Constant(llmetadata, None)
|
|
|
|
elif isinstance(operand, str):
|
|
|
|
return ll.MetaDataString(self.llmodule, operand)
|
|
|
|
elif isinstance(operand, bool):
|
|
|
|
return ll.Constant(lli1, operand)
|
|
|
|
elif isinstance(operand, int):
|
|
|
|
return ll.Constant(lli32, operand)
|
|
|
|
elif isinstance(operand, (list, tuple)):
|
|
|
|
return self.emit(operand)
|
|
|
|
elif isinstance(operand, ll.Value):
|
|
|
|
return operand
|
|
|
|
else:
|
|
|
|
print(operand)
|
|
|
|
assert False
|
|
|
|
return self.llmodule.add_metadata(list(map(map_operand, operands)))
|
|
|
|
|
|
|
|
@memoize
|
|
|
|
def emit_filename(self, source_buffer):
|
|
|
|
source_dir, source_file = os.path.split(source_buffer.name)
|
|
|
|
return self.emit([source_file, source_dir])
|
|
|
|
|
|
|
|
@memoize
|
|
|
|
def emit_compile_unit(self, source_buffer, llsubprograms):
|
|
|
|
return self.emit([
|
|
|
|
DW_TAG_compile_unit,
|
|
|
|
self.emit_filename(source_buffer), # filename
|
|
|
|
DW_LANG_Python, # source language
|
|
|
|
"ARTIQ", # producer
|
|
|
|
False, # optimized?
|
|
|
|
"", # linker flags
|
|
|
|
0, # runtime version
|
|
|
|
[], # enum types
|
|
|
|
[], # retained types
|
|
|
|
llsubprograms, # subprograms
|
|
|
|
[], # global variables
|
|
|
|
[], # imported entities
|
|
|
|
"", # split debug filename
|
|
|
|
2, # kind (full=1, lines only=2)
|
|
|
|
])
|
|
|
|
|
|
|
|
@memoize
|
|
|
|
def emit_file(self, source_buffer):
|
|
|
|
return self.emit([
|
|
|
|
DW_TAG_file_type,
|
|
|
|
self.emit_filename(source_buffer), # filename
|
|
|
|
])
|
|
|
|
|
|
|
|
@memoize
|
|
|
|
def emit_subroutine_type(self, typ):
|
|
|
|
return self.emit([
|
|
|
|
DW_TAG_subroutine_type,
|
|
|
|
None, # filename
|
|
|
|
None, # context descriptor
|
|
|
|
"", # name
|
|
|
|
0, # line number
|
|
|
|
0, # (i64) size in bits
|
|
|
|
0, # (i64) alignment in bits
|
|
|
|
0, # (i64) offset in bits
|
|
|
|
0, # flags
|
|
|
|
None, # derived from
|
|
|
|
[None], # members
|
|
|
|
0, # runtime languages
|
|
|
|
None, # base type with vtable pointer
|
|
|
|
None, # template parameters
|
|
|
|
None # unique identifier
|
|
|
|
])
|
|
|
|
|
|
|
|
@memoize
|
|
|
|
def emit_subprogram(self, func, llfunc):
|
|
|
|
source_buffer = func.loc.source_buffer
|
|
|
|
display_name = "{}{}".format(func.name, types.TypePrinter().name(func.type))
|
|
|
|
subprogram = self.emit([
|
|
|
|
DW_TAG_subprogram,
|
|
|
|
self.emit_filename(source_buffer), # filename
|
|
|
|
self.emit_file(source_buffer), # context descriptor
|
|
|
|
func.name, # name
|
|
|
|
display_name, # display name
|
|
|
|
llfunc.name, # linkage name
|
|
|
|
func.loc.line(), # line number where defined
|
|
|
|
self.emit_subroutine_type(func.type), # type descriptor
|
|
|
|
func.is_internal, # local to compile unit?
|
|
|
|
True, # global is defined in the compile unit?
|
|
|
|
0, # virtuality
|
|
|
|
0, # index into a virtual function
|
|
|
|
None, # base type with vtable pointer
|
|
|
|
0, # flags
|
|
|
|
False, # optimized?
|
|
|
|
llfunc, # LLVM function
|
|
|
|
None, # template parameters
|
|
|
|
None, # function declaration descriptor
|
|
|
|
[], # function variables
|
|
|
|
func.loc.line(), # line number where scope begins
|
|
|
|
])
|
|
|
|
self.subprograms.append(subprogram)
|
|
|
|
return subprogram
|
|
|
|
|
|
|
|
@memoize
|
|
|
|
def emit_loc(self, loc, scope, inlined_scope=None):
|
|
|
|
return self.emit([
|
|
|
|
loc.line(), # line
|
|
|
|
loc.column(), # column
|
|
|
|
scope, # scope
|
|
|
|
inlined_scope, # inlined scope
|
|
|
|
])
|
|
|
|
|
|
|
|
def finalize(self, source_buffer):
|
|
|
|
llident = self.llmodule.add_named_metadata('llvm.ident')
|
|
|
|
llident.add(self.emit(["ARTIQ"]))
|
|
|
|
|
|
|
|
llflags = self.llmodule.add_named_metadata('llvm.module.flags')
|
|
|
|
llflags.add(self.emit([2, "Debug Info Version", 1]))
|
|
|
|
|
|
|
|
llcompile_units = self.llmodule.add_named_metadata('llvm.dbg.cu')
|
|
|
|
llcompile_units.add(self.emit_compile_unit(source_buffer, tuple(self.subprograms)))
|
2015-08-10 14:12:34 +08:00
|
|
|
|
|
|
|
|
2015-07-21 09:54:34 +08:00
|
|
|
class LLVMIRGenerator:
|
2015-08-26 12:56:01 +08:00
|
|
|
def __init__(self, engine, module_name, target, object_map):
|
2015-08-09 07:17:19 +08:00
|
|
|
self.engine = engine
|
2015-07-30 01:35:16 +08:00
|
|
|
self.target = target
|
2015-08-26 12:56:01 +08:00
|
|
|
self.object_map = object_map
|
2015-07-30 01:35:16 +08:00
|
|
|
self.llcontext = target.llcontext
|
2015-07-21 09:54:34 +08:00
|
|
|
self.llmodule = ll.Module(context=self.llcontext, name=module_name)
|
2015-07-30 01:35:16 +08:00
|
|
|
self.llmodule.triple = target.triple
|
2015-08-09 19:39:21 +08:00
|
|
|
self.llmodule.data_layout = target.data_layout
|
2015-07-21 09:54:34 +08:00
|
|
|
self.llfunction = None
|
|
|
|
self.llmap = {}
|
2015-08-26 12:56:01 +08:00
|
|
|
self.llobject_map = {}
|
2015-08-10 20:11:52 +08:00
|
|
|
self.phis = []
|
|
|
|
self.debug_info_emitter = DebugInfoEmitter(self.llmodule)
|
2015-07-21 09:54:34 +08:00
|
|
|
|
2015-08-20 06:06:03 +08:00
|
|
|
def needs_sret(self, lltyp, may_be_large=True):
|
|
|
|
if isinstance(lltyp, ll.VoidType):
|
|
|
|
return False
|
|
|
|
elif isinstance(lltyp, ll.IntType) and lltyp.width <= 32:
|
|
|
|
return False
|
|
|
|
elif isinstance(lltyp, ll.PointerType):
|
|
|
|
return False
|
|
|
|
elif may_be_large and isinstance(lltyp, ll.DoubleType):
|
|
|
|
return False
|
|
|
|
elif may_be_large and isinstance(lltyp, ll.LiteralStructType) \
|
|
|
|
and len(lltyp.elements) <= 2:
|
|
|
|
return not any([self.needs_sret(elt, may_be_large=False) for elt in lltyp.elements])
|
|
|
|
else:
|
|
|
|
return True
|
|
|
|
|
2015-07-21 18:45:27 +08:00
|
|
|
def llty_of_type(self, typ, bare=False, for_return=False):
|
2015-07-23 08:15:36 +08:00
|
|
|
typ = typ.find()
|
2015-07-21 09:54:34 +08:00
|
|
|
if types.is_tuple(typ):
|
2015-07-23 08:15:36 +08:00
|
|
|
return ll.LiteralStructType([self.llty_of_type(eltty) for eltty in typ.elts])
|
2015-08-11 00:25:48 +08:00
|
|
|
elif types.is_rpc_function(typ) or types.is_c_function(typ):
|
2015-08-09 07:17:19 +08:00
|
|
|
if for_return:
|
2015-08-10 14:12:34 +08:00
|
|
|
return llvoid
|
2015-08-09 07:17:19 +08:00
|
|
|
else:
|
|
|
|
return ll.LiteralStructType([])
|
2015-08-20 03:37:22 +08:00
|
|
|
elif types._is_pointer(typ):
|
|
|
|
return llptr
|
2015-07-21 09:54:34 +08:00
|
|
|
elif types.is_function(typ):
|
2015-08-20 06:06:03 +08:00
|
|
|
sretarg = []
|
|
|
|
llretty = self.llty_of_type(typ.ret, for_return=True)
|
|
|
|
if self.needs_sret(llretty):
|
|
|
|
sretarg = [llretty.as_pointer()]
|
|
|
|
llretty = llvoid
|
|
|
|
|
2015-08-10 14:12:34 +08:00
|
|
|
envarg = llptr
|
2015-08-20 06:06:03 +08:00
|
|
|
llty = ll.FunctionType(args=sretarg + [envarg] +
|
2015-07-21 09:54:34 +08:00
|
|
|
[self.llty_of_type(typ.args[arg])
|
|
|
|
for arg in typ.args] +
|
|
|
|
[self.llty_of_type(ir.TOption(typ.optargs[arg]))
|
|
|
|
for arg in typ.optargs],
|
2015-08-20 06:06:03 +08:00
|
|
|
return_type=llretty)
|
|
|
|
|
|
|
|
# TODO: actually mark the first argument as sret (also noalias nocapture).
|
|
|
|
# llvmlite currently does not have support for this;
|
|
|
|
# https://github.com/numba/llvmlite/issues/91.
|
|
|
|
if sretarg:
|
|
|
|
llty.__has_sret = True
|
|
|
|
else:
|
|
|
|
llty.__has_sret = False
|
|
|
|
|
2015-07-21 18:45:27 +08:00
|
|
|
if bare:
|
|
|
|
return llty
|
|
|
|
else:
|
|
|
|
return ll.LiteralStructType([envarg, llty.as_pointer()])
|
2015-08-19 13:39:22 +08:00
|
|
|
elif types.is_method(typ):
|
|
|
|
llfuncty = self.llty_of_type(types.get_method_function(typ))
|
|
|
|
llselfty = self.llty_of_type(types.get_method_self(typ))
|
|
|
|
return ll.LiteralStructType([llfuncty, llselfty])
|
2015-07-21 09:54:34 +08:00
|
|
|
elif builtins.is_none(typ):
|
|
|
|
if for_return:
|
2015-08-10 14:12:34 +08:00
|
|
|
return llvoid
|
2015-07-21 09:54:34 +08:00
|
|
|
else:
|
|
|
|
return ll.LiteralStructType([])
|
|
|
|
elif builtins.is_bool(typ):
|
2015-08-10 14:12:34 +08:00
|
|
|
return lli1
|
2015-07-21 09:54:34 +08:00
|
|
|
elif builtins.is_int(typ):
|
|
|
|
return ll.IntType(builtins.get_int_width(typ))
|
|
|
|
elif builtins.is_float(typ):
|
2015-08-10 14:12:34 +08:00
|
|
|
return lldouble
|
2015-07-25 10:37:37 +08:00
|
|
|
elif builtins.is_str(typ) or ir.is_exn_typeinfo(typ):
|
2015-08-10 14:12:34 +08:00
|
|
|
return llptr
|
2015-07-21 09:54:34 +08:00
|
|
|
elif builtins.is_list(typ):
|
|
|
|
lleltty = self.llty_of_type(builtins.get_iterable_elt(typ))
|
2015-08-10 14:12:34 +08:00
|
|
|
return ll.LiteralStructType([lli32, lleltty.as_pointer()])
|
2015-07-21 09:54:34 +08:00
|
|
|
elif builtins.is_range(typ):
|
|
|
|
lleltty = self.llty_of_type(builtins.get_iterable_elt(typ))
|
|
|
|
return ll.LiteralStructType([lleltty, lleltty, lleltty])
|
|
|
|
elif ir.is_basic_block(typ):
|
2015-08-10 14:12:34 +08:00
|
|
|
return llptr
|
2015-07-21 09:54:34 +08:00
|
|
|
elif ir.is_option(typ):
|
2015-08-10 14:12:34 +08:00
|
|
|
return ll.LiteralStructType([lli1, self.llty_of_type(typ.params["inner"])])
|
2015-07-21 09:54:34 +08:00
|
|
|
elif ir.is_environment(typ):
|
2015-12-18 23:41:51 +08:00
|
|
|
llty = self.llcontext.get_identified_type("env.{}".format(typ.env_name))
|
|
|
|
if llty.elements is None:
|
|
|
|
llty.elements = [self.llty_of_type(typ.params[name]) for name in typ.params]
|
|
|
|
|
2015-07-21 18:45:27 +08:00
|
|
|
if bare:
|
2015-07-21 09:54:34 +08:00
|
|
|
return llty
|
|
|
|
else:
|
|
|
|
return llty.as_pointer()
|
2015-07-25 10:37:37 +08:00
|
|
|
else: # Catch-all for exceptions and custom classes
|
|
|
|
if builtins.is_exception(typ):
|
2015-08-15 23:04:12 +08:00
|
|
|
name = "class.Exception" # they all share layout
|
|
|
|
elif types.is_constructor(typ):
|
|
|
|
name = "class.{}".format(typ.name)
|
2015-07-25 10:37:37 +08:00
|
|
|
else:
|
2015-08-28 08:46:50 +08:00
|
|
|
name = "instance.{}".format(typ.name)
|
2015-07-25 10:37:37 +08:00
|
|
|
|
|
|
|
llty = self.llcontext.get_identified_type(name)
|
|
|
|
if llty.elements is None:
|
2015-08-28 04:40:46 +08:00
|
|
|
# First setting elements to [] will allow us to handle
|
|
|
|
# self-referential types.
|
|
|
|
llty.elements = []
|
2015-07-25 10:37:37 +08:00
|
|
|
llty.elements = [self.llty_of_type(attrtyp)
|
|
|
|
for attrtyp in typ.attributes.values()]
|
|
|
|
|
|
|
|
if bare or not builtins.is_allocated(typ):
|
|
|
|
return llty
|
|
|
|
else:
|
|
|
|
return llty.as_pointer()
|
2015-07-21 09:54:34 +08:00
|
|
|
|
2015-08-27 18:01:04 +08:00
|
|
|
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")
|
|
|
|
else:
|
|
|
|
as_bytes = value
|
|
|
|
|
|
|
|
if name is None:
|
|
|
|
name = self.llmodule.get_unique_name("str")
|
|
|
|
|
|
|
|
llstr = self.llmodule.get_global(name)
|
|
|
|
if llstr is None:
|
|
|
|
llstrty = ll.ArrayType(lli8, len(as_bytes))
|
|
|
|
llstr = ll.GlobalVariable(self.llmodule, llstrty, name)
|
|
|
|
llstr.global_constant = True
|
|
|
|
llstr.initializer = ll.Constant(llstrty, bytearray(as_bytes))
|
|
|
|
llstr.linkage = linkage
|
|
|
|
llstr.unnamed_addr = unnamed_addr
|
|
|
|
return llstr.bitcast(llptr)
|
|
|
|
|
2015-07-21 09:54:34 +08:00
|
|
|
def llconst_of_const(self, const):
|
|
|
|
llty = self.llty_of_type(const.type)
|
|
|
|
if const.value is None:
|
|
|
|
return ll.Constant(llty, [])
|
|
|
|
elif const.value is True:
|
|
|
|
return ll.Constant(llty, True)
|
|
|
|
elif const.value is False:
|
|
|
|
return ll.Constant(llty, False)
|
|
|
|
elif isinstance(const.value, (int, float)):
|
|
|
|
return ll.Constant(llty, const.value)
|
2015-08-09 07:17:19 +08:00
|
|
|
elif isinstance(const.value, (str, bytes)):
|
2015-07-25 10:37:37 +08:00
|
|
|
if ir.is_exn_typeinfo(const.type):
|
|
|
|
# Exception typeinfo; should be merged with identical others
|
|
|
|
name = "__artiq_exn_" + const.value
|
|
|
|
linkage = "linkonce"
|
|
|
|
unnamed_addr = False
|
|
|
|
else:
|
|
|
|
# Just a string
|
2015-08-27 18:01:04 +08:00
|
|
|
name = None
|
2015-07-25 10:37:37 +08:00
|
|
|
linkage = "private"
|
|
|
|
unnamed_addr = True
|
|
|
|
|
2015-08-27 18:01:04 +08:00
|
|
|
return self.llstr_of_str(const.value, name=name,
|
|
|
|
linkage=linkage, unnamed_addr=unnamed_addr)
|
2015-07-21 09:54:34 +08:00
|
|
|
else:
|
|
|
|
assert False
|
|
|
|
|
2015-07-22 03:32:10 +08:00
|
|
|
def llbuiltin(self, name):
|
2015-08-31 23:59:33 +08:00
|
|
|
llglobal = self.llmodule.get_global(name)
|
|
|
|
if llglobal is not None:
|
|
|
|
return llglobal
|
2015-07-22 03:32:10 +08:00
|
|
|
|
2015-07-22 07:58:59 +08:00
|
|
|
if name in "llvm.donothing":
|
2015-08-10 14:12:34 +08:00
|
|
|
llty = ll.FunctionType(llvoid, [])
|
2015-07-22 07:58:59 +08:00
|
|
|
elif name in "llvm.trap":
|
2015-08-10 14:12:34 +08:00
|
|
|
llty = ll.FunctionType(llvoid, [])
|
2015-07-22 23:34:52 +08:00
|
|
|
elif name == "llvm.floor.f64":
|
2015-08-10 14:12:34 +08:00
|
|
|
llty = ll.FunctionType(lldouble, [lldouble])
|
2015-07-22 03:32:10 +08:00
|
|
|
elif name == "llvm.round.f64":
|
2015-08-10 14:12:34 +08:00
|
|
|
llty = ll.FunctionType(lldouble, [lldouble])
|
2015-07-22 03:32:10 +08:00
|
|
|
elif name == "llvm.pow.f64":
|
2015-08-10 14:12:34 +08:00
|
|
|
llty = ll.FunctionType(lldouble, [lldouble, lldouble])
|
2015-07-22 03:32:10 +08:00
|
|
|
elif name == "llvm.powi.f64":
|
2015-08-10 14:12:34 +08:00
|
|
|
llty = ll.FunctionType(lldouble, [lldouble, lli32])
|
2015-07-22 23:34:52 +08:00
|
|
|
elif name == "llvm.copysign.f64":
|
2015-08-10 14:12:34 +08:00
|
|
|
llty = ll.FunctionType(lldouble, [lldouble, lldouble])
|
2015-08-09 21:16:41 +08:00
|
|
|
elif name == "llvm.stacksave":
|
2015-08-10 14:12:34 +08:00
|
|
|
llty = ll.FunctionType(llptr, [])
|
2015-08-09 21:16:41 +08:00
|
|
|
elif name == "llvm.stackrestore":
|
2015-08-10 14:12:34 +08:00
|
|
|
llty = ll.FunctionType(llvoid, [llptr])
|
2015-07-30 01:35:16 +08:00
|
|
|
elif name == self.target.print_function:
|
2015-08-10 14:12:34 +08:00
|
|
|
llty = ll.FunctionType(llvoid, [llptr], var_arg=True)
|
2015-07-25 10:37:37 +08:00
|
|
|
elif name == "__artiq_personality":
|
2015-08-10 14:12:34 +08:00
|
|
|
llty = ll.FunctionType(lli32, [], var_arg=True)
|
2015-07-27 17:36:21 +08:00
|
|
|
elif name == "__artiq_raise":
|
2015-08-10 14:12:34 +08:00
|
|
|
llty = ll.FunctionType(llvoid, [self.llty_of_type(builtins.TException())])
|
2015-07-27 17:36:21 +08:00
|
|
|
elif name == "__artiq_reraise":
|
2015-08-10 14:12:34 +08:00
|
|
|
llty = ll.FunctionType(llvoid, [])
|
2015-08-09 07:25:58 +08:00
|
|
|
elif name == "send_rpc":
|
2015-08-10 14:12:34 +08:00
|
|
|
llty = ll.FunctionType(llvoid, [lli32, llptr],
|
2015-08-09 07:17:19 +08:00
|
|
|
var_arg=True)
|
2015-08-09 21:16:41 +08:00
|
|
|
elif name == "recv_rpc":
|
2015-08-10 14:12:34 +08:00
|
|
|
llty = ll.FunctionType(lli32, [llptr])
|
2015-08-31 23:59:33 +08:00
|
|
|
elif name == "now":
|
|
|
|
llty = lli64
|
2015-12-10 23:11:00 +08:00
|
|
|
elif name == "watchdog_set":
|
|
|
|
llty = ll.FunctionType(lli32, [lli32])
|
|
|
|
elif name == "watchdog_clear":
|
|
|
|
llty = ll.FunctionType(llvoid, [lli32])
|
2015-07-22 03:32:10 +08:00
|
|
|
else:
|
|
|
|
assert False
|
2015-07-27 17:36:21 +08:00
|
|
|
|
2015-08-31 23:59:33 +08:00
|
|
|
if isinstance(llty, ll.FunctionType):
|
|
|
|
llglobal = ll.Function(self.llmodule, llty, name)
|
|
|
|
if name in ("__artiq_raise", "__artiq_reraise", "llvm.trap"):
|
|
|
|
llglobal.attributes.add("noreturn")
|
|
|
|
else:
|
|
|
|
llglobal = ll.GlobalVariable(self.llmodule, llty, name)
|
|
|
|
|
|
|
|
return llglobal
|
2015-07-22 03:32:10 +08:00
|
|
|
|
2015-07-21 09:54:34 +08:00
|
|
|
def map(self, value):
|
2015-07-21 18:45:27 +08:00
|
|
|
if isinstance(value, (ir.Argument, ir.Instruction, ir.BasicBlock)):
|
2015-07-21 09:54:34 +08:00
|
|
|
return self.llmap[value]
|
|
|
|
elif isinstance(value, ir.Constant):
|
|
|
|
return self.llconst_of_const(value)
|
2015-07-21 18:45:27 +08:00
|
|
|
elif isinstance(value, ir.Function):
|
|
|
|
llfun = self.llmodule.get_global(value.name)
|
|
|
|
if llfun is None:
|
2015-07-25 10:37:37 +08:00
|
|
|
llfun = ll.Function(self.llmodule, self.llty_of_type(value.type, bare=True),
|
|
|
|
value.name)
|
2015-07-30 01:35:16 +08:00
|
|
|
return llfun
|
2015-07-21 09:54:34 +08:00
|
|
|
else:
|
|
|
|
assert False
|
|
|
|
|
|
|
|
def process(self, functions):
|
|
|
|
for func in functions:
|
|
|
|
self.process_function(func)
|
|
|
|
|
2015-08-10 20:11:52 +08:00
|
|
|
if any(functions):
|
|
|
|
self.debug_info_emitter.finalize(functions[0].loc.source_buffer)
|
|
|
|
|
2015-07-22 09:13:04 +08:00
|
|
|
return self.llmodule
|
|
|
|
|
2015-07-21 09:54:34 +08:00
|
|
|
def process_function(self, func):
|
|
|
|
try:
|
2015-07-21 18:45:27 +08:00
|
|
|
self.llfunction = self.llmodule.get_global(func.name)
|
2015-08-09 02:48:21 +08:00
|
|
|
|
2015-07-21 18:45:27 +08:00
|
|
|
if self.llfunction is None:
|
2015-09-01 04:02:02 +08:00
|
|
|
llfunty = self.llty_of_type(func.type, bare=True)
|
2015-07-21 18:45:27 +08:00
|
|
|
self.llfunction = ll.Function(self.llmodule, llfunty, func.name)
|
2015-08-09 02:48:21 +08:00
|
|
|
|
2015-07-30 01:35:16 +08:00
|
|
|
if func.is_internal:
|
2015-07-22 00:54:22 +08:00
|
|
|
self.llfunction.linkage = 'internal'
|
2015-07-21 18:45:27 +08:00
|
|
|
|
2015-08-09 02:48:21 +08:00
|
|
|
self.llfunction.attributes.add('uwtable')
|
|
|
|
|
2015-07-21 09:54:34 +08:00
|
|
|
self.llbuilder = ll.IRBuilder()
|
2015-08-10 20:11:52 +08:00
|
|
|
llblock_map = {}
|
|
|
|
|
|
|
|
disubprogram = self.debug_info_emitter.emit_subprogram(func, self.llfunction)
|
2015-07-21 09:54:34 +08:00
|
|
|
|
2015-07-21 18:45:27 +08:00
|
|
|
# First, map arguments.
|
2015-09-01 04:02:02 +08:00
|
|
|
if self.llfunction.type.pointee.__has_sret:
|
|
|
|
llactualargs = self.llfunction.args[1:]
|
|
|
|
else:
|
|
|
|
llactualargs = self.llfunction.args
|
|
|
|
|
|
|
|
for arg, llarg in zip(func.arguments, llactualargs):
|
2015-07-21 18:45:27 +08:00
|
|
|
self.llmap[arg] = llarg
|
|
|
|
|
|
|
|
# Second, create all basic blocks.
|
2015-07-21 09:54:34 +08:00
|
|
|
for block in func.basic_blocks:
|
|
|
|
llblock = self.llfunction.append_basic_block(block.name)
|
|
|
|
self.llmap[block] = llblock
|
|
|
|
|
2015-07-21 18:45:27 +08:00
|
|
|
# Third, translate all instructions.
|
2015-07-21 09:54:34 +08:00
|
|
|
for block in func.basic_blocks:
|
|
|
|
self.llbuilder.position_at_end(self.llmap[block])
|
|
|
|
for insn in block.instructions:
|
2015-08-20 03:18:20 +08:00
|
|
|
if insn.loc is not None:
|
|
|
|
self.llbuilder.debug_metadata = \
|
|
|
|
self.debug_info_emitter.emit_loc(insn.loc, disubprogram)
|
|
|
|
|
2015-07-21 09:54:34 +08:00
|
|
|
llinsn = getattr(self, "process_" + type(insn).__name__)(insn)
|
|
|
|
assert llinsn is not None
|
|
|
|
self.llmap[insn] = llinsn
|
|
|
|
|
2015-08-10 01:24:16 +08:00
|
|
|
# There is no 1:1 correspondence between ARTIQ and LLVM
|
|
|
|
# basic blocks, because sometimes we expand a single ARTIQ
|
|
|
|
# instruction so that the result spans several LLVM basic
|
2015-12-10 20:50:28 +08:00
|
|
|
# blocks. This only really matters for phis, which are thus
|
|
|
|
# using a different map (the following one).
|
2015-08-10 20:11:52 +08:00
|
|
|
llblock_map[block] = self.llbuilder.basic_block
|
2015-08-10 01:24:16 +08:00
|
|
|
|
2015-08-10 20:11:52 +08:00
|
|
|
# Fourth, add incoming values to phis.
|
|
|
|
for phi, llphi in self.phis:
|
|
|
|
for value, block in phi.incoming():
|
|
|
|
llphi.add_incoming(self.map(value), llblock_map[block])
|
2015-07-21 09:54:34 +08:00
|
|
|
finally:
|
|
|
|
self.llfunction = None
|
2015-08-10 20:11:52 +08:00
|
|
|
self.llmap = {}
|
2015-08-11 05:41:31 +08:00
|
|
|
self.phis = []
|
2015-07-21 09:54:34 +08:00
|
|
|
|
|
|
|
def process_Phi(self, insn):
|
|
|
|
llinsn = self.llbuilder.phi(self.llty_of_type(insn.type), name=insn.name)
|
2015-08-10 20:11:52 +08:00
|
|
|
self.phis.append((insn, llinsn))
|
2015-07-21 09:54:34 +08:00
|
|
|
return llinsn
|
|
|
|
|
2015-07-25 10:37:37 +08:00
|
|
|
def llindex(self, index):
|
2015-08-10 14:12:34 +08:00
|
|
|
return ll.Constant(lli32, index)
|
2015-07-25 10:37:37 +08:00
|
|
|
|
2015-07-21 09:54:34 +08:00
|
|
|
def process_Alloc(self, insn):
|
|
|
|
if ir.is_environment(insn.type):
|
2015-07-21 18:45:27 +08:00
|
|
|
return self.llbuilder.alloca(self.llty_of_type(insn.type, bare=True),
|
2015-07-21 09:54:34 +08:00
|
|
|
name=insn.name)
|
2015-07-22 07:58:59 +08:00
|
|
|
elif ir.is_option(insn.type):
|
|
|
|
if len(insn.operands) == 0: # empty
|
|
|
|
llvalue = ll.Constant(self.llty_of_type(insn.type), ll.Undefined)
|
2015-08-10 14:12:34 +08:00
|
|
|
return self.llbuilder.insert_value(llvalue, ll.Constant(lli1, False), 0,
|
2015-07-22 07:58:59 +08:00
|
|
|
name=insn.name)
|
|
|
|
elif len(insn.operands) == 1: # full
|
|
|
|
llvalue = ll.Constant(self.llty_of_type(insn.type), ll.Undefined)
|
2015-08-10 14:12:34 +08:00
|
|
|
llvalue = self.llbuilder.insert_value(llvalue, ll.Constant(lli1, True), 0)
|
2015-07-22 07:58:59 +08:00
|
|
|
return self.llbuilder.insert_value(llvalue, self.map(insn.operands[0]), 1,
|
|
|
|
name=insn.name)
|
|
|
|
else:
|
|
|
|
assert False
|
2015-07-21 09:54:34 +08:00
|
|
|
elif builtins.is_list(insn.type):
|
|
|
|
llsize = self.map(insn.operands[0])
|
|
|
|
llvalue = ll.Constant(self.llty_of_type(insn.type), ll.Undefined)
|
|
|
|
llvalue = self.llbuilder.insert_value(llvalue, llsize, 0)
|
|
|
|
llalloc = self.llbuilder.alloca(self.llty_of_type(builtins.get_iterable_elt(insn.type)),
|
|
|
|
size=llsize)
|
|
|
|
llvalue = self.llbuilder.insert_value(llvalue, llalloc, 1, name=insn.name)
|
|
|
|
return llvalue
|
2015-08-15 23:04:12 +08:00
|
|
|
elif not builtins.is_allocated(insn.type):
|
|
|
|
llvalue = ll.Constant(self.llty_of_type(insn.type), ll.Undefined)
|
|
|
|
for index, elt in enumerate(insn.operands):
|
|
|
|
llvalue = self.llbuilder.insert_value(llvalue, self.map(elt), index)
|
|
|
|
llvalue.name = insn.name
|
|
|
|
return llvalue
|
|
|
|
else: # catchall for exceptions and custom (allocated) classes
|
2015-07-25 10:37:37 +08:00
|
|
|
llalloc = self.llbuilder.alloca(self.llty_of_type(insn.type, bare=True))
|
|
|
|
for index, operand in enumerate(insn.operands):
|
|
|
|
lloperand = self.map(operand)
|
|
|
|
llfieldptr = self.llbuilder.gep(llalloc, [self.llindex(0), self.llindex(index)])
|
|
|
|
self.llbuilder.store(lloperand, llfieldptr)
|
|
|
|
return llalloc
|
2015-07-21 09:54:34 +08:00
|
|
|
|
2015-08-15 23:04:12 +08:00
|
|
|
def llptr_to_var(self, llenv, env_ty, var_name, var_type=None):
|
|
|
|
if var_name in env_ty.params and (var_type is None or
|
|
|
|
env_ty.params[var_name] == var_type):
|
2015-07-21 09:54:34 +08:00
|
|
|
var_index = list(env_ty.params.keys()).index(var_name)
|
|
|
|
return self.llbuilder.gep(llenv, [self.llindex(0), self.llindex(var_index)])
|
|
|
|
else:
|
2015-08-23 04:56:17 +08:00
|
|
|
outer_index = list(env_ty.params.keys()).index("$outer")
|
2015-07-21 09:54:34 +08:00
|
|
|
llptr = self.llbuilder.gep(llenv, [self.llindex(0), self.llindex(outer_index)])
|
|
|
|
llouterenv = self.llbuilder.load(llptr)
|
2015-08-23 04:56:17 +08:00
|
|
|
return self.llptr_to_var(llouterenv, env_ty.params["$outer"], var_name)
|
2015-07-21 09:54:34 +08:00
|
|
|
|
|
|
|
def process_GetLocal(self, insn):
|
|
|
|
env = insn.environment()
|
|
|
|
llptr = self.llptr_to_var(self.map(env), env.type, insn.var_name)
|
|
|
|
return self.llbuilder.load(llptr)
|
|
|
|
|
2015-08-15 23:04:12 +08:00
|
|
|
def process_GetConstructor(self, insn):
|
|
|
|
env = insn.environment()
|
|
|
|
llptr = self.llptr_to_var(self.map(env), env.type, insn.var_name, insn.type)
|
|
|
|
return self.llbuilder.load(llptr)
|
|
|
|
|
2015-07-21 09:54:34 +08:00
|
|
|
def process_SetLocal(self, insn):
|
|
|
|
env = insn.environment()
|
|
|
|
llptr = self.llptr_to_var(self.map(env), env.type, insn.var_name)
|
2015-07-21 18:45:27 +08:00
|
|
|
llvalue = self.map(insn.value())
|
2015-07-25 10:37:37 +08:00
|
|
|
if isinstance(llvalue, ll.Block):
|
|
|
|
llvalue = ll.BlockAddress(self.llfunction, llvalue)
|
2015-07-21 18:45:27 +08:00
|
|
|
if llptr.type.pointee != llvalue.type:
|
|
|
|
# The environment argument is an i8*, so that all closures can
|
|
|
|
# unify with each other regardless of environment type or size.
|
2015-08-23 04:56:17 +08:00
|
|
|
# We fixup the type on assignment into the "$outer" slot.
|
2015-11-24 00:20:33 +08:00
|
|
|
assert insn.var_name == '$outer'
|
2015-07-21 18:45:27 +08:00
|
|
|
llvalue = self.llbuilder.bitcast(llvalue, llptr.type.pointee)
|
|
|
|
return self.llbuilder.store(llvalue, llptr)
|
2015-07-21 09:54:34 +08:00
|
|
|
|
|
|
|
def attr_index(self, insn):
|
|
|
|
return list(insn.object().type.attributes.keys()).index(insn.attr)
|
|
|
|
|
|
|
|
def process_GetAttr(self, insn):
|
|
|
|
if types.is_tuple(insn.object().type):
|
2015-07-22 03:32:10 +08:00
|
|
|
return self.llbuilder.extract_value(self.map(insn.object()), insn.attr,
|
2015-07-21 09:54:34 +08:00
|
|
|
name=insn.name)
|
2015-07-21 19:27:48 +08:00
|
|
|
elif not builtins.is_allocated(insn.object().type):
|
2015-07-21 09:54:34 +08:00
|
|
|
return self.llbuilder.extract_value(self.map(insn.object()), self.attr_index(insn),
|
|
|
|
name=insn.name)
|
|
|
|
else:
|
|
|
|
llptr = self.llbuilder.gep(self.map(insn.object()),
|
|
|
|
[self.llindex(0), self.llindex(self.attr_index(insn))],
|
|
|
|
name=insn.name)
|
|
|
|
return self.llbuilder.load(llptr)
|
|
|
|
|
|
|
|
def process_SetAttr(self, insn):
|
2015-07-25 10:37:37 +08:00
|
|
|
assert builtins.is_allocated(insn.object().type)
|
2015-07-21 09:54:34 +08:00
|
|
|
llptr = self.llbuilder.gep(self.map(insn.object()),
|
|
|
|
[self.llindex(0), self.llindex(self.attr_index(insn))],
|
|
|
|
name=insn.name)
|
2015-07-25 10:37:37 +08:00
|
|
|
return self.llbuilder.store(self.map(insn.value()), llptr)
|
2015-07-21 09:54:34 +08:00
|
|
|
|
|
|
|
def process_GetElem(self, insn):
|
|
|
|
llelts = self.llbuilder.extract_value(self.map(insn.list()), 1)
|
|
|
|
llelt = self.llbuilder.gep(llelts, [self.map(insn.index())],
|
|
|
|
inbounds=True)
|
|
|
|
return self.llbuilder.load(llelt)
|
|
|
|
|
|
|
|
def process_SetElem(self, insn):
|
|
|
|
llelts = self.llbuilder.extract_value(self.map(insn.list()), 1)
|
|
|
|
llelt = self.llbuilder.gep(llelts, [self.map(insn.index())],
|
|
|
|
inbounds=True)
|
|
|
|
return self.llbuilder.store(self.map(insn.value()), llelt)
|
|
|
|
|
|
|
|
def process_Coerce(self, insn):
|
|
|
|
typ, value_typ = insn.type, insn.value().type
|
|
|
|
if builtins.is_int(typ) and builtins.is_float(value_typ):
|
|
|
|
return self.llbuilder.fptosi(self.map(insn.value()), self.llty_of_type(typ),
|
|
|
|
name=insn.name)
|
|
|
|
elif builtins.is_float(typ) and builtins.is_int(value_typ):
|
|
|
|
return self.llbuilder.sitofp(self.map(insn.value()), self.llty_of_type(typ),
|
|
|
|
name=insn.name)
|
|
|
|
elif builtins.is_int(typ) and builtins.is_int(value_typ):
|
|
|
|
if builtins.get_int_width(typ) > builtins.get_int_width(value_typ):
|
|
|
|
return self.llbuilder.sext(self.map(insn.value()), self.llty_of_type(typ),
|
|
|
|
name=insn.name)
|
2015-07-23 00:09:14 +08:00
|
|
|
else: # builtins.get_int_width(typ) <= builtins.get_int_width(value_typ):
|
2015-07-21 09:54:34 +08:00
|
|
|
return self.llbuilder.trunc(self.map(insn.value()), self.llty_of_type(typ),
|
|
|
|
name=insn.name)
|
|
|
|
else:
|
|
|
|
assert False
|
|
|
|
|
|
|
|
def process_Arith(self, insn):
|
|
|
|
if isinstance(insn.op, ast.Add):
|
|
|
|
if builtins.is_float(insn.type):
|
|
|
|
return self.llbuilder.fadd(self.map(insn.lhs()), self.map(insn.rhs()),
|
|
|
|
name=insn.name)
|
|
|
|
else:
|
|
|
|
return self.llbuilder.add(self.map(insn.lhs()), self.map(insn.rhs()),
|
|
|
|
name=insn.name)
|
|
|
|
elif isinstance(insn.op, ast.Sub):
|
|
|
|
if builtins.is_float(insn.type):
|
|
|
|
return self.llbuilder.fsub(self.map(insn.lhs()), self.map(insn.rhs()),
|
|
|
|
name=insn.name)
|
|
|
|
else:
|
|
|
|
return self.llbuilder.sub(self.map(insn.lhs()), self.map(insn.rhs()),
|
|
|
|
name=insn.name)
|
|
|
|
elif isinstance(insn.op, ast.Mult):
|
|
|
|
if builtins.is_float(insn.type):
|
|
|
|
return self.llbuilder.fmul(self.map(insn.lhs()), self.map(insn.rhs()),
|
|
|
|
name=insn.name)
|
|
|
|
else:
|
|
|
|
return self.llbuilder.mul(self.map(insn.lhs()), self.map(insn.rhs()),
|
|
|
|
name=insn.name)
|
|
|
|
elif isinstance(insn.op, ast.Div):
|
|
|
|
if builtins.is_float(insn.lhs().type):
|
|
|
|
return self.llbuilder.fdiv(self.map(insn.lhs()), self.map(insn.rhs()),
|
|
|
|
name=insn.name)
|
|
|
|
else:
|
|
|
|
lllhs = self.llbuilder.sitofp(self.map(insn.lhs()), self.llty_of_type(insn.type))
|
|
|
|
llrhs = self.llbuilder.sitofp(self.map(insn.rhs()), self.llty_of_type(insn.type))
|
|
|
|
return self.llbuilder.fdiv(lllhs, llrhs,
|
|
|
|
name=insn.name)
|
|
|
|
elif isinstance(insn.op, ast.FloorDiv):
|
|
|
|
if builtins.is_float(insn.type):
|
|
|
|
llvalue = self.llbuilder.fdiv(self.map(insn.lhs()), self.map(insn.rhs()))
|
2015-07-22 23:34:52 +08:00
|
|
|
return self.llbuilder.call(self.llbuiltin("llvm.floor.f64"), [llvalue],
|
2015-07-21 09:54:34 +08:00
|
|
|
name=insn.name)
|
|
|
|
else:
|
|
|
|
return self.llbuilder.sdiv(self.map(insn.lhs()), self.map(insn.rhs()),
|
|
|
|
name=insn.name)
|
|
|
|
elif isinstance(insn.op, ast.Mod):
|
2015-07-22 23:34:52 +08:00
|
|
|
# Python only has the modulo operator, LLVM only has the remainder
|
2015-07-21 09:54:34 +08:00
|
|
|
if builtins.is_float(insn.type):
|
2015-07-22 23:34:52 +08:00
|
|
|
llvalue = self.llbuilder.frem(self.map(insn.lhs()), self.map(insn.rhs()))
|
|
|
|
return self.llbuilder.call(self.llbuiltin("llvm.copysign.f64"),
|
|
|
|
[llvalue, self.map(insn.rhs())],
|
2015-07-21 09:54:34 +08:00
|
|
|
name=insn.name)
|
|
|
|
else:
|
2015-07-22 23:34:52 +08:00
|
|
|
lllhs, llrhs = map(self.map, (insn.lhs(), insn.rhs()))
|
|
|
|
llxorsign = self.llbuilder.and_(self.llbuilder.xor(lllhs, llrhs),
|
|
|
|
ll.Constant(lllhs.type, 1 << lllhs.type.width - 1))
|
|
|
|
llnegate = self.llbuilder.icmp_unsigned('!=',
|
|
|
|
llxorsign, ll.Constant(llxorsign.type, 0))
|
|
|
|
llvalue = self.llbuilder.srem(lllhs, llrhs)
|
|
|
|
llnegvalue = self.llbuilder.sub(ll.Constant(llvalue.type, 0), llvalue)
|
|
|
|
return self.llbuilder.select(llnegate, llnegvalue, llvalue)
|
2015-07-21 09:54:34 +08:00
|
|
|
elif isinstance(insn.op, ast.Pow):
|
|
|
|
if builtins.is_float(insn.type):
|
2015-07-22 03:32:10 +08:00
|
|
|
return self.llbuilder.call(self.llbuiltin("llvm.pow.f64"),
|
|
|
|
[self.map(insn.lhs()), self.map(insn.rhs())],
|
2015-07-21 09:54:34 +08:00
|
|
|
name=insn.name)
|
|
|
|
else:
|
2015-08-10 14:12:34 +08:00
|
|
|
lllhs = self.llbuilder.sitofp(self.map(insn.lhs()), lldouble)
|
|
|
|
llrhs = self.llbuilder.trunc(self.map(insn.rhs()), lli32)
|
2015-07-22 23:34:52 +08:00
|
|
|
llvalue = self.llbuilder.call(self.llbuiltin("llvm.powi.f64"), [lllhs, llrhs])
|
2015-07-21 09:54:34 +08:00
|
|
|
return self.llbuilder.fptosi(llvalue, self.llty_of_type(insn.type),
|
|
|
|
name=insn.name)
|
|
|
|
elif isinstance(insn.op, ast.LShift):
|
2015-07-23 05:58:41 +08:00
|
|
|
lllhs, llrhs = map(self.map, (insn.lhs(), insn.rhs()))
|
|
|
|
llrhs_max = ll.Constant(llrhs.type, builtins.get_int_width(insn.lhs().type))
|
|
|
|
llrhs_overflow = self.llbuilder.icmp_signed('>=', llrhs, llrhs_max)
|
|
|
|
llvalue_zero = ll.Constant(lllhs.type, 0)
|
|
|
|
llvalue = self.llbuilder.shl(lllhs, llrhs)
|
|
|
|
return self.llbuilder.select(llrhs_overflow, llvalue_zero, llvalue,
|
|
|
|
name=insn.name)
|
2015-07-21 09:54:34 +08:00
|
|
|
elif isinstance(insn.op, ast.RShift):
|
2015-07-23 05:58:41 +08:00
|
|
|
lllhs, llrhs = map(self.map, (insn.lhs(), insn.rhs()))
|
|
|
|
llrhs_max = ll.Constant(llrhs.type, builtins.get_int_width(insn.lhs().type) - 1)
|
|
|
|
llrhs_overflow = self.llbuilder.icmp_signed('>', llrhs, llrhs_max)
|
|
|
|
llvalue = self.llbuilder.ashr(lllhs, llrhs)
|
|
|
|
llvalue_max = self.llbuilder.ashr(lllhs, llrhs_max) # preserve sign bit
|
|
|
|
return self.llbuilder.select(llrhs_overflow, llvalue_max, llvalue,
|
|
|
|
name=insn.name)
|
2015-07-21 09:54:34 +08:00
|
|
|
elif isinstance(insn.op, ast.BitAnd):
|
|
|
|
return self.llbuilder.and_(self.map(insn.lhs()), self.map(insn.rhs()),
|
|
|
|
name=insn.name)
|
|
|
|
elif isinstance(insn.op, ast.BitOr):
|
|
|
|
return self.llbuilder.or_(self.map(insn.lhs()), self.map(insn.rhs()),
|
|
|
|
name=insn.name)
|
|
|
|
elif isinstance(insn.op, ast.BitXor):
|
|
|
|
return self.llbuilder.xor(self.map(insn.lhs()), self.map(insn.rhs()),
|
|
|
|
name=insn.name)
|
|
|
|
else:
|
|
|
|
assert False
|
|
|
|
|
|
|
|
def process_Compare(self, insn):
|
2015-07-22 23:34:52 +08:00
|
|
|
if isinstance(insn.op, (ast.Eq, ast.Is)):
|
2015-07-21 09:54:34 +08:00
|
|
|
op = '=='
|
2015-07-22 23:34:52 +08:00
|
|
|
elif isinstance(insn.op, (ast.NotEq, ast.IsNot)):
|
2015-07-21 09:54:34 +08:00
|
|
|
op = '!='
|
|
|
|
elif isinstance(insn.op, ast.Gt):
|
|
|
|
op = '>'
|
|
|
|
elif isinstance(insn.op, ast.GtE):
|
|
|
|
op = '>='
|
|
|
|
elif isinstance(insn.op, ast.Lt):
|
|
|
|
op = '<'
|
|
|
|
elif isinstance(insn.op, ast.LtE):
|
|
|
|
op = '<='
|
|
|
|
else:
|
|
|
|
assert False
|
|
|
|
|
2015-07-22 23:34:52 +08:00
|
|
|
lllhs, llrhs = map(self.map, (insn.lhs(), insn.rhs()))
|
|
|
|
assert lllhs.type == llrhs.type
|
|
|
|
|
|
|
|
if isinstance(lllhs.type, ll.IntType):
|
|
|
|
return self.llbuilder.icmp_signed(op, lllhs, llrhs,
|
|
|
|
name=insn.name)
|
|
|
|
elif isinstance(lllhs.type, ll.PointerType):
|
|
|
|
return self.llbuilder.icmp_unsigned(op, lllhs, llrhs,
|
|
|
|
name=insn.name)
|
2015-08-10 14:12:34 +08:00
|
|
|
elif isinstance(lllhs.type, ll.DoubleType):
|
2015-07-22 23:34:52 +08:00
|
|
|
return self.llbuilder.fcmp_ordered(op, lllhs, llrhs,
|
2015-07-21 09:54:34 +08:00
|
|
|
name=insn.name)
|
2015-07-22 23:34:52 +08:00
|
|
|
elif isinstance(lllhs.type, ll.LiteralStructType):
|
|
|
|
# Compare aggregates (such as lists or ranges) element-by-element.
|
2015-08-10 14:12:34 +08:00
|
|
|
llvalue = ll.Constant(lli1, True)
|
2015-07-22 23:34:52 +08:00
|
|
|
for index in range(len(lllhs.type.elements)):
|
|
|
|
lllhselt = self.llbuilder.extract_value(lllhs, index)
|
|
|
|
llrhselt = self.llbuilder.extract_value(llrhs, index)
|
|
|
|
llresult = self.llbuilder.icmp_unsigned('==', lllhselt, llrhselt)
|
|
|
|
llvalue = self.llbuilder.select(llresult, llvalue,
|
2015-08-10 14:12:34 +08:00
|
|
|
ll.Constant(lli1, False))
|
|
|
|
return self.llbuilder.icmp_unsigned(op, llvalue, ll.Constant(lli1, True),
|
2015-07-22 23:34:52 +08:00
|
|
|
name=insn.name)
|
2015-07-21 09:54:34 +08:00
|
|
|
else:
|
2015-07-22 23:34:52 +08:00
|
|
|
print(lllhs, llrhs)
|
|
|
|
assert False
|
2015-07-21 09:54:34 +08:00
|
|
|
|
|
|
|
def process_Builtin(self, insn):
|
|
|
|
if insn.op == "nop":
|
2015-07-22 03:32:10 +08:00
|
|
|
return self.llbuilder.call(self.llbuiltin("llvm.donothing"), [])
|
2015-07-22 07:58:59 +08:00
|
|
|
if insn.op == "abort":
|
|
|
|
return self.llbuilder.call(self.llbuiltin("llvm.trap"), [])
|
|
|
|
elif insn.op == "is_some":
|
2015-07-22 23:34:52 +08:00
|
|
|
lloptarg = self.map(insn.operands[0])
|
|
|
|
return self.llbuilder.extract_value(lloptarg, 0,
|
2015-07-22 07:58:59 +08:00
|
|
|
name=insn.name)
|
2015-07-21 09:54:34 +08:00
|
|
|
elif insn.op == "unwrap":
|
2015-07-22 23:34:52 +08:00
|
|
|
lloptarg = self.map(insn.operands[0])
|
|
|
|
return self.llbuilder.extract_value(lloptarg, 1,
|
2015-07-22 07:58:59 +08:00
|
|
|
name=insn.name)
|
|
|
|
elif insn.op == "unwrap_or":
|
2015-07-22 23:34:52 +08:00
|
|
|
lloptarg, lldefault = map(self.map, insn.operands)
|
|
|
|
llhas_arg = self.llbuilder.extract_value(lloptarg, 0)
|
|
|
|
llarg = self.llbuilder.extract_value(lloptarg, 1)
|
|
|
|
return self.llbuilder.select(llhas_arg, llarg, lldefault,
|
2015-07-21 09:54:34 +08:00
|
|
|
name=insn.name)
|
|
|
|
elif insn.op == "round":
|
2015-07-22 23:34:52 +08:00
|
|
|
llarg = self.map(insn.operands[0])
|
|
|
|
llvalue = self.llbuilder.call(self.llbuiltin("llvm.round.f64"), [llarg])
|
|
|
|
return self.llbuilder.fptosi(llvalue, self.llty_of_type(insn.type),
|
|
|
|
name=insn.name)
|
2015-07-21 09:54:34 +08:00
|
|
|
elif insn.op == "globalenv":
|
|
|
|
def get_outer(llenv, env_ty):
|
2015-08-23 04:56:17 +08:00
|
|
|
if "$outer" in env_ty.params:
|
|
|
|
outer_index = list(env_ty.params.keys()).index("$outer")
|
2015-07-21 09:54:34 +08:00
|
|
|
llptr = self.llbuilder.gep(llenv, [self.llindex(0), self.llindex(outer_index)])
|
|
|
|
llouterenv = self.llbuilder.load(llptr)
|
2015-08-23 04:56:17 +08:00
|
|
|
return self.llptr_to_var(llouterenv, env_ty.params["$outer"], var_name)
|
2015-07-21 09:54:34 +08:00
|
|
|
else:
|
|
|
|
return llenv
|
|
|
|
|
|
|
|
env, = insn.operands
|
|
|
|
return get_outer(self.map(env), env.type)
|
|
|
|
elif insn.op == "len":
|
|
|
|
lst, = insn.operands
|
|
|
|
return self.llbuilder.extract_value(self.map(lst), 0)
|
2015-07-22 03:32:10 +08:00
|
|
|
elif insn.op == "printf":
|
|
|
|
# We only get integers, floats, pointers and strings here.
|
|
|
|
llargs = map(self.map, insn.operands)
|
2015-07-30 01:35:16 +08:00
|
|
|
return self.llbuilder.call(self.llbuiltin(self.target.print_function), llargs,
|
2015-07-22 03:32:10 +08:00
|
|
|
name=insn.name)
|
2015-07-25 10:37:37 +08:00
|
|
|
elif insn.op == "exncast":
|
|
|
|
# This is an identity cast at LLVM IR level.
|
|
|
|
return self.map(insn.operands[0])
|
2015-08-31 23:59:33 +08:00
|
|
|
elif insn.op == "now_mu":
|
|
|
|
return self.llbuilder.load(self.llbuiltin("now"), name=insn.name)
|
|
|
|
elif insn.op == "at_mu":
|
|
|
|
time, = insn.operands
|
|
|
|
return self.llbuilder.store(self.map(time), self.llbuiltin("now"))
|
2015-11-21 03:22:47 +08:00
|
|
|
elif insn.op == "delay_mu":
|
|
|
|
interval, = insn.operands
|
|
|
|
llnowptr = self.llbuiltin("now")
|
|
|
|
llnow = self.llbuilder.load(llnowptr)
|
|
|
|
lladjusted = self.llbuilder.add(llnow, self.map(interval))
|
|
|
|
return self.llbuilder.store(lladjusted, llnowptr)
|
2015-12-10 23:11:00 +08:00
|
|
|
elif insn.op == "watchdog_set":
|
|
|
|
interval, = insn.operands
|
|
|
|
return self.llbuilder.call(self.llbuiltin("watchdog_set"), [self.map(interval)])
|
|
|
|
elif insn.op == "watchdog_clear":
|
|
|
|
id, = insn.operands
|
|
|
|
return self.llbuilder.call(self.llbuiltin("watchdog_clear"), [self.map(id)])
|
2015-07-21 09:54:34 +08:00
|
|
|
else:
|
|
|
|
assert False
|
|
|
|
|
2015-07-21 18:45:27 +08:00
|
|
|
def process_Closure(self, insn):
|
|
|
|
llvalue = ll.Constant(self.llty_of_type(insn.target_function.type), ll.Undefined)
|
2015-08-10 14:12:34 +08:00
|
|
|
llenv = self.llbuilder.bitcast(self.map(insn.environment()), llptr)
|
2015-07-21 18:45:27 +08:00
|
|
|
llvalue = self.llbuilder.insert_value(llvalue, llenv, 0)
|
|
|
|
llvalue = self.llbuilder.insert_value(llvalue, self.map(insn.target_function), 1,
|
|
|
|
name=insn.name)
|
|
|
|
return llvalue
|
2015-07-21 09:54:34 +08:00
|
|
|
|
2015-08-09 21:16:41 +08:00
|
|
|
def _prepare_closure_call(self, insn):
|
2015-08-11 00:25:48 +08:00
|
|
|
llclosure = self.map(insn.target_function())
|
|
|
|
llargs = [self.map(arg) for arg in insn.arguments()]
|
|
|
|
llenv = self.llbuilder.extract_value(llclosure, 0)
|
|
|
|
llfun = self.llbuilder.extract_value(llclosure, 1)
|
2015-08-09 21:16:41 +08:00
|
|
|
return llfun, [llenv] + list(llargs)
|
|
|
|
|
2015-08-11 00:25:48 +08:00
|
|
|
def _prepare_ffi_call(self, insn):
|
|
|
|
llargs = [self.map(arg) for arg in insn.arguments()]
|
2015-08-28 16:03:12 +08:00
|
|
|
llfunname = insn.target_function().type.name
|
|
|
|
llfun = self.llmodule.get_global(llfunname)
|
|
|
|
if llfun is None:
|
|
|
|
llfunty = ll.FunctionType(self.llty_of_type(insn.type, for_return=True),
|
|
|
|
[llarg.type for llarg in llargs])
|
|
|
|
llfun = ll.Function(self.llmodule, llfunty,
|
|
|
|
insn.target_function().type.name)
|
2015-08-11 00:25:48 +08:00
|
|
|
return llfun, list(llargs)
|
|
|
|
|
2015-08-10 01:17:00 +08:00
|
|
|
# See session.c:{send,receive}_rpc_value and comm_generic.py:_{send,receive}_rpc_value.
|
2015-08-09 21:16:41 +08:00
|
|
|
def _rpc_tag(self, typ, error_handler):
|
2015-08-09 07:17:19 +08:00
|
|
|
if types.is_tuple(typ):
|
|
|
|
assert len(typ.elts) < 256
|
|
|
|
return b"t" + bytes([len(typ.elts)]) + \
|
2015-08-09 21:16:41 +08:00
|
|
|
b"".join([self._rpc_tag(elt_type, error_handler)
|
2015-08-09 07:17:19 +08:00
|
|
|
for elt_type in typ.elts])
|
|
|
|
elif builtins.is_none(typ):
|
|
|
|
return b"n"
|
|
|
|
elif builtins.is_bool(typ):
|
|
|
|
return b"b"
|
|
|
|
elif builtins.is_int(typ, types.TValue(32)):
|
|
|
|
return b"i"
|
|
|
|
elif builtins.is_int(typ, types.TValue(64)):
|
|
|
|
return b"I"
|
|
|
|
elif builtins.is_float(typ):
|
|
|
|
return b"f"
|
|
|
|
elif builtins.is_str(typ):
|
|
|
|
return b"s"
|
|
|
|
elif builtins.is_list(typ):
|
|
|
|
return b"l" + self._rpc_tag(builtins.get_iterable_elt(typ),
|
2015-08-09 21:16:41 +08:00
|
|
|
error_handler)
|
2015-08-09 07:17:19 +08:00
|
|
|
elif builtins.is_range(typ):
|
|
|
|
return b"r" + self._rpc_tag(builtins.get_iterable_elt(typ),
|
2015-08-09 21:16:41 +08:00
|
|
|
error_handler)
|
2015-08-09 07:17:19 +08:00
|
|
|
elif ir.is_option(typ):
|
|
|
|
return b"o" + self._rpc_tag(typ.params["inner"],
|
2015-08-09 21:16:41 +08:00
|
|
|
error_handler)
|
2015-08-26 12:56:01 +08:00
|
|
|
elif '__objectid__' in typ.attributes:
|
|
|
|
return b"O"
|
2015-08-09 07:17:19 +08:00
|
|
|
else:
|
2015-08-09 21:16:41 +08:00
|
|
|
error_handler(typ)
|
|
|
|
|
|
|
|
def _build_rpc(self, fun_loc, fun_type, args, llnormalblock, llunwindblock):
|
2015-08-10 14:12:34 +08:00
|
|
|
llservice = ll.Constant(lli32, fun_type.service)
|
2015-08-09 21:16:41 +08:00
|
|
|
|
|
|
|
tag = b""
|
|
|
|
|
|
|
|
for arg in args:
|
|
|
|
def arg_error_handler(typ):
|
|
|
|
printer = types.TypePrinter()
|
|
|
|
note = diagnostic.Diagnostic("note",
|
|
|
|
"value of type {type}",
|
|
|
|
{"type": printer.name(typ)},
|
|
|
|
arg.loc)
|
|
|
|
diag = diagnostic.Diagnostic("error",
|
|
|
|
"type {type} is not supported in remote procedure calls",
|
2015-08-23 05:01:55 +08:00
|
|
|
{"type": printer.name(arg.type)},
|
2015-08-09 21:16:41 +08:00
|
|
|
arg.loc)
|
|
|
|
self.engine.process(diag)
|
|
|
|
tag += self._rpc_tag(arg.type, arg_error_handler)
|
|
|
|
tag += b":"
|
|
|
|
|
|
|
|
def ret_error_handler(typ):
|
2015-08-09 07:17:19 +08:00
|
|
|
printer = types.TypePrinter()
|
|
|
|
note = diagnostic.Diagnostic("note",
|
|
|
|
"value of type {type}",
|
|
|
|
{"type": printer.name(typ)},
|
2015-08-09 21:16:41 +08:00
|
|
|
fun_loc)
|
|
|
|
diag = diagnostic.Diagnostic("error",
|
|
|
|
"return type {type} is not supported in remote procedure calls",
|
|
|
|
{"type": printer.name(fun_type.ret)},
|
|
|
|
fun_loc)
|
2015-08-09 07:17:19 +08:00
|
|
|
self.engine.process(diag)
|
2015-08-09 21:16:41 +08:00
|
|
|
tag += self._rpc_tag(fun_type.ret, ret_error_handler)
|
|
|
|
tag += b"\x00"
|
2015-08-09 07:17:19 +08:00
|
|
|
|
2015-08-27 18:01:04 +08:00
|
|
|
lltag = self.llstr_of_str(tag)
|
2015-08-09 07:17:19 +08:00
|
|
|
|
2015-08-09 21:16:41 +08:00
|
|
|
llstackptr = self.llbuilder.call(self.llbuiltin("llvm.stacksave"), [])
|
2015-08-09 07:17:19 +08:00
|
|
|
|
|
|
|
llargs = []
|
|
|
|
for arg in args:
|
|
|
|
llarg = self.map(arg)
|
|
|
|
llargslot = self.llbuilder.alloca(llarg.type)
|
|
|
|
self.llbuilder.store(llarg, llargslot)
|
|
|
|
llargs.append(llargslot)
|
|
|
|
|
2015-08-09 21:16:41 +08:00
|
|
|
self.llbuilder.call(self.llbuiltin("send_rpc"),
|
|
|
|
[llservice, lltag] + llargs)
|
|
|
|
|
|
|
|
# Don't waste stack space on saved arguments.
|
|
|
|
self.llbuilder.call(self.llbuiltin("llvm.stackrestore"), [llstackptr])
|
|
|
|
|
|
|
|
# T result = {
|
|
|
|
# void *ptr = NULL;
|
|
|
|
# loop: int size = rpc_recv("tag", ptr);
|
|
|
|
# if(size) { ptr = alloca(size); goto loop; }
|
|
|
|
# else *(T*)ptr
|
|
|
|
# }
|
|
|
|
llprehead = self.llbuilder.basic_block
|
|
|
|
llhead = self.llbuilder.append_basic_block(name=llprehead.name + ".rpc.head")
|
|
|
|
if llunwindblock:
|
|
|
|
llheadu = self.llbuilder.append_basic_block(name=llprehead.name + ".rpc.head.unwind")
|
|
|
|
llalloc = self.llbuilder.append_basic_block(name=llprehead.name + ".rpc.alloc")
|
|
|
|
lltail = self.llbuilder.append_basic_block(name=llprehead.name + ".rpc.tail")
|
|
|
|
|
2015-08-10 01:17:00 +08:00
|
|
|
llretty = self.llty_of_type(fun_type.ret)
|
|
|
|
llslot = self.llbuilder.alloca(llretty)
|
2015-08-10 14:12:34 +08:00
|
|
|
llslotgen = self.llbuilder.bitcast(llslot, llptr)
|
2015-08-09 21:16:41 +08:00
|
|
|
self.llbuilder.branch(llhead)
|
|
|
|
|
|
|
|
self.llbuilder.position_at_end(llhead)
|
2015-08-10 01:17:00 +08:00
|
|
|
llphi = self.llbuilder.phi(llslotgen.type)
|
|
|
|
llphi.add_incoming(llslotgen, llprehead)
|
2015-08-09 21:16:41 +08:00
|
|
|
if llunwindblock:
|
2015-08-10 01:17:00 +08:00
|
|
|
llsize = self.llbuilder.invoke(self.llbuiltin("recv_rpc"), [llphi],
|
2015-08-09 21:16:41 +08:00
|
|
|
llheadu, llunwindblock)
|
|
|
|
self.llbuilder.position_at_end(llheadu)
|
|
|
|
else:
|
2015-08-10 01:17:00 +08:00
|
|
|
llsize = self.llbuilder.call(self.llbuiltin("recv_rpc"), [llphi])
|
2015-08-09 21:16:41 +08:00
|
|
|
lldone = self.llbuilder.icmp_unsigned('==', llsize, ll.Constant(llsize.type, 0))
|
|
|
|
self.llbuilder.cbranch(lldone, lltail, llalloc)
|
|
|
|
|
|
|
|
self.llbuilder.position_at_end(llalloc)
|
2015-08-10 14:12:34 +08:00
|
|
|
llalloca = self.llbuilder.alloca(lli8, llsize)
|
2015-08-10 01:17:00 +08:00
|
|
|
llphi.add_incoming(llalloca, llalloc)
|
2015-08-09 21:16:41 +08:00
|
|
|
self.llbuilder.branch(llhead)
|
|
|
|
|
|
|
|
self.llbuilder.position_at_end(lltail)
|
2015-08-10 01:17:00 +08:00
|
|
|
llret = self.llbuilder.load(llslot)
|
2015-08-09 21:16:41 +08:00
|
|
|
if not builtins.is_allocated(fun_type.ret):
|
|
|
|
# We didn't allocate anything except the slot for the value itself.
|
|
|
|
# Don't waste stack space.
|
|
|
|
self.llbuilder.call(self.llbuiltin("llvm.stackrestore"), [llstackptr])
|
|
|
|
if llnormalblock:
|
|
|
|
self.llbuilder.branch(llnormalblock)
|
|
|
|
return llret
|
2015-08-09 07:17:19 +08:00
|
|
|
|
2015-08-09 21:16:41 +08:00
|
|
|
def process_Call(self, insn):
|
2015-08-09 07:17:19 +08:00
|
|
|
if types.is_rpc_function(insn.target_function().type):
|
2015-08-09 21:16:41 +08:00
|
|
|
return self._build_rpc(insn.target_function().loc,
|
|
|
|
insn.target_function().type,
|
2015-08-09 07:17:19 +08:00
|
|
|
insn.arguments(),
|
2015-08-09 21:16:41 +08:00
|
|
|
llnormalblock=None, llunwindblock=None)
|
2015-08-11 00:25:48 +08:00
|
|
|
elif types.is_c_function(insn.target_function().type):
|
|
|
|
llfun, llargs = self._prepare_ffi_call(insn)
|
|
|
|
return self.llbuilder.call(llfun, llargs,
|
|
|
|
name=insn.name)
|
2015-08-09 07:17:19 +08:00
|
|
|
else:
|
2015-08-09 21:16:41 +08:00
|
|
|
llfun, llargs = self._prepare_closure_call(insn)
|
2015-08-20 06:06:03 +08:00
|
|
|
|
|
|
|
if llfun.type.pointee.__has_sret:
|
|
|
|
llstackptr = self.llbuilder.call(self.llbuiltin("llvm.stacksave"), [])
|
|
|
|
|
|
|
|
llresultslot = self.llbuilder.alloca(llfun.type.pointee.args[0].pointee)
|
|
|
|
self.llbuilder.call(llfun, [llresultslot] + llargs)
|
|
|
|
llresult = self.llbuilder.load(llresultslot)
|
|
|
|
|
|
|
|
self.llbuilder.call(self.llbuiltin("llvm.stackrestore"), [llstackptr])
|
|
|
|
|
|
|
|
return llresult
|
|
|
|
else:
|
|
|
|
return self.llbuilder.call(llfun, llargs,
|
|
|
|
name=insn.name)
|
2015-07-21 09:54:34 +08:00
|
|
|
|
2015-07-25 10:37:37 +08:00
|
|
|
def process_Invoke(self, insn):
|
|
|
|
llnormalblock = self.map(insn.normal_target())
|
|
|
|
llunwindblock = self.map(insn.exception_target())
|
2015-08-09 21:16:41 +08:00
|
|
|
if types.is_rpc_function(insn.target_function().type):
|
|
|
|
return self._build_rpc(insn.target_function().loc,
|
|
|
|
insn.target_function().type,
|
|
|
|
insn.arguments(),
|
|
|
|
llnormalblock, llunwindblock)
|
2015-08-11 00:25:48 +08:00
|
|
|
elif types.is_c_function(insn.target_function().type):
|
|
|
|
llfun, llargs = self._prepare_ffi_call(insn)
|
|
|
|
return self.llbuilder.invoke(llfun, llargs, llnormalblock, llunwindblock,
|
|
|
|
name=insn.name)
|
2015-08-09 21:16:41 +08:00
|
|
|
else:
|
|
|
|
llfun, llargs = self._prepare_closure_call(insn)
|
|
|
|
return self.llbuilder.invoke(llfun, llargs, llnormalblock, llunwindblock,
|
|
|
|
name=insn.name)
|
2015-07-25 10:37:37 +08:00
|
|
|
|
2015-08-26 12:56:01 +08:00
|
|
|
def _quote(self, value, typ, path):
|
|
|
|
value_id = id(value)
|
|
|
|
if value_id in self.llobject_map:
|
|
|
|
return self.llobject_map[value_id]
|
|
|
|
|
|
|
|
global_name = ""
|
|
|
|
llty = self.llty_of_type(typ)
|
|
|
|
|
|
|
|
if types.is_constructor(typ) or types.is_instance(typ):
|
|
|
|
llfields = []
|
|
|
|
for attr in typ.attributes:
|
|
|
|
if attr == "__objectid__":
|
|
|
|
objectid = self.object_map.store(value)
|
|
|
|
llfields.append(ll.Constant(lli32, objectid))
|
|
|
|
global_name = "object.{}".format(objectid)
|
|
|
|
else:
|
|
|
|
llfields.append(self._quote(getattr(value, attr), typ.attributes[attr],
|
2015-08-27 18:01:04 +08:00
|
|
|
lambda: path() + [attr]))
|
2015-09-01 13:33:33 +08:00
|
|
|
llconst = ll.Constant(llty.pointee, llfields)
|
2015-08-26 12:56:01 +08:00
|
|
|
|
2015-09-01 13:33:33 +08:00
|
|
|
llglobal = ll.GlobalVariable(self.llmodule, llconst.type, global_name)
|
|
|
|
llglobal.initializer = llconst
|
|
|
|
llglobal.linkage = "private"
|
|
|
|
self.llobject_map[value_id] = llglobal
|
|
|
|
return llglobal
|
2015-08-26 12:56:01 +08:00
|
|
|
elif builtins.is_none(typ):
|
|
|
|
assert value is None
|
2015-08-27 18:01:04 +08:00
|
|
|
return ll.Constant.literal_struct([])
|
2015-08-26 12:56:01 +08:00
|
|
|
elif builtins.is_bool(typ):
|
|
|
|
assert value in (True, False)
|
2015-09-01 13:33:33 +08:00
|
|
|
return ll.Constant(llty, value)
|
2015-08-26 12:56:01 +08:00
|
|
|
elif builtins.is_int(typ):
|
2015-08-28 16:24:15 +08:00
|
|
|
assert isinstance(value, (int, language_core.int))
|
2015-09-01 13:33:33 +08:00
|
|
|
return ll.Constant(llty, int(value))
|
2015-08-26 12:56:01 +08:00
|
|
|
elif builtins.is_float(typ):
|
|
|
|
assert isinstance(value, float)
|
2015-09-01 13:33:33 +08:00
|
|
|
return ll.Constant(llty, value)
|
2015-08-26 12:56:01 +08:00
|
|
|
elif builtins.is_str(typ):
|
|
|
|
assert isinstance(value, (str, bytes))
|
2015-08-27 18:01:04 +08:00
|
|
|
return self.llstr_of_str(value)
|
2015-09-01 13:33:33 +08:00
|
|
|
elif builtins.is_list(typ):
|
|
|
|
assert isinstance(value, list)
|
|
|
|
elt_type = builtins.get_iterable_elt(typ)
|
|
|
|
llelts = [self._quote(value[i], elt_type, lambda: path() + [str(i)])
|
|
|
|
for i in range(len(value))]
|
|
|
|
lleltsary = ll.Constant(ll.ArrayType(llelts[0].type, len(llelts)), llelts)
|
|
|
|
|
|
|
|
llglobal = ll.GlobalVariable(self.llmodule, lleltsary.type, "quoted.list")
|
|
|
|
llglobal.initializer = lleltsary
|
|
|
|
llglobal.linkage = "private"
|
|
|
|
|
|
|
|
lleltsptr = llglobal.bitcast(lleltsary.type.element.as_pointer())
|
|
|
|
llconst = ll.Constant(llty, [ll.Constant(lli32, len(llelts)), lleltsptr])
|
|
|
|
return llconst
|
2015-08-28 08:46:50 +08:00
|
|
|
elif types.is_function(typ):
|
|
|
|
# RPC and C functions have no runtime representation; ARTIQ
|
|
|
|
# functions are initialized explicitly.
|
|
|
|
return ll.Constant(llty, ll.Undefined)
|
2015-08-26 12:56:01 +08:00
|
|
|
else:
|
2015-08-27 18:53:18 +08:00
|
|
|
print(typ)
|
2015-08-26 12:56:01 +08:00
|
|
|
assert False
|
|
|
|
|
|
|
|
def process_Quote(self, insn):
|
|
|
|
assert self.object_map is not None
|
|
|
|
return self._quote(insn.value, insn.type, lambda: [repr(insn.value)])
|
|
|
|
|
2015-07-21 09:54:34 +08:00
|
|
|
def process_Select(self, insn):
|
2015-07-22 03:32:10 +08:00
|
|
|
return self.llbuilder.select(self.map(insn.condition()),
|
|
|
|
self.map(insn.if_true()), self.map(insn.if_false()))
|
2015-07-21 09:54:34 +08:00
|
|
|
|
|
|
|
def process_Branch(self, insn):
|
|
|
|
return self.llbuilder.branch(self.map(insn.target()))
|
|
|
|
|
2015-11-21 03:22:47 +08:00
|
|
|
process_Delay = process_Branch
|
|
|
|
|
2015-07-21 09:54:34 +08:00
|
|
|
def process_BranchIf(self, insn):
|
|
|
|
return self.llbuilder.cbranch(self.map(insn.condition()),
|
|
|
|
self.map(insn.if_true()), self.map(insn.if_false()))
|
|
|
|
|
2015-07-25 10:37:37 +08:00
|
|
|
def process_IndirectBranch(self, insn):
|
|
|
|
llinsn = self.llbuilder.branch_indirect(self.map(insn.target()))
|
|
|
|
for dest in insn.destinations():
|
|
|
|
llinsn.add_destination(self.map(dest))
|
|
|
|
return llinsn
|
2015-07-21 09:54:34 +08:00
|
|
|
|
|
|
|
def process_Return(self, insn):
|
2015-07-21 18:45:27 +08:00
|
|
|
if builtins.is_none(insn.value().type):
|
2015-07-21 09:54:34 +08:00
|
|
|
return self.llbuilder.ret_void()
|
|
|
|
else:
|
2015-08-20 06:06:03 +08:00
|
|
|
if self.llfunction.type.pointee.__has_sret:
|
|
|
|
self.llbuilder.store(self.map(insn.value()), self.llfunction.args[0])
|
|
|
|
return self.llbuilder.ret_void()
|
|
|
|
else:
|
|
|
|
return self.llbuilder.ret(self.map(insn.value()))
|
2015-07-21 09:54:34 +08:00
|
|
|
|
|
|
|
def process_Unreachable(self, insn):
|
|
|
|
return self.llbuilder.unreachable()
|
|
|
|
|
2015-12-10 23:02:32 +08:00
|
|
|
def _gen_raise(self, insn, func, args):
|
2015-07-27 14:10:20 +08:00
|
|
|
if insn.exception_target() is not None:
|
|
|
|
llnormalblock = self.llfunction.append_basic_block("unreachable")
|
|
|
|
llnormalblock.terminator = ll.Unreachable(llnormalblock)
|
|
|
|
llnormalblock.instructions.append(llnormalblock.terminator)
|
|
|
|
|
|
|
|
llunwindblock = self.map(insn.exception_target())
|
2015-12-10 23:02:32 +08:00
|
|
|
llinsn = self.llbuilder.invoke(func, args,
|
2015-07-27 14:10:20 +08:00
|
|
|
llnormalblock, llunwindblock,
|
|
|
|
name=insn.name)
|
|
|
|
else:
|
2015-12-10 23:02:32 +08:00
|
|
|
llinsn = self.llbuilder.call(func, args,
|
2015-07-27 14:10:20 +08:00
|
|
|
name=insn.name)
|
|
|
|
self.llbuilder.unreachable()
|
2015-07-25 10:37:37 +08:00
|
|
|
llinsn.attributes.add('noreturn')
|
2015-07-21 09:54:34 +08:00
|
|
|
return llinsn
|
|
|
|
|
2015-12-10 23:02:32 +08:00
|
|
|
def process_Raise(self, insn):
|
|
|
|
llexn = self.map(insn.value())
|
|
|
|
return self._gen_raise(insn, self.llbuiltin("__artiq_raise"), [llexn])
|
|
|
|
|
2015-07-27 17:36:21 +08:00
|
|
|
def process_Reraise(self, insn):
|
2015-12-10 23:02:32 +08:00
|
|
|
return self._gen_raise(insn, self.llbuiltin("__artiq_reraise"), [])
|
2015-07-27 17:36:21 +08:00
|
|
|
|
2015-07-25 10:37:37 +08:00
|
|
|
def process_LandingPad(self, insn):
|
2015-07-27 14:10:20 +08:00
|
|
|
# Layout on return from landing pad: {%_Unwind_Exception*, %Exception*}
|
2015-08-10 20:11:52 +08:00
|
|
|
lllandingpadty = ll.LiteralStructType([llptr, llptr])
|
2015-07-27 14:10:20 +08:00
|
|
|
lllandingpad = self.llbuilder.landingpad(lllandingpadty,
|
2015-07-27 17:36:21 +08:00
|
|
|
self.llbuiltin("__artiq_personality"),
|
|
|
|
cleanup=True)
|
2015-07-27 14:10:20 +08:00
|
|
|
llrawexn = self.llbuilder.extract_value(lllandingpad, 1)
|
2015-07-25 12:01:25 +08:00
|
|
|
llexn = self.llbuilder.bitcast(llrawexn, self.llty_of_type(insn.type))
|
|
|
|
llexnnameptr = self.llbuilder.gep(llexn, [self.llindex(0), self.llindex(0)])
|
2015-07-25 10:37:37 +08:00
|
|
|
llexnname = self.llbuilder.load(llexnnameptr)
|
|
|
|
|
|
|
|
for target, typ in insn.clauses():
|
|
|
|
if typ is None:
|
|
|
|
llclauseexnname = ll.Constant(
|
|
|
|
self.llty_of_type(ir.TExceptionTypeInfo()), None)
|
|
|
|
else:
|
|
|
|
llclauseexnname = self.llconst_of_const(
|
|
|
|
ir.Constant(typ.name, ir.TExceptionTypeInfo()))
|
|
|
|
lllandingpad.add_clause(ll.CatchClause(llclauseexnname))
|
|
|
|
|
2015-07-25 12:01:25 +08:00
|
|
|
if typ is None:
|
2015-07-25 10:37:37 +08:00
|
|
|
self.llbuilder.branch(self.map(target))
|
2015-07-25 12:01:25 +08:00
|
|
|
else:
|
|
|
|
llmatchingclause = self.llbuilder.icmp_unsigned('==', llexnname, llclauseexnname)
|
|
|
|
with self.llbuilder.if_then(llmatchingclause):
|
|
|
|
self.llbuilder.branch(self.map(target))
|
2015-07-25 10:37:37 +08:00
|
|
|
|
2015-07-25 12:01:25 +08:00
|
|
|
if self.llbuilder.basic_block.terminator is None:
|
2015-07-27 17:36:21 +08:00
|
|
|
self.llbuilder.branch(self.map(insn.cleanup()))
|
2015-07-21 09:54:34 +08:00
|
|
|
|
2015-07-25 12:01:25 +08:00
|
|
|
return llexn
|