language: replace coredevice int with numpy.{int32,int64}.

Fixes #453.
This commit is contained in:
whitequark 2016-07-06 04:44:21 +00:00
parent fa71b40c80
commit 906db876a6
10 changed files with 43 additions and 223 deletions

View File

@ -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):

View File

@ -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 literal>) -> 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 literal>) -> 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))
]

View File

@ -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)

View File

@ -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":

View File

@ -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):

View File

@ -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):

View File

@ -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):

View File

@ -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,

View File

@ -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)

View File

@ -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)))