198 lines
4.8 KiB
Python
198 lines
4.8 KiB
Python
|
import sys
|
||
|
|
||
|
import numpy as np
|
||
|
|
||
|
import numba.core.typing.cffi_utils as cffi_support
|
||
|
from numba.tests.support import import_dynamic, temp_directory
|
||
|
from numba.core.types import complex128
|
||
|
|
||
|
|
||
|
def load_inline_module():
|
||
|
"""
|
||
|
Create an inline module, return the corresponding ffi and dll objects.
|
||
|
"""
|
||
|
from cffi import FFI
|
||
|
|
||
|
# We can't rely on libc availability on Windows anymore, so we use our
|
||
|
# own compiled wrappers (see https://bugs.python.org/issue23606).
|
||
|
|
||
|
defs = """
|
||
|
double _numba_test_sin(double x);
|
||
|
double _numba_test_cos(double x);
|
||
|
double _numba_test_funcptr(double (*func)(double));
|
||
|
bool _numba_test_boolean(void);
|
||
|
"""
|
||
|
|
||
|
ffi = FFI()
|
||
|
ffi.cdef(defs)
|
||
|
# Load the _helperlib namespace
|
||
|
from numba import _helperlib
|
||
|
return ffi, ffi.dlopen(_helperlib.__file__)
|
||
|
|
||
|
|
||
|
def load_ool_module():
|
||
|
"""
|
||
|
Compile an out-of-line module, return the corresponding ffi and
|
||
|
module objects.
|
||
|
"""
|
||
|
from cffi import FFI
|
||
|
|
||
|
numba_complex = """
|
||
|
typedef struct _numba_complex {
|
||
|
double real;
|
||
|
double imag;
|
||
|
} numba_complex;
|
||
|
"""
|
||
|
|
||
|
bool_define = """
|
||
|
#ifdef _MSC_VER
|
||
|
#define false 0
|
||
|
#define true 1
|
||
|
#define bool int
|
||
|
#else
|
||
|
#include <stdbool.h>
|
||
|
#endif
|
||
|
"""
|
||
|
|
||
|
defs = numba_complex + """
|
||
|
bool boolean(void);
|
||
|
double sin(double x);
|
||
|
double cos(double x);
|
||
|
int foo(int a, int b, int c);
|
||
|
void vsSin(int n, float* x, float* y);
|
||
|
void vdSin(int n, double* x, double* y);
|
||
|
void vector_real(numba_complex *c, double *real, int n);
|
||
|
void vector_imag(numba_complex *c, double *imag, int n);
|
||
|
"""
|
||
|
|
||
|
source = numba_complex + bool_define + """
|
||
|
static bool boolean(void)
|
||
|
{
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
static int foo(int a, int b, int c)
|
||
|
{
|
||
|
return a + b * c;
|
||
|
}
|
||
|
|
||
|
void vsSin(int n, float* x, float* y) {
|
||
|
int i;
|
||
|
for (i=0; i<n; i++)
|
||
|
y[i] = sin(x[i]);
|
||
|
}
|
||
|
|
||
|
void vdSin(int n, double* x, double* y) {
|
||
|
int i;
|
||
|
for (i=0; i<n; i++)
|
||
|
y[i] = sin(x[i]);
|
||
|
}
|
||
|
|
||
|
static void vector_real(numba_complex *c, double *real, int n) {
|
||
|
int i;
|
||
|
for (i = 0; i < n; i++)
|
||
|
real[i] = c[i].real;
|
||
|
}
|
||
|
|
||
|
static void vector_imag(numba_complex *c, double *imag, int n) {
|
||
|
int i;
|
||
|
for (i = 0; i < n; i++)
|
||
|
imag[i] = c[i].imag;
|
||
|
}
|
||
|
"""
|
||
|
|
||
|
ffi = FFI()
|
||
|
ffi.set_source('cffi_usecases_ool', source)
|
||
|
ffi.cdef(defs, override=True)
|
||
|
tmpdir = temp_directory('test_cffi')
|
||
|
ffi.compile(tmpdir=tmpdir)
|
||
|
sys.path.append(tmpdir)
|
||
|
try:
|
||
|
mod = import_dynamic('cffi_usecases_ool')
|
||
|
cffi_support.register_module(mod)
|
||
|
cffi_support.register_type(mod.ffi.typeof('struct _numba_complex'),
|
||
|
complex128)
|
||
|
return mod.ffi, mod
|
||
|
finally:
|
||
|
sys.path.remove(tmpdir)
|
||
|
|
||
|
|
||
|
def init():
|
||
|
"""
|
||
|
Initialize module globals. This can invoke external utilities, hence not
|
||
|
being executed implicitly at module import.
|
||
|
"""
|
||
|
global ffi, cffi_sin, cffi_cos, cffi_bool
|
||
|
|
||
|
if ffi is None:
|
||
|
ffi, dll = load_inline_module()
|
||
|
cffi_sin = dll._numba_test_sin
|
||
|
cffi_cos = dll._numba_test_cos
|
||
|
cffi_bool = dll._numba_test_boolean
|
||
|
del dll
|
||
|
|
||
|
def init_ool():
|
||
|
"""
|
||
|
Same as init() for OOL mode.
|
||
|
"""
|
||
|
global ffi_ool, cffi_sin_ool, cffi_cos_ool, cffi_foo, cffi_bool_ool
|
||
|
global vsSin, vdSin, vector_real, vector_imag
|
||
|
|
||
|
if ffi_ool is None:
|
||
|
ffi_ool, mod = load_ool_module()
|
||
|
cffi_sin_ool = mod.lib.sin
|
||
|
cffi_cos_ool = mod.lib.cos
|
||
|
cffi_foo = mod.lib.foo
|
||
|
cffi_bool_ool = mod.lib.boolean
|
||
|
vsSin = mod.lib.vsSin
|
||
|
vdSin = mod.lib.vdSin
|
||
|
vector_real = mod.lib.vector_real
|
||
|
vector_imag = mod.lib.vector_imag
|
||
|
del mod
|
||
|
|
||
|
ffi = ffi_ool = None
|
||
|
|
||
|
|
||
|
def use_cffi_sin(x):
|
||
|
return cffi_sin(x) * 2
|
||
|
|
||
|
def use_two_funcs(x):
|
||
|
return cffi_sin(x) - cffi_cos(x)
|
||
|
|
||
|
def use_cffi_sin_ool(x):
|
||
|
return cffi_sin_ool(x) * 2
|
||
|
|
||
|
def use_cffi_boolean_true():
|
||
|
return cffi_bool_ool()
|
||
|
|
||
|
def use_two_funcs_ool(x):
|
||
|
return cffi_sin_ool(x) - cffi_cos_ool(x)
|
||
|
|
||
|
def use_func_pointer(fa, fb, x):
|
||
|
if x > 0:
|
||
|
return fa(x)
|
||
|
else:
|
||
|
return fb(x)
|
||
|
|
||
|
def use_user_defined_symbols():
|
||
|
return cffi_foo(1, 2, 3)
|
||
|
|
||
|
# The from_buffer method is member of cffi.FFI, and also of CompiledFFI objects
|
||
|
# (cffi_usecases_ool.ffi is a CompiledFFI object) so we use both in these
|
||
|
# functions.
|
||
|
|
||
|
def vector_sin_float32(x, y):
|
||
|
vsSin(len(x), ffi.from_buffer(x), ffi_ool.from_buffer(y))
|
||
|
|
||
|
def vector_sin_float64(x, y):
|
||
|
vdSin(len(x), ffi.from_buffer(x), ffi_ool.from_buffer(y))
|
||
|
|
||
|
|
||
|
# For testing pointer to structs from buffers
|
||
|
|
||
|
def vector_extract_real(x, y):
|
||
|
vector_real(ffi.from_buffer(x), ffi.from_buffer(y), len(x))
|
||
|
|
||
|
def vector_extract_imag(x, y):
|
||
|
vector_imag(ffi.from_buffer(x), ffi.from_buffer(y), len(x))
|