Skip to content

Commit

Permalink
Merge branch 'subtree'
Browse files Browse the repository at this point in the history
  • Loading branch information
markflorisson committed Oct 21, 2012
2 parents 82ef7bd + 421ae88 commit d9a3743
Show file tree
Hide file tree
Showing 8 changed files with 155 additions and 48 deletions.
33 changes: 18 additions & 15 deletions minivect/complex_support.py
@@ -1,6 +1,4 @@
import ctypes
import numpy as np

from miniutils import ctypes
from minitypes import *

### Taken from Numba ###
Expand Down Expand Up @@ -45,19 +43,24 @@ def _complex_result_wrapper(*args, **kws):
return _complex_result_wrapper
return _make_complex_result_wrapper

class Complex64(ctypes.Structure, ComplexMixin):
_fields_ = [('real', ctypes.c_float), ('imag', ctypes.c_float)]
_numpy_ty_ = np.complex64
try:
import numpy as np
except ImportError:
pass
else:
class Complex64(ctypes.Structure, ComplexMixin):
_fields_ = [('real', ctypes.c_float), ('imag', ctypes.c_float)]
_numpy_ty_ = np.complex64

class Complex128(ctypes.Structure, ComplexMixin):
_fields_ = [('real', ctypes.c_double), ('imag', ctypes.c_double)]
_numpy_ty_ = np.complex128
class Complex128(ctypes.Structure, ComplexMixin):
_fields_ = [('real', ctypes.c_double), ('imag', ctypes.c_double)]
_numpy_ty_ = np.complex128

if hasattr(np, 'complex256'):
class Complex256(ctypes.Structure, ComplexMixin):
_fields_ = [('real', ctypes.c_longdouble), ('imag', ctypes.c_longdouble)]
_numpy_ty_ = np.complex256
else:
Complex256 = None
if hasattr(np, 'complex256'):
class Complex256(ctypes.Structure, ComplexMixin):
_fields_ = [('real', ctypes.c_longdouble), ('imag', ctypes.c_longdouble)]
_numpy_ty_ = np.complex256
else:
Complex256 = None

### End Taken from Numba ###
8 changes: 5 additions & 3 deletions minivect/ctypes_conversion.py
Expand Up @@ -4,9 +4,12 @@
"""

import math

from miniutils import ctypes
from minitypes import *

try:
from ctypes import *
_ctypes_func_type = type(ctypes.CFUNCTYPE(ctypes.c_int))
_ctypes_pointer_type = type(ctypes.POINTER(ctypes.c_int))
_ctypes_array_type = type(ctypes.c_int * 2)
Expand Down Expand Up @@ -98,8 +101,7 @@ def convert_from_ctypes(type):
"""
Convert a ctypes type to a minitype
"""
from minitypes import *
from ctypes import *
import ctypes

ctypes_map = {
c_char : char,
Expand Down Expand Up @@ -130,7 +132,7 @@ def convert_from_ctypes(type):
return ctypes_map[type]
elif isinstance(type, _ctypes_ptr_type):
return convert_from_ctypes(type._type_).pointer()
elif isinstance(type, _ctypes_ptr_type):
elif isinstance(type, _ctypes_array_type):
base_type = convert_from_ctypes(type._type_)
return CArrayType(base_type, type._length_)
elif isinstance(type, _ctypes_func_type):
Expand Down
7 changes: 5 additions & 2 deletions minivect/miniast.py
Expand Up @@ -304,6 +304,9 @@ def graphviz(self, node, graphviz_name="AST"):
graphviz_graph = visitor.visit(node)
return graphviz_graph.to_string()

def is_object(self, type):
return isinstance(type, minitypes.ObjectType)

class CContext(Context):
"Set defaults for C code generation."

Expand Down Expand Up @@ -339,9 +342,9 @@ def __init__(self, context):
def _infer_type(self, value):
"Used to infer types for self.constant()"
if isinstance(value, (int, long)):
return minitypes.IntType()
return minitypes.long_
elif isinstance(value, float):
return minitypes.FloatType()
return minitypes.double
elif isinstance(value, str):
return minitypes.CStringType()
else:
Expand Down
142 changes: 120 additions & 22 deletions minivect/minitypes.py
Expand Up @@ -165,7 +165,7 @@ def promote_arrays(self, type1, type2):
"Promote two array types in an expression to a new array type"
equal_ndim = type1.ndim == type2.ndim
return ArrayType(self.promote_types(type1.dtype, type2.dtype),
ndim=miniutils.max(type1.ndim, type2.ndim),
ndim=miniutils.max((type1.ndim, type2.ndim)),
is_c_contig=(equal_ndim and type1.is_c_contig and
type2.is_c_contig),
is_f_contig=(equal_ndim and type1.is_f_contig and
Expand Down Expand Up @@ -207,7 +207,7 @@ def map_dtype(dtype):
"""
import numpy as np

if dtype.byteorder not in ('=', nbo) and dtype.kind in ('iufbc'):
if dtype.byteorder not in ('=', nbo, '|') and dtype.kind in ('iufbc'):
raise minierror.UnmappableTypeError(
"Only native byteorder is supported", dtype)

Expand Down Expand Up @@ -237,7 +237,9 @@ def map_dtype(dtype):
elif dtype.kind == 'V':
fields = [(name, map_dtype(dtype.fields[name][0]))
for name in dtype.names]
return struct(fields, packed=not dtype.isalignedstruct)
is_aligned = dtype.alignment != 1
return struct(fields, packed=not getattr(dtype, 'isalignedstruct',
is_aligned))
elif dtype.kind == 'O':
return object_

Expand Down Expand Up @@ -362,6 +364,9 @@ def subtype_list(self):
def comparison_type_list(self):
return self.subtype_list

def _is_object(self, context):
return context.is_object(self)

def __eq__(self, other):
# Don't use isinstance here, compare on exact type to be consistent
# with __hash__. Override where sensible
Expand Down Expand Up @@ -433,6 +438,11 @@ def __getattr__(self, attr):
return False
return getattr(type(self), attr)

def __call__(self, *args):
"""Return a FunctionType with return_type and args set
"""
return FunctionType(self, args)

class ArrayType(Type):
"""
An array type. ArrayType may be sliced to obtain a subtype:
Expand Down Expand Up @@ -576,6 +586,8 @@ class NamedType(Type):
def __eq__(self, other):
return isinstance(other, NamedType) and self.name == other.name

__hash__ = Type.__hash__ # !@#$ py3k

def __repr__(self):
if self.qualifiers:
return "%s %s" % (self.name, " ".join(self.qualifiers))
Expand Down Expand Up @@ -616,9 +628,16 @@ class IntType(NumericType):
signed = True
rank = 4
itemsize = 4
typecode = None

kind = INT_KIND

def __init__(self, typecode=None, **kwds):
super(IntType, self).__init__(**kwds)
self.typecode = typecode
if typecode is not None:
self.itemsize = struct_.calcsize(typecode)

def to_llvm(self, context):
if self.itemsize == 1:
return lc.Type.int(8)
Expand Down Expand Up @@ -677,7 +696,7 @@ class Py_ssize_t_Type(IntType):

def __init__(self, **kwds):
super(Py_ssize_t_Type, self).__init__(**kwds)
self.itemsize = _plat_bits / 8
self.itemsize = getsize('c_ssize_t', _plat_bits // 8)

class NPyIntp(IntType):
is_numpy_intp = True
Expand Down Expand Up @@ -720,13 +739,25 @@ class ObjectType(Type):
def __repr__(self):
return "PyObject *"

def pass_by_ref(type):
return type.is_struct or type.is_complex

class FunctionType(Type):
subtypes = ['return_type', 'args']
is_function = True
is_vararg = False

struct_by_reference = False

def __init__(self, return_type, args, name=None, **kwds):
super(FunctionType, self).__init__(**kwds)
self.return_type = return_type
self.args = args
self.name = name

def to_llvm(self, context):
assert self.return_type is not None
self = self.actual_signature
return lc.Type.function(self.return_type.to_llvm(context),
[arg_type.to_llvm(context)
for arg_type in self.args],
Expand All @@ -736,8 +767,39 @@ def __str__(self):
args = map(str, self.args)
if self.is_vararg:
args.append("...")
if self.name:
namestr = self.name + ' '
else:
namestr = ''
return "%s%s (*)(%s)" % (namestr, self.return_type, ", ".join(args))

@property
def actual_signature(self):
"""
Passing structs by value is not properly supported for different
calling conventions in LLVM, so we take an extra argument
pointing to a caller-allocated struct value.
"""
if self.struct_by_reference:
args = []
for arg in self.args:
if pass_by_ref(arg):
arg = arg.pointer()
args.append(arg)

return "%s (*)(%s)" % (self.return_type, ", ".join(args))
return_type = self.return_type
if pass_by_ref(self.return_type):
return_type = void
args.append(self.return_type.pointer())

self = FunctionType(return_type, args)

return self

@property
def struct_return_type(self):
# Function returns a struct.
return self.return_type.pointer()

class VectorType(Type):
subtypes = ['element_type']
Expand Down Expand Up @@ -773,8 +835,8 @@ def __str__(self):
else:
raise NotImplementedError

def _sort_key(keyvalue):
field_name, field_type = keyvalue

def _sort_types_key(field_type):
if field_type.is_complex:
return field_type.base_type.rank * 2
elif field_type.is_numeric or field_type.is_struct:
Expand All @@ -788,6 +850,10 @@ def _sort_key(keyvalue):
else:
return 1

def _sort_key(keyvalue):
field_name, field_type = keyvalue
return _sort_types_key(field_type)

def sort_types(types_dict):
# reverse sort on rank, forward sort on name
d = {}
Expand Down Expand Up @@ -861,6 +927,12 @@ def to_llvm(self, context):
def comparison_type_list(self):
return self.fields

def getsize(ctypes_name, default):
try:
ctypes.sizeof(getattr(ctypes, ctypes_name))
except (ImportError, AttributeError):
return default

#
### Internal types
#
Expand All @@ -870,29 +942,29 @@ def comparison_type_list(self):
#
### Public types
#
Py_ssize_t = Py_ssize_t_Type()

try:
npy_intp = NPyIntp()
except ImportError:
npy_intp = None

size_t = IntType(name="size_t", rank=8.5, itemsize=8, signed=False)
char = CharType(name="char")
short = IntType(name="short", rank=2, itemsize=struct_.calcsize('h'))
int_ = IntType(name="int", rank=4, itemsize=struct_.calcsize('i'))
long_ = IntType(name="long", rank=5, itemsize=struct_.calcsize('l'))
longlong = IntType(name="PY_LONG_LONG", rank=8, itemsize=struct_.calcsize('q'))
Py_ssize_t = Py_ssize_t_Type()


uchar = CharType(name="unsigned char", signed=False)
size_t = IntType(name="size_t", rank=8.5,
itemsize=getsize('c_size_t', _plat_bits / 8), signed=False)
char = CharType(name="char", typecode='b')
short = IntType(name="short", rank=2, typecode='h')
int_ = IntType(name="int", rank=4, typecode='i')
long_ = IntType(name="long", rank=5, typecode='l')
longlong = IntType(name="PY_LONG_LONG", rank=8, typecode='q')

uchar = CharType(name="unsigned char", signed=False, typecode='B')
ushort = IntType(name="unsigned short", rank=2.5,
itemsize=struct_.calcsize('H'), signed=False)
uint = IntType(name="unsigned int", rank=4.5,
itemsize=struct_.calcsize('I'), signed=False)
ulong = IntType(name="unsigned long", rank=5.5,
itemsize=struct_.calcsize('L'), signed=False)
typecode='H', signed=False)
uint = IntType(name="unsigned int", rank=4.5, typecode='I', signed=False)
ulong = IntType(name="unsigned long", rank=5.5, typecode='L', signed=False)
ulonglong = IntType(name="unsigned PY_LONG_LONG", rank=8.5,
itemsize=struct_.calcsize('Q'), signed=False)
typecode='Q', signed=False)

bool_ = BoolType()
object_ = ObjectType()
Expand All @@ -919,6 +991,32 @@ def comparison_type_list(self):
complex256 = ComplexType(name="complex256", base_type=float128,
rank=20, itemsize=32)

integral = []
native_integral = []
floating = []
complextypes = []

for typename in __all__:
minitype = globals()[typename]
if minitype is None:
continue

if minitype.is_int:
integral.append(minitype)
elif minitype.is_float:
floating.append(minitype)
elif minitype.is_complex:
complextypes.append(minitype)

numeric = integral + floating + complextypes
native_integral.extend((Py_ssize_t, size_t))

integral.sort(key=_sort_types_key)
native_integral = [minitype for minitype in integral
if minitype.typecode is not None]
floating.sort(key=_sort_types_key)
complextypes.sort(key=_sort_types_key)

def get_utility():
import numpy

Expand Down
2 changes: 0 additions & 2 deletions minivect/miniutils.py
Expand Up @@ -31,8 +31,6 @@ def __getattr__(self, attr):
lc = UnavailableImport("llvm.core")

import treepath
import xmldumper
from xmldumper import etree, tostring

#
### Convenience utilities
Expand Down

0 comments on commit d9a3743

Please sign in to comment.