def printf(builder, format_string, *values): str_const = Constant.stringz(format_string) global_str_const = get_module(builder).add_global_variable( str_const.type, '') global_str_const.initializer = str_const idx = [Constant.int(Type.int(32), 0), Constant.int(Type.int(32), 0)] str_addr = global_str_const.gep(idx) args = [] for v in values: if isinstance(v, int): args.append(Constant.int(Type.int(), v)) elif isinstance(v, float): args.append(Constant.real(Type.double(), v)) else: args.append(v) functype = Type.function(Type.int(32), [Type.pointer(Type.int(8))], True) fn = get_module(builder).get_or_insert_function(functype, 'printf') builder.call(fn, [str_addr] + args)
def __init__(self, context, builder, value=None, ref=None, cast_ref=False): self._type = context.get_struct_type(self) self._context = context self._builder = builder if ref is None: self._value = alloca_once(builder, self._type) if value is not None: assert not is_pointer(value.type) assert value.type == self._type, (value.type, self._type) builder.store(value, self._value) else: assert value is None assert is_pointer(ref.type) if self._type != ref.type.pointee: if cast_ref: ref = builder.bitcast(ref, Type.pointer(self._type)) else: raise TypeError( "mismatching pointer type: got %s, expected %s" % (ref.type.pointee, self._type)) self._value = ref self._namemap = {} self._fdmap = [] self._typemap = [] base = Constant.int(Type.int(), 0) for i, (k, tp) in enumerate(self._fields): self._namemap[k] = i self._fdmap.append((base, Constant.int(Type.int(), i))) self._typemap.append(tp)
def for_range(builder, count, intp): start = Constant.int(intp, 0) stop = count bbcond = append_basic_block(builder, "for.cond") bbbody = append_basic_block(builder, "for.body") bbend = append_basic_block(builder, "for.end") bbstart = builder.basic_block builder.branch(bbcond) ONE = Constant.int(intp, 1) with goto_block(builder, bbcond): index = builder.phi(intp, name="loop.index") pred = builder.icmp(lc.ICMP_SLT, index, stop) builder.cbranch(pred, bbbody, bbend) with goto_block(builder, bbbody): yield index bbbody = builder.basic_block incr = builder.add(index, ONE) terminate(builder, bbcond) index.add_incoming(start, bbstart) index.add_incoming(incr, bbbody) builder.position_at_end(bbend)
def divmod_by_constant(builder, val, divisor): """ Compute the (quotient, remainder) of *val* divided by the constant positive *divisor*. The semantics reflects those of Python integer floor division, rather than C's / LLVM's signed division and modulo. The difference lies with a negative *val*. """ assert divisor > 0 divisor = Constant.int(val.type, divisor) one = Constant.int(val.type, 1) quot = alloca_once(builder, val.type) with builder.if_else(is_neg_int(builder, val)) as (if_neg, if_pos): with if_pos: # quot = val / divisor quot_val = builder.sdiv(val, divisor) builder.store(quot_val, quot) with if_neg: # quot = -1 + (val + 1) / divisor val_plus_one = builder.add(val, one) quot_val = builder.sdiv(val_plus_one, divisor) builder.store(builder.sub(quot_val, one), quot) # rem = val - quot * divisor # (should be slightly faster than a separate modulo operation) quot_val = builder.load(quot) rem_val = builder.sub(val, builder.mul(quot_val, divisor)) return quot_val, rem_val
def timedelta_floor_div_timedelta(context, builder, sig, args): [va, vb] = args [ta, tb] = sig.args ll_ret_type = context.get_value_type(sig.return_type) not_nan = are_not_nat(builder, [va, vb]) ret = cgutils.alloca_once(builder, ll_ret_type, name='ret') zero = Constant.int(ll_ret_type, 0) one = Constant.int(ll_ret_type, 1) builder.store(zero, ret) with cgutils.if_likely(builder, not_nan): va, vb = normalize_timedeltas(context, builder, va, vb, ta, tb) # is the denominator zero or NaT? denom_ok = builder.not_(builder.icmp_signed('==', vb, zero)) with cgutils.if_likely(builder, denom_ok): # is either arg negative? vaneg = builder.icmp_signed('<', va, zero) neg = builder.or_(vaneg, builder.icmp_signed('<', vb, zero)) with builder.if_else(neg) as (then, otherwise): with then: # one or more value negative with builder.if_else(vaneg) as (negthen, negotherwise): with negthen: top = builder.sub(va, one) div = builder.sdiv(top, vb) builder.store(div, ret) with negotherwise: top = builder.add(va, one) div = builder.sdiv(top, vb) builder.store(div, ret) with otherwise: div = builder.sdiv(va, vb) builder.store(div, ret) res = builder.load(ret) return impl_ret_untracked(context, builder, sig.return_type, res)
def get_constant(self, ty, val): assert not self.is_struct_type(ty) lty = self.get_value_type(ty) if ty == types.none: assert val is None return self.get_dummy_value() elif ty == types.boolean: return Constant.int(Type.int(1), int(val)) elif ty in types.signed_domain: return Constant.int_signextend(lty, val) elif ty in types.unsigned_domain: return Constant.int(lty, val) elif ty in types.real_domain: return Constant.real(lty, val) elif isinstance(ty, types.UniTuple): consts = [self.get_constant(ty.dtype, v) for v in val] return Constant.array(consts[0].type, consts) raise NotImplementedError("cannot lower constant of type '%s'" % (ty,))
def divmod_by_constant(builder, val, divisor): """ Compute the (quotient, remainder) of *val* divided by the constant positive *divisor*. The semantics reflects those of Python integer floor division, rather than C's / LLVM's signed division and modulo. The difference lies with a negative *val*. """ assert divisor > 0 divisor = Constant.int(val.type, divisor) one = Constant.int(val.type, 1) quot = alloca_once(builder, val.type) with ifelse(builder, is_neg_int(builder, val)) as (if_neg, if_pos): with if_pos: # quot = val / divisor quot_val = builder.sdiv(val, divisor) builder.store(quot_val, quot) with if_neg: # quot = -1 + (val + 1) / divisor val_plus_one = builder.add(val, one) quot_val = builder.sdiv(val_plus_one, divisor) builder.store(builder.sub(quot_val, one), quot) # rem = val - quot * divisor # (should be slightly faster than a separate modulo operation) quot_val = builder.load(quot) rem_val = builder.sub(val, builder.mul(quot_val, divisor)) return quot_val, rem_val
def make_exception_switch(self, api, builder, code): """Handle user defined exceptions. Build a switch to check which exception class was raised. """ nexc = len(self.exceptions) elseblk = cgutils.append_basic_block(builder, ".invalid.user.exception") swt = builder.switch(code, elseblk, n=nexc) for num, exc in self.exceptions.items(): bb = cgutils.append_basic_block(builder, ".user.exception.%d" % num) swt.add_case(Constant.int(code.type, num), bb) builder.position_at_end(bb) api.raise_exception(exc, exc) builder.ret(api.get_null_object()) builder.position_at_end(elseblk) # Handle native error elseblk = cgutils.append_basic_block(builder, ".invalid.native.error") swt = builder.switch(code, elseblk, n=len(errcode.error_names)) msgfmt = "{error} in native function: {fname}" for errnum, errname in errcode.error_names.items(): bb = cgutils.append_basic_block(builder, ".native.error.%d" % errnum) swt.add_case(Constant.int(code.type, errnum), bb) builder.position_at_end(bb) api.raise_native_error(msgfmt.format(error=errname, fname=self.fndesc.mangled_name)) builder.ret(api.get_null_object()) builder.position_at_end(elseblk) msg = "unknown error in native function: %s" % self.fndesc.mangled_name api.raise_native_error(msg)
def for_range(builder, count, intp): start = Constant.int(intp, 0) stop = count bbcond = builder.append_basic_block("for.cond") bbbody = builder.append_basic_block("for.body") bbend = builder.append_basic_block("for.end") bbstart = builder.basic_block builder.branch(bbcond) ONE = Constant.int(intp, 1) with builder.goto_block(bbcond): index = builder.phi(intp, name="loop.index") pred = builder.icmp(lc.ICMP_SLT, index, stop) builder.cbranch(pred, bbbody, bbend) with builder.goto_block(bbbody): yield index bbbody = builder.basic_block incr = builder.add(index, ONE) terminate(builder, bbcond) index.add_incoming(start, bbstart) index.add_incoming(incr, bbbody) builder.position_at_end(bbend)
def int_power_func_body(context, builder, x, y): pcounter = cgutils.alloca_once(builder, y.type) presult = cgutils.alloca_once(builder, x.type) result = Constant.int(x.type, 1) counter = y builder.store(counter, pcounter) builder.store(result, presult) bbcond = cgutils.append_basic_block(builder, ".cond") bbbody = cgutils.append_basic_block(builder, ".body") bbexit = cgutils.append_basic_block(builder, ".exit") del counter del result builder.branch(bbcond) with cgutils.goto_block(builder, bbcond): counter = builder.load(pcounter) ONE = Constant.int(counter.type, 1) ZERO = Constant.null(counter.type) builder.store(builder.sub(counter, ONE), pcounter) pred = builder.icmp(lc.ICMP_SGT, counter, ZERO) builder.cbranch(pred, bbbody, bbexit) with cgutils.goto_block(builder, bbbody): result = builder.load(presult) builder.store(builder.mul(result, x), presult) builder.branch(bbcond) builder.position_at_end(bbexit) return builder.load(presult)
def get_constant(self, ty, val): assert not self.is_struct_type(ty) lty = self.get_value_type(ty) if ty == types.none: assert val is None return self.get_dummy_value() elif ty == types.boolean: return Constant.int(Type.int(1), int(val)) elif ty in types.signed_domain: return Constant.int_signextend(lty, val) elif ty in types.unsigned_domain: return Constant.int(lty, val) elif ty in types.real_domain: return Constant.real(lty, val) elif isinstance(ty, (types.NPDatetime, types.NPTimedelta)): return Constant.real(lty, val.astype(numpy.int64)) elif isinstance(ty, (types.UniTuple, types.NamedUniTuple)): consts = [self.get_constant(ty.dtype, v) for v in val] return Constant.array(consts[0].type, consts) raise NotImplementedError("cannot lower constant of type '%s'" % (ty,))
def get_constant(self, ty, val): assert not self.is_struct_type(ty) lty = self.get_value_type(ty) if ty == types.none: assert val is None return self.get_dummy_value() elif ty == types.boolean: return Constant.int(Type.int(1), int(val)) elif ty in types.signed_domain: return Constant.int_signextend(lty, val) elif ty in types.unsigned_domain: return Constant.int(lty, val) elif ty in types.real_domain: return Constant.real(lty, val) elif isinstance(ty, types.UniTuple): consts = [self.get_constant(ty.dtype, v) for v in val] return Constant.array(consts[0].type, consts) raise NotImplementedError(ty)
def _long_from_native_int(self, ival, func_name, native_int_type, signed): fnty = Type.function(self.pyobj, [native_int_type]) fn = self._get_function(fnty, name=func_name) resptr = cgutils.alloca_once(self.builder, self.pyobj) if PYVERSION < (3, 0): # Under Python 2, we try to return a PyInt object whenever # the given number fits in a C long. pyint_fnty = Type.function(self.pyobj, [self.long]) pyint_fn = self._get_function(pyint_fnty, name="PyInt_FromLong") long_max = Constant.int(native_int_type, _helperlib.long_max) if signed: long_min = Constant.int(native_int_type, _helperlib.long_min) use_pyint = self.builder.and_( self.builder.icmp(lc.ICMP_SGE, ival, long_min), self.builder.icmp(lc.ICMP_SLE, ival, long_max), ) else: use_pyint = self.builder.icmp(lc.ICMP_ULE, ival, long_max) with self.builder.if_else(use_pyint) as (then, otherwise): with then: downcast_ival = self.builder.trunc(ival, self.long) res = self.builder.call(pyint_fn, [downcast_ival]) self.builder.store(res, resptr) with otherwise: res = self.builder.call(fn, [ival]) self.builder.store(res, resptr) else: fn = self._get_function(fnty, name=func_name) self.builder.store(self.builder.call(fn, [ival]), resptr) return self.builder.load(resptr)
def unpack_tuple(self, args, name, n_min, n_max, *objs): charptr = Type.pointer(Type.int(8)) argtypes = [self.pyobj, charptr, self.py_ssize_t, self.py_ssize_t] fnty = Type.function(Type.int(), argtypes, var_arg=True) fn = self._get_function(fnty, name="PyArg_UnpackTuple") n_min = Constant.int(self.py_ssize_t, n_min) n_max = Constant.int(self.py_ssize_t, n_max) if isinstance(name, str): name = self.context.insert_const_string(self.builder.module, name) return self.builder.call(fn, [args, name, n_min, n_max] + list(objs))
def get_item_pointer2(builder, data, shape, strides, layout, inds, wraparound=False): if wraparound: # Wraparound indices = [] for ind, dimlen in zip(inds, shape): ZERO = Constant.null(ind.type) negative = builder.icmp(lc.ICMP_SLT, ind, ZERO) wrapped = builder.add(dimlen, ind) selected = builder.select(negative, wrapped, ind) indices.append(selected) else: indices = inds if not indices: # Indexing with empty tuple return builder.gep(data, [get_null_value(Type.int(32))]) intp = indices[0].type # Indexing code if layout in 'CF': steps = [] # Compute steps for each dimension if layout == 'C': # C contiguous for i in range(len(shape)): last = Constant.int(intp, 1) for j in shape[i + 1:]: last = builder.mul(last, j) steps.append(last) elif layout == 'F': # F contiguous for i in range(len(shape)): last = Constant.int(intp, 1) for j in shape[:i]: last = builder.mul(last, j) steps.append(last) else: raise Exception("unreachable") # Compute index loc = Constant.int(intp, 0) for i, s in zip(indices, steps): tmp = builder.mul(i, s) loc = builder.add(loc, tmp) ptr = builder.gep(data, [loc]) return ptr else: # Any layout dimoffs = [builder.mul(s, i) for s, i in zip(strides, indices)] offset = functools.reduce(builder.add, dimoffs) return pointer_add(builder, data, offset)
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 memset(builder, ptr, size, value): """ Fill *size* bytes starting from *ptr* with *value*. """ sizety = size.type memset = "llvm.memset.p0i8.i%d" % (sizety.width) i32 = lc.Type.int(32) i8 = lc.Type.int(8) i8_star = i8.as_pointer() i1 = lc.Type.int(1) fn = builder.module.declare_intrinsic('llvm.memset', (i8_star, size.type)) ptr = builder.bitcast(ptr, i8_star) if isinstance(value, int): value = Constant.int(i8, value) builder.call(fn, [ptr, value, size, Constant.int(i32, 0), Constant.int(i1, 0)])
def lower_finalize_func_body(self, builder, genptr): """ Lower the body of the generator's finalizer: decref all live state variables. """ pyapi = self.context.get_python_api(builder) resume_index_ptr = self.get_resume_index_ptr(builder, genptr) resume_index = builder.load(resume_index_ptr) # If resume_index is 0, next() was never called # If resume_index is -1, generator terminated cleanly # (note function arguments are saved in state variables, # so they don't need a separate cleanup step) need_cleanup = builder.icmp_signed('>', resume_index, Constant.int(resume_index.type, 0)) with cgutils.if_unlikely(builder, need_cleanup): # Decref all live vars (some may be NULL) gen_state_ptr = self.get_state_ptr(builder, genptr) for state_index in range(len(self.gentype.state_types)): state_slot = cgutils.gep_inbounds(builder, gen_state_ptr, 0, state_index) ty = self.gentype.state_types[state_index] val = self.context.unpack_value(builder, ty, state_slot) pyapi.decref(val) builder.ret_void()
def return_from_generator(self, lower): """ Emit a StopIteration at generator end and mark the generator exhausted. """ indexval = Constant.int(self.resume_index_ptr.type.pointee, -1) lower.builder.store(indexval, self.resume_index_ptr) self.call_conv.return_stop_iteration(lower.builder)
def lower_finalize_func_body(self, builder, genptr): """ Lower the body of the generator's finalizer: decref all live state variables. """ pyapi = self.context.get_python_api(builder) resume_index_ptr = self.get_resume_index_ptr(builder, genptr) resume_index = builder.load(resume_index_ptr) # If resume_index is 0, next() was never called # If resume_index is -1, generator terminated cleanly # (note function arguments are saved in state variables, # so they don't need a separate cleanup step) need_cleanup = builder.icmp_signed( '>', resume_index, Constant.int(resume_index.type, 0)) with cgutils.if_unlikely(builder, need_cleanup): # Decref all live vars (some may be NULL) gen_state_ptr = self.get_state_ptr(builder, genptr) for state_index in range(len(self.gentype.state_types)): state_slot = cgutils.gep_inbounds(builder, gen_state_ptr, 0, state_index) ty = self.gentype.state_types[state_index] val = self.context.unpack_value(builder, ty, state_slot) pyapi.decref(val) builder.ret_void()
def timedelta_sign_impl(context, builder, sig, args): val, = args ret = alloc_timedelta_result(builder) zero = Constant.int(TIMEDELTA64, 0) with cgutils.ifelse(builder, builder.icmp(lc.ICMP_SGT, val, zero) ) as (gt_zero, le_zero): with gt_zero: builder.store(Constant.int(TIMEDELTA64, 1), ret) with le_zero: with cgutils.ifelse(builder, builder.icmp(lc.ICMP_EQ, val, zero) ) as (eq_zero, lt_zero): with eq_zero: builder.store(Constant.int(TIMEDELTA64, 0), ret) with lt_zero: builder.store(Constant.int(TIMEDELTA64, -1), ret) return builder.load(ret)
def timedelta_sign_impl(context, builder, sig, args): val, = args ret = alloc_timedelta_result(builder) zero = Constant.int(TIMEDELTA64, 0) with builder.if_else(builder.icmp(lc.ICMP_SGT, val, zero)) as (gt_zero, le_zero): with gt_zero: builder.store(Constant.int(TIMEDELTA64, 1), ret) with le_zero: with builder.if_else(builder.icmp(lc.ICMP_EQ, val, zero)) as (eq_zero, lt_zero): with eq_zero: builder.store(Constant.int(TIMEDELTA64, 0), ret) with lt_zero: builder.store(Constant.int(TIMEDELTA64, -1), ret) return builder.load(ret)
def timedelta_mod_timedelta(context, builder, sig, args): # inspired by https://github.com/numpy/numpy/blob/fe8072a12d65e43bd2e0b0f9ad67ab0108cc54b3/numpy/core/src/umath/loops.c.src#L1424 # alg is basically as `a % b`: # if a or b is NaT return NaT # elseif b is 0 return NaT # else pretend a and b are int and do pythonic int modulus [va, vb] = args [ta, tb] = sig.args not_nan = are_not_nat(builder, [va, vb]) ll_ret_type = context.get_value_type(sig.return_type) ret = alloc_timedelta_result(builder) builder.store(NAT, ret) zero = Constant.int(ll_ret_type, 0) with cgutils.if_likely(builder, not_nan): va, vb = normalize_timedeltas(context, builder, va, vb, ta, tb) # is the denominator zero or NaT? denom_ok = builder.not_(builder.icmp_signed('==', vb, zero)) with cgutils.if_likely(builder, denom_ok): # is either arg negative? vapos = builder.icmp_signed('>', va, zero) vbpos = builder.icmp_signed('>', vb, zero) rem = builder.srem(va, vb) cond = builder.or_(builder.and_(vapos, vbpos), builder.icmp_signed('==', rem, zero)) with builder.if_else(cond) as (then, otherwise): with then: builder.store(rem, ret) with otherwise: builder.store(builder.add(rem, vb), ret) res = builder.load(ret) return impl_ret_untracked(context, builder, sig.return_type, res)
def gen_prologue(self, builder, pyapi): # Get an environment object for the function ll_intp = self.context.get_value_type(types.intp) ll_pyobj = self.context.get_value_type(types.pyobject) self.envptr = Constant.int(ll_intp, id(self.env)).inttoptr(ll_pyobj) # Acquire the GIL self.gil = pyapi.gil_ensure()
def inbound_gep(builder, ptr, *inds): idx = [] for i in inds: if isinstance(i, int): ind = Constant.int(Type.int(32), i) else: ind = i idx.append(ind) return builder.gep(ptr, idx, inbounds=True)
def gep(builder, ptr, *inds): idx = [] for i in inds: if isinstance(i, int): ind = Constant.int(Type.int(64), i) else: ind = i idx.append(ind) return builder.gep(ptr, idx)
def increment_index(builder, val): """ Increment an index *val*. """ one = Constant.int(val.type, 1) # We pass the "nsw" flag in the hope that LLVM understands the index # never changes sign. Unfortunately this doesn't always work # (e.g. ndindex()). return builder.add(val, one, flags=['nsw'])
def dict_new(self, presize=0): if presize == 0: fnty = Type.function(self.pyobj, ()) fn = self._get_function(fnty, name="PyDict_New") return self.builder.call(fn, ()) else: fnty = Type.function(self.pyobj, [self.py_ssize_t]) fn = self._get_function(fnty, name="_PyDict_NewPresized") return self.builder.call(fn, [Constant.int(self.py_ssize_t, presize)])
def set_cuda_kernel(lfunc): from llvmlite.llvmpy.core import MetaData, MetaDataString, Constant, Type m = lfunc.module ops = lfunc, MetaDataString.get(m, "kernel"), Constant.int(Type.int(), 1) md = MetaData.get(m, ops) nmd = m.get_or_insert_named_metadata('nvvm.annotations') nmd.add(md)
def for_range(builder, count, start=None, intp=None): """ Generate LLVM IR for a for-loop in [start, count). *start* is equal to 0 by default. Yields a Loop namedtuple with the following members: - `index` is the loop index's value - `do_break` is a no-argument callable to break out of the loop """ if intp is None: intp = count.type if start is None: start = Constant.int(intp, 0) stop = count bbcond = builder.append_basic_block("for.cond") bbbody = builder.append_basic_block("for.body") bbend = builder.append_basic_block("for.end") def do_break(): builder.branch(bbend) bbstart = builder.basic_block builder.branch(bbcond) ONE = Constant.int(intp, 1) with builder.goto_block(bbcond): index = builder.phi(intp, name="loop.index") pred = builder.icmp(lc.ICMP_SLT, index, stop) builder.cbranch(pred, bbbody, bbend) with builder.goto_block(bbbody): yield Loop(index, do_break) # Update bbbody as a new basic block may have been activated bbbody = builder.basic_block incr = builder.add(index, ONE) terminate(builder, bbcond) index.add_incoming(start, bbstart) index.add_incoming(incr, bbbody) builder.position_at_end(bbend)
def gep(builder, ptr, *inds): idx = [] for i in inds: if isinstance(i, int): # NOTE: llvm only accepts int32 inside structs, not int64 ind = Constant.int(Type.int(32), i) else: ind = i idx.append(ind) return builder.gep(ptr, idx)
def lower_yield_suspend(self): # Save live vars in state for state_index, name in zip(self.live_var_indices, self.live_vars): state_slot = cgutils.gep(self.builder, self.gen_state_ptr, 0, state_index) ty = self.gentype.state_types[state_index] val = self.lower.loadvar(name) self.context.pack_value(self.builder, ty, val, state_slot) # Save resume index indexval = Constant.int(self.resume_index_ptr.type.pointee, self.inst.index) self.builder.store(indexval, self.resume_index_ptr)
def memset(builder, ptr, size, value): """ Fill *size* bytes starting from *ptr* with *value*. """ sizety = size.type memset = "llvm.memset.p0i8.i%d" % (sizety.width) module = get_module(builder) i32 = lc.Type.int(32) i8 = lc.Type.int(8) i1 = lc.Type.int(1) # void @llvm.memset.p0i8.iXY(i8* <dest>, i8 <val>, # iXY <len>, i32 <align>, i1 <isvolatile>) ptr = builder.bitcast(ptr, lc.Type.pointer(i8)) fnty = lc.Type.function(lc.Type.void(), [ptr.type, i8, sizety, i32, i1]) fn = module.get_or_insert_function(fnty, name=memset) if isinstance(value, int): value = Constant.int(i8, value) builder.call(fn, [ptr, value, size, Constant.int(i32, 0), Constant.int(i1, 0)])
def printf(builder, format_string, *values): str_const = Constant.stringz(format_string) global_str_const = get_module(builder).add_global_variable(str_const.type, '') global_str_const.initializer = str_const idx = [Constant.int(Type.int(32), 0), Constant.int(Type.int(32), 0)] str_addr = global_str_const.gep(idx) args = [] for v in values: if isinstance(v, int): args.append(Constant.int(Type.int(), v)) elif isinstance(v, float): args.append(Constant.real(Type.double(), v)) else: args.append(v) functype = Type.function(Type.int(32), [Type.pointer(Type.int(8))], True) fn = get_module(builder).get_or_insert_function(functype, 'printf') builder.call(fn, [str_addr] + args)
def gep(builder, ptr, *inds, **kws): name = kws.pop('name', '') idx = [] for i in inds: if isinstance(i, int): # NOTE: llvm only accepts int32 inside structs, not int64 ind = Constant.int(Type.int(32), i) else: ind = i idx.append(ind) return builder.gep(ptr, idx, name=name)
def timedelta_sign_impl(context, builder, sig, args): """ np.sign(timedelta64) """ val, = args ret = alloc_timedelta_result(builder) zero = Constant.int(TIMEDELTA64, 0) with builder.if_else(builder.icmp(lc.ICMP_SGT, val, zero) ) as (gt_zero, le_zero): with gt_zero: builder.store(Constant.int(TIMEDELTA64, 1), ret) with le_zero: with builder.if_else(builder.icmp(lc.ICMP_EQ, val, zero) ) as (eq_zero, lt_zero): with eq_zero: builder.store(Constant.int(TIMEDELTA64, 0), ret) with lt_zero: builder.store(Constant.int(TIMEDELTA64, -1), ret) res = builder.load(ret) return impl_ret_untracked(context, builder, sig.return_type, res)
def timedelta_sign_impl(context, builder, sig, args): """ np.sign(timedelta64) """ (val,) = args ret = alloc_timedelta_result(builder) zero = Constant.int(TIMEDELTA64, 0) with builder.if_else(builder.icmp(lc.ICMP_SGT, val, zero)) as (gt_zero, le_zero): with gt_zero: builder.store(Constant.int(TIMEDELTA64, 1), ret) with le_zero: with builder.if_else(builder.icmp(lc.ICMP_EQ, val, zero)) as ( eq_zero, lt_zero, ): with eq_zero: builder.store(Constant.int(TIMEDELTA64, 0), ret) with lt_zero: builder.store(Constant.int(TIMEDELTA64, -1), ret) res = builder.load(ret) return impl_ret_untracked(context, builder, sig.return_type, res)
def gen_prologue(self, builder): # Create an environment object for the function moduledict = self.fndesc.lookup_module().__dict__ self.env = _dynfunc.Environment(globals=moduledict) ll_intp = self.context.get_value_type(types.intp) ll_pyobj = self.context.get_value_type(types.pyobject) self.envptr = Constant.int(ll_intp, id(self.env)).inttoptr(ll_pyobj) # Acquire the GIL self.pyapi = self.context.get_python_api(builder) self.gil = self.pyapi.gil_ensure()
def int_sign_impl(context, builder, sig, args): """ np.sign(int) """ [x] = args POS = Constant.int(x.type, 1) NEG = Constant.int(x.type, -1) ZERO = Constant.int(x.type, 0) cmp_zero = builder.icmp(lc.ICMP_EQ, x, ZERO) cmp_pos = builder.icmp(lc.ICMP_SGT, x, ZERO) presult = cgutils.alloca_once(builder, x.type) bb_zero = builder.append_basic_block(".zero") bb_postest = builder.append_basic_block(".postest") bb_pos = builder.append_basic_block(".pos") bb_neg = builder.append_basic_block(".neg") bb_exit = builder.append_basic_block(".exit") builder.cbranch(cmp_zero, bb_zero, bb_postest) with builder.goto_block(bb_zero): builder.store(ZERO, presult) builder.branch(bb_exit) with builder.goto_block(bb_postest): builder.cbranch(cmp_pos, bb_pos, bb_neg) with builder.goto_block(bb_pos): builder.store(POS, presult) builder.branch(bb_exit) with builder.goto_block(bb_neg): builder.store(NEG, presult) builder.branch(bb_exit) builder.position_at_end(bb_exit) res = builder.load(presult) return impl_ret_untracked(context, builder, sig.return_type, res)
def for_range(builder, count, intp=None): """ Generate LLVM IR for a for-loop in [0, count). Yields a Loop namedtuple with the following members: - `index` is the loop index's value - `do_break` is a no-argument callable to break out of the loop """ if intp is None: intp = count.type start = Constant.int(intp, 0) stop = count bbcond = builder.append_basic_block("for.cond") bbbody = builder.append_basic_block("for.body") bbend = builder.append_basic_block("for.end") def do_break(): builder.branch(bbend) bbstart = builder.basic_block builder.branch(bbcond) ONE = Constant.int(intp, 1) with builder.goto_block(bbcond): index = builder.phi(intp, name="loop.index") pred = builder.icmp(lc.ICMP_SLT, index, stop) builder.cbranch(pred, bbbody, bbend) with builder.goto_block(bbbody): yield Loop(index, do_break) # Update bbbody as a new basic block may have been activated bbbody = builder.basic_block incr = builder.add(index, ONE) terminate(builder, bbcond) index.add_incoming(start, bbstart) index.add_incoming(incr, bbbody) builder.position_at_end(bbend)
def pointer_add(builder, ptr, offset, return_type=None): """ Add an integral *offset* to pointer *ptr*, and return a pointer of *return_type* (or, if omitted, the same type as *ptr*). Note the computation is done in bytes, and ignores the width of the pointed item type. """ intptr = builder.ptrtoint(ptr, intp_t) if isinstance(offset, int): offset = Constant.int(intp_t, offset) intptr = builder.add(intptr, offset) return builder.inttoptr(intptr, return_type or ptr.type)