<filename>blaze/blir/exc.py
import sys
import time
import array
import ctypes
import numpy as np
from os.path import realpath, dirname, join
from types import ModuleType

from bind import wrap_llvm_module

import llvm.ee as le
from llvm.workaround.avx_support import detect_avx_support

any_type = ctypes.c_char_p

_nptypemap = {
    'c': ctypes.c_char,
    'b': ctypes.c_ubyte,
    'B': ctypes.c_byte,
    'h': ctypes.c_short,
    'H': ctypes.c_ushort,
    'i': ctypes.c_int,
    'I': ctypes.c_uint,
    'l': ctypes.c_long,
    'L': ctypes.c_ulong,
    'f': ctypes.c_float,
    'd': ctypes.c_double,
}

# limited for now
_pytypemap = {
    int   : ctypes.c_int,
    float : ctypes.c_float,
    bool  : ctypes.c_byte,
}

#------------------------------------------------------------------------
# Arguments
#------------------------------------------------------------------------

class Array(ctypes.Structure):
    _fields_ = [
        ("data"    , ctypes.c_void_p),
        ("nd"      , ctypes.c_int),
        ("strides" , ctypes.POINTER(ctypes.c_int)),
    ]

def fake_array(dataptr):
    dims = 1
    _strides = (8,)
    strides = (ctypes.c_int*dims)(*_strides)
    return Array(dataptr, 1, strides)

def array_decon(na):
    ctype = _nptypemap[na.dtype.char]
    _strides = ((s/na.dtype.itemsize) for s in na.strides)

    data = na.ctypes.data_as(ctypes.POINTER(ctype))
    dims = len(na.strides)
    strides = (ctypes.c_int*dims)(*_strides)
    return data, dims, strides

def adapt(arg, val):
    """
    Adapt arguments to pass to ExecutionEngine.
    """

    if isinstance(val, np.ndarray):
        ndarray = arg._type_ # auto-generated by bitey

        data, dims, strides = array_decon(val)
        return ndarray(data, dims, strides)

    elif isinstance(val, array.array):
        raise NotImplementedError

    elif isinstance(val, list):
        # Build an array from an iterable, not the best thing to
        # do performance-wise usually...
        ndarray = arg._type_ # auto-generated by bitey

        ctype = _pytypemap[type(val[0])]

        data = (ctype*len(val))(*val)
        dims = 1
        strides = (ctypes.c_int*1)(len(val))

        return ndarray(data, dims, strides)

    elif isinstance(val, (int, long, str, float)):
        return val

    elif isinstance(val, tuple):
        return arg._type_(*val)

    elif isinstance(val, ctypes.Structure):
        return ctypes.cast(ctypes.pointer(val), arg._type_)

    else:
        return ctypes.c_char_p(id(val))

def wrap_arguments(fn, args):
    if args:
        largs = map(adapt, fn.argtypes, args)
    else:
        largs = ()
    return largs

#------------------------------------------------------------------------
# Toplevel
#------------------------------------------------------------------------

class Context(object):

    def __init__(self, env, libs=None):
        self.destroyed = False
        libs = libs or ['prelude']

        for lib in libs:
            if 'darwin' in sys.platform:
                prelude = join(dirname(realpath(__file__)), lib + '.dylib')
            elif 'linux' in sys.platform:
                prelude = join(dirname(realpath(__file__)), lib+ '.so')
            else:
                raise NotImplementedError

            # XXX: yeah, don't do this
            ctypes._dlopen(prelude, ctypes.RTLD_GLOBAL)

        cgen = env['cgen']

        self.__namespace = cgen.globals
        self.__llmodule = cgen.module.clone()

        if not detect_avx_support():
            tc = le.TargetMachine.new(features='-avx', cm=le.CM_JITDEFAULT)
        else:
            tc = le.TargetMachine.new(features='', cm=le.CM_JITDEFAULT)

        eb = le.EngineBuilder.new(self.__llmodule)
        self.__engine = eb.create(tc)
        #self.__engine.run_function(cgen.globals['__module'], [])

        mod = ModuleType('blir_wrapper')
        wrap_llvm_module(cgen.module, self.__engine, mod)

        self.__mod = mod

    def lookup_fn(self, fname):
        return getattr(self.__mod, fname)

    def lookup_fnptr(self, fname):
        return self.__engine.get_pointer_to_function(self.__namespace[fname])

    @property
    def mod(self):
        return self.__mod

    def destroy(self):
        if not self.destroyed:
            del self.__engine
        else:
            raise RuntimeError("Context already destroyed")

#------------------------------------------------------------------------
# Execution
#------------------------------------------------------------------------

# mostly just delegates to Bitey because I don't feel like rolling a
# ctypes wrapper, this is just for debugging anyways so whatever.
def execute(ctx, args=None, fname=None, timing=False):

    args = args or ()

    try:
        lfn = ctx.lookup_fn(fname or 'main')
    except AttributeError:
        raise Exception, 'Compiled module has no toplevel function %s' % fname
    largs = wrap_arguments(lfn, args)

    if timing:
        start = time.time()

    res = None
    if len(lfn.argtypes) == 0:
        res = lfn()
    elif len(lfn.argtypes) == len(args):
        res = lfn(*largs)
    else:
        print 'Invalid number of arguments to main function.'

    if timing:
        print 'Time %.6f' % (time.time() - start)

    return res

<filename>blaze/blir/exc.py
import sys
import time
import array
import ctypes
import numpy as np
from os.path import realpath, dirname, join
from types import ModuleType

from bind import wrap_llvm_module

import llvm.ee as le
from llvm.workaround.avx_support import detect_avx_support

any_type = ctypes.c_char_p

_nptypemap = {
    'c': ctypes.c_char,
    'b': ctypes.c_ubyte,
    'B': ctypes.c_byte,
    'h': ctypes.c_short,
    'H': ctypes.c_ushort,
    'i': ctypes.c_int,
    'I': ctypes.c_uint,
    'l': ctypes.c_long,
    'L': ctypes.c_ulong,
    'f': ctypes.c_float,
    'd': ctypes.c_double,
}

# limited for now
_pytypemap = {
    int   : ctypes.c_int,
    float : ctypes.c_float,
    bool  : ctypes.c_byte,
}

#------------------------------------------------------------------------
# Arguments
#------------------------------------------------------------------------

class Array(ctypes.Structure):
    _fields_ = [
        ("data"    , ctypes.c_void_p),
        ("nd"      , ctypes.c_int),
        ("strides" , ctypes.POINTER(ctypes.c_int)),
    ]

def fake_array(dataptr):
    dims = 1
    _strides = (8,)
    strides = (ctypes.c_int*dims)(*_strides)
    return Array(dataptr, 1, strides)

def array_decon(na):
    ctype = _nptypemap[na.dtype.char]
    _strides = ((s/na.dtype.itemsize) for s in na.strides)

    data = na.ctypes.data_as(ctypes.POINTER(ctype))
    dims = len(na.strides)
    strides = (ctypes.c_int*dims)(*_strides)
    return data, dims, strides

def adapt(arg, val):
    """
    Adapt arguments to pass to ExecutionEngine.
    """

    if isinstance(val, np.ndarray):
        ndarray = arg._type_ # auto-generated by bitey

        data, dims, strides = array_decon(val)
        return ndarray(data, dims, strides)

    elif isinstance(val, array.array):
        raise NotImplementedError

    elif isinstance(val, list):
        # Build an array from an iterable, not the best thing to
        # do performance-wise usually...
        ndarray = arg._type_ # auto-generated by bitey

        ctype = _pytypemap[type(val[0])]

        data = (ctype*len(val))(*val)
        dims = 1
        strides = (ctypes.c_int*1)(len(val))

        return ndarray(data, dims, strides)

    elif isinstance(val, (int, long, str, float)):
        return val

    elif isinstance(val, tuple):
        return arg._type_(*val)

    elif isinstance(val, ctypes.Structure):
        return ctypes.cast(ctypes.pointer(val), arg._type_)

    else:
        return ctypes.c_char_p(id(val))

def wrap_arguments(fn, args):
    if args:
        largs = map(adapt, fn.argtypes, args)
    else:
        largs = ()
    return largs

#------------------------------------------------------------------------
# Toplevel
#------------------------------------------------------------------------

class Context(object):

    def __init__(self, env, libs=None):
        self.destroyed = False
        libs = libs or ['prelude']

        for lib in libs:
            if 'darwin' in sys.platform:
                prelude = join(dirname(realpath(__file__)), lib + '.dylib')
            elif 'linux' in sys.platform:
                prelude = join(dirname(realpath(__file__)), lib+ '.so')
            else:
                raise NotImplementedError

            # XXX: yeah, don't do this
            ctypes._dlopen(prelude, ctypes.RTLD_GLOBAL)

        cgen = env['cgen']

        self.__namespace = cgen.globals
        self.__llmodule = cgen.module.clone()

        if not detect_avx_support():
            tc = le.TargetMachine.new(features='-avx', cm=le.CM_JITDEFAULT)
        else:
            tc = le.TargetMachine.new(features='', cm=le.CM_JITDEFAULT)

        eb = le.EngineBuilder.new(self.__llmodule)
        self.__engine = eb.create(tc)
        #self.__engine.run_function(cgen.globals['__module'], [])

        mod = ModuleType('blir_wrapper')
        wrap_llvm_module(cgen.module, self.__engine, mod)

        self.__mod = mod

    def lookup_fn(self, fname):
        return getattr(self.__mod, fname)

    def lookup_fnptr(self, fname):
        return self.__engine.get_pointer_to_function(self.__namespace[fname])

    @property
    def mod(self):
        return self.__mod

    def destroy(self):
        if not self.destroyed:
            del self.__engine
        else:
            raise RuntimeError("Context already destroyed")

#------------------------------------------------------------------------
# Execution
#------------------------------------------------------------------------

# mostly just delegates to Bitey because I don't feel like rolling a
# ctypes wrapper, this is just for debugging anyways so whatever.
def execute(ctx, args=None, fname=None, timing=False):

    args = args or ()

    try:
        lfn = ctx.lookup_fn(fname or 'main')
    except AttributeError:
        raise Exception, 'Compiled module has no toplevel function %s' % fname
    largs = wrap_arguments(lfn, args)

    if timing:
        start = time.time()

    res = None
    if len(lfn.argtypes) == 0:
        res = lfn()
    elif len(lfn.argtypes) == len(args):
        res = lfn(*largs)
    else:
        print 'Invalid number of arguments to main function.'

    if timing:
        print 'Time %.6f' % (time.time() - start)

    return res

# limited for now #------------------------------------------------------------------------ # Arguments #------------------------------------------------------------------------ Adapt arguments to pass to ExecutionEngine. # auto-generated by bitey # Build an array from an iterable, not the best thing to # do performance-wise usually... # auto-generated by bitey #------------------------------------------------------------------------ # Toplevel #------------------------------------------------------------------------ # XXX: yeah, don't do this #self.__engine.run_function(cgen.globals['__module'], []) #------------------------------------------------------------------------ # Execution #------------------------------------------------------------------------ # mostly just delegates to Bitey because I don't feel like rolling a # ctypes wrapper, this is just for debugging anyways so whatever.