def box_list(typ, val, c): """ Convert native list *val* to a list object. """ list = listobj.ListInstance(c.context, c.builder, typ, val) obj = list.parent res = cgutils.alloca_once_value(c.builder, obj) with c.builder.if_else(cgutils.is_not_null(c.builder, obj)) as (has_parent, otherwise): with has_parent: # List is actually reflected => return the original object # (note not all list instances whose *type* is reflected are # actually reflected; see numba.tests.test_lists for an example) c.pyapi.incref(obj) with otherwise: # Build a new Python list nitems = list.size obj = c.pyapi.list_new(nitems) with c.builder.if_then(cgutils.is_not_null(c.builder, obj), likely=True): with cgutils.for_range(c.builder, nitems) as loop: item = list.getitem(loop.index) list.incref_value(item) itemobj = c.box(typ.dtype, item) c.pyapi.list_setitem(obj, loop.index, itemobj) c.builder.store(obj, res) # Steal NRT ref c.context.nrt.decref(c.builder, typ, val) return c.builder.load(res)
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 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) env_manager = context.get_env_manager(builder) if context.enable_nrt: context.nrt.incref(builder, ty, val) obj = pyapi.from_native_value(ty, val, env_manager) 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 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 box_set(typ, val, c): """ Convert native set *val* to a set object. """ inst = setobj.SetInstance(c.context, c.builder, typ, val) obj = inst.parent res = cgutils.alloca_once_value(c.builder, obj) with c.builder.if_else(cgutils.is_not_null(c.builder, obj)) as (has_parent, otherwise): with has_parent: # Set is actually reflected => return the original object # (note not all set instances whose *type* is reflected are # actually reflected; see numba.tests.test_sets for an example) c.pyapi.incref(obj) with otherwise: # Build a new Python list and then create a set from that payload = inst.payload ok, listobj = _native_set_to_python_list(typ, payload, c) with c.builder.if_then(ok, likely=True): obj = c.pyapi.set_new(listobj) c.pyapi.decref(listobj) c.builder.store(obj, res) # Steal NRT ref c.context.nrt.decref(c.builder, typ, val) return c.builder.load(res)
def box_lsttype(typ, val, c): context = c.context builder = c.builder # XXX deduplicate ctor = cgutils.create_struct_proxy(typ) lstruct = ctor(context, builder, value=val) # Returns the plain MemInfo boxed_meminfo = c.box( types.MemInfoPointer(types.voidptr), lstruct.meminfo, ) modname = c.context.insert_const_string( c.builder.module, 'numba.typed.typedlist', ) typedlist_mod = c.pyapi.import_module_noblock(modname) fmp_fn = c.pyapi.object_getattr_string(typedlist_mod, '_from_meminfo_ptr') lsttype_obj = c.pyapi.unserialize(c.pyapi.serialize_object(typ)) result_var = builder.alloca(c.pyapi.pyobj) builder.store(cgutils.get_null_value(c.pyapi.pyobj), result_var) with builder.if_then(cgutils.is_not_null(builder, lsttype_obj)): res = c.pyapi.call_function_objargs( fmp_fn, (boxed_meminfo, lsttype_obj), ) c.pyapi.decref(fmp_fn) c.pyapi.decref(typedlist_mod) c.pyapi.decref(boxed_meminfo) builder.store(res, result_var) return builder.load(result_var)
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.cpython.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 unbox_set(typ, obj, c): """ Convert set *obj* to a native set. If set was previously unboxed, we reuse the existing native set to ensure consistency. """ size = c.pyapi.set_size(obj) errorptr = cgutils.alloca_once_value(c.builder, cgutils.false_bit) setptr = cgutils.alloca_once(c.builder, c.context.get_value_type(typ)) # See if the set was previously unboxed, if so, re-use the meminfo. ptr = c.pyapi.object_get_private_data(obj) with c.builder.if_else(cgutils.is_not_null(c.builder, ptr)) \ as (has_meminfo, otherwise): with has_meminfo: # Set was previously unboxed => reuse meminfo inst = setobj.SetInstance.from_meminfo(c.context, c.builder, typ, ptr) if typ.reflected: inst.parent = obj c.builder.store(inst.value, setptr) with otherwise: _python_set_to_native(typ, obj, c, size, setptr, errorptr) def cleanup(): # Clean up the associated pointer, as the meminfo is now invalid. c.pyapi.object_reset_private_data(obj) return NativeValue(c.builder.load(setptr), is_error=c.builder.load(errorptr), cleanup=cleanup)
def unbox_(typ, obj, c): ptr_obj = c.pyapi.object_getattr_string(obj, "address") ctx = cgutils.create_struct_proxy(typ)(c.context, c.builder) ctx.ptr = c.pyapi.long_as_voidptr(ptr_obj) c.pyapi.decref(ptr_obj) is_error = cgutils.is_not_null(c.builder, c.pyapi.err_occurred()) return NativeValue(ctx._getvalue(), is_error=is_error)
def unbox_buffer(typ, obj, c): """ Convert a Py_buffer-providing object to a native array structure. """ buf = c.pyapi.alloca_buffer() res = c.pyapi.get_buffer(obj, buf) is_error = cgutils.is_not_null(c.builder, res) nativearycls = c.context.make_array(typ) nativeary = nativearycls(c.context, c.builder) aryptr = nativeary._getpointer() with cgutils.if_likely(c.builder, c.builder.not_(is_error)): ptr = c.builder.bitcast(aryptr, c.pyapi.voidptr) if c.context.enable_nrt: c.pyapi.nrt_adapt_buffer_from_python(buf, ptr) else: c.pyapi.numba_buffer_adaptor(buf, ptr) def cleanup(): c.pyapi.release_buffer(buf) return NativeValue(c.builder.load(aryptr), is_error=is_error, cleanup=cleanup)
def unbox_execution_progress(typ, obj, c): """ Convert a ExecutionProgress object to a native structure. """ output_progress_to_console_obj = c.pyapi.object_getattr_string( obj, "output_progress_to_console") is_true = c.pyapi.object_istrue(output_progress_to_console_obj) zero = ir.Constant(is_true.type, 0) lower_bound_obj = c.pyapi.object_getattr_string(obj, "lower_bound") number_of_decimal_places_obj = c.pyapi.object_getattr_string( obj, "number_of_decimal_places") execution_progress = cgutils.create_struct_proxy(typ)(c.context, c.builder) execution_progress.output_progress_to_console = c.builder.icmp_signed( '!=', is_true, zero) execution_progress.lower_bound = c.pyapi.float_as_double(lower_bound_obj) ll_type = c.context.get_argument_type(types.intc) val = cgutils.alloca_once(c.builder, ll_type) longobj = c.pyapi.number_long(number_of_decimal_places_obj) with c.pyapi.if_object_ok(longobj): llval = c.pyapi.long_as_longlong(longobj) c.pyapi.decref(longobj) c.builder.store(c.builder.trunc(llval, ll_type), val) execution_progress.number_of_decimal_places = c.builder.load(val) c.pyapi.decref(lower_bound_obj) is_error = cgutils.is_not_null(c.builder, c.pyapi.err_occurred()) return NativeValue(execution_progress._getvalue(), is_error=is_error)
def unbox_funcptr(typ, obj, c): if typ.get_pointer is None: raise NotImplementedError(typ) # Call get_pointer() on the object to get the raw pointer value ptrty = c.context.get_function_pointer_type(typ) ret = cgutils.alloca_once_value(c.builder, ir.Constant(ptrty, None), name="fnptr") ser = c.pyapi.serialize_object(typ.get_pointer) get_pointer = c.pyapi.unserialize(ser) with cgutils.if_likely(c.builder, cgutils.is_not_null(c.builder, get_pointer)): intobj = c.pyapi.call_function_objargs(get_pointer, (obj,)) c.pyapi.decref(get_pointer) with cgutils.if_likely(c.builder, cgutils.is_not_null(c.builder, intobj)): ptr = c.pyapi.long_as_voidptr(intobj) c.pyapi.decref(intobj) c.builder.store(c.builder.bitcast(ptr, ptrty), ret) return NativeValue(c.builder.load(ret), is_error=c.pyapi.c_api_error())
def check_occurred(self): """ Return if an exception occurred. """ 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 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_dict = pyapi.dict_new() 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(arr_typ, Categorical): arr_obj = box_Categorical(arr_typ, arr, c) # context.nrt.incref(builder, arr_typ, arr) 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.dict_setitem(df_dict, cname_obj, arr_obj) pyapi.decref(arr_obj) pyapi.decref(cname_obj) df_obj = pyapi.call_method(class_obj, "DataFrame", (df_dict,)) pyapi.decref(df_dict) # 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(arr_obj) pyapi.decref(class_obj) # pyapi.gil_release(gil_state) # release GIL return df_obj
def unbox_MultiVector(typ: MultiVectorType, obj: MultiVector, c) -> NativeValue: value = c.pyapi.object_getattr_string(obj, "value") layout = c.pyapi.object_getattr_string(obj, "layout") mv = cgutils.create_struct_proxy(typ)(c.context, c.builder) mv.layout = c.unbox(typ.layout_type, layout).value mv.value = c.unbox(typ.value_type, value).value c.pyapi.decref(value) c.pyapi.decref(layout) is_error = cgutils.is_not_null(c.builder, c.pyapi.err_occurred()) return NativeValue(mv._getvalue(), is_error=is_error)
def unbox_random_state(typ, obj, c): """Convert a `RandomState` object to a native `RandomStateNumbaModel` structure. Note that this will create a 'fake' structure which will just get the `RandomState` objects accepted in Numba functions but the actual information of the Numba's random state is stored internally and can be accessed anytime using ``numba._helperlib.rnd_get_np_state_ptr()``. """ interval = cgutils.create_struct_proxy(typ)(c.context, c.builder) is_error = cgutils.is_not_null(c.builder, c.pyapi.err_occurred()) return NativeValue(interval._getvalue(), is_error=is_error)
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 unbox_empty_index(typ, val, c): index_struct = cgutils.create_struct_proxy(typ)(c.context, c.builder) if typ.is_named: name_obj = c.pyapi.object_getattr_string(val, "name") index_struct.name = numba.cpython.unicode.unbox_unicode_str( types.unicode_type, name_obj, c).value c.pyapi.decref(name_obj) is_error = cgutils.is_not_null(c.builder, c.pyapi.err_occurred()) return NativeValue(index_struct._getvalue(), is_error=is_error)
def unbox_doubledouble(typ, obj, c): """ Convert a DoubleDouble object to a native doubledouble structure. """ x_obj = c.pyapi.object_getattr_string(obj, "x") y_obj = c.pyapi.object_getattr_string(obj, "y") doubledouble = cgutils.create_struct_proxy(typ)(c.context, c.builder) doubledouble.x = c.pyapi.float_as_double(x_obj) doubledouble.y = c.pyapi.float_as_double(y_obj) c.pyapi.decref(x_obj) c.pyapi.decref(y_obj) is_error = cgutils.is_not_null(c.builder, c.pyapi.err_occurred()) return NativeValue(doubledouble._getvalue(), is_error=is_error)
def unbox_interval(typ, obj, c): """ Convert a Interval object to a native interval structure. """ lo_obj = c.pyapi.object_getattr_string(obj, "lo") hi_obj = c.pyapi.object_getattr_string(obj, "hi") interval = cgutils.create_struct_proxy(typ)(c.context, c.builder) interval.lo = c.pyapi.float_as_double(lo_obj) interval.hi = c.pyapi.float_as_double(hi_obj) c.pyapi.decref(lo_obj) c.pyapi.decref(hi_obj) is_error = cgutils.is_not_null(c.builder, c.pyapi.err_occurred()) return NativeValue(interval._getvalue(), is_error=is_error)
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(DATETIME64, 1970)) multiple_of_4 = cgutils.is_null( builder, builder.and_(actual_year, Constant(DATETIME64, 3))) not_multiple_of_100 = cgutils.is_not_null( builder, builder.srem(actual_year, Constant(DATETIME64, 100))) multiple_of_400 = cgutils.is_null( builder, builder.srem(actual_year, Constant(DATETIME64, 400))) return builder.and_(multiple_of_4, builder.or_(not_multiple_of_100, multiple_of_400))
def unbox_int64_index(typ, val, c): # TODO: support index unboxing with reference to parent in Numba? int64_index = cgutils.create_struct_proxy(typ)(c.context, c.builder) index_data = c.pyapi.object_getattr_string(val, "_data") int64_index.data = unbox_array(typ.data, index_data, c).value c.pyapi.decref(index_data) if typ.is_named: name_obj = c.pyapi.object_getattr_string(val, "name") int64_index.name = numba.cpython.unicode.unbox_unicode_str( types.unicode_type, name_obj, c).value c.pyapi.decref(name_obj) is_error = cgutils.is_not_null(c.builder, c.pyapi.err_occurred()) return NativeValue(int64_index._getvalue(), is_error=is_error)
def unbox_array(typ, obj, c): """ Convert a Numpy array object to a native array structure. """ # This is necessary because unbox_buffer() does not work on some # dtypes, e.g. datetime64 and timedelta64. # TODO check matching dtype. # currently, mismatching dtype will still work and causes # potential memory corruption nativearycls = c.context.make_array(typ) nativeary = nativearycls(c.context, c.builder) aryptr = nativeary._getpointer() ptr = c.builder.bitcast(aryptr, c.pyapi.voidptr) if c.context.enable_nrt: errcode = c.pyapi.nrt_adapt_ndarray_from_python(obj, ptr) else: errcode = c.pyapi.numba_array_adaptor(obj, ptr) # TODO: here we have minimal typechecking by the itemsize. # need to do better try: expected_itemsize = numpy_support.as_dtype(typ.dtype).itemsize except NotImplementedError: # Don't check types that can't be `as_dtype()`-ed itemsize_mismatch = cgutils.false_bit else: expected_itemsize = nativeary.itemsize.type(expected_itemsize) itemsize_mismatch = c.builder.icmp_unsigned( '!=', nativeary.itemsize, expected_itemsize, ) failed = c.builder.or_( cgutils.is_not_null(c.builder, errcode), itemsize_mismatch, ) # Handle error with c.builder.if_then(failed, likely=False): c.pyapi.err_set_string( "PyExc_TypeError", "can't unbox array from PyObject into " "native value. The object maybe of a " "different type") return NativeValue(c.builder.load(aryptr), is_error=failed)
def _native_set_to_python_list(typ, payload, c): """ Create a Python list from a native set's items. """ nitems = payload.used listobj = c.pyapi.list_new(nitems) ok = cgutils.is_not_null(c.builder, listobj) with c.builder.if_then(ok, likely=True): index = cgutils.alloca_once_value(c.builder, ir.Constant(nitems.type, 0)) with payload._iterate() as loop: i = c.builder.load(index) item = loop.entry.key itemobj = c.box(typ.dtype, item) c.pyapi.list_setitem(listobj, i, itemobj) i = c.builder.add(i, ir.Constant(i.type, 1)) c.builder.store(i, index) return ok, listobj
def box_charseq(typ, val, c): rawptr = cgutils.alloca_once_value(c.builder, value=val) strptr = c.builder.bitcast(rawptr, c.pyapi.cstring) fullsize = c.context.get_constant(types.intp, typ.count) zero = fullsize.type(0) one = fullsize.type(1) count = cgutils.alloca_once_value(c.builder, zero) # Find the length of the string, mimicking Numpy's behaviour: # search for the last non-null byte in the underlying storage # (e.g. b'A\0\0B\0\0\0' will return the logical string b'A\0\0B') with cgutils.loop_nest(c.builder, [fullsize], fullsize.type) as [idx]: # Get char at idx ch = c.builder.load(c.builder.gep(strptr, [idx])) # If the char is a non-null-byte, store the next index as count with c.builder.if_then(cgutils.is_not_null(c.builder, ch)): c.builder.store(c.builder.add(idx, one), count) strlen = c.builder.load(count) return c.pyapi.bytes_from_string_and_size(strptr, strlen)
def unbox_int64_index(typ, val, c): nlevels = len(typ.levels) levels_types = typ.levels_types codes_types = typ.codes_types multi_index = cgutils.create_struct_proxy(typ)(c.context, c.builder) py_levels_data = c.pyapi.object_getattr_string(val, "levels") native_levels_data = [] for i in range(nlevels): idx = c.pyapi.long_from_ulonglong( c.context.get_constant(types.int64, i)) level_data = c.pyapi.object_getitem(py_levels_data, idx) native_levels_data.append( _unbox_index_data(levels_types[i], level_data, c).value) c.pyapi.decref(level_data) c.pyapi.decref(py_levels_data) multi_index.levels = c.context.make_tuple(c.builder, typ.levels, native_levels_data) py_codes_data = c.pyapi.object_getattr_string(val, "codes") native_codes_data = [] for i in range(nlevels): idx = c.pyapi.long_from_ulonglong( c.context.get_constant(types.int64, i)) code_data = c.pyapi.object_getitem(py_codes_data, idx) native_codes_data.append( unbox_array(codes_types[i], code_data, c).value) c.pyapi.decref(code_data) c.pyapi.decref(py_codes_data) multi_index.codes = c.context.make_tuple(c.builder, typ.codes, native_codes_data) if typ.is_named: name_obj = c.pyapi.object_getattr_string(val, "name") multi_index.name = numba.cpython.unicode.unbox_unicode_str( types.unicode_type, name_obj, c).value c.pyapi.decref(name_obj) is_error = cgutils.is_not_null(c.builder, c.pyapi.err_occurred()) return NativeValue(multi_index._getvalue(), is_error=is_error)
def box_unicodecharseq(typ, val, c): # XXX could kind be determined from strptr? unicode_kind = { 1: c.pyapi.py_unicode_1byte_kind, 2: c.pyapi.py_unicode_2byte_kind, 4: c.pyapi.py_unicode_4byte_kind}[numpy_support.sizeof_unicode_char] kind = c.context.get_constant(types.int32, unicode_kind) rawptr = cgutils.alloca_once_value(c.builder, value=val) strptr = c.builder.bitcast(rawptr, c.pyapi.cstring) fullsize = c.context.get_constant(types.intp, typ.count) zero = fullsize.type(0) one = fullsize.type(1) step = fullsize.type(numpy_support.sizeof_unicode_char) count = cgutils.alloca_once_value(c.builder, zero) with cgutils.loop_nest(c.builder, [fullsize], fullsize.type) as [idx]: # Get char at idx ch = c.builder.load(c.builder.gep(strptr, [c.builder.mul(idx, step)])) # If the char is a non-null-byte, store the next index as count with c.builder.if_then(cgutils.is_not_null(c.builder, ch)): c.builder.store(c.builder.add(idx, one), count) strlen = c.builder.load(count) return c.pyapi.string_from_kind_and_data(kind, strptr, strlen)
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) envgv_array = self._emit_envgvs_array(llvm_module, builder, pyapi) ret = self._emit_module_init_code(llvm_module, builder, mod, method_array, env_array, envgv_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 lower_expr(self, expr): if expr.op == 'binop': return self.lower_binop(expr, expr.fn, inplace=False) elif expr.op == 'inplace_binop': return self.lower_binop(expr, expr.fn, inplace=True) elif expr.op == 'unary': value = self.loadvar(expr.value.name) if expr.fn == operator.neg: res = self.pyapi.number_negative(value) elif expr.fn == operator.pos: res = self.pyapi.number_positive(value) elif expr.fn == operator.not_: res = self.pyapi.object_not(value) self.check_int_status(res) res = self.pyapi.bool_from_bool(res) elif expr.fn == operator.invert: 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) args = self.pyapi.tuple_pack(argvals) if expr.vararg: # Expand *args new_args = self.pyapi.number_add( args, self.loadvar(expr.vararg.name)) self.decref(args) args = new_args if not expr.kws: # No named arguments ret = self.pyapi.call(fn, args, None) else: # Named arguments keyvalues = [(k, self.loadvar(v.name)) for k, v in expr.kws] 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) for k, v in expr.items: key = self.loadvar(k.name) value = self.loadvar(v.name) ok = self.pyapi.dict_setitem(res, key, value) self.check_int_status(ok) 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 self.builder.if_else(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): self.return_exception(ValueError) 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 elif expr.op == 'phi': raise LoweringError("PHI not stripped") elif expr.op == 'null': # Make null value return cgutils.get_null_value(self.pyapi.pyobj) else: raise NotImplementedError(expr)