forked from M-Labs/artiq
parent
5a2306ae5a
commit
1a518ea7eb
|
@ -260,7 +260,7 @@ def is_array(typ, elt=None):
|
||||||
return types.is_mono(typ, "array")
|
return types.is_mono(typ, "array")
|
||||||
|
|
||||||
def is_listish(typ, elt=None):
|
def is_listish(typ, elt=None):
|
||||||
return is_list(typ, elt) or is_array(typ, elt)
|
return is_list(typ, elt) or is_array(typ, elt) or (elt is None and is_str(typ))
|
||||||
|
|
||||||
def is_range(typ, elt=None):
|
def is_range(typ, elt=None):
|
||||||
if elt is not None:
|
if elt is not None:
|
||||||
|
@ -283,6 +283,10 @@ def is_iterable(typ):
|
||||||
def get_iterable_elt(typ):
|
def get_iterable_elt(typ):
|
||||||
if is_iterable(typ):
|
if is_iterable(typ):
|
||||||
return typ.find()["elt"].find()
|
return typ.find()["elt"].find()
|
||||||
|
elif is_str(typ):
|
||||||
|
return TInt(types.TValue(8))
|
||||||
|
else:
|
||||||
|
assert False
|
||||||
|
|
||||||
def is_collection(typ):
|
def is_collection(typ):
|
||||||
typ = typ.find()
|
typ = typ.find()
|
||||||
|
|
|
@ -478,8 +478,12 @@ class ARTIQIRGenerator(algorithm.Visitor):
|
||||||
|
|
||||||
def iterable_len(self, value, typ=_size_type):
|
def iterable_len(self, value, typ=_size_type):
|
||||||
if builtins.is_listish(value.type):
|
if builtins.is_listish(value.type):
|
||||||
|
if isinstance(value, ir.Constant):
|
||||||
|
name = None
|
||||||
|
else:
|
||||||
|
name = "{}.len".format(value.name)
|
||||||
return self.append(ir.Builtin("len", [value], typ,
|
return self.append(ir.Builtin("len", [value], typ,
|
||||||
name="{}.len".format(value.name)))
|
name=name))
|
||||||
elif builtins.is_range(value.type):
|
elif builtins.is_range(value.type):
|
||||||
start = self.append(ir.GetAttr(value, "start"))
|
start = self.append(ir.GetAttr(value, "start"))
|
||||||
stop = self.append(ir.GetAttr(value, "stop"))
|
stop = self.append(ir.GetAttr(value, "stop"))
|
||||||
|
@ -1313,7 +1317,7 @@ class ARTIQIRGenerator(algorithm.Visitor):
|
||||||
loc=node.right.loc)
|
loc=node.right.loc)
|
||||||
|
|
||||||
return self.append(ir.Arith(node.op, lhs, rhs))
|
return self.append(ir.Arith(node.op, lhs, rhs))
|
||||||
elif isinstance(node.op, ast.Add): # list + list, tuple + tuple
|
elif isinstance(node.op, ast.Add): # list + list, tuple + tuple, str + str
|
||||||
lhs, rhs = self.visit(node.left), self.visit(node.right)
|
lhs, rhs = self.visit(node.left), self.visit(node.right)
|
||||||
if types.is_tuple(node.left.type) and types.is_tuple(node.right.type):
|
if types.is_tuple(node.left.type) and types.is_tuple(node.right.type):
|
||||||
elts = []
|
elts = []
|
||||||
|
@ -1327,6 +1331,10 @@ class ARTIQIRGenerator(algorithm.Visitor):
|
||||||
rhs_length = self.iterable_len(rhs)
|
rhs_length = self.iterable_len(rhs)
|
||||||
|
|
||||||
result_length = self.append(ir.Arith(ast.Add(loc=None), lhs_length, rhs_length))
|
result_length = self.append(ir.Arith(ast.Add(loc=None), lhs_length, rhs_length))
|
||||||
|
if builtins.is_str(node.left.type):
|
||||||
|
result_last = result_length
|
||||||
|
result_length = self.append(ir.Arith(ast.Add(loc=None), result_length,
|
||||||
|
ir.Constant(1, self._size_type)))
|
||||||
result = self.append(ir.Alloc([result_length], node.type))
|
result = self.append(ir.Alloc([result_length], node.type))
|
||||||
|
|
||||||
# Copy lhs
|
# Copy lhs
|
||||||
|
@ -1350,6 +1358,10 @@ class ARTIQIRGenerator(algorithm.Visitor):
|
||||||
lambda index: self.append(ir.Compare(ast.Lt(loc=None), index, rhs_length)),
|
lambda index: self.append(ir.Compare(ast.Lt(loc=None), index, rhs_length)),
|
||||||
body_gen)
|
body_gen)
|
||||||
|
|
||||||
|
if builtins.is_str(node.left.type):
|
||||||
|
self.append(ir.SetElem(result, result_last,
|
||||||
|
ir.Constant(0, builtins.TInt(types.TValue(8)))))
|
||||||
|
|
||||||
return result
|
return result
|
||||||
else:
|
else:
|
||||||
assert False
|
assert False
|
||||||
|
|
|
@ -394,6 +394,10 @@ class Inferencer(algorithm.Visitor):
|
||||||
self._unify(left.type, right.type,
|
self._unify(left.type, right.type,
|
||||||
left.loc, right.loc)
|
left.loc, right.loc)
|
||||||
return left.type, left.type, right.type
|
return left.type, left.type, right.type
|
||||||
|
elif builtins.is_str(left.type) or builtins.is_str(right.type):
|
||||||
|
self._unify(left.type, right.type,
|
||||||
|
left.loc, right.loc)
|
||||||
|
return left.type, left.type, right.type
|
||||||
else:
|
else:
|
||||||
return self._coerce_numeric((left, right), lambda typ: (typ, typ, typ))
|
return self._coerce_numeric((left, right), lambda typ: (typ, typ, typ))
|
||||||
elif isinstance(op, ast.Mult):
|
elif isinstance(op, ast.Mult):
|
||||||
|
|
|
@ -344,6 +344,8 @@ class LLVMIRGenerator:
|
||||||
llty = ll.FunctionType(llvoid, [self.llty_of_type(builtins.TException())])
|
llty = ll.FunctionType(llvoid, [self.llty_of_type(builtins.TException())])
|
||||||
elif name == "__artiq_reraise":
|
elif name == "__artiq_reraise":
|
||||||
llty = ll.FunctionType(llvoid, [])
|
llty = ll.FunctionType(llvoid, [])
|
||||||
|
elif name == "strlen":
|
||||||
|
llty = ll.FunctionType(lli32, [llptr])
|
||||||
elif name == "strcmp":
|
elif name == "strcmp":
|
||||||
llty = ll.FunctionType(lli32, [llptr, llptr])
|
llty = ll.FunctionType(lli32, [llptr, llptr])
|
||||||
elif name == "send_rpc":
|
elif name == "send_rpc":
|
||||||
|
@ -610,6 +612,10 @@ class LLVMIRGenerator:
|
||||||
name=insn.name)
|
name=insn.name)
|
||||||
else:
|
else:
|
||||||
assert False
|
assert False
|
||||||
|
elif builtins.is_str(insn.type):
|
||||||
|
llsize = self.map(insn.operands[0])
|
||||||
|
llvalue = self.llbuilder.alloca(lli8, size=llsize)
|
||||||
|
return llvalue
|
||||||
elif builtins.is_listish(insn.type):
|
elif builtins.is_listish(insn.type):
|
||||||
llsize = self.map(insn.operands[0])
|
llsize = self.map(insn.operands[0])
|
||||||
llvalue = ll.Constant(self.llty_of_type(insn.type), ll.Undefined)
|
llvalue = ll.Constant(self.llty_of_type(insn.type), ll.Undefined)
|
||||||
|
@ -818,18 +824,27 @@ class LLVMIRGenerator:
|
||||||
return self.llbuilder.store(llvalue, llptr)
|
return self.llbuilder.store(llvalue, llptr)
|
||||||
|
|
||||||
def process_GetElem(self, insn):
|
def process_GetElem(self, insn):
|
||||||
llelts = self.llbuilder.extract_value(self.map(insn.list()), 1)
|
lst, idx = insn.list(), insn.index()
|
||||||
llelt = self.llbuilder.gep(llelts, [self.map(insn.index())],
|
lllst, llidx = map(self.map, (lst, idx))
|
||||||
inbounds=True)
|
if builtins.is_str(lst.type):
|
||||||
llvalue = self.llbuilder.load(llelt)
|
llelt = self.llbuilder.gep(lllst, [llidx], inbounds=True)
|
||||||
|
llvalue = self.llbuilder.load(llelt)
|
||||||
|
else:
|
||||||
|
llelts = self.llbuilder.extract_value(lllst, 1)
|
||||||
|
llelt = self.llbuilder.gep(llelts, [llidx], inbounds=True)
|
||||||
|
llvalue = self.llbuilder.load(llelt)
|
||||||
if isinstance(llvalue.type, ll.PointerType):
|
if isinstance(llvalue.type, ll.PointerType):
|
||||||
self.mark_dereferenceable(llvalue)
|
self.mark_dereferenceable(llvalue)
|
||||||
return llvalue
|
return llvalue
|
||||||
|
|
||||||
def process_SetElem(self, insn):
|
def process_SetElem(self, insn):
|
||||||
llelts = self.llbuilder.extract_value(self.map(insn.list()), 1)
|
lst, idx = insn.list(), insn.index()
|
||||||
llelt = self.llbuilder.gep(llelts, [self.map(insn.index())],
|
lllst, llidx = map(self.map, (lst, idx))
|
||||||
inbounds=True)
|
if builtins.is_str(lst.type):
|
||||||
|
llelt = self.llbuilder.gep(lllst, [llidx], inbounds=True)
|
||||||
|
else:
|
||||||
|
llelts = self.llbuilder.extract_value(lllst, 1)
|
||||||
|
llelt = self.llbuilder.gep(llelts, [llidx], inbounds=True)
|
||||||
return self.llbuilder.store(self.map(insn.value()), llelt)
|
return self.llbuilder.store(self.map(insn.value()), llelt)
|
||||||
|
|
||||||
def process_Coerce(self, insn):
|
def process_Coerce(self, insn):
|
||||||
|
@ -1045,8 +1060,11 @@ class LLVMIRGenerator:
|
||||||
env, = insn.operands
|
env, = insn.operands
|
||||||
return get_outer(self.map(env), env.type)
|
return get_outer(self.map(env), env.type)
|
||||||
elif insn.op == "len":
|
elif insn.op == "len":
|
||||||
lst, = insn.operands
|
collection, = insn.operands
|
||||||
return self.llbuilder.extract_value(self.map(lst), 0)
|
if builtins.is_str(collection.type):
|
||||||
|
return self.llbuilder.call(self.llbuiltin("strlen"), [self.map(collection)])
|
||||||
|
else:
|
||||||
|
return self.llbuilder.extract_value(self.map(collection), 0)
|
||||||
elif insn.op in ("printf", "rtio_log"):
|
elif insn.op in ("printf", "rtio_log"):
|
||||||
# We only get integers, floats, pointers and strings here.
|
# We only get integers, floats, pointers and strings here.
|
||||||
llargs = map(self.map, insn.operands)
|
llargs = map(self.map, insn.operands)
|
||||||
|
|
|
@ -351,6 +351,6 @@ class EscapeValidator(algorithm.Visitor):
|
||||||
{"type": types.TypePrinter().name(node.value.type)},
|
{"type": types.TypePrinter().name(node.value.type)},
|
||||||
node.value.loc)
|
node.value.loc)
|
||||||
diag = diagnostic.Diagnostic("error",
|
diag = diagnostic.Diagnostic("error",
|
||||||
"cannot return a mutable value that does not live forever", {},
|
"cannot return an allocated value that does not live forever", {},
|
||||||
node.value.loc, notes=self._diagnostics_for(region, node.value.loc) + [note])
|
node.value.loc, notes=self._diagnostics_for(region, node.value.loc) + [note])
|
||||||
self.engine.process(diag)
|
self.engine.process(diag)
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
# RUN: %python -m artiq.compiler.testbench.embedding %s
|
||||||
|
|
||||||
|
from artiq.experiment import *
|
||||||
|
|
||||||
|
@kernel
|
||||||
|
def foo():
|
||||||
|
return "x"
|
||||||
|
|
||||||
|
@kernel
|
||||||
|
def entrypoint():
|
||||||
|
foo()
|
|
@ -0,0 +1,19 @@
|
||||||
|
# RUN: %python -m artiq.compiler.testbench.embedding +diag %s 2>%t
|
||||||
|
# RUN: OutputCheck %s --file-to-check=%t
|
||||||
|
|
||||||
|
from artiq.experiment import *
|
||||||
|
|
||||||
|
@kernel
|
||||||
|
def foo():
|
||||||
|
# CHECK-NOT-L: ${LINE:+1}: error:
|
||||||
|
return "x"
|
||||||
|
|
||||||
|
@kernel
|
||||||
|
def bar():
|
||||||
|
# CHECK-L: ${LINE:+1}: error: cannot return an allocated value that does not live forever
|
||||||
|
return "x" + "y"
|
||||||
|
|
||||||
|
@kernel
|
||||||
|
def entrypoint():
|
||||||
|
foo()
|
||||||
|
bar()
|
|
@ -0,0 +1,4 @@
|
||||||
|
# RUN: %python -m artiq.compiler.testbench.jit %s
|
||||||
|
# RUN: %python %s
|
||||||
|
|
||||||
|
assert ("x" + "y") == "xy"
|
Loading…
Reference in New Issue