def real_sign_impl(context, builder, sig, args): """ np.sign(float) """ [x] = args POS = Constant.real(x.type, 1) NEG = Constant.real(x.type, -1) ZERO = Constant.real(x.type, 0) presult = cgutils.alloca_once(builder, x.type) is_pos = builder.fcmp(lc.FCMP_OGT, x, ZERO) is_neg = builder.fcmp(lc.FCMP_OLT, x, ZERO) with builder.if_else(is_pos) as (gt_zero, not_gt_zero): with gt_zero: builder.store(POS, presult) with not_gt_zero: with builder.if_else(is_neg) as (lt_zero, not_lt_zero): with lt_zero: builder.store(NEG, presult) with not_lt_zero: # For both NaN and 0, the result of sign() is simply # the input value. builder.store(x, presult) res = builder.load(presult) return impl_ret_untracked(context, builder, sig.return_type, res)
def real_sign_impl(context, builder, sig, args): [x] = args POS = Constant.real(x.type, 1) NEG = Constant.real(x.type, -1) ZERO = Constant.real(x.type, 0) presult = cgutils.alloca_once(builder, x.type) is_pos = builder.fcmp(lc.FCMP_OGT, x, ZERO) is_neg = builder.fcmp(lc.FCMP_OLT, x, ZERO) with builder.if_else(is_pos) as (gt_zero, not_gt_zero): with gt_zero: builder.store(POS, presult) with not_gt_zero: with builder.if_else(is_neg) as (lt_zero, not_lt_zero): with lt_zero: builder.store(NEG, presult) with not_lt_zero: # For both NaN and 0, the result of sign() is simply # the input value. builder.store(x, presult) res = builder.load(presult) 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.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.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 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 is_true(self, builder, typ, val): if typ in types.integer_domain: return builder.icmp(lc.ICMP_NE, val, Constant.null(val.type)) elif typ in types.real_domain: return builder.fcmp(lc.FCMP_UNE, val, Constant.real(val.type, 0)) elif typ in types.complex_domain: cmplx = self.make_complex(typ)(self, builder, val) real_istrue = self.is_true(builder, typ.underlying_float, cmplx.real) imag_istrue = self.is_true(builder, typ.underlying_float, cmplx.imag) return builder.or_(real_istrue, imag_istrue) raise NotImplementedError("is_true", val, typ)
def timedelta_over_timedelta(context, builder, sig, args): [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 = cgutils.alloca_once(builder, ll_ret_type, name='ret') builder.store(Constant.real(ll_ret_type, float('nan')), ret) with cgutils.if_likely(builder, not_nan): va, vb = normalize_timedeltas(context, builder, va, vb, ta, tb) va = builder.sitofp(va, ll_ret_type) vb = builder.sitofp(vb, ll_ret_type) builder.store(builder.fdiv(va, vb), ret) return builder.load(ret)
def timedelta_over_timedelta(context, builder, sig, args): [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 = cgutils.alloca_once(builder, ll_ret_type, name='ret') builder.store(Constant.real(ll_ret_type, float('nan')), ret) with cgutils.if_likely(builder, not_nan): va, vb = normalize_timedeltas(context, builder, va, vb, ta, tb) va = builder.sitofp(va, ll_ret_type) vb = builder.sitofp(vb, ll_ret_type) builder.store(builder.fdiv(va, vb), ret) return builder.load(ret)
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 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 real_divmod_func_body(context, builder, vx, wx): # Reference Objects/floatobject.c # # float_divmod(PyObject *v, PyObject *w) # { # double vx, wx; # double div, mod, floordiv; # CONVERT_TO_DOUBLE(v, vx); # CONVERT_TO_DOUBLE(w, wx); # mod = fmod(vx, wx); # /* fmod is typically exact, so vx-mod is *mathematically* an # exact multiple of wx. But this is fp arithmetic, and fp # vx - mod is an approximation; the result is that div may # not be an exact integral value after the division, although # it will always be very close to one. # */ # div = (vx - mod) / wx; # if (mod) { # /* ensure the remainder has the same sign as the denominator */ # if ((wx < 0) != (mod < 0)) { # mod += wx; # div -= 1.0; # } # } # else { # /* the remainder is zero, and in the presence of signed zeroes # fmod returns different results across platforms; ensure # it has the same sign as the denominator; we'd like to do # "mod = wx * 0.0", but that may get optimized away */ # mod *= mod; /* hide "mod = +0" from optimizer */ # if (wx < 0.0) # mod = -mod; # } # /* snap quotient to nearest integral value */ # if (div) { # floordiv = floor(div); # if (div - floordiv > 0.5) # floordiv += 1.0; # } # else { # /* div is zero - get the same sign as the true quotient */ # div *= div; /* hide "div = +0" from optimizers */ # floordiv = div * vx / wx; /* zero w/ sign of vx/wx */ # } # return Py_BuildValue("(dd)", floordiv, mod); # } pmod = cgutils.alloca_once(builder, vx.type) pdiv = cgutils.alloca_once(builder, vx.type) pfloordiv = cgutils.alloca_once(builder, vx.type) mod = builder.frem(vx, wx) div = builder.fdiv(builder.fsub(vx, mod), wx) builder.store(mod, pmod) builder.store(div, pdiv) ZERO = Constant.real(vx.type, 0) ONE = Constant.real(vx.type, 1) mod_istrue = builder.fcmp(lc.FCMP_ONE, mod, ZERO) wx_ltz = builder.fcmp(lc.FCMP_OLT, wx, ZERO) mod_ltz = builder.fcmp(lc.FCMP_OLT, mod, ZERO) with builder.if_then(mod_istrue): wx_ltz_ne_mod_ltz = builder.icmp(lc.ICMP_NE, wx_ltz, mod_ltz) with builder.if_then(wx_ltz_ne_mod_ltz): mod = builder.fadd(mod, wx) div = builder.fsub(div, ONE) builder.store(mod, pmod) builder.store(div, pdiv) del mod del div with cgutils.ifnot(builder, mod_istrue): mod = builder.load(pmod) mod = builder.fmul(mod, mod) builder.store(mod, pmod) del mod with builder.if_then(wx_ltz): mod = builder.load(pmod) mod = builder.fsub(ZERO, mod) builder.store(mod, pmod) del mod div = builder.load(pdiv) div_istrue = builder.fcmp(lc.FCMP_ONE, div, ZERO) with builder.if_then(div_istrue): module = builder.module floorfn = lc.Function.intrinsic(module, lc.INTR_FLOOR, [wx.type]) floordiv = builder.call(floorfn, [div]) floordivdiff = builder.fsub(div, floordiv) floordivincr = builder.fadd(floordiv, ONE) HALF = Constant.real(wx.type, 0.5) pred = builder.fcmp(lc.FCMP_OGT, floordivdiff, HALF) floordiv = builder.select(pred, floordivincr, floordiv) builder.store(floordiv, pfloordiv) with cgutils.ifnot(builder, div_istrue): div = builder.fmul(div, div) builder.store(div, pdiv) floordiv = builder.fdiv(builder.fmul(div, vx), wx) builder.store(floordiv, pfloordiv) return builder.load(pfloordiv), builder.load(pmod)
def real_divmod_func_body(context, builder, vx, wx): # Reference Objects/floatobject.c # # float_divmod(PyObject *v, PyObject *w) # { # double vx, wx; # double div, mod, floordiv; # CONVERT_TO_DOUBLE(v, vx); # CONVERT_TO_DOUBLE(w, wx); # mod = fmod(vx, wx); # /* fmod is typically exact, so vx-mod is *mathematically* an # exact multiple of wx. But this is fp arithmetic, and fp # vx - mod is an approximation; the result is that div may # not be an exact integral value after the division, although # it will always be very close to one. # */ # div = (vx - mod) / wx; # if (mod) { # /* ensure the remainder has the same sign as the denominator */ # if ((wx < 0) != (mod < 0)) { # mod += wx; # div -= 1.0; # } # } # else { # /* the remainder is zero, and in the presence of signed zeroes # fmod returns different results across platforms; ensure # it has the same sign as the denominator; we'd like to do # "mod = wx * 0.0", but that may get optimized away */ # mod *= mod; /* hide "mod = +0" from optimizer */ # if (wx < 0.0) # mod = -mod; # } # /* snap quotient to nearest integral value */ # if (div) { # floordiv = floor(div); # if (div - floordiv > 0.5) # floordiv += 1.0; # } # else { # /* div is zero - get the same sign as the true quotient */ # div *= div; /* hide "div = +0" from optimizers */ # floordiv = div * vx / wx; /* zero w/ sign of vx/wx */ # } # return Py_BuildValue("(dd)", floordiv, mod); # } pmod = cgutils.alloca_once(builder, vx.type) pdiv = cgutils.alloca_once(builder, vx.type) pfloordiv = cgutils.alloca_once(builder, vx.type) mod = builder.frem(vx, wx) div = builder.fdiv(builder.fsub(vx, mod), wx) builder.store(mod, pmod) builder.store(div, pdiv) # Note the use of negative zero for proper negating with `ZERO - x` ZERO = vx.type(0.0) NZERO = vx.type(-0.0) ONE = vx.type(1.0) mod_istrue = builder.fcmp_unordered('!=', mod, ZERO) wx_ltz = builder.fcmp_ordered('<', wx, ZERO) mod_ltz = builder.fcmp_ordered('<', mod, ZERO) with builder.if_else(mod_istrue, likely=True) as (if_nonzero_mod, if_zero_mod): with if_nonzero_mod: # `mod` is non-zero or NaN # Ensure the remainder has the same sign as the denominator wx_ltz_ne_mod_ltz = builder.icmp(lc.ICMP_NE, wx_ltz, mod_ltz) with builder.if_then(wx_ltz_ne_mod_ltz): builder.store(builder.fsub(div, ONE), pdiv) builder.store(builder.fadd(mod, wx), pmod) with if_zero_mod: # `mod` is zero, select the proper sign depending on # the denominator's sign mod = builder.select(wx_ltz, NZERO, ZERO) builder.store(mod, pmod) del mod, div div = builder.load(pdiv) div_istrue = builder.fcmp(lc.FCMP_ONE, div, ZERO) with builder.if_then(div_istrue): realtypemap = {'float': types.float32, 'double': types.float64} realtype = realtypemap[str(wx.type)] floorfn = context.get_function(math.floor, typing.signature(realtype, realtype)) floordiv = floorfn(builder, [div]) floordivdiff = builder.fsub(div, floordiv) floordivincr = builder.fadd(floordiv, ONE) HALF = Constant.real(wx.type, 0.5) pred = builder.fcmp(lc.FCMP_OGT, floordivdiff, HALF) floordiv = builder.select(pred, floordivincr, floordiv) builder.store(floordiv, pfloordiv) with cgutils.ifnot(builder, div_istrue): div = builder.fmul(div, div) builder.store(div, pdiv) floordiv = builder.fdiv(builder.fmul(div, vx), wx) builder.store(floordiv, pfloordiv) return builder.load(pfloordiv), builder.load(pmod)
def real_divmod_func_body(context, builder, vx, wx): # Reference Objects/floatobject.c # # float_divmod(PyObject *v, PyObject *w) # { # double vx, wx; # double div, mod, floordiv; # CONVERT_TO_DOUBLE(v, vx); # CONVERT_TO_DOUBLE(w, wx); # mod = fmod(vx, wx); # /* fmod is typically exact, so vx-mod is *mathematically* an # exact multiple of wx. But this is fp arithmetic, and fp # vx - mod is an approximation; the result is that div may # not be an exact integral value after the division, although # it will always be very close to one. # */ # div = (vx - mod) / wx; # if (mod) { # /* ensure the remainder has the same sign as the denominator */ # if ((wx < 0) != (mod < 0)) { # mod += wx; # div -= 1.0; # } # } # else { # /* the remainder is zero, and in the presence of signed zeroes # fmod returns different results across platforms; ensure # it has the same sign as the denominator; we'd like to do # "mod = wx * 0.0", but that may get optimized away */ # mod *= mod; /* hide "mod = +0" from optimizer */ # if (wx < 0.0) # mod = -mod; # } # /* snap quotient to nearest integral value */ # if (div) { # floordiv = floor(div); # if (div - floordiv > 0.5) # floordiv += 1.0; # } # else { # /* div is zero - get the same sign as the true quotient */ # div *= div; /* hide "div = +0" from optimizers */ # floordiv = div * vx / wx; /* zero w/ sign of vx/wx */ # } # return Py_BuildValue("(dd)", floordiv, mod); # } pmod = cgutils.alloca_once(builder, vx.type) pdiv = cgutils.alloca_once(builder, vx.type) pfloordiv = cgutils.alloca_once(builder, vx.type) mod = builder.frem(vx, wx) div = builder.fdiv(builder.fsub(vx, mod), wx) builder.store(mod, pmod) builder.store(div, pdiv) # Note the use of negative zero for proper negating with `ZERO - x` ZERO = vx.type(0.0) NZERO = vx.type(-0.0) ONE = vx.type(1.0) mod_istrue = builder.fcmp_unordered('!=', mod, ZERO) wx_ltz = builder.fcmp_ordered('<', wx, ZERO) mod_ltz = builder.fcmp_ordered('<', mod, ZERO) with builder.if_else(mod_istrue, likely=True) as (if_nonzero_mod, if_zero_mod): with if_nonzero_mod: # `mod` is non-zero or NaN # Ensure the remainder has the same sign as the denominator wx_ltz_ne_mod_ltz = builder.icmp(lc.ICMP_NE, wx_ltz, mod_ltz) with builder.if_then(wx_ltz_ne_mod_ltz): builder.store(builder.fsub(div, ONE), pdiv) builder.store(builder.fadd(mod, wx), pmod) with if_zero_mod: # `mod` is zero, select the proper sign depending on # the denominator's sign mod = builder.select(wx_ltz, NZERO, ZERO) builder.store(mod, pmod) del mod, div div = builder.load(pdiv) div_istrue = builder.fcmp(lc.FCMP_ONE, div, ZERO) with builder.if_then(div_istrue): realtypemap = {'float': types.float32, 'double': types.float64} realtype = realtypemap[str(wx.type)] floorfn = context.get_function(math.floor, typing.signature(realtype, realtype)) floordiv = floorfn(builder, [div]) floordivdiff = builder.fsub(div, floordiv) floordivincr = builder.fadd(floordiv, ONE) HALF = Constant.real(wx.type, 0.5) pred = builder.fcmp(lc.FCMP_OGT, floordivdiff, HALF) floordiv = builder.select(pred, floordivincr, floordiv) builder.store(floordiv, pfloordiv) with cgutils.ifnot(builder, div_istrue): div = builder.fmul(div, div) builder.store(div, pdiv) floordiv = builder.fdiv(builder.fmul(div, vx), wx) builder.store(floordiv, pfloordiv) return builder.load(pfloordiv), builder.load(pmod)
def real_divmod_func_body(context, builder, vx, wx): # Reference Objects/floatobject.c # # float_divmod(PyObject *v, PyObject *w) # { # double vx, wx; # double div, mod, floordiv; # CONVERT_TO_DOUBLE(v, vx); # CONVERT_TO_DOUBLE(w, wx); # mod = fmod(vx, wx); # /* fmod is typically exact, so vx-mod is *mathematically* an # exact multiple of wx. But this is fp arithmetic, and fp # vx - mod is an approximation; the result is that div may # not be an exact integral value after the division, although # it will always be very close to one. # */ # div = (vx - mod) / wx; # if (mod) { # /* ensure the remainder has the same sign as the denominator */ # if ((wx < 0) != (mod < 0)) { # mod += wx; # div -= 1.0; # } # } # else { # /* the remainder is zero, and in the presence of signed zeroes # fmod returns different results across platforms; ensure # it has the same sign as the denominator; we'd like to do # "mod = wx * 0.0", but that may get optimized away */ # mod *= mod; /* hide "mod = +0" from optimizer */ # if (wx < 0.0) # mod = -mod; # } # /* snap quotient to nearest integral value */ # if (div) { # floordiv = floor(div); # if (div - floordiv > 0.5) # floordiv += 1.0; # } # else { # /* div is zero - get the same sign as the true quotient */ # div *= div; /* hide "div = +0" from optimizers */ # floordiv = div * vx / wx; /* zero w/ sign of vx/wx */ # } # return Py_BuildValue("(dd)", floordiv, mod); # } pmod = cgutils.alloca_once(builder, vx.type) pdiv = cgutils.alloca_once(builder, vx.type) pfloordiv = cgutils.alloca_once(builder, vx.type) mod = builder.frem(vx, wx) div = builder.fdiv(builder.fsub(vx, mod), wx) builder.store(mod, pmod) builder.store(div, pdiv) ZERO = Constant.real(vx.type, 0) ONE = Constant.real(vx.type, 1) mod_istrue = builder.fcmp(lc.FCMP_ONE, mod, ZERO) wx_ltz = builder.fcmp(lc.FCMP_OLT, wx, ZERO) mod_ltz = builder.fcmp(lc.FCMP_OLT, mod, ZERO) with cgutils.ifthen(builder, mod_istrue): wx_ltz_ne_mod_ltz = builder.icmp(lc.ICMP_NE, wx_ltz, mod_ltz) with cgutils.ifthen(builder, wx_ltz_ne_mod_ltz): mod = builder.fadd(mod, wx) div = builder.fsub(div, ONE) builder.store(mod, pmod) builder.store(div, pdiv) del mod del div with cgutils.ifnot(builder, mod_istrue): mod = builder.load(pmod) mod = builder.fmul(mod, mod) builder.store(mod, pmod) del mod with cgutils.ifthen(builder, wx_ltz): mod = builder.load(pmod) mod = builder.fsub(ZERO, mod) builder.store(mod, pmod) del mod div = builder.load(pdiv) div_istrue = builder.fcmp(lc.FCMP_ONE, div, ZERO) with cgutils.ifthen(builder, div_istrue): module = cgutils.get_module(builder) floorfn = lc.Function.intrinsic(module, lc.INTR_FLOOR, [wx.type]) floordiv = builder.call(floorfn, [div]) floordivdiff = builder.fsub(div, floordiv) floordivincr = builder.fadd(floordiv, ONE) HALF = Constant.real(wx.type, 0.5) pred = builder.fcmp(lc.FCMP_OGT, floordivdiff, HALF) floordiv = builder.select(pred, floordivincr, floordiv) builder.store(floordiv, pfloordiv) with cgutils.ifnot(builder, div_istrue): div = builder.fmul(div, div) builder.store(div, pdiv) floordiv = builder.fdiv(builder.fmul(div, vx), wx) builder.store(floordiv, pfloordiv) return builder.load(pfloordiv), builder.load(pmod)