forked from M-Labs/artiq
compiler: Basic support for creation of multidimensional arrays
Breaks all uses of array(), as indexing is not yet implemented.
This commit is contained in:
parent
56010c49fb
commit
575be2aeca
|
@ -86,6 +86,10 @@ class TArray(types.TMono):
|
||||||
if elt is None:
|
if elt is None:
|
||||||
elt = types.TVar()
|
elt = types.TVar()
|
||||||
super().__init__("array", {"elt": elt})
|
super().__init__("array", {"elt": elt})
|
||||||
|
self.attributes = OrderedDict([
|
||||||
|
("shape", TList(TInt32())),
|
||||||
|
("buffer", TList(elt)),
|
||||||
|
])
|
||||||
|
|
||||||
def _array_printer(typ, printer, depth, max_depth):
|
def _array_printer(typ, printer, depth, max_depth):
|
||||||
return "numpy.array(elt={})".format(printer.name(typ["elt"], depth, max_depth))
|
return "numpy.array(elt={})".format(printer.name(typ["elt"], depth, max_depth))
|
||||||
|
|
|
@ -1637,7 +1637,7 @@ class ARTIQIRGenerator(algorithm.Visitor):
|
||||||
return self.append(ir.Coerce(arg, node.type))
|
return self.append(ir.Coerce(arg, node.type))
|
||||||
else:
|
else:
|
||||||
assert False
|
assert False
|
||||||
elif (types.is_builtin(typ, "list") or types.is_builtin(typ, "array") or
|
elif (types.is_builtin(typ, "list") or
|
||||||
types.is_builtin(typ, "bytearray") or types.is_builtin(typ, "bytes")):
|
types.is_builtin(typ, "bytearray") or types.is_builtin(typ, "bytes")):
|
||||||
if len(node.args) == 0 and len(node.keywords) == 0:
|
if len(node.args) == 0 and len(node.keywords) == 0:
|
||||||
length = ir.Constant(0, builtins.TInt32())
|
length = ir.Constant(0, builtins.TInt32())
|
||||||
|
@ -1660,6 +1660,77 @@ class ARTIQIRGenerator(algorithm.Visitor):
|
||||||
return result
|
return result
|
||||||
else:
|
else:
|
||||||
assert False
|
assert False
|
||||||
|
elif types.is_builtin(typ, "array"):
|
||||||
|
if len(node.args) == 1 and len(node.keywords) == 0:
|
||||||
|
result_type = node.type.find()
|
||||||
|
arg = self.visit(node.args[0])
|
||||||
|
|
||||||
|
num_dims = 0
|
||||||
|
result_elt = result_type["elt"].find()
|
||||||
|
inner_type = arg.type.find()
|
||||||
|
while True:
|
||||||
|
if inner_type == result_elt:
|
||||||
|
# TODO: What about types needing coercion (e.g. int32 to int64)?
|
||||||
|
break
|
||||||
|
assert builtins.is_iterable(inner_type)
|
||||||
|
num_dims += 1
|
||||||
|
inner_type = builtins.get_iterable_elt(inner_type)
|
||||||
|
|
||||||
|
# Derive shape from first element on each level (currently, type
|
||||||
|
# inference make sure arrays are always rectangular; in the future, we
|
||||||
|
# might want to insert a runtime check here).
|
||||||
|
#
|
||||||
|
# While we are at it, also total up overall number of elements
|
||||||
|
shape = self.append(
|
||||||
|
ir.Alloc([ir.Constant(num_dims, self._size_type)],
|
||||||
|
result_type.attributes["shape"]))
|
||||||
|
first_elt = arg
|
||||||
|
dim_idx = 0
|
||||||
|
num_total_elts = None
|
||||||
|
while True:
|
||||||
|
length = self.iterable_len(first_elt)
|
||||||
|
self.append(
|
||||||
|
ir.SetElem(shape, ir.Constant(dim_idx, length.type), length))
|
||||||
|
if num_total_elts is None:
|
||||||
|
num_total_elts = length
|
||||||
|
else:
|
||||||
|
num_total_elts = self.append(
|
||||||
|
ir.Arith(ast.Mult(loc=None), num_total_elts, length))
|
||||||
|
|
||||||
|
dim_idx += 1
|
||||||
|
if dim_idx == num_dims:
|
||||||
|
break
|
||||||
|
first_elt = self.iterable_get(first_elt,
|
||||||
|
ir.Constant(0, length.type))
|
||||||
|
|
||||||
|
# Assign buffer from nested iterables.
|
||||||
|
buffer = self.append(
|
||||||
|
ir.Alloc([num_total_elts], result_type.attributes["buffer"]))
|
||||||
|
def body_gen(index):
|
||||||
|
# TODO: This is hilariously inefficient; we really want to emit a
|
||||||
|
# nested loop for the source and keep one running index for the
|
||||||
|
# target buffer.
|
||||||
|
indices = []
|
||||||
|
mod_idx = index
|
||||||
|
for dim_idx in reversed(range(1, num_dims)):
|
||||||
|
dim_len = self.append(ir.GetElem(shape, ir.Constant(dim_idx, self._size_type)))
|
||||||
|
indices.append(self.append(ir.Arith(ast.Mod(loc=None), mod_idx, dim_len)))
|
||||||
|
mod_idx = self.append(ir.Arith(ast.FloorDiv(loc=None), mod_idx, dim_len))
|
||||||
|
indices.append(mod_idx)
|
||||||
|
|
||||||
|
elt = arg
|
||||||
|
for idx in reversed(indices):
|
||||||
|
elt = self.iterable_get(elt, idx)
|
||||||
|
self.append(ir.SetElem(buffer, index, elt))
|
||||||
|
return self.append(
|
||||||
|
ir.Arith(ast.Add(loc=None), index, ir.Constant(1, length.type)))
|
||||||
|
self._make_loop(
|
||||||
|
ir.Constant(0, length.type), lambda index: self.append(
|
||||||
|
ir.Compare(ast.Lt(loc=None), index, num_total_elts)), body_gen)
|
||||||
|
|
||||||
|
return self.append(ir.Alloc([shape, buffer], node.type))
|
||||||
|
else:
|
||||||
|
assert False
|
||||||
elif types.is_builtin(typ, "range"):
|
elif types.is_builtin(typ, "range"):
|
||||||
elt_typ = builtins.get_iterable_elt(node.type)
|
elt_typ = builtins.get_iterable_elt(node.type)
|
||||||
if len(node.args) == 1 and len(node.keywords) == 0:
|
if len(node.args) == 1 and len(node.keywords) == 0:
|
||||||
|
|
|
@ -246,6 +246,10 @@ class LLVMIRGenerator:
|
||||||
return ll.IntType(builtins.get_int_width(typ))
|
return ll.IntType(builtins.get_int_width(typ))
|
||||||
elif builtins.is_float(typ):
|
elif builtins.is_float(typ):
|
||||||
return lldouble
|
return lldouble
|
||||||
|
elif builtins.is_array(typ):
|
||||||
|
llshapety = self.llty_of_type(typ.attributes["shape"])
|
||||||
|
llbufferty = self.llty_of_type(typ.attributes["buffer"])
|
||||||
|
return ll.LiteralStructType([llshapety, llbufferty])
|
||||||
elif builtins.is_listish(typ):
|
elif builtins.is_listish(typ):
|
||||||
lleltty = self.llty_of_type(builtins.get_iterable_elt(typ))
|
lleltty = self.llty_of_type(builtins.get_iterable_elt(typ))
|
||||||
return ll.LiteralStructType([lleltty.as_pointer(), lli32])
|
return ll.LiteralStructType([lleltty.as_pointer(), lli32])
|
||||||
|
@ -733,7 +737,7 @@ class LLVMIRGenerator:
|
||||||
name=insn.name)
|
name=insn.name)
|
||||||
else:
|
else:
|
||||||
assert False
|
assert False
|
||||||
elif builtins.is_listish(insn.type):
|
elif builtins.is_listish(insn.type) and not builtins.is_array(insn.type):
|
||||||
llsize = self.map(insn.operands[0])
|
llsize = self.map(insn.operands[0])
|
||||||
lleltty = self.llty_of_type(builtins.get_iterable_elt(insn.type))
|
lleltty = self.llty_of_type(builtins.get_iterable_elt(insn.type))
|
||||||
llalloc = self.llbuilder.alloca(lleltty, size=llsize)
|
llalloc = self.llbuilder.alloca(lleltty, size=llsize)
|
||||||
|
@ -741,7 +745,8 @@ class LLVMIRGenerator:
|
||||||
llvalue = self.llbuilder.insert_value(llvalue, llalloc, 0, name=insn.name)
|
llvalue = self.llbuilder.insert_value(llvalue, llalloc, 0, name=insn.name)
|
||||||
llvalue = self.llbuilder.insert_value(llvalue, llsize, 1)
|
llvalue = self.llbuilder.insert_value(llvalue, llsize, 1)
|
||||||
return llvalue
|
return llvalue
|
||||||
elif not builtins.is_allocated(insn.type) or ir.is_keyword(insn.type):
|
elif (not builtins.is_allocated(insn.type) or ir.is_keyword(insn.type)
|
||||||
|
or builtins.is_array(insn.type)):
|
||||||
llvalue = ll.Constant(self.llty_of_type(insn.type), ll.Undefined)
|
llvalue = ll.Constant(self.llty_of_type(insn.type), ll.Undefined)
|
||||||
for index, elt in enumerate(insn.operands):
|
for index, elt in enumerate(insn.operands):
|
||||||
llvalue = self.llbuilder.insert_value(llvalue, self.map(elt), index)
|
llvalue = self.llbuilder.insert_value(llvalue, self.map(elt), index)
|
||||||
|
|
|
@ -2,4 +2,7 @@
|
||||||
# REQUIRES: exceptions
|
# REQUIRES: exceptions
|
||||||
|
|
||||||
ary = array([1, 2, 3])
|
ary = array([1, 2, 3])
|
||||||
assert [x*x for x in ary] == [1, 4, 9]
|
# FIXME: Implement ndarray indexing
|
||||||
|
# assert [x*x for x in ary] == [1, 4, 9]
|
||||||
|
|
||||||
|
matrix = array([[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]])
|
||||||
|
|
Loading…
Reference in New Issue