From 906db876a68ac0308203f145b3bed653b10493ba Mon Sep 17 00:00:00 2001 From: whitequark Date: Wed, 6 Jul 2016 04:44:21 +0000 Subject: [PATCH] language: replace coredevice int with numpy.{int32,int64}. Fixes #453. --- artiq/compiler/embedding.py | 10 +- artiq/compiler/transforms/inferencer.py | 24 +-- .../compiler/transforms/llvm_ir_generator.py | 4 +- artiq/coredevice/comm_generic.py | 6 +- artiq/coredevice/spi.py | 10 +- artiq/coredevice/ttl.py | 12 +- artiq/language/core.py | 147 +----------------- artiq/protocols/pyon.py | 4 - artiq/test/coredevice/test_embedding.py | 5 +- artiq/test/test_language.py | 44 ------ 10 files changed, 43 insertions(+), 223 deletions(-) delete mode 100644 artiq/test/test_language.py diff --git a/artiq/compiler/embedding.py b/artiq/compiler/embedding.py index a3b47e3c2..0bf9effd1 100644 --- a/artiq/compiler/embedding.py +++ b/artiq/compiler/embedding.py @@ -5,7 +5,7 @@ the references to the host objects and translates the functions annotated as ``@kernel`` when they are referenced. """ -import sys, os, re, linecache, inspect, textwrap, types as pytypes +import sys, os, re, linecache, inspect, textwrap, types as pytypes, numpy from collections import OrderedDict, defaultdict from pythonparser import ast, algorithm, source, diagnostic, parse_buffer @@ -165,8 +165,12 @@ class ASTSynthesizer: typ = builtins.TFloat() return asttyped.NumT(n=value, ctx=None, type=typ, loc=self._add(repr(value))) - elif isinstance(value, language_core.int): - typ = builtins.TInt(width=types.TValue(value.width)) + elif isinstance(value, numpy.int32): + typ = builtins.TInt32() + return asttyped.NumT(n=int(value), ctx=None, type=typ, + loc=self._add(repr(value))) + elif isinstance(value, numpy.int64): + typ = builtins.TInt64() return asttyped.NumT(n=int(value), ctx=None, type=typ, loc=self._add(repr(value))) elif isinstance(value, str): diff --git a/artiq/compiler/transforms/inferencer.py b/artiq/compiler/transforms/inferencer.py index 56eeeb9a0..f10552cbf 100644 --- a/artiq/compiler/transforms/inferencer.py +++ b/artiq/compiler/transforms/inferencer.py @@ -620,9 +620,9 @@ class Inferencer(algorithm.Visitor): node.loc, None) elif types.is_builtin(typ, "int"): valid_forms = lambda: [ - valid_form("int() -> int(width='a)"), - valid_form("int(x:'a) -> int(width='b) where 'a is numeric"), - valid_form("int(x:'a, width='b:) -> int(width='b) where 'a is numeric") + valid_form("int() -> numpy.int?"), + valid_form("int(x:'a) -> numpy.int?"), + valid_form("int(x:'a, width=?) -> numpy.int?") ] self._unify(node.type, builtins.TInt(), @@ -715,11 +715,11 @@ class Inferencer(algorithm.Visitor): diagnose(valid_forms()) elif types.is_builtin(typ, "range"): valid_forms = lambda: [ - valid_form("range(max:int(width='a)) -> range(elt=int(width='a))"), - valid_form("range(min:int(width='a), max:int(width='a)) " - "-> range(elt=int(width='a))"), - valid_form("range(min:int(width='a), max:int(width='a), " - "step:int(width='a)) -> range(elt=int(width='a))"), + valid_form("range(max:numpy.int?) -> range(elt=numpy.int?)"), + valid_form("range(min:numpy.int?, max:numpy.int?) " + "-> range(elt=numpy.int?)"), + valid_form("range(min:numpy.int?, max:numpy.int?, " + "step:numpy.int?) -> range(elt=numpy.int?)"), ] range_elt = builtins.TInt(types.TVar()) @@ -734,7 +734,7 @@ class Inferencer(algorithm.Visitor): diagnose(valid_forms()) elif types.is_builtin(typ, "len"): valid_forms = lambda: [ - valid_form("len(x:'a) -> int(width='b) where 'a is iterable"), + valid_form("len(x:'a) -> numpy.int?"), ] if len(node.args) == 1 and len(node.keywords) == 0: @@ -762,8 +762,8 @@ class Inferencer(algorithm.Visitor): diagnose(valid_forms()) elif types.is_builtin(typ, "round"): valid_forms = lambda: [ - valid_form("round(x:float) -> int(width='a)"), - valid_form("round(x:float, width='b:) -> int(width='b)") + valid_form("round(x:float) -> numpy.int?"), + valid_form("round(x:float, width=?) -> numpy.int?") ] self._unify(node.type, builtins.TInt(), @@ -793,7 +793,7 @@ class Inferencer(algorithm.Visitor): fn = typ.name valid_forms = lambda: [ - valid_form("{}(x:int(width='a), y:int(width='a)) -> int(width='a)".format(fn)), + valid_form("{}(x:numpy.int?, y:numpy.int?) -> numpy.int?".format(fn)), valid_form("{}(x:float, y:float) -> float".format(fn)) ] diff --git a/artiq/compiler/transforms/llvm_ir_generator.py b/artiq/compiler/transforms/llvm_ir_generator.py index b1d464dca..7e8a67e78 100644 --- a/artiq/compiler/transforms/llvm_ir_generator.py +++ b/artiq/compiler/transforms/llvm_ir_generator.py @@ -3,7 +3,7 @@ into LLVM intermediate representation. """ -import os, re, types as pytypes +import os, re, types as pytypes, numpy from collections import defaultdict from pythonparser import ast, diagnostic from llvmlite_artiq import ir as ll, binding as llvm @@ -1397,7 +1397,7 @@ class LLVMIRGenerator: assert value in (True, False) return ll.Constant(llty, value) elif builtins.is_int(typ): - assert isinstance(value, (int, language_core.int)) + assert isinstance(value, (int, numpy.int32, numpy.int64)) return ll.Constant(llty, int(value)) elif builtins.is_float(typ): assert isinstance(value, float) diff --git a/artiq/coredevice/comm_generic.py b/artiq/coredevice/comm_generic.py index 7a94f0459..09a5500db 100644 --- a/artiq/coredevice/comm_generic.py +++ b/artiq/coredevice/comm_generic.py @@ -1,12 +1,12 @@ import struct import logging import traceback +import numpy from enum import Enum from fractions import Fraction from collections import namedtuple from artiq.coredevice import exceptions -from artiq.language.core import int as wrapping_int from artiq import __version__ as software_version @@ -317,9 +317,9 @@ class CommGeneric: elif tag == "b": return bool(self._read_int8()) elif tag == "i": - return wrapping_int(self._read_int32(), 32) + return numpy.int32(self._read_int32()) elif tag == "I": - return wrapping_int(self._read_int64(), 64) + return numpy.int64(self._read_int64()) elif tag == "f": return self._read_float64() elif tag == "F": diff --git a/artiq/coredevice/spi.py b/artiq/coredevice/spi.py index 8edd08246..e2c551ff5 100644 --- a/artiq/coredevice/spi.py +++ b/artiq/coredevice/spi.py @@ -1,5 +1,7 @@ +import numpy + from artiq.language.core import (kernel, portable, seconds_to_mu, now_mu, - delay_mu, int, mu_to_seconds) + delay_mu, mu_to_seconds) from artiq.language.units import MHz from artiq.coredevice.rtio import rtio_output, rtio_input_data @@ -60,9 +62,9 @@ class SPIMaster: self.ref_period_mu = seconds_to_mu(self.core.coarse_ref_period, self.core) self.channel = channel - self.write_period_mu = int(0, 64) - self.read_period_mu = int(0, 64) - self.xfer_period_mu = int(0, 64) + self.write_period_mu = numpy.int64(0) + self.read_period_mu = numpy.int64(0) + self.xfer_period_mu = numpy.int64(0) @portable def frequency_to_div(self, f): diff --git a/artiq/coredevice/ttl.py b/artiq/coredevice/ttl.py index 2052e4dc3..305cb6873 100644 --- a/artiq/coredevice/ttl.py +++ b/artiq/coredevice/ttl.py @@ -1,3 +1,5 @@ +import numpy + from artiq.language.core import * from artiq.language.types import * from artiq.coredevice.rtio import rtio_output, rtio_input_timestamp @@ -17,7 +19,7 @@ class TTLOut: self.channel = channel # in RTIO cycles - self.o_previous_timestamp = int(0, width=64) + self.o_previous_timestamp = numpy.int64(0) @kernel def output(self): @@ -101,8 +103,8 @@ class TTLInOut: self.channel = channel # in RTIO cycles - self.o_previous_timestamp = int(0, width=64) - self.i_previous_timestamp = int(0, width=64) + self.o_previous_timestamp = numpy.int64(0) + self.i_previous_timestamp = numpy.int64(0) @kernel def set_oe(self, oe): @@ -282,8 +284,8 @@ class TTLClockGen: self.channel = channel # in RTIO cycles - self.previous_timestamp = int(0, width=64) - self.acc_width = int(24, width=64) + self.previous_timestamp = numpy.int64(0) + self.acc_width = numpy.int64(24) @portable def frequency_to_ftw(self, frequency): diff --git a/artiq/language/core.py b/artiq/language/core.py index c8a15c00f..85660ab55 100644 --- a/artiq/language/core.py +++ b/artiq/language/core.py @@ -4,10 +4,10 @@ Core ARTIQ extensions to the Python language. from collections import namedtuple from functools import wraps +import numpy -__all__ = ["host_int", "int", "host_round", "round", - "kernel", "portable", "syscall", "host_only", +__all__ = ["kernel", "portable", "syscall", "host_only", "set_time_manager", "set_watchdog_factory", "TerminationRequested"] @@ -20,147 +20,6 @@ kernel_globals = ( ) __all__.extend(kernel_globals) -host_int = int - -class int: - """ - Arbitrary-precision integers for static compilation. - - The static compiler does not use unlimited-precision integers, - like Python normally does, because of their unbounded memory requirements. - Instead, it allows to choose a bit width (usually 32 or 64) at compile-time, - and all computations follow wrap-around semantics on overflow. - - This class implements the same semantics on the host. - - For example: - - >>> a = int(1, width=64) - >>> b = int(3, width=64) + 2 - >>> isinstance(a, int) - True - >>> isinstance(b, int) - True - >>> a + b - int(6, width=64) - >>> int(10, width=32) + 0x7fffffff - int(9, width=32) - >>> int(0x80000000) - int(-2147483648, width=32) - """ - - __slots__ = ['_value', '_width'] - - def __new__(cls, value, width=32): - if isinstance(value, int): - return value - else: - sign_bit = 2 ** (width - 1) - value = host_int(value) - if value & sign_bit: - value = -1 & ~sign_bit + (value & (sign_bit - 1)) + 1 - else: - value &= sign_bit - 1 - - self = super().__new__(cls) - self._value = value - self._width = width - return self - - @property - def width(self): - return self._width - - def __int__(self): - return self._value - - def __float__(self): - return float(self._value) - - def __str__(self): - return str(self._value) - - # range() etc call __index__, not __int__ - def __index__(self): - return self._value - - def __repr__(self): - return "int({}, width={})".format(self._value, self._width) - - def _unaryop(lower_fn): - def operator(self): - return int(lower_fn(self._value), self._width) - return operator - - __neg__ = _unaryop(host_int.__neg__) - __pos__ = _unaryop(host_int.__pos__) - __abs__ = _unaryop(host_int.__abs__) - __invert__ = _unaryop(host_int.__invert__) - __round__ = _unaryop(host_int.__round__) - - def _binaryop(lower_fn, rlower_fn=None): - def operator(self, other): - if isinstance(other, host_int): - return int(lower_fn(self._value, other), self._width) - elif isinstance(other, int): - width = self._width if self._width > other._width else other._width - return int(lower_fn(self._value, other._value), width) - elif rlower_fn: - return getattr(other, rlower_fn)(self._value) - else: - return NotImplemented - return operator - - __add__ = __iadd__ = _binaryop(host_int.__add__, "__radd__") - __sub__ = __isub__ = _binaryop(host_int.__sub__, "__rsub__") - __mul__ = __imul__ = _binaryop(host_int.__mul__, "__rmul__") - __truediv__ = __itruediv__ = _binaryop(host_int.__truediv__, "__rtruediv__") - __floordiv__ = __ifloordiv__ = _binaryop(host_int.__floordiv__, "__rfloordiv__") - __mod__ = __imod__ = _binaryop(host_int.__mod__, "__rmod__") - __pow__ = __ipow__ = _binaryop(host_int.__pow__, "__rpow__") - - __radd__ = _binaryop(host_int.__radd__, "__add__") - __rsub__ = _binaryop(host_int.__rsub__, "__sub__") - __rmul__ = _binaryop(host_int.__rmul__, "__mul__") - __rfloordiv__ = _binaryop(host_int.__rfloordiv__, "__floordiv__") - __rtruediv__ = _binaryop(host_int.__rtruediv__, "__truediv__") - __rmod__ = _binaryop(host_int.__rmod__, "__mod__") - __rpow__ = _binaryop(host_int.__rpow__, "__pow__") - - __lshift__ = __ilshift__ = _binaryop(host_int.__lshift__) - __rshift__ = __irshift__ = _binaryop(host_int.__rshift__) - __and__ = __iand__ = _binaryop(host_int.__and__) - __or__ = __ior__ = _binaryop(host_int.__or__) - __xor__ = __ixor__ = _binaryop(host_int.__xor__) - - __rlshift__ = _binaryop(host_int.__rlshift__) - __rrshift__ = _binaryop(host_int.__rrshift__) - __rand__ = _binaryop(host_int.__rand__) - __ror__ = _binaryop(host_int.__ror__) - __rxor__ = _binaryop(host_int.__rxor__) - - def _compareop(lower_fn, rlower_fn): - def operator(self, other): - if isinstance(other, host_int): - return lower_fn(self._value, other) - elif isinstance(other, int): - return lower_fn(self._value, other._value) - else: - return getattr(other, rlower_fn)(self._value) - return operator - - __eq__ = _compareop(host_int.__eq__, "__ne__") - __ne__ = _compareop(host_int.__ne__, "__eq__") - __gt__ = _compareop(host_int.__gt__, "__le__") - __ge__ = _compareop(host_int.__ge__, "__lt__") - __lt__ = _compareop(host_int.__lt__, "__ge__") - __le__ = _compareop(host_int.__le__, "__gt__") - -host_round = round - -def round(value, width=32): - return int(host_round(value), width) - _ARTIQEmbeddedInfo = namedtuple("_ARTIQEmbeddedInfo", "core_name function syscall forbidden flags") @@ -342,7 +201,7 @@ def seconds_to_mu(seconds, core=None): """ if core is None: raise ValueError("Core device must be specified for time conversion") - return round(seconds//core.ref_period, width=64) + return numpy.int64(seconds//core.ref_period) def mu_to_seconds(mu, core=None): diff --git a/artiq/protocols/pyon.py b/artiq/protocols/pyon.py index 20a89e355..092e46b52 100644 --- a/artiq/protocols/pyon.py +++ b/artiq/protocols/pyon.py @@ -25,8 +25,6 @@ import tempfile import numpy -from ..language.core import int as wrapping_int - _encode_map = { type(None): "none", @@ -41,7 +39,6 @@ _encode_map = { set: "set", dict: "dict", slice: "slice", - wrapping_int: "number", Fraction: "fraction", OrderedDict: "ordereddict", numpy.ndarray: "nparray" @@ -192,7 +189,6 @@ _eval_dict = { "true": True, "slice": slice, - "int": wrapping_int, "Fraction": Fraction, "OrderedDict": OrderedDict, "nparray": _nparray, diff --git a/artiq/test/coredevice/test_embedding.py b/artiq/test/coredevice/test_embedding.py index 9fd4410a2..8ae19fd47 100644 --- a/artiq/test/coredevice/test_embedding.py +++ b/artiq/test/coredevice/test_embedding.py @@ -1,3 +1,4 @@ +import numpy from time import sleep from artiq.experiment import * @@ -28,8 +29,8 @@ class RoundtripTest(ExperimentCase): self.assertRoundtrip(False) def test_int(self): - self.assertRoundtrip(42) - self.assertRoundtrip(int(42, width=64)) + self.assertRoundtrip(numpy.int32(42)) + self.assertRoundtrip(numpy.int64(42)) def test_float(self): self.assertRoundtrip(42.0) diff --git a/artiq/test/test_language.py b/artiq/test/test_language.py deleted file mode 100644 index 103df4569..000000000 --- a/artiq/test/test_language.py +++ /dev/null @@ -1,44 +0,0 @@ -import unittest - -from artiq.language.core import * - - -class LanguageCoreTest(unittest.TestCase): - def test_unary(self): - self.assertEqual(int(10), +int(10)) - self.assertEqual(int(-10), -int(10)) - self.assertEqual(int(~10), ~int(10)) - self.assertEqual(int(10), round(int(10))) - - def test_arith(self): - self.assertEqual(int(9), int(4) + int(5)) - self.assertEqual(int(9), int(4) + 5) - self.assertEqual(int(9), 5 + int(4)) - - self.assertEqual(9.0, int(4) + 5.0) - self.assertEqual(9.0, 5.0 + int(4)) - - a = int(5) - a += int(2) - a += 2 - self.assertEqual(int(9), a) - - def test_compare(self): - self.assertTrue(int(9) > int(8)) - self.assertTrue(int(9) > 8) - self.assertTrue(int(9) > 8.0) - self.assertTrue(9 > int(8)) - self.assertTrue(9.0 > int(8)) - - def test_bitwise(self): - self.assertEqual(int(0x100), int(0x10) << int(4)) - self.assertEqual(int(0x100), int(0x10) << 4) - self.assertEqual(int(0x100), 0x10 << int(4)) - - def test_wraparound(self): - self.assertEqual(int(0xffffffff), int(-1)) - self.assertTrue(int(0x7fffffff) > int(1)) - self.assertTrue(int(0x80000000) < int(-1)) - - self.assertEqual(int(9), int(10) + int(0xffffffff)) - self.assertEqual(-1.0, float(int(0xfffffffe) + int(1)))