Skip to content

Commit f3b727b

Browse files
committedDec 17, 2014
py2llvm: replace array with list
1 parent 6ca39f7 commit f3b727b

File tree

10 files changed

+174
-129
lines changed

10 files changed

+174
-129
lines changed
 

‎artiq/language/core.py

-16
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
"""
55

66
from collections import namedtuple as _namedtuple
7-
from copy import copy as _copy
87
from functools import wraps as _wraps
98

109
from artiq.language import units as _units
@@ -71,21 +70,6 @@ def round64(x):
7170
return int64(round(x))
7271

7372

74-
def array(element, count):
75-
"""Creates an array.
76-
77-
The array is initialized with the value of ``element`` repeated ``count``
78-
times. Elements can be read and written using the regular Python index
79-
syntax.
80-
81-
For static compilation, ``count`` must be a fixed integer.
82-
83-
Arrays of arrays are supported.
84-
85-
"""
86-
return [_copy(element) for i in range(count)]
87-
88-
8973
_KernelFunctionInfo = _namedtuple("_KernelFunctionInfo", "core_name k_function")
9074

9175

‎artiq/py2llvm/arrays.py

-70
This file was deleted.

‎artiq/py2llvm/ast_body.py

+92-12
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
import llvmlite.ir as ll
44

5-
from artiq.py2llvm import values, base_types, fractions, arrays, iterators
5+
from artiq.py2llvm import values, base_types, fractions, lists, iterators
66
from artiq.py2llvm.tools import is_terminated
77

88

@@ -177,14 +177,6 @@ def _visit_expr_Call(self, node):
177177
denominator = self.visit_expression(node.args[1])
178178
r.set_value_nd(self.builder, numerator, denominator)
179179
return r
180-
elif fn == "array":
181-
element = self.visit_expression(node.args[0])
182-
if (isinstance(node.args[1], ast.Num)
183-
and isinstance(node.args[1].n, int)):
184-
count = node.args[1].n
185-
else:
186-
raise ValueError("Array size must be integer and constant")
187-
return arrays.VArray(element, count)
188180
elif fn == "range":
189181
return iterators.IRange(
190182
self.builder,
@@ -201,6 +193,56 @@ def _visit_expr_Attribute(self, node):
201193
value = self.visit_expression(node.value)
202194
return value.o_getattr(node.attr, self.builder)
203195

196+
def _visit_expr_List(self, node):
197+
elts = [self.visit_expression(elt) for elt in node.elts]
198+
if elts:
199+
el_type = elts[0].new()
200+
for elt in elts[1:]:
201+
el_type.merge(elt)
202+
else:
203+
el_type = VNone()
204+
count = len(elts)
205+
r = lists.VList(el_type, count)
206+
r.elts = elts
207+
return r
208+
209+
def _visit_expr_ListComp(self, node):
210+
if len(node.generators) != 1:
211+
raise NotImplementedError
212+
generator = node.generators[0]
213+
if not isinstance(generator, ast.comprehension):
214+
raise NotImplementedError
215+
if not isinstance(generator.target, ast.Name):
216+
raise NotImplementedError
217+
target = generator.target.id
218+
if not isinstance(generator.iter, ast.Call):
219+
raise NotImplementedError
220+
if not isinstance(generator.iter.func, ast.Name):
221+
raise NotImplementedError
222+
if generator.iter.func.id != "range":
223+
raise NotImplementedError
224+
if len(generator.iter.args) != 1:
225+
raise NotImplementedError
226+
if not isinstance(generator.iter.args[0], ast.Num):
227+
raise NotImplementedError
228+
count = generator.iter.args[0].n
229+
230+
# Prevent incorrect use of the generator target, if it is defined in
231+
# the local function namespace.
232+
if target in self.ns:
233+
old_target_val = self.ns[target]
234+
del self.ns[target]
235+
else:
236+
old_target_val = None
237+
elt = self.visit_expression(node.elt)
238+
if old_target_val is not None:
239+
self.ns[target] = old_target_val
240+
241+
el_type = elt.new()
242+
r = lists.VList(el_type, count)
243+
r.elt = elt
244+
return r
245+
204246
def _visit_expr_Subscript(self, node):
205247
value = self.visit_expression(node.value)
206248
if isinstance(node.slice, ast.Index):
@@ -227,9 +269,47 @@ def _bb_terminated(self):
227269

228270
def _visit_stmt_Assign(self, node):
229271
val = self.visit_expression(node.value)
230-
for target in node.targets:
231-
target = self.visit_expression(target)
232-
target.set_value(self.builder, val)
272+
if isinstance(node.value, ast.List):
273+
if len(node.targets) > 1:
274+
raise NotImplementedError
275+
target = self.visit_expression(node.targets[0])
276+
target.set_count(self.builder, val.alloc_count)
277+
for i, elt in enumerate(val.elts):
278+
idx = base_types.VInt()
279+
idx.set_const_value(self.builder, i)
280+
target.o_subscript(idx, self.builder).set_value(self.builder,
281+
elt)
282+
elif isinstance(node.value, ast.ListComp):
283+
if len(node.targets) > 1:
284+
raise NotImplementedError
285+
target = self.visit_expression(node.targets[0])
286+
target.set_count(self.builder, val.alloc_count)
287+
288+
i = base_types.VInt()
289+
i.alloca(self.builder)
290+
i.auto_store(self.builder, ll.Constant(ll.IntType(32), 0))
291+
292+
function = self.builder.basic_block.function
293+
copy_block = function.append_basic_block("ai_copy")
294+
end_block = function.append_basic_block("ai_end")
295+
self.builder.branch(copy_block)
296+
297+
self.builder.position_at_end(copy_block)
298+
target.o_subscript(i, self.builder).set_value(self.builder,
299+
val.elt)
300+
i.auto_store(self.builder, self.builder.add(
301+
i.auto_load(self.builder),
302+
ll.Constant(ll.IntType(32), 1)))
303+
cont = self.builder.icmp_signed(
304+
"<", i.auto_load(self.builder),
305+
ll.Constant(ll.IntType(32), val.alloc_count))
306+
self.builder.cbranch(cont, copy_block, end_block)
307+
308+
self.builder.position_at_end(end_block)
309+
else:
310+
for target in node.targets:
311+
target = self.visit_expression(target)
312+
target.set_value(self.builder, val)
233313

234314
def _visit_stmt_AugAssign(self, node):
235315
target = self.visit_expression(node.target)

‎artiq/py2llvm/lists.py

+52
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import llvmlite.ir as ll
2+
3+
from artiq.py2llvm.values import VGeneric
4+
5+
6+
class VList(VGeneric):
7+
def __init__(self, el_type, alloc_count):
8+
VGeneric.__init__(self)
9+
self.el_type = el_type
10+
self.alloc_count = alloc_count
11+
12+
def get_llvm_type(self):
13+
count = 0 if self.alloc_count is None else self.alloc_count
14+
return ll.LiteralStructType([ll.IntType(32),
15+
ll.ArrayType(self.el_type.get_llvm_type(),
16+
count)])
17+
18+
def __repr__(self):
19+
return "<VList:{} x{}>".format(
20+
repr(self.el_type),
21+
"?" if self.alloc_count is None else self.alloc_count)
22+
23+
def same_type(self, other):
24+
return (isinstance(other, VList)
25+
and self.el_type.same_type(other.el_type))
26+
27+
def merge(self, other):
28+
if isinstance(other, VList):
29+
self.el_type.merge(other.el_type)
30+
else:
31+
raise TypeError("Incompatible types: {} and {}"
32+
.format(repr(self), repr(other)))
33+
34+
def merge_subscript(self, other):
35+
self.el_type.merge(other)
36+
37+
def set_count(self, builder, count):
38+
count_ptr = builder.gep(self.llvm_value, [
39+
ll.Constant(ll.IntType(32), 0),
40+
ll.Constant(ll.IntType(32), 0)])
41+
builder.store(ll.Constant(ll.IntType(32), count), count_ptr)
42+
43+
def o_subscript(self, index, builder):
44+
r = self.el_type.new()
45+
if builder is not None:
46+
index = index.o_int(builder).auto_load(builder)
47+
ssa_r = builder.gep(self.llvm_value, [
48+
ll.Constant(ll.IntType(32), 0),
49+
ll.Constant(ll.IntType(32), 1),
50+
index])
51+
r.auto_store(builder, ssa_r)
52+
return r

‎artiq/py2llvm/values.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ def auto_store(self, builder, llvm_value):
3939
raise RuntimeError(
4040
"Attempted to set LLVM SSA value multiple times")
4141

42-
def alloca(self, builder, name):
42+
def alloca(self, builder, name=""):
4343
if self.llvm_value is not None:
4444
raise RuntimeError("Attempted to alloca existing LLVM value "+name)
4545
self.llvm_value = builder.alloca(self.get_llvm_type(), name=name)

‎artiq/test/py2llvm.py

+25-26
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@
77

88
import llvmlite.binding as llvm
99

10-
from artiq.language.core import int64, array
10+
from artiq.language.core import int64
1111
from artiq.py2llvm.infer_types import infer_function_types
12-
from artiq.py2llvm import base_types, arrays
12+
from artiq.py2llvm import base_types, lists
1313
from artiq.py2llvm.module import Module
1414

1515

@@ -71,22 +71,22 @@ def test_return(self):
7171
self.assertEqual(self.ns["return"].nbits, 64)
7272

7373

74-
def test_array_types():
75-
a = array(0, 5)
74+
def test_list_types():
75+
a = [0, 0, 0, 0, 0]
7676
for i in range(2):
7777
a[i] = int64(8)
7878
return a
7979

8080

81-
class FunctionArrayTypesCase(unittest.TestCase):
81+
class FunctionListTypesCase(unittest.TestCase):
8282
def setUp(self):
83-
self.ns = _build_function_types(test_array_types)
83+
self.ns = _build_function_types(test_list_types)
8484

85-
def test_array_types(self):
86-
self.assertIsInstance(self.ns["a"], arrays.VArray)
87-
self.assertIsInstance(self.ns["a"].el_init, base_types.VInt)
88-
self.assertEqual(self.ns["a"].el_init.nbits, 64)
89-
self.assertEqual(self.ns["a"].count, 5)
85+
def test_list_types(self):
86+
self.assertIsInstance(self.ns["a"], lists.VList)
87+
self.assertIsInstance(self.ns["a"].el_type, base_types.VInt)
88+
self.assertEqual(self.ns["a"].el_type.nbits, 64)
89+
self.assertEqual(self.ns["a"].alloc_count, 5)
9090
self.assertIsInstance(self.ns["i"], base_types.VInt)
9191
self.assertEqual(self.ns["i"].nbits, 32)
9292

@@ -212,20 +212,19 @@ def frac_arith_float_rev(op, a, b, x):
212212
return x / Fraction(a, b)
213213

214214

215-
def array_test():
216-
a = array(array(2, 5), 5)
217-
a[3][2] = 11
218-
a[4][1] = 42
219-
a[0][0] += 6
215+
def list_test():
216+
x = 80
217+
a = [3 for x in range(7)]
218+
b = [1, 2, 4, 5, 4, 0, 5]
219+
a[3] = x
220+
a[0] += 6
221+
a[1] = b[1] + b[2]
220222

221223
acc = 0
222-
for i in range(5):
223-
for j in range(5):
224-
if i + j == 2 or i + j == 1:
225-
continue
226-
if i and j and a[i][j]:
227-
acc += 1
228-
acc += a[i][j]
224+
for i in range(7):
225+
if i and a[i]:
226+
acc += 1
227+
acc += a[i]
229228
return acc
230229

231230

@@ -364,9 +363,9 @@ def test_frac_div_float(self):
364363
self._test_frac_arith_float(3, False)
365364
self._test_frac_arith_float(3, True)
366365

367-
def test_array(self):
368-
array_test_c = CompiledFunction(array_test, dict())
369-
self.assertEqual(array_test_c(), array_test())
366+
def test_list(self):
367+
list_test_c = CompiledFunction(list_test, dict())
368+
self.assertEqual(list_test_c(), list_test())
370369

371370
def test_corner_cases(self):
372371
corner_cases_c = CompiledFunction(corner_cases, dict())

‎artiq/transforms/tools.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
core_language.time_to_cycles, core_language.cycles_to_time,
1111
core_language.syscall,
1212
range, bool, int, float, round,
13-
core_language.int64, core_language.round64, core_language.array,
13+
core_language.int64, core_language.round64,
1414
Fraction, units.Quantity, units.check_unit, core_language.EncodedException
1515
)
1616
embeddable_func_names = {func.__name__ for func in embeddable_funcs}

‎doc/manual/getting_started.rst

+1-1
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ A number of Python algorithmic features can be used inside a kernel for compilat
6666
* 64-bit signed integers (:class:`artiq.language.core.int64`)
6767
* Signed rational numbers with 64-bit numerator and 64-bit denominator
6868
* Double-precision floating point numbers
69-
* Arrays of the above types and arrays of arrays, at an arbitrary depth (:class:`artiq.language.core.array`)
69+
* Lists of the above types. Lists of lists are not supported.
7070

7171
For a demonstration of some of these features, see the ``mandelbrot.py`` example.
7272

‎examples/photon_histogram.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ def cool_detect(self):
2323

2424
@kernel
2525
def run(self):
26-
hist = array(0, self.nbins)
26+
hist = [0 for _ in range (self.nbins)]
2727

2828
for i in range(self.repeats):
2929
n = self.cool_detect()

‎examples/transport.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ def one(self):
9494

9595
@kernel
9696
def repeat(self):
97-
hist = array(0, self.nbins)
97+
hist = [0 for _ in range(self.nbins)]
9898

9999
for i in range(self.repeats):
100100
n = self.one()

0 commit comments

Comments
 (0)
Please sign in to comment.