def raise_error(self, builder, api, status): """ Given a non-ok *status*, raise the corresponding Python exception. """ bbend = builder.function.append_basic_block() with builder.if_then(status.is_user_exc): # Unserialize user exception. # Make sure another error may not interfere. api.err_clear() exc = api.unserialize(status.excinfoptr) with cgutils.if_likely(builder, cgutils.is_not_null(builder, exc)): api.raise_object(exc) # steals ref builder.branch(bbend) with builder.if_then(status.is_stop_iteration): api.err_set_none("PyExc_StopIteration") builder.branch(bbend) with builder.if_then(status.is_python_exc): # Error already raised => nothing to do builder.branch(bbend) api.err_set_string("PyExc_SystemError", "unknown error when calling native function") builder.branch(bbend) builder.position_at_end(bbend)
def codegen(context, builder, signature, args): instance, = args # TODO: probably a more general way to do this second_element = builder.extract_value(instance, [1]) result = cgutils.is_not_null(builder, second_element) return result
def print_item_impl(context, builder, sig, args): """ Print a single native value by boxing it in a Python object and invoking the Python interpreter's print routine. """ ty, = sig.args val, = args pyapi = context.get_python_api(builder) if context.enable_nrt: context.nrt_incref(builder, ty, val) # XXX unfortunately, we don't have access to the env manager from here obj = pyapi.from_native_value(ty, val) with builder.if_else(cgutils.is_not_null(builder, obj), likely=True) as (if_ok, if_error): with if_ok: pyapi.print_object(obj) pyapi.decref(obj) with if_error: cstr = context.insert_const_string(builder.module, "the print() function") strobj = pyapi.string_from_string(cstr) pyapi.err_write_unraisable(strobj) pyapi.decref(strobj) res = context.get_dummy_value() return impl_ret_untracked(context, builder, sig.return_type, res)
def check_occurred(self): err_occurred = cgutils.is_not_null(self.builder, self.pyapi.err_occurred()) with cgutils.if_unlikely(self.builder, err_occurred): # FIXME: this should decref all live variables before returning self.return_exception_raised()
def print_item_impl(context, builder, sig, args): """ Print a single native value by boxing it in a Python object and invoking the Python interpreter's print routine. """ ty, = sig.args val, = args pyapi = context.get_python_api(builder) if context.enable_nrt: context.nrt.incref(builder, ty, val) # XXX unfortunately, we don't have access to the env manager from here obj = pyapi.from_native_value(ty, val) with builder.if_else(cgutils.is_not_null(builder, obj), likely=True) as (if_ok, if_error): with if_ok: pyapi.print_object(obj) pyapi.decref(obj) with if_error: cstr = context.insert_const_string(builder.module, "the print() function") strobj = pyapi.string_from_string(cstr) pyapi.err_write_unraisable(strobj) pyapi.decref(strobj) res = context.get_dummy_value() return impl_ret_untracked(context, builder, sig.return_type, res)
def set_iter_valid(self, state, item): iterstate = PyIterState(self.context, self.builder, ref=state) iterstate.valid = cgutils.as_bool_byte( self.builder, cgutils.is_not_null(self.builder, item)) with cgutils.if_unlikely(self.builder, self.is_null(item)): self.check_occurred()
def unbox_pandas_timestamp(typ, val, c): year_obj = c.pyapi.object_getattr_string(val, "year") month_obj = c.pyapi.object_getattr_string(val, "month") day_obj = c.pyapi.object_getattr_string(val, "day") hour_obj = c.pyapi.object_getattr_string(val, "hour") minute_obj = c.pyapi.object_getattr_string(val, "minute") second_obj = c.pyapi.object_getattr_string(val, "second") microsecond_obj = c.pyapi.object_getattr_string(val, "microsecond") nanosecond_obj = c.pyapi.object_getattr_string(val, "nanosecond") pd_timestamp = cgutils.create_struct_proxy(typ)(c.context, c.builder) pd_timestamp.year = c.pyapi.long_as_longlong(year_obj) pd_timestamp.month = c.pyapi.long_as_longlong(month_obj) pd_timestamp.day = c.pyapi.long_as_longlong(day_obj) pd_timestamp.hour = c.pyapi.long_as_longlong(hour_obj) pd_timestamp.minute = c.pyapi.long_as_longlong(minute_obj) pd_timestamp.second = c.pyapi.long_as_longlong(second_obj) pd_timestamp.microsecond = c.pyapi.long_as_longlong(microsecond_obj) pd_timestamp.nanosecond = c.pyapi.long_as_longlong(nanosecond_obj) c.pyapi.decref(year_obj) c.pyapi.decref(month_obj) c.pyapi.decref(day_obj) c.pyapi.decref(hour_obj) c.pyapi.decref(minute_obj) c.pyapi.decref(second_obj) c.pyapi.decref(microsecond_obj) c.pyapi.decref(nanosecond_obj) is_error = cgutils.is_not_null(c.builder, c.pyapi.err_occurred()) return NativeValue(pd_timestamp._getvalue(), is_error=is_error)
def box_dataframe(typ, val, c): context = c.context builder = c.builder n_cols = len(typ.columns) col_names = typ.columns arr_typs = typ.data dtypes = [a.dtype for a in arr_typs] # TODO: check Categorical dataframe = cgutils.create_struct_proxy(typ)(context, builder, value=val) col_arrs = [ builder.extract_value(dataframe.data, i) for i in range(n_cols) ] # df unboxed from Python has_parent = cgutils.is_not_null(builder, dataframe.parent) pyapi = c.pyapi # gil_state = pyapi.gil_ensure() # acquire GIL mod_name = context.insert_const_string(c.builder.module, "pandas") class_obj = pyapi.import_module_noblock(mod_name) df_obj = pyapi.call_method(class_obj, "DataFrame", ()) for i, cname, arr, arr_typ, dtype in zip(range(n_cols), col_names, col_arrs, arr_typs, dtypes): # df['cname'] = boxed_arr # TODO: datetime.date, DatetimeIndex? name_str = context.insert_const_string(c.builder.module, cname) cname_obj = pyapi.string_from_string(name_str) if dtype == string_type: arr_obj = box_str_arr(arr_typ, arr, c) elif isinstance(dtype, PDCategoricalDtype): arr_obj = box_categorical_array(arr_typ, arr, c) # context.nrt.incref(builder, arr_typ, arr) elif arr_typ == string_array_split_view_type: arr_obj = box_str_arr_split_view(arr_typ, arr, c) elif dtype == types.List(string_type): arr_obj = box_list(list_string_array_type, arr, c) # context.nrt.incref(builder, arr_typ, arr) # TODO required? # pyapi.print_object(arr_obj) else: arr_obj = box_array(arr_typ, arr, c) # TODO: is incref required? # context.nrt.incref(builder, arr_typ, arr) pyapi.object_setitem(df_obj, cname_obj, arr_obj) # pyapi.decref(arr_obj) pyapi.decref(cname_obj) # set df.index if necessary if typ.index != types.none: arr_obj = _box_series_data(typ.index.dtype, typ.index, dataframe.index, c) pyapi.object_setattr_string(df_obj, 'index', arr_obj) pyapi.decref(class_obj) # pyapi.gil_release(gil_state) # release GIL return df_obj
def set_iter_valid(self, state, item): iterstate = PyIterState(self.context, self.builder, ref=state) iterstate.valid = cgutils.as_bool_byte(self.builder, cgutils.is_not_null(self.builder, item)) with cgutils.if_unlikely(self.builder, self.is_null(item)): self.check_occurred()
def list_pack(self, items): n = len(items) seq = self.list_new(self.context.get_constant(types.intp, n)) not_null = cgutils.is_not_null(self.builder, seq) with cgutils.if_likely(self.builder, not_null): for i in range(n): idx = self.context.get_constant(types.intp, i) self.incref(items[i]) self.list_setitem(seq, idx, items[i]) return seq
def check_lapack_return(context, builder, res): """ Check the integer error return from one of the LAPACK wrappers in _helperlib.c. """ with builder.if_then(cgutils.is_not_null(builder, res), likely=False): # Those errors shouldn't happen, it's easier to just abort the process pyapi = context.get_python_api(builder) pyapi.gil_ensure() pyapi.fatal_error("LAPACK wrapper returned with an error")
def to_native_array(self, ary, typ): # TODO check matching dtype. # currently, mismatching dtype will still work and causes # potential memory corruption nativearycls = self.context.make_array(typ) nativeary = nativearycls(self.context, self.builder) aryptr = nativeary._getpointer() ptr = self.builder.bitcast(aryptr, self.voidptr) errcode = self.numba_array_adaptor(ary, ptr) failed = cgutils.is_not_null(self.builder, errcode) return self.builder.load(aryptr), failed
def store(retval): is_ok = cgutils.is_not_null(builder, retval) # If an error is raised by the object mode ufunc, it will # simply get caught by the Numpy ufunc machinery. with builder.if_then(is_ok, likely=True): # Unbox native = pyapi.to_native_value(signature.return_type, retval) assert native.cleanup is None # Store out.store_direct(native.value, builder.load(store_offset)) # Release owned reference pyapi.decref(retval)
def dict_pack(self, keyvalues): """ Args ----- keyvalues: iterable of (str, llvm.Value of PyObject*) """ dictobj = self.dict_new() not_null = cgutils.is_not_null(self.builder, dictobj) with cgutils.if_likely(self.builder, not_null): for k, v in keyvalues: self.dict_setitem_string(dictobj, k, v) return dictobj
def is_leap_year(builder, year_val): """ Return a predicate indicating whether *year_val* (offset by 1970) is a leap year. """ actual_year = builder.add(year_val, Constant.int(DATETIME64, 1970)) multiple_of_4 = cgutils.is_null( builder, builder.and_(actual_year, Constant.int(DATETIME64, 3))) not_multiple_of_100 = cgutils.is_not_null( builder, builder.srem(actual_year, Constant.int(DATETIME64, 100))) multiple_of_400 = cgutils.is_null( builder, builder.srem(actual_year, Constant.int(DATETIME64, 400))) return builder.and_(multiple_of_4, builder.or_(not_multiple_of_100, multiple_of_400))
def make_exception_switch(self, api, builder, status): """ Handle user exceptions. Unserialize the exception info and raise it. """ code = status.code # Handle user exceptions with cgutils.ifthen(builder, status.is_user_exc): exc = api.unserialize(status.excinfoptr) with cgutils.if_likely(builder, cgutils.is_not_null(builder, exc)): api.raise_object(exc) # steals ref builder.ret(api.get_null_object()) msg = "unknown error in native function: %s" % self.fndesc.mangled_name api.err_set_string("PyExc_SystemError", msg)
def to_native_array(self, typ, ary): # TODO check matching dtype. # currently, mismatching dtype will still work and causes # potential memory corruption voidptr = Type.pointer(Type.int(8)) nativearycls = self.context.make_array(typ) nativeary = nativearycls(self.context, self.builder) aryptr = nativeary._getpointer() ptr = self.builder.bitcast(aryptr, voidptr) errcode = self.numba_array_adaptor(ary, ptr) failed = cgutils.is_not_null(self.builder, errcode) with cgutils.if_unlikely(self.builder, failed): # TODO self.builder.unreachable() return self.builder.load(aryptr)
def unbox_datetime_date_array(typ, val, c): # n = object_length(c, val) #cgutils.printf(c.builder, "len %d\n", n) arr_typ = types.Array(types.intp, 1, 'C') out_arr = _empty_nd_impl(c.context, c.builder, arr_typ, [n]) with cgutils.for_range(c.builder, n) as loop: dt_date = sequence_getitem(c, val, loop.index) int_date = unbox_datetime_date(datetime_date_type, dt_date, c).value dataptr, shapes, strides = basic_indexing( c.context, c.builder, arr_typ, out_arr, (types.intp,), (loop.index,)) store_item(c.context, c.builder, arr_typ, int_date, dataptr) is_error = cgutils.is_not_null(c.builder, c.pyapi.err_occurred()) return NativeValue(out_arr._getvalue(), is_error=is_error)
def unbox_unicode_str(typ, obj, c): """ Convert a unicode str object to a native unicode structure. """ ok, data, length, kind = c.pyapi.string_as_string_size_and_kind(obj) uni_str = cgutils.create_struct_proxy(typ)(c.context, c.builder) uni_str.data = data uni_str.length = length uni_str.kind = kind uni_str.meminfo = c.pyapi.nrt_meminfo_new_from_pyobject( data, # the borrowed data pointer obj, # the owner pyobject; the call will incref it. ) uni_str.parent = obj is_error = cgutils.is_not_null(c.builder, c.pyapi.err_occurred()) return NativeValue(uni_str._getvalue(), is_error=is_error)
def unbox_str_series(typ, val, c): """ Unbox a Pandas String Series. We just redirect to StringArray implementation. """ dtype = StringArrayPayloadType() payload = cgutils.create_struct_proxy(dtype)(c.context, c.builder) string_array = c.context.make_helper(c.builder, typ) # function signature of string_array_from_sequence # we use void* instead of PyObject* fnty = lir.FunctionType(lir.VoidType(), [ lir.IntType(8).as_pointer(), lir.IntType(64).as_pointer(), lir.IntType(32).as_pointer().as_pointer(), lir.IntType(8).as_pointer().as_pointer(), lir.IntType(8).as_pointer().as_pointer(), ]) fn = c.builder.module.get_or_insert_function( fnty, name="string_array_from_sequence") c.builder.call(fn, [ val, string_array._get_ptr_by_name('num_items'), payload._get_ptr_by_name('offsets'), payload._get_ptr_by_name('data'), payload._get_ptr_by_name('null_bitmap'), ]) # the raw data is now copied to payload # The native representation is a proxy to the payload, we need to # get a proxy and attach the payload and meminfo meminfo, meminfo_data_ptr = construct_string_array(c.context, c.builder) c.builder.store(payload._getvalue(), meminfo_data_ptr) string_array.meminfo = meminfo string_array.offsets = payload.offsets string_array.data = payload.data string_array.null_bitmap = payload.null_bitmap string_array.num_total_chars = c.builder.zext( c.builder.load( c.builder.gep(string_array.offsets, [string_array.num_items])), lir.IntType(64)) # FIXME how to check that the returned size is > 0? is_error = cgutils.is_not_null(c.builder, c.pyapi.err_occurred()) return NativeValue(string_array._getvalue(), is_error=is_error)
def unbox_unicode_str(typ, obj, c): """ Convert a unicode str object to a native unicode structure. """ ok, data, length, kind, hashv = c.pyapi.string_as_string_size_and_kind(obj) uni_str = cgutils.create_struct_proxy(typ)(c.context, c.builder) uni_str.data = data uni_str.length = length uni_str.kind = kind uni_str.hash = hashv uni_str.meminfo = c.pyapi.nrt_meminfo_new_from_pyobject( data, # the borrowed data pointer obj, # the owner pyobject; the call will incref it. ) uni_str.parent = obj is_error = cgutils.is_not_null(c.builder, c.pyapi.err_occurred()) return NativeValue(uni_str._getvalue(), is_error=is_error)
def to_native_buffer(self, obj, typ): buf = self.alloca_buffer() res = self.get_buffer(obj, buf) is_error = cgutils.is_not_null(self.builder, res) nativearycls = self.context.make_array(typ) nativeary = nativearycls(self.context, self.builder) aryptr = nativeary._getpointer() with cgutils.if_likely(self.builder, self.builder.not_(is_error)): ptr = self.builder.bitcast(aryptr, self.voidptr) self.numba_buffer_adaptor(buf, ptr) def cleanup(): self.release_buffer(buf) return NativeValue(self.builder.load(aryptr), is_error=is_error, cleanup=cleanup)
def make_exception_switch(self, api, builder, status): """ Handle user exceptions. Unserialize the exception info and raise it. """ code = status.code # Handle user exceptions with builder.if_then(status.is_user_exc): exc = api.unserialize(status.excinfoptr) with cgutils.if_likely(builder, cgutils.is_not_null(builder, exc)): api.raise_object(exc) # steals ref builder.ret(api.get_null_object()) with builder.if_then(status.is_stop_iteration): api.err_set_none("PyExc_StopIteration") builder.ret(api.get_null_object()) msg = "unknown error in native function: %s" % self.fndesc.mangled_name api.err_set_string("PyExc_SystemError", msg)
def unbox_datetime_date(typ, val, c): year_obj = c.pyapi.object_getattr_string(val, "year") month_obj = c.pyapi.object_getattr_string(val, "month") day_obj = c.pyapi.object_getattr_string(val, "day") yll = c.pyapi.long_as_longlong(year_obj) mll = c.pyapi.long_as_longlong(month_obj) dll = c.pyapi.long_as_longlong(day_obj) nopython_date = c.builder.add(dll, c.builder.add(c.builder.shl(yll, lir.Constant(lir.IntType(64), 32)), c.builder.shl(mll, lir.Constant(lir.IntType(64), 16)))) c.pyapi.decref(year_obj) c.pyapi.decref(month_obj) c.pyapi.decref(day_obj) is_error = cgutils.is_not_null(c.builder, c.pyapi.err_occurred()) return NativeValue(nopython_date, is_error=is_error)
def unbox_range_index(typ, val, c): start_obj = c.pyapi.object_getattr_string(val, "start") stop_obj = c.pyapi.object_getattr_string(val, "stop") step_obj = c.pyapi.object_getattr_string(val, "step") # TODO: support range unboxing with reference to parent in Numba? range_index = cgutils.create_struct_proxy(typ)(c.context, c.builder) range_index_data = cgutils.create_struct_proxy(RangeIndexDataType)(c.context, c.builder) range_index_data.start = c.pyapi.long_as_longlong(start_obj) range_index_data.stop = c.pyapi.long_as_longlong(stop_obj) range_index_data.step = c.pyapi.long_as_longlong(step_obj) range_index.data = range_index_data._getvalue() if typ.is_named: name_obj = c.pyapi.object_getattr_string(val, "name") range_index.name = numba.unicode.unbox_unicode_str( types.unicode_type, name_obj, c).value c.pyapi.decref(name_obj) c.pyapi.decref(start_obj) c.pyapi.decref(stop_obj) c.pyapi.decref(step_obj) is_error = cgutils.is_not_null(c.builder, c.pyapi.err_occurred()) return NativeValue(range_index._getvalue(), is_error=is_error)
def to_native_value(self, obj, typ): builder = self.builder def c_api_error(): return cgutils.is_not_null(builder, self.err_occurred()) if isinstance(typ, types.Object) or typ == types.pyobject: return NativeValue(obj) elif typ == types.boolean: istrue = self.object_istrue(obj) zero = Constant.null(istrue.type) val = builder.icmp(lc.ICMP_NE, istrue, zero) return NativeValue(val, is_error=c_api_error()) elif isinstance(typ, types.Integer): val = self.to_native_int(obj, typ) return NativeValue(val, is_error=c_api_error()) elif typ == types.float32: fobj = self.number_float(obj) fval = self.float_as_double(fobj) self.decref(fobj) val = builder.fptrunc(fval, self.context.get_argument_type(typ)) return NativeValue(val, is_error=c_api_error()) elif typ == types.float64: fobj = self.number_float(obj) val = self.float_as_double(fobj) self.decref(fobj) return NativeValue(val, is_error=c_api_error()) elif typ in (types.complex128, types.complex64): cplxcls = self.context.make_complex(types.complex128) cplx = cplxcls(self.context, builder) pcplx = cplx._getpointer() ok = self.complex_adaptor(obj, pcplx) failed = cgutils.is_false(builder, ok) with cgutils.if_unlikely(builder, failed): self.err_set_string("PyExc_TypeError", "conversion to %s failed" % (typ,)) if typ == types.complex64: c64cls = self.context.make_complex(typ) c64 = c64cls(self.context, builder) freal = self.context.cast(builder, cplx.real, types.float64, types.float32) fimag = self.context.cast(builder, cplx.imag, types.float64, types.float32) c64.real = freal c64.imag = fimag return NativeValue(c64._getvalue(), is_error=failed) else: return NativeValue(cplx._getvalue(), is_error=failed) elif isinstance(typ, types.NPDatetime): val = self.extract_np_datetime(obj) return NativeValue(val, is_error=c_api_error()) elif isinstance(typ, types.NPTimedelta): val = self.extract_np_timedelta(obj) return NativeValue(val, is_error=c_api_error()) elif isinstance(typ, types.Record): buf = self.alloca_buffer() ptr = self.extract_record_data(obj, buf) is_error = cgutils.is_null(self.builder, ptr) ltyp = self.context.get_value_type(typ) val = builder.bitcast(ptr, ltyp) def cleanup(): self.release_buffer(buf) return NativeValue(val, cleanup=cleanup, is_error=is_error) elif isinstance(typ, types.Array): val, failed = self.to_native_array(obj, typ) return NativeValue(val, is_error=failed) elif isinstance(typ, types.Buffer): return self.to_native_buffer(obj, typ) elif isinstance(typ, types.Optional): return self.to_native_optional(obj, typ) elif isinstance(typ, (types.Tuple, types.UniTuple)): return self.to_native_tuple(obj, typ) elif isinstance(typ, types.Generator): return self.to_native_generator(obj, typ) elif isinstance(typ, types.ExternalFunctionPointer): if typ.get_pointer is not None: # Call get_pointer() on the object to get the raw pointer value ptrty = self.context.get_function_pointer_type(typ) ret = cgutils.alloca_once_value(builder, Constant.null(ptrty), name='fnptr') ser = self.serialize_object(typ.get_pointer) get_pointer = self.unserialize(ser) with cgutils.if_likely(builder, cgutils.is_not_null(builder, get_pointer)): intobj = self.call_function_objargs(get_pointer, (obj,)) self.decref(get_pointer) with cgutils.if_likely(builder, cgutils.is_not_null(builder, intobj)): ptr = self.long_as_voidptr(intobj) self.decref(intobj) builder.store(builder.bitcast(ptr, ptrty), ret) return NativeValue(builder.load(ret), is_error=c_api_error()) raise NotImplementedError("cannot convert %s to native value" % (typ,))
def box_str_arr_split_view(typ, val, c): context = c.context builder = c.builder sp_view = context.make_helper(builder, string_array_split_view_type, val) # create array of objects with num_items shape mod_name = c.context.insert_const_string(c.builder.module, "numpy") np_class_obj = c.pyapi.import_module_noblock(mod_name) dtype = c.pyapi.object_getattr_string(np_class_obj, 'object_') l_num_items = builder.sext(sp_view.num_items, c.pyapi.longlong) num_items_obj = c.pyapi.long_from_longlong(l_num_items) out_arr = c.pyapi.call_method(np_class_obj, "ndarray", (num_items_obj, dtype)) # Array setitem call arr_get_fnty = LLType.function( lir.IntType(8).as_pointer(), [c.pyapi.pyobj, c.pyapi.py_ssize_t]) arr_get_fn = c.pyapi._get_function(arr_get_fnty, name="array_getptr1") arr_setitem_fnty = LLType.function( lir.VoidType(), [c.pyapi.pyobj, lir.IntType(8).as_pointer(), c.pyapi.pyobj]) arr_setitem_fn = c.pyapi._get_function(arr_setitem_fnty, name="array_setitem") # for each string with cgutils.for_range(builder, sp_view.num_items) as loop: str_ind = loop.index # start and end offset of string's list in index_offsets # sp_view.index_offsets[str_ind] list_start_offset = builder.sext( builder.load(builder.gep(sp_view.index_offsets, [str_ind])), lir.IntType(64)) # sp_view.index_offsets[str_ind+1] list_end_offset = builder.sext( builder.load( builder.gep(sp_view.index_offsets, [builder.add(str_ind, str_ind.type(1))])), lir.IntType(64)) # cgutils.printf(builder, "%d %d\n", list_start, list_end) # Build a new Python list nitems = builder.sub(list_end_offset, list_start_offset) nitems = builder.sub(nitems, nitems.type(1)) # cgutils.printf(builder, "str %lld n %lld\n", str_ind, nitems) list_obj = c.pyapi.list_new(nitems) with c.builder.if_then(cgutils.is_not_null(c.builder, list_obj), likely=True): with cgutils.for_range(c.builder, nitems) as loop: # data_offsets of current list start_index = builder.add(list_start_offset, loop.index) data_start = builder.load( builder.gep(sp_view.data_offsets, [start_index])) # add 1 since starts from -1 data_start = builder.add(data_start, data_start.type(1)) data_end = builder.load( builder.gep( sp_view.data_offsets, [builder.add(start_index, start_index.type(1))])) # cgutils.printf(builder, "ind %lld %lld\n", data_start, data_end) data_ptr = builder.gep(builder.extract_value(sp_view.data, 0), [data_start]) str_size = builder.sext(builder.sub(data_end, data_start), lir.IntType(64)) str_obj = c.pyapi.string_from_string_and_size( data_ptr, str_size) c.pyapi.list_setitem(list_obj, loop.index, str_obj) arr_ptr = builder.call(arr_get_fn, [out_arr, str_ind]) builder.call(arr_setitem_fn, [out_arr, arr_ptr, list_obj]) c.pyapi.decref(np_class_obj) return out_arr
def _emit_python_wrapper(self, llvm_module): # Figure out the Python C API module creation function, and # get a LLVM function for it. create_module_fn = llvm_module.add_function(*self.module_create_definition) create_module_fn.linkage = lc.LINKAGE_EXTERNAL # Define a constant string for the module name. mod_name_const = self.context.insert_const_string(llvm_module, self.module_name) mod_def_base_init = lc.Constant.struct( (lt._pyobject_head_init, # PyObject_HEAD lc.Constant.null(self.m_init_ty), # m_init lc.Constant.null(lt._llvm_py_ssize_t), # m_index lc.Constant.null(lt._pyobject_head_p), # m_copy ) ) mod_def_base = llvm_module.add_global_variable(mod_def_base_init.type, '.module_def_base') mod_def_base.initializer = mod_def_base_init mod_def_base.linkage = lc.LINKAGE_INTERNAL method_array = self._emit_method_array(llvm_module) mod_def_init = lc.Constant.struct( (mod_def_base_init, # m_base mod_name_const, # m_name lc.Constant.null(self._char_star), # m_doc lc.Constant.int(lt._llvm_py_ssize_t, -1), # m_size method_array, # m_methods lc.Constant.null(self.inquiry_ty), # m_reload lc.Constant.null(self.traverseproc_ty), # m_traverse lc.Constant.null(self.inquiry_ty), # m_clear lc.Constant.null(self.freefunc_ty) # m_free ) ) # Define a constant string for the module name. mod_def = llvm_module.add_global_variable(mod_def_init.type, '.module_def') mod_def.initializer = mod_def_init mod_def.linkage = lc.LINKAGE_INTERNAL # Define the module initialization function. mod_init_fn = llvm_module.add_function(*self.module_init_definition) entry = mod_init_fn.append_basic_block('Entry') builder = lc.Builder(entry) pyapi = self.context.get_python_api(builder) mod = builder.call(create_module_fn, (mod_def, lc.Constant.int(lt._int32, sys.api_version))) # Test if module has been created correctly. # (XXX for some reason comparing with the NULL constant fails llvm # with an assertion in pydebug mode) with builder.if_then(cgutils.is_null(builder, mod)): builder.ret(NULL.bitcast(mod_init_fn.type.pointee.return_type)) env_array = self._emit_environment_array(llvm_module, builder, pyapi) ret = self._emit_module_init_code(llvm_module, builder, mod, method_array, env_array) if ret is not None: with builder.if_then(cgutils.is_not_null(builder, ret)): # Init function errored out builder.ret(lc.Constant.null(mod.type)) builder.ret(mod) self.dll_exports.append(mod_init_fn.name)
def c_api_error(self): return cgutils.is_not_null(self.builder, self.err_occurred())
def check_occurred(self): err_occurred = cgutils.is_not_null(self.builder, self.pyapi.err_occurred()) with cgutils.if_unlikely(self.builder, err_occurred): self.return_exception_raised()
def if_object_ok(self, obj): with cgutils.if_likely(self.builder, cgutils.is_not_null(self.builder, obj)): yield
def lower_expr(self, expr): if expr.op == 'binop': return self.lower_binop(expr, inplace=False) elif expr.op == 'inplace_binop': return self.lower_binop(expr, inplace=True) elif expr.op == 'unary': value = self.loadvar(expr.value.name) if expr.fn == '-': res = self.pyapi.number_negative(value) elif expr.fn == '+': res = self.pyapi.number_positive(value) elif expr.fn == 'not': res = self.pyapi.object_not(value) self.check_int_status(res) longval = self.builder.zext(res, self.pyapi.long) res = self.pyapi.bool_from_long(longval) elif expr.fn == '~': res = self.pyapi.number_invert(value) else: raise NotImplementedError(expr) self.check_error(res) return res elif expr.op == 'call': argvals = [self.loadvar(a.name) for a in expr.args] fn = self.loadvar(expr.func.name) if not expr.kws: # No keyword ret = self.pyapi.call_function_objargs(fn, argvals) else: # Have Keywords keyvalues = [(k, self.loadvar(v.name)) for k, v in expr.kws] args = self.pyapi.tuple_pack(argvals) kws = self.pyapi.dict_pack(keyvalues) ret = self.pyapi.call(fn, args, kws) self.decref(kws) self.decref(args) self.check_error(ret) return ret elif expr.op == 'getattr': obj = self.loadvar(expr.value.name) res = self.pyapi.object_getattr(obj, self._freeze_string(expr.attr)) self.check_error(res) return res elif expr.op == 'build_tuple': items = [self.loadvar(it.name) for it in expr.items] res = self.pyapi.tuple_pack(items) self.check_error(res) return res elif expr.op == 'build_list': items = [self.loadvar(it.name) for it in expr.items] res = self.pyapi.list_pack(items) self.check_error(res) return res elif expr.op == 'build_map': res = self.pyapi.dict_new(expr.size) self.check_error(res) return res elif expr.op == 'build_set': items = [self.loadvar(it.name) for it in expr.items] res = self.pyapi.set_new() self.check_error(res) for it in items: ok = self.pyapi.set_add(res, it) self.check_int_status(ok) return res elif expr.op == 'getiter': obj = self.loadvar(expr.value.name) res = self.pyapi.object_getiter(obj) self.check_error(res) return res elif expr.op == 'iternext': iterobj = self.loadvar(expr.value.name) item = self.pyapi.iter_next(iterobj) is_valid = cgutils.is_not_null(self.builder, item) pair = self.pyapi.tuple_new(2) with cgutils.ifelse(self.builder, is_valid) as (then, otherwise): with then: self.pyapi.tuple_setitem(pair, 0, item) with otherwise: self.check_occurred() # Make the tuple valid by inserting None as dummy # iteration "result" (it will be ignored). self.pyapi.tuple_setitem(pair, 0, self.pyapi.make_none()) self.pyapi.tuple_setitem(pair, 1, self.pyapi.bool_from_bool(is_valid)) return pair elif expr.op == 'pair_first': pair = self.loadvar(expr.value.name) first = self.pyapi.tuple_getitem(pair, 0) self.incref(first) return first elif expr.op == 'pair_second': pair = self.loadvar(expr.value.name) second = self.pyapi.tuple_getitem(pair, 1) self.incref(second) return second elif expr.op == 'exhaust_iter': iterobj = self.loadvar(expr.value.name) tup = self.pyapi.sequence_tuple(iterobj) self.check_error(tup) # Check tuple size is as expected tup_size = self.pyapi.tuple_size(tup) expected_size = self.context.get_constant(types.intp, expr.count) has_wrong_size = self.builder.icmp(lc.ICMP_NE, tup_size, expected_size) with cgutils.if_unlikely(self.builder, has_wrong_size): excid = self.add_exception(ValueError) self.context.return_user_exc(self.builder, excid) return tup elif expr.op == 'getitem': value = self.loadvar(expr.value.name) index = self.loadvar(expr.index.name) res = self.pyapi.object_getitem(value, index) self.check_error(res) return res elif expr.op == 'static_getitem': value = self.loadvar(expr.value.name) index = self.context.get_constant(types.intp, expr.index) indexobj = self.pyapi.long_from_ssize_t(index) self.check_error(indexobj) res = self.pyapi.object_getitem(value, indexobj) self.decref(indexobj) self.check_error(res) return res elif expr.op == 'getslice': target = self.loadvar(expr.target.name) start = self.loadvar(expr.start.name) stop = self.loadvar(expr.stop.name) slicefn = self.get_builtin_obj("slice") sliceobj = self.pyapi.call_function_objargs(slicefn, (start, stop)) self.decref(slicefn) self.check_error(sliceobj) res = self.pyapi.object_getitem(target, sliceobj) self.check_error(res) return res elif expr.op == 'cast': val = self.loadvar(expr.value.name) self.incref(val) return val else: raise NotImplementedError(expr)
def lower_expr(self, expr): if expr.op == 'binop': return self.lower_binop(expr, inplace=False) elif expr.op == 'inplace_binop': return self.lower_binop(expr, inplace=True) elif expr.op == 'unary': value = self.loadvar(expr.value.name) if expr.fn == '-': res = self.pyapi.number_negative(value) elif expr.fn == '+': res = self.pyapi.number_positive(value) elif expr.fn == 'not': res = self.pyapi.object_not(value) self.check_int_status(res) longval = self.builder.zext(res, self.pyapi.long) res = self.pyapi.bool_from_long(longval) elif expr.fn == '~': res = self.pyapi.number_invert(value) else: raise NotImplementedError(expr) self.check_error(res) return res elif expr.op == 'call': argvals = [self.loadvar(a.name) for a in expr.args] fn = self.loadvar(expr.func.name) if not expr.kws: # No keyword ret = self.pyapi.call_function_objargs(fn, argvals) else: # Have Keywords keyvalues = [(k, self.loadvar(v.name)) for k, v in expr.kws] args = self.pyapi.tuple_pack(argvals) kws = self.pyapi.dict_pack(keyvalues) ret = self.pyapi.call(fn, args, kws) self.decref(kws) self.decref(args) self.check_error(ret) return ret elif expr.op == 'getattr': obj = self.loadvar(expr.value.name) res = self.pyapi.object_getattr_string(obj, expr.attr) self.check_error(res) return res elif expr.op == 'build_tuple': items = [self.loadvar(it.name) for it in expr.items] res = self.pyapi.tuple_pack(items) self.check_error(res) return res elif expr.op == 'build_list': items = [self.loadvar(it.name) for it in expr.items] res = self.pyapi.list_pack(items) self.check_error(res) return res elif expr.op == 'build_map': res = self.pyapi.dict_new(expr.size) self.check_error(res) return res elif expr.op == 'build_set': items = [self.loadvar(it.name) for it in expr.items] res = self.pyapi.set_new() self.check_error(res) for it in items: ok = self.pyapi.set_add(res, it) self.check_int_status(ok) return res elif expr.op == 'getiter': obj = self.loadvar(expr.value.name) res = self.pyapi.object_getiter(obj) self.check_error(res) return res elif expr.op == 'iternext': iterobj = self.loadvar(expr.value.name) item = self.pyapi.iter_next(iterobj) is_valid = cgutils.is_not_null(self.builder, item) pair = self.pyapi.tuple_new(2) with cgutils.ifelse(self.builder, is_valid) as (then, otherwise): with then: self.pyapi.tuple_setitem(pair, 0, item) with otherwise: self.check_occurred() # Make the tuple valid by inserting None as dummy # iteration "result" (it will be ignored). self.pyapi.tuple_setitem(pair, 0, self.pyapi.make_none()) self.pyapi.tuple_setitem(pair, 1, self.pyapi.bool_from_bool(is_valid)) return pair elif expr.op == 'pair_first': pair = self.loadvar(expr.value.name) first = self.pyapi.tuple_getitem(pair, 0) self.incref(first) return first elif expr.op == 'pair_second': pair = self.loadvar(expr.value.name) second = self.pyapi.tuple_getitem(pair, 1) self.incref(second) return second elif expr.op == 'exhaust_iter': iterobj = self.loadvar(expr.value.name) tup = self.pyapi.sequence_tuple(iterobj) self.check_error(tup) # Check tuple size is as expected tup_size = self.pyapi.tuple_size(tup) expected_size = self.context.get_constant(types.intp, expr.count) has_wrong_size = self.builder.icmp(lc.ICMP_NE, tup_size, expected_size) with cgutils.if_unlikely(self.builder, has_wrong_size): excid = self.add_exception(ValueError) self.context.return_user_exc(self.builder, excid) return tup elif expr.op == 'getitem': value = self.loadvar(expr.value.name) index = self.loadvar(expr.index.name) res = self.pyapi.object_getitem(value, index) self.check_error(res) return res elif expr.op == 'static_getitem': value = self.loadvar(expr.value.name) index = self.context.get_constant(types.intp, expr.index) indexobj = self.pyapi.long_from_ssize_t(index) self.check_error(indexobj) res = self.pyapi.object_getitem(value, indexobj) self.decref(indexobj) self.check_error(res) return res elif expr.op == 'getslice': target = self.loadvar(expr.target.name) start = self.loadvar(expr.start.name) stop = self.loadvar(expr.stop.name) slicefn = self.get_builtin_obj("slice") sliceobj = self.pyapi.call_function_objargs(slicefn, (start, stop)) self.decref(slicefn) self.check_error(sliceobj) res = self.pyapi.object_getitem(target, sliceobj) self.check_error(res) return res elif expr.op == 'cast': val = self.loadvar(expr.value.name) self.incref(val) return val else: raise NotImplementedError(expr)
def check_blas_return(context, builder, res): with builder.if_then(cgutils.is_not_null(builder, res), likely=False): # Those errors shouldn't happen, it's easier to just abort the process pyapi = context.get_python_api(builder) pyapi.gil_ensure() pyapi.fatal_error("BLAS wrapper returned with an error")
def _emit_python_wrapper(self, llvm_module): # Figure out the Python C API module creation function, and # get a LLVM function for it. create_module_fn = llvm_module.add_function( *self.module_create_definition) create_module_fn.linkage = lc.LINKAGE_EXTERNAL # Define a constant string for the module name. mod_name_const = self.context.insert_const_string( llvm_module, self.module_name) mod_def_base_init = lc.Constant.struct(( lt._pyobject_head_init, # PyObject_HEAD lc.Constant.null(self.m_init_ty), # m_init lc.Constant.null(lt._llvm_py_ssize_t), # m_index lc.Constant.null(lt._pyobject_head_p), # m_copy )) mod_def_base = llvm_module.add_global_variable(mod_def_base_init.type, '.module_def_base') mod_def_base.initializer = mod_def_base_init mod_def_base.linkage = lc.LINKAGE_INTERNAL method_array = self._emit_method_array(llvm_module) mod_def_init = lc.Constant.struct(( mod_def_base_init, # m_base mod_name_const, # m_name lc.Constant.null(self._char_star), # m_doc lc.Constant.int(lt._llvm_py_ssize_t, -1), # m_size method_array, # m_methods lc.Constant.null(self.inquiry_ty), # m_reload lc.Constant.null(self.traverseproc_ty), # m_traverse lc.Constant.null(self.inquiry_ty), # m_clear lc.Constant.null(self.freefunc_ty) # m_free )) # Define a constant string for the module name. mod_def = llvm_module.add_global_variable(mod_def_init.type, '.module_def') mod_def.initializer = mod_def_init mod_def.linkage = lc.LINKAGE_INTERNAL # Define the module initialization function. mod_init_fn = llvm_module.add_function(*self.module_init_definition) entry = mod_init_fn.append_basic_block('Entry') builder = lc.Builder(entry) pyapi = self.context.get_python_api(builder) mod = builder.call( create_module_fn, (mod_def, lc.Constant.int(lt._int32, sys.api_version))) # Test if module has been created correctly. # (XXX for some reason comparing with the NULL constant fails llvm # with an assertion in pydebug mode) with builder.if_then(cgutils.is_null(builder, mod)): builder.ret(NULL.bitcast(mod_init_fn.type.pointee.return_type)) env_array = self._emit_environment_array(llvm_module, builder, pyapi) ret = self._emit_module_init_code(llvm_module, builder, mod, method_array, env_array) if ret is not None: with builder.if_then(cgutils.is_not_null(builder, ret)): # Init function errored out builder.ret(lc.Constant.null(mod.type)) builder.ret(mod) self.dll_exports.append(mod_init_fn.name)