1import math
2import numbers
3
4import numpy as np
5
6from llvmlite import ir
7from llvmlite.ir import Constant
8
9from numba.core.imputils import impl_ret_untracked
10from numba.core import typing, types, errors, cgutils
11from numba.cpython.unsafe.numbers import viewer
12
13def _int_arith_flags(rettype):
14 """
15 Return the modifier flags for integer arithmetic.
16 """
17 if rettype.signed:
18 # Ignore the effects of signed overflow. This is important for
19 # optimization of some indexing operations. For example
20 # array[i+1] could see `i+1` trigger a signed overflow and
21 # give a negative number. With Python's indexing, a negative
22 # index is treated differently: its resolution has a runtime cost.
23 # Telling LLVM to ignore signed overflows allows it to optimize
24 # away the check for a negative `i+1` if it knows `i` is positive.
25 return ['nsw']
26 else:
27 return []
28
29
30def int_add_impl(context, builder, sig, args):
31 [va, vb] = args
32 [ta, tb] = sig.args
33 a = context.cast(builder, va, ta, sig.return_type)
34 b = context.cast(builder, vb, tb, sig.return_type)
35 res = builder.add(a, b, flags=_int_arith_flags(sig.return_type))
36 return impl_ret_untracked(context, builder, sig.return_type, res)
37
38
39def int_sub_impl(context, builder, sig, args):
40 [va, vb] = args
41 [ta, tb] = sig.args
42 a = context.cast(builder, va, ta, sig.return_type)
43 b = context.cast(builder, vb, tb, sig.return_type)
44 res = builder.sub(a, b, flags=_int_arith_flags(sig.return_type))
45 return impl_ret_untracked(context, builder, sig.return_type, res)
46
47
48def int_mul_impl(context, builder, sig, args):
49 [va, vb] = args
50 [ta, tb] = sig.args
51 a = context.cast(builder, va, ta, sig.return_type)
52 b = context.cast(builder, vb, tb, sig.return_type)
53 res = builder.mul(a, b, flags=_int_arith_flags(sig.return_type))
54 return impl_ret_untracked(context, builder, sig.return_type, res)
55
56
57def int_divmod_signed(context, builder, ty, x, y):
58 """
59 Reference Objects/intobject.c
60 xdivy = x / y;
61 xmody = (long)(x - (unsigned long)xdivy * y);
62 /* If the signs of x and y differ, and the remainder is non-0,
63 * C89 doesn't define whether xdivy is now the floor or the
64 * ceiling of the infinitely precise quotient. We want the floor,
65 * and we have it iff the remainder's sign matches y's.
66 */
67 if (xmody && ((y ^ xmody) < 0) /* i.e. and signs differ */) {
68 xmody += y;
69 --xdivy;
70 assert(xmody && ((y ^ xmody) >= 0));
71 }
72 *p_xdivy = xdivy;
73 *p_xmody = xmody;
74 """
75 assert x.type == y.type
76
77 ZERO = y.type(0)
78 ONE = y.type(1)
79
80 # NOTE: On x86 at least, dividing the lowest representable integer
81 # (e.g. 0x80000000 for int32) by -1 causes a SIFGPE (division overflow),
82 # causing the process to crash.
83 # We return 0, 0 instead (more or less like Numpy).
84
85 resdiv = cgutils.alloca_once_value(builder, ZERO)
86 resmod = cgutils.alloca_once_value(builder, ZERO)
87
88 is_overflow = builder.and_(
89 builder.icmp_signed('==', x, x.type(ty.minval)),
90 builder.icmp_signed('==', y, y.type(-1)))
91
92 with builder.if_then(builder.not_(is_overflow), likely=True):
93 # Note LLVM will optimize this to a single divmod instruction,
94 # if available on the target CPU (e.g. x86).
95 xdivy = builder.sdiv(x, y)
96 xmody = builder.srem(x, y)
97
98 y_xor_xmody_ltz = builder.icmp_signed('<', builder.xor(y, xmody), ZERO)
99 xmody_istrue = builder.icmp_signed('!=', xmody, ZERO)
100 cond = builder.and_(xmody_istrue, y_xor_xmody_ltz)
101
102 with builder.if_else(cond) as (if_different_signs, if_same_signs):
103 with if_same_signs:
104 builder.store(xdivy, resdiv)
105 builder.store(xmody, resmod)
106
107 with if_different_signs:
108 builder.store(builder.sub(xdivy, ONE), resdiv)
109 builder.store(builder.add(xmody, y), resmod)
110
111 return builder.load(resdiv), builder.load(resmod)
112
113
114def int_divmod(context, builder, ty, x, y):
115 """
116 Integer divmod(x, y). The caller must ensure that y != 0.
117 """
118 if ty.signed:
119 return int_divmod_signed(context, builder, ty, x, y)
120 else:
121 return builder.udiv(x, y), builder.urem(x, y)
122
123
124def _int_divmod_impl(context, builder, sig, args, zerodiv_message):
125 va, vb = args
126 ta, tb = sig.args
127
128 ty = sig.return_type
129 if isinstance(ty, types.UniTuple):
130 ty = ty.dtype
131 a = context.cast(builder, va, ta, ty)
132 b = context.cast(builder, vb, tb, ty)
133 quot = cgutils.alloca_once(builder, a.type, name="quot")
134 rem = cgutils.alloca_once(builder, a.type, name="rem")
135
136 with builder.if_else(cgutils.is_scalar_zero(builder, b), likely=False
137 ) as (if_zero, if_non_zero):
138 with if_zero:
139 if not context.error_model.fp_zero_division(
140 builder, (zerodiv_message,)):
141 # No exception raised => return 0
142 # XXX We should also set the FPU exception status, but
143 # there's no easy way to do that from LLVM.
144 builder.store(b, quot)
145 builder.store(b, rem)
146 with if_non_zero:
147 q, r = int_divmod(context, builder, ty, a, b)
148 builder.store(q, quot)
149 builder.store(r, rem)
150
151 return quot, rem
152
153
154# @lower_builtin(divmod, types.Integer, types.Integer)
155def int_divmod_impl(context, builder, sig, args):
156 quot, rem = _int_divmod_impl(context, builder, sig, args,
157 "integer divmod by zero")
158
159 return cgutils.pack_array(builder,
160 (builder.load(quot), builder.load(rem)))
161
162
163# @lower_builtin(operator.floordiv, types.Integer, types.Integer)
164# @lower_builtin(operator.ifloordiv, types.Integer, types.Integer)
165def int_floordiv_impl(context, builder, sig, args):
166 quot, rem = _int_divmod_impl(context, builder, sig, args,
167 "integer division by zero")
168 return builder.load(quot)
169
170
171# @lower_builtin(operator.truediv, types.Integer, types.Integer)
172# @lower_builtin(operator.itruediv, types.Integer, types.Integer)
173def int_truediv_impl(context, builder, sig, args):
174 [va, vb] = args
175 [ta, tb] = sig.args
176 a = context.cast(builder, va, ta, sig.return_type)
177 b = context.cast(builder, vb, tb, sig.return_type)
178 with cgutils.if_zero(builder, b):
179 context.error_model.fp_zero_division(builder, ("division by zero",))
180 res = builder.fdiv(a, b)
181 return impl_ret_untracked(context, builder, sig.return_type, res)
182
183
184# @lower_builtin(operator.mod, types.Integer, types.Integer)
185# @lower_builtin(operator.imod, types.Integer, types.Integer)
186def int_rem_impl(context, builder, sig, args):
187 quot, rem = _int_divmod_impl(context, builder, sig, args,
188 "integer modulo by zero")
189 return builder.load(rem)
190
191
192def _get_power_zerodiv_return(context, return_type):
193 if (isinstance(return_type, types.Integer)
194 and not context.error_model.raise_on_fp_zero_division):
195 # If not raising, return 0x8000... when computing 0 ** <negative number>
196 return -1 << (return_type.bitwidth - 1)
197 else:
198 return False
199
200
201def int_power_impl(context, builder, sig, args):
202 """
203 a ^ b, where a is an integer or real, and b an integer
204 """
205 is_integer = isinstance(sig.args[0], types.Integer)
206 tp = sig.return_type
207 zerodiv_return = _get_power_zerodiv_return(context, tp)
208
209 def int_power(a, b):
210 # Ensure computations are done with a large enough width
211 r = tp(1)
212 a = tp(a)
213 if b < 0:
214 invert = True
215 exp = -b
216 if exp < 0:
217 raise OverflowError
218 if is_integer:
219 if a == 0:
220 if zerodiv_return:
221 return zerodiv_return
222 else:
223 raise ZeroDivisionError("0 cannot be raised to a negative power")
224 if a != 1 and a != -1:
225 return 0
226 else:
227 invert = False
228 exp = b
229 if exp > 0x10000:
230 # Optimization cutoff: fallback on the generic algorithm
231 return math.pow(a, float(b))
232 while exp != 0:
233 if exp & 1:
234 r *= a
235 exp >>= 1
236 a *= a
237
238 return 1.0 / r if invert else r
239
240 res = context.compile_internal(builder, int_power, sig, args)
241 return impl_ret_untracked(context, builder, sig.return_type, res)
242
243
244# @lower_builtin(operator.pow, types.Integer, types.IntegerLiteral)
245# @lower_builtin(operator.ipow, types.Integer, types.IntegerLiteral)
246# @lower_builtin(operator.pow, types.Float, types.IntegerLiteral)
247# @lower_builtin(operator.ipow, types.Float, types.IntegerLiteral)
248def static_power_impl(context, builder, sig, args):
249 """
250 a ^ b, where a is an integer or real, and b a constant integer
251 """
252 exp = sig.args[1].value
253 if not isinstance(exp, numbers.Integral):
254 raise NotImplementedError
255 if abs(exp) > 0x10000:
256 # Optimization cutoff: fallback on the generic algorithm above
257 raise NotImplementedError
258 invert = exp < 0
259 exp = abs(exp)
260
261 tp = sig.return_type
262 is_integer = isinstance(tp, types.Integer)
263 zerodiv_return = _get_power_zerodiv_return(context, tp)
264
265 val = context.cast(builder, args[0], sig.args[0], tp)
266 lty = val.type
267
268 def mul(a, b):
269 if is_integer:
270 return builder.mul(a, b)
271 else:
272 return builder.fmul(a, b)
273
274 # Unroll the exponentiation loop
275 res = lty(1)
276 a = val
277 while exp != 0:
278 if exp & 1:
279 res = mul(res, val)
280 exp >>= 1
281 val = mul(val, val)
282
283 if invert:
284 # If the exponent was negative, fix the result by inverting it
285 if is_integer:
286 # Integer inversion
287 def invert_impl(a):
288 if a == 0:
289 if zerodiv_return:
290 return zerodiv_return
291 else:
292 raise ZeroDivisionError("0 cannot be raised to a negative power")
293 if a != 1 and a != -1:
294 return 0
295 else:
296 return a
297
298 else:
299 # Real inversion
300 def invert_impl(a):
301 return 1.0 / a
302
303 res = context.compile_internal(builder, invert_impl,
304 typing.signature(tp, tp), (res,))
305
306 return res
307
308
309def int_slt_impl(context, builder, sig, args):
310 res = builder.icmp_signed('<', *args)
311 return impl_ret_untracked(context, builder, sig.return_type, res)
312
313
314def int_sle_impl(context, builder, sig, args):
315 res = builder.icmp_signed('<=', *args)
316 return impl_ret_untracked(context, builder, sig.return_type, res)
317
318
319def int_sgt_impl(context, builder, sig, args):
320 res = builder.icmp_signed('>', *args)
321 return impl_ret_untracked(context, builder, sig.return_type, res)
322
323
324def int_sge_impl(context, builder, sig, args):
325 res = builder.icmp_signed('>=', *args)
326 return impl_ret_untracked(context, builder, sig.return_type, res)
327
328
329def int_ult_impl(context, builder, sig, args):
330 res = builder.icmp_unsigned('<', *args)
331 return impl_ret_untracked(context, builder, sig.return_type, res)
332
333
334def int_ule_impl(context, builder, sig, args):
335 res = builder.icmp_unsigned('<=', *args)
336 return impl_ret_untracked(context, builder, sig.return_type, res)
337
338
339def int_ugt_impl(context, builder, sig, args):
340 res = builder.icmp_unsigned('>', *args)
341 return impl_ret_untracked(context, builder, sig.return_type, res)
342
343
344def int_uge_impl(context, builder, sig, args):
345 res = builder.icmp_unsigned('>=', *args)
346 return impl_ret_untracked(context, builder, sig.return_type, res)
347
348
349def int_eq_impl(context, builder, sig, args):
350 res = builder.icmp_unsigned('==', *args)
351 return impl_ret_untracked(context, builder, sig.return_type, res)
352
353
354def int_ne_impl(context, builder, sig, args):
355 res = builder.icmp_unsigned('!=', *args)
356 return impl_ret_untracked(context, builder, sig.return_type, res)
357
358
359def int_signed_unsigned_cmp(op):
360 def impl(context, builder, sig, args):
361 (left, right) = args
362 # This code is translated from the NumPy source.
363 # What we're going to do is divide the range of a signed value at zero.
364 # If the signed value is less than zero, then we can treat zero as the
365 # unsigned value since the unsigned value is necessarily zero or larger
366 # and any signed comparison between a negative value and zero/infinity
367 # will yield the same result. If the signed value is greater than or
368 # equal to zero, then we can safely cast it to an unsigned value and do
369 # the expected unsigned-unsigned comparison operation.
370 # Original: https://github.com/numpy/numpy/pull/23713
371 cmp_zero = builder.icmp_signed('<', left, Constant(left.type, 0))
372 lt_zero = builder.icmp_signed(op, left, Constant(left.type, 0))
373 ge_zero = builder.icmp_unsigned(op, left, right)
374 res = builder.select(cmp_zero, lt_zero, ge_zero)
375 return impl_ret_untracked(context, builder, sig.return_type, res)
376 return impl
377
378
379def int_unsigned_signed_cmp(op):
380 def impl(context, builder, sig, args):
381 (left, right) = args
382 # See the function `int_signed_unsigned_cmp` for implementation notes.
383 cmp_zero = builder.icmp_signed('<', right, Constant(right.type, 0))
384 lt_zero = builder.icmp_signed(op, Constant(right.type, 0), right)
385 ge_zero = builder.icmp_unsigned(op, left, right)
386 res = builder.select(cmp_zero, lt_zero, ge_zero)
387 return impl_ret_untracked(context, builder, sig.return_type, res)
388 return impl
389
390
391def int_abs_impl(context, builder, sig, args):
392 [x] = args
393 ZERO = Constant(x.type, None)
394 ltz = builder.icmp_signed('<', x, ZERO)
395 negated = builder.neg(x)
396 res = builder.select(ltz, negated, x)
397 return impl_ret_untracked(context, builder, sig.return_type, res)
398
399
400def uint_abs_impl(context, builder, sig, args):
401 [x] = args
402 return impl_ret_untracked(context, builder, sig.return_type, x)
403
404
405def int_shl_impl(context, builder, sig, args):
406 [valty, amtty] = sig.args
407 [val, amt] = args
408 val = context.cast(builder, val, valty, sig.return_type)
409 amt = context.cast(builder, amt, amtty, sig.return_type)
410 res = builder.shl(val, amt)
411 return impl_ret_untracked(context, builder, sig.return_type, res)
412
413
414def int_shr_impl(context, builder, sig, args):
415 [valty, amtty] = sig.args
416 [val, amt] = args
417 val = context.cast(builder, val, valty, sig.return_type)
418 amt = context.cast(builder, amt, amtty, sig.return_type)
419 if sig.return_type.signed:
420 res = builder.ashr(val, amt)
421 else:
422 res = builder.lshr(val, amt)
423 return impl_ret_untracked(context, builder, sig.return_type, res)
424
425
426def int_and_impl(context, builder, sig, args):
427 [at, bt] = sig.args
428 [av, bv] = args
429 cav = context.cast(builder, av, at, sig.return_type)
430 cbc = context.cast(builder, bv, bt, sig.return_type)
431 res = builder.and_(cav, cbc)
432 return impl_ret_untracked(context, builder, sig.return_type, res)
433
434
435def int_or_impl(context, builder, sig, args):
436 [at, bt] = sig.args
437 [av, bv] = args
438 cav = context.cast(builder, av, at, sig.return_type)
439 cbc = context.cast(builder, bv, bt, sig.return_type)
440 res = builder.or_(cav, cbc)
441 return impl_ret_untracked(context, builder, sig.return_type, res)
442
443
444def int_xor_impl(context, builder, sig, args):
445 [at, bt] = sig.args
446 [av, bv] = args
447 cav = context.cast(builder, av, at, sig.return_type)
448 cbc = context.cast(builder, bv, bt, sig.return_type)
449 res = builder.xor(cav, cbc)
450 return impl_ret_untracked(context, builder, sig.return_type, res)
451
452
453def int_negate_impl(context, builder, sig, args):
454 [typ] = sig.args
455 [val] = args
456 # Negate before upcasting, for unsigned numbers
457 res = builder.neg(val)
458 res = context.cast(builder, res, typ, sig.return_type)
459 return impl_ret_untracked(context, builder, sig.return_type, res)
460
461
462def int_positive_impl(context, builder, sig, args):
463 [typ] = sig.args
464 [val] = args
465 res = context.cast(builder, val, typ, sig.return_type)
466 return impl_ret_untracked(context, builder, sig.return_type, res)
467
468
469def int_invert_impl(context, builder, sig, args):
470 [typ] = sig.args
471 [val] = args
472 # Invert before upcasting, for unsigned numbers
473 res = builder.xor(val, Constant(val.type, int('1' * val.type.width, 2)))
474 res = context.cast(builder, res, typ, sig.return_type)
475 return impl_ret_untracked(context, builder, sig.return_type, res)
476
477
478def int_sign_impl(context, builder, sig, args):
479 """
480 np.sign(int)
481 """
482 [x] = args
483 POS = Constant(x.type, 1)
484 NEG = Constant(x.type, -1)
485 ZERO = Constant(x.type, 0)
486
487 cmp_zero = builder.icmp_unsigned('==', x, ZERO)
488 cmp_pos = builder.icmp_signed('>', x, ZERO)
489
490 presult = cgutils.alloca_once(builder, x.type)
491
492 bb_zero = builder.append_basic_block(".zero")
493 bb_postest = builder.append_basic_block(".postest")
494 bb_pos = builder.append_basic_block(".pos")
495 bb_neg = builder.append_basic_block(".neg")
496 bb_exit = builder.append_basic_block(".exit")
497
498 builder.cbranch(cmp_zero, bb_zero, bb_postest)
499
500 with builder.goto_block(bb_zero):
501 builder.store(ZERO, presult)
502 builder.branch(bb_exit)
503
504 with builder.goto_block(bb_postest):
505 builder.cbranch(cmp_pos, bb_pos, bb_neg)
506
507 with builder.goto_block(bb_pos):
508 builder.store(POS, presult)
509 builder.branch(bb_exit)
510
511 with builder.goto_block(bb_neg):
512 builder.store(NEG, presult)
513 builder.branch(bb_exit)
514
515 builder.position_at_end(bb_exit)
516 res = builder.load(presult)
517 return impl_ret_untracked(context, builder, sig.return_type, res)
518
519
520def bool_negate_impl(context, builder, sig, args):
521 [typ] = sig.args
522 [val] = args
523 res = context.cast(builder, val, typ, sig.return_type)
524 res = builder.neg(res)
525 return impl_ret_untracked(context, builder, sig.return_type, res)
526
527
528def bool_unary_positive_impl(context, builder, sig, args):
529 [typ] = sig.args
530 [val] = args
531 res = context.cast(builder, val, typ, sig.return_type)
532 return impl_ret_untracked(context, builder, sig.return_type, res)
533
534
535# lower_builtin(operator.eq, types.boolean, types.boolean)(int_eq_impl)
536# lower_builtin(operator.ne, types.boolean, types.boolean)(int_ne_impl)
537# lower_builtin(operator.lt, types.boolean, types.boolean)(int_ult_impl)
538# lower_builtin(operator.le, types.boolean, types.boolean)(int_ule_impl)
539# lower_builtin(operator.gt, types.boolean, types.boolean)(int_ugt_impl)
540# lower_builtin(operator.ge, types.boolean, types.boolean)(int_uge_impl)
541# lower_builtin(operator.neg, types.boolean)(bool_negate_impl)
542# lower_builtin(operator.pos, types.boolean)(bool_unary_positive_impl)
543
544
545# def _implement_integer_operators():
546# ty = types.Integer
547
548# lower_builtin(operator.add, ty, ty)(int_add_impl)
549# lower_builtin(operator.iadd, ty, ty)(int_add_impl)
550# lower_builtin(operator.sub, ty, ty)(int_sub_impl)
551# lower_builtin(operator.isub, ty, ty)(int_sub_impl)
552# lower_builtin(operator.mul, ty, ty)(int_mul_impl)
553# lower_builtin(operator.imul, ty, ty)(int_mul_impl)
554# lower_builtin(operator.eq, ty, ty)(int_eq_impl)
555# lower_builtin(operator.ne, ty, ty)(int_ne_impl)
556
557# lower_builtin(operator.lshift, ty, ty)(int_shl_impl)
558# lower_builtin(operator.ilshift, ty, ty)(int_shl_impl)
559# lower_builtin(operator.rshift, ty, ty)(int_shr_impl)
560# lower_builtin(operator.irshift, ty, ty)(int_shr_impl)
561
562# lower_builtin(operator.neg, ty)(int_negate_impl)
563# lower_builtin(operator.pos, ty)(int_positive_impl)
564
565# lower_builtin(operator.pow, ty, ty)(int_power_impl)
566# lower_builtin(operator.ipow, ty, ty)(int_power_impl)
567# lower_builtin(pow, ty, ty)(int_power_impl)
568
569# for ty in types.unsigned_domain:
570# lower_builtin(operator.lt, ty, ty)(int_ult_impl)
571# lower_builtin(operator.le, ty, ty)(int_ule_impl)
572# lower_builtin(operator.gt, ty, ty)(int_ugt_impl)
573# lower_builtin(operator.ge, ty, ty)(int_uge_impl)
574# lower_builtin(operator.pow, types.Float, ty)(int_power_impl)
575# lower_builtin(operator.ipow, types.Float, ty)(int_power_impl)
576# lower_builtin(pow, types.Float, ty)(int_power_impl)
577# lower_builtin(abs, ty)(uint_abs_impl)
578
579# lower_builtin(operator.lt, types.IntegerLiteral, types.IntegerLiteral)(int_slt_impl)
580# lower_builtin(operator.gt, types.IntegerLiteral, types.IntegerLiteral)(int_slt_impl)
581# lower_builtin(operator.le, types.IntegerLiteral, types.IntegerLiteral)(int_slt_impl)
582# lower_builtin(operator.ge, types.IntegerLiteral, types.IntegerLiteral)(int_slt_impl)
583# for ty in types.signed_domain:
584# lower_builtin(operator.lt, ty, ty)(int_slt_impl)
585# lower_builtin(operator.le, ty, ty)(int_sle_impl)
586# lower_builtin(operator.gt, ty, ty)(int_sgt_impl)
587# lower_builtin(operator.ge, ty, ty)(int_sge_impl)
588# lower_builtin(operator.pow, types.Float, ty)(int_power_impl)
589# lower_builtin(operator.ipow, types.Float, ty)(int_power_impl)
590# lower_builtin(pow, types.Float, ty)(int_power_impl)
591# lower_builtin(abs, ty)(int_abs_impl)
592
593# def _implement_bitwise_operators():
594# for ty in (types.Boolean, types.Integer):
595# lower_builtin(operator.and_, ty, ty)(int_and_impl)
596# lower_builtin(operator.iand, ty, ty)(int_and_impl)
597# lower_builtin(operator.or_, ty, ty)(int_or_impl)
598# lower_builtin(operator.ior, ty, ty)(int_or_impl)
599# lower_builtin(operator.xor, ty, ty)(int_xor_impl)
600# lower_builtin(operator.ixor, ty, ty)(int_xor_impl)
601
602# lower_builtin(operator.invert, ty)(int_invert_impl)
603
604# _implement_integer_operators()
605
606# _implement_bitwise_operators()
607
608
609def real_add_impl(context, builder, sig, args):
610 res = builder.fadd(*args)
611 return impl_ret_untracked(context, builder, sig.return_type, res)
612
613
614def real_sub_impl(context, builder, sig, args):
615 res = builder.fsub(*args)
616 return impl_ret_untracked(context, builder, sig.return_type, res)
617
618
619def real_mul_impl(context, builder, sig, args):
620 res = builder.fmul(*args)
621 return impl_ret_untracked(context, builder, sig.return_type, res)
622
623
624def real_div_impl(context, builder, sig, args):
625 with cgutils.if_zero(builder, args[1]):
626 context.error_model.fp_zero_division(builder, ("division by zero",))
627 res = builder.fdiv(*args)
628 return impl_ret_untracked(context, builder, sig.return_type, res)
629
630
631def real_divmod(context, builder, x, y):
632 assert x.type == y.type
633 floatty = x.type
634
635 module = builder.module
636 fname = context.mangler(".numba.python.rem", [x.type])
637 fnty = ir.FunctionType(floatty, (floatty, floatty, ir.PointerType(floatty)))
638 fn = cgutils.get_or_insert_function(module, fnty, fname)
639
640 if fn.is_declaration:
641 fn.linkage = 'linkonce_odr'
642 fnbuilder = ir.IRBuilder(fn.append_basic_block('entry'))
643 fx, fy, pmod = fn.args
644 div, mod = real_divmod_func_body(context, fnbuilder, fx, fy)
645 fnbuilder.store(mod, pmod)
646 fnbuilder.ret(div)
647
648 pmod = cgutils.alloca_once(builder, floatty)
649 quotient = builder.call(fn, (x, y, pmod))
650 return quotient, builder.load(pmod)
651
652
653def real_divmod_func_body(context, builder, vx, wx):
654 # Reference Objects/floatobject.c
655 #
656 # float_divmod(PyObject *v, PyObject *w)
657 # {
658 # double vx, wx;
659 # double div, mod, floordiv;
660 # CONVERT_TO_DOUBLE(v, vx);
661 # CONVERT_TO_DOUBLE(w, wx);
662 # mod = fmod(vx, wx);
663 # /* fmod is typically exact, so vx-mod is *mathematically* an
664 # exact multiple of wx. But this is fp arithmetic, and fp
665 # vx - mod is an approximation; the result is that div may
666 # not be an exact integral value after the division, although
667 # it will always be very close to one.
668 # */
669 # div = (vx - mod) / wx;
670 # if (mod) {
671 # /* ensure the remainder has the same sign as the denominator */
672 # if ((wx < 0) != (mod < 0)) {
673 # mod += wx;
674 # div -= 1.0;
675 # }
676 # }
677 # else {
678 # /* the remainder is zero, and in the presence of signed zeroes
679 # fmod returns different results across platforms; ensure
680 # it has the same sign as the denominator; we'd like to do
681 # "mod = wx * 0.0", but that may get optimized away */
682 # mod *= mod; /* hide "mod = +0" from optimizer */
683 # if (wx < 0.0)
684 # mod = -mod;
685 # }
686 # /* snap quotient to nearest integral value */
687 # if (div) {
688 # floordiv = floor(div);
689 # if (div - floordiv > 0.5)
690 # floordiv += 1.0;
691 # }
692 # else {
693 # /* div is zero - get the same sign as the true quotient */
694 # div *= div; /* hide "div = +0" from optimizers */
695 # floordiv = div * vx / wx; /* zero w/ sign of vx/wx */
696 # }
697 # return Py_BuildValue("(dd)", floordiv, mod);
698 # }
699 pmod = cgutils.alloca_once(builder, vx.type)
700 pdiv = cgutils.alloca_once(builder, vx.type)
701 pfloordiv = cgutils.alloca_once(builder, vx.type)
702
703 mod = builder.frem(vx, wx)
704 div = builder.fdiv(builder.fsub(vx, mod), wx)
705
706 builder.store(mod, pmod)
707 builder.store(div, pdiv)
708
709 # Note the use of negative zero for proper negating with `ZERO - x`
710 ZERO = vx.type(0.0)
711 NZERO = vx.type(-0.0)
712 ONE = vx.type(1.0)
713 mod_istrue = builder.fcmp_unordered('!=', mod, ZERO)
714 wx_ltz = builder.fcmp_ordered('<', wx, ZERO)
715 mod_ltz = builder.fcmp_ordered('<', mod, ZERO)
716
717 with builder.if_else(mod_istrue, likely=True) as (if_nonzero_mod, if_zero_mod):
718 with if_nonzero_mod:
719 # `mod` is non-zero or NaN
720 # Ensure the remainder has the same sign as the denominator
721 wx_ltz_ne_mod_ltz = builder.icmp_unsigned('!=', wx_ltz, mod_ltz)
722
723 with builder.if_then(wx_ltz_ne_mod_ltz):
724 builder.store(builder.fsub(div, ONE), pdiv)
725 builder.store(builder.fadd(mod, wx), pmod)
726
727 with if_zero_mod:
728 # `mod` is zero, select the proper sign depending on
729 # the denominator's sign
730 mod = builder.select(wx_ltz, NZERO, ZERO)
731 builder.store(mod, pmod)
732
733 del mod, div
734
735 div = builder.load(pdiv)
736 div_istrue = builder.fcmp_ordered('!=', div, ZERO)
737
738 with builder.if_then(div_istrue):
739 realtypemap = {'float': types.float32,
740 'double': types.float64}
741 realtype = realtypemap[str(wx.type)]
742 floorfn = context.get_function(math.floor,
743 typing.signature(realtype, realtype))
744 floordiv = floorfn(builder, [div])
745 floordivdiff = builder.fsub(div, floordiv)
746 floordivincr = builder.fadd(floordiv, ONE)
747 HALF = Constant(wx.type, 0.5)
748 pred = builder.fcmp_ordered('>', floordivdiff, HALF)
749 floordiv = builder.select(pred, floordivincr, floordiv)
750 builder.store(floordiv, pfloordiv)
751
752 with cgutils.ifnot(builder, div_istrue):
753 div = builder.fmul(div, div)
754 builder.store(div, pdiv)
755 floordiv = builder.fdiv(builder.fmul(div, vx), wx)
756 builder.store(floordiv, pfloordiv)
757
758 return builder.load(pfloordiv), builder.load(pmod)
759
760
761# @lower_builtin(divmod, types.Float, types.Float)
762def real_divmod_impl(context, builder, sig, args, loc=None):
763 x, y = args
764 quot = cgutils.alloca_once(builder, x.type, name="quot")
765 rem = cgutils.alloca_once(builder, x.type, name="rem")
766
767 with builder.if_else(cgutils.is_scalar_zero(builder, y), likely=False
768 ) as (if_zero, if_non_zero):
769 with if_zero:
770 if not context.error_model.fp_zero_division(
771 builder, ("modulo by zero",), loc):
772 # No exception raised => compute the nan result,
773 # and set the FP exception word for Numpy warnings.
774 q = builder.fdiv(x, y)
775 r = builder.frem(x, y)
776 builder.store(q, quot)
777 builder.store(r, rem)
778 with if_non_zero:
779 q, r = real_divmod(context, builder, x, y)
780 builder.store(q, quot)
781 builder.store(r, rem)
782
783 return cgutils.pack_array(builder,
784 (builder.load(quot), builder.load(rem)))
785
786
787def real_mod_impl(context, builder, sig, args, loc=None):
788 x, y = args
789 res = cgutils.alloca_once(builder, x.type)
790 with builder.if_else(cgutils.is_scalar_zero(builder, y), likely=False
791 ) as (if_zero, if_non_zero):
792 with if_zero:
793 if not context.error_model.fp_zero_division(
794 builder, ("modulo by zero",), loc):
795 # No exception raised => compute the nan result,
796 # and set the FP exception word for Numpy warnings.
797 rem = builder.frem(x, y)
798 builder.store(rem, res)
799 with if_non_zero:
800 _, rem = real_divmod(context, builder, x, y)
801 builder.store(rem, res)
802 return impl_ret_untracked(context, builder, sig.return_type,
803 builder.load(res))
804
805
806def real_floordiv_impl(context, builder, sig, args, loc=None):
807 x, y = args
808 res = cgutils.alloca_once(builder, x.type)
809 with builder.if_else(cgutils.is_scalar_zero(builder, y), likely=False
810 ) as (if_zero, if_non_zero):
811 with if_zero:
812 if not context.error_model.fp_zero_division(
813 builder, ("division by zero",), loc):
814 # No exception raised => compute the +/-inf or nan result,
815 # and set the FP exception word for Numpy warnings.
816 quot = builder.fdiv(x, y)
817 builder.store(quot, res)
818 with if_non_zero:
819 quot, _ = real_divmod(context, builder, x, y)
820 builder.store(quot, res)
821 return impl_ret_untracked(context, builder, sig.return_type,
822 builder.load(res))
823
824
825def real_power_impl(context, builder, sig, args):
826 x, y = args
827 module = builder.module
828 if context.implement_powi_as_math_call:
829 imp = context.get_function(math.pow, sig)
830 res = imp(builder, args)
831 else:
832 fn = module.declare_intrinsic('llvm.pow', [y.type])
833 res = builder.call(fn, (x, y))
834 return impl_ret_untracked(context, builder, sig.return_type, res)
835
836
837def real_lt_impl(context, builder, sig, args):
838 res = builder.fcmp_ordered('<', *args)
839 return impl_ret_untracked(context, builder, sig.return_type, res)
840
841
842def real_le_impl(context, builder, sig, args):
843 res = builder.fcmp_ordered('<=', *args)
844 return impl_ret_untracked(context, builder, sig.return_type, res)
845
846
847def real_gt_impl(context, builder, sig, args):
848 res = builder.fcmp_ordered('>', *args)
849 return impl_ret_untracked(context, builder, sig.return_type, res)
850
851
852def real_ge_impl(context, builder, sig, args):
853 res = builder.fcmp_ordered('>=', *args)
854 return impl_ret_untracked(context, builder, sig.return_type, res)
855
856
857def real_eq_impl(context, builder, sig, args):
858 res = builder.fcmp_ordered('==', *args)
859 return impl_ret_untracked(context, builder, sig.return_type, res)
860
861
862def real_ne_impl(context, builder, sig, args):
863 res = builder.fcmp_unordered('!=', *args)
864 return impl_ret_untracked(context, builder, sig.return_type, res)
865
866
867def real_abs_impl(context, builder, sig, args):
868 [ty] = sig.args
869 sig = typing.signature(ty, ty)
870 impl = context.get_function(math.fabs, sig)
871 return impl(builder, args)
872
873
874def real_negate_impl(context, builder, sig, args):
875 from numba.cpython import mathimpl
876 res = mathimpl.negate_real(builder, args[0])
877 return impl_ret_untracked(context, builder, sig.return_type, res)
878
879
880def real_positive_impl(context, builder, sig, args):
881 [typ] = sig.args
882 [val] = args
883 res = context.cast(builder, val, typ, sig.return_type)
884 return impl_ret_untracked(context, builder, sig.return_type, res)
885
886
887def real_sign_impl(context, builder, sig, args):
888 """
889 np.sign(float)
890 """
891 [x] = args
892 POS = Constant(x.type, 1)
893 NEG = Constant(x.type, -1)
894 ZERO = Constant(x.type, 0)
895
896 presult = cgutils.alloca_once(builder, x.type)
897
898 is_pos = builder.fcmp_ordered('>', x, ZERO)
899 is_neg = builder.fcmp_ordered('<', x, ZERO)
900
901 with builder.if_else(is_pos) as (gt_zero, not_gt_zero):
902 with gt_zero:
903 builder.store(POS, presult)
904 with not_gt_zero:
905 with builder.if_else(is_neg) as (lt_zero, not_lt_zero):
906 with lt_zero:
907 builder.store(NEG, presult)
908 with not_lt_zero:
909 # For both NaN and 0, the result of sign() is simply
910 # the input value.
911 builder.store(x, presult)
912
913 res = builder.load(presult)
914 return impl_ret_untracked(context, builder, sig.return_type, res)
915
916
917# ty = types.Float
918
919# lower_builtin(operator.add, ty, ty)(real_add_impl)
920# lower_builtin(operator.iadd, ty, ty)(real_add_impl)
921# lower_builtin(operator.sub, ty, ty)(real_sub_impl)
922# lower_builtin(operator.isub, ty, ty)(real_sub_impl)
923# lower_builtin(operator.mul, ty, ty)(real_mul_impl)
924# lower_builtin(operator.imul, ty, ty)(real_mul_impl)
925# lower_builtin(operator.floordiv, ty, ty)(real_floordiv_impl)
926# lower_builtin(operator.ifloordiv, ty, ty)(real_floordiv_impl)
927# lower_builtin(operator.truediv, ty, ty)(real_div_impl)
928# lower_builtin(operator.itruediv, ty, ty)(real_div_impl)
929# lower_builtin(operator.mod, ty, ty)(real_mod_impl)
930# lower_builtin(operator.imod, ty, ty)(real_mod_impl)
931# lower_builtin(operator.pow, ty, ty)(real_power_impl)
932# lower_builtin(operator.ipow, ty, ty)(real_power_impl)
933# lower_builtin(pow, ty, ty)(real_power_impl)
934
935# lower_builtin(operator.eq, ty, ty)(real_eq_impl)
936# lower_builtin(operator.ne, ty, ty)(real_ne_impl)
937# lower_builtin(operator.lt, ty, ty)(real_lt_impl)
938# lower_builtin(operator.le, ty, ty)(real_le_impl)
939# lower_builtin(operator.gt, ty, ty)(real_gt_impl)
940# lower_builtin(operator.ge, ty, ty)(real_ge_impl)
941
942# lower_builtin(abs, ty)(real_abs_impl)
943
944# lower_builtin(operator.neg, ty)(real_negate_impl)
945# lower_builtin(operator.pos, ty)(real_positive_impl)
946
947# del ty
948
949
950# @lower_getattr(types.Complex, "real")
951def complex_real_impl(context, builder, typ, value):
952 cplx = context.make_complex(builder, typ, value=value)
953 res = cplx.real
954 return impl_ret_untracked(context, builder, typ, res)
955
956# @lower_getattr(types.Complex, "imag")
957def complex_imag_impl(context, builder, typ, value):
958 cplx = context.make_complex(builder, typ, value=value)
959 res = cplx.imag
960 return impl_ret_untracked(context, builder, typ, res)
961
962# @lower_builtin("complex.conjugate", types.Complex)
963def complex_conjugate_impl(context, builder, sig, args):
964 from numba.cpython import mathimpl
965 z = context.make_complex(builder, sig.args[0], args[0])
966 z.imag = mathimpl.negate_real(builder, z.imag)
967 res = z._getvalue()
968 return impl_ret_untracked(context, builder, sig.return_type, res)
969
970def real_real_impl(context, builder, typ, value):
971 return impl_ret_untracked(context, builder, typ, value)
972
973def real_imag_impl(context, builder, typ, value):
974 res = cgutils.get_null_value(value.type)
975 return impl_ret_untracked(context, builder, typ, res)
976
977def real_conjugate_impl(context, builder, sig, args):
978 return impl_ret_untracked(context, builder, sig.return_type, args[0])
979
980# for cls in (types.Float, types.Integer):
981# lower_getattr(cls, "real")(real_real_impl)
982# lower_getattr(cls, "imag")(real_imag_impl)
983# lower_builtin("complex.conjugate", cls)(real_conjugate_impl)
984
985
986# @lower_builtin(operator.pow, types.Complex, types.Complex)
987# @lower_builtin(operator.ipow, types.Complex, types.Complex)
988# @lower_builtin(pow, types.Complex, types.Complex)
989def complex_power_impl(context, builder, sig, args):
990 [ca, cb] = args
991 ty = sig.args[0]
992 fty = ty.underlying_float
993 a = context.make_helper(builder, ty, value=ca)
994 b = context.make_helper(builder, ty, value=cb)
995 c = context.make_helper(builder, ty)
996 module = builder.module
997 pa = a._getpointer()
998 pb = b._getpointer()
999 pc = c._getpointer()
1000
1001 # Optimize for square because cpow loses a lot of precision
1002 TWO = context.get_constant(fty, 2)
1003 ZERO = context.get_constant(fty, 0)
1004
1005 b_real_is_two = builder.fcmp_ordered('==', b.real, TWO)
1006 b_imag_is_zero = builder.fcmp_ordered('==', b.imag, ZERO)
1007 b_is_two = builder.and_(b_real_is_two, b_imag_is_zero)
1008
1009 with builder.if_else(b_is_two) as (then, otherwise):
1010 with then:
1011 # Lower as multiplication
1012 res = complex_mul_impl(context, builder, sig, (ca, ca))
1013 cres = context.make_helper(builder, ty, value=res)
1014 c.real = cres.real
1015 c.imag = cres.imag
1016
1017 with otherwise:
1018 # Lower with call to external function
1019 func_name = {
1020 types.complex64: "numba_cpowf",
1021 types.complex128: "numba_cpow",
1022 }[ty]
1023 fnty = ir.FunctionType(ir.VoidType(), [pa.type] * 3)
1024 cpow = cgutils.get_or_insert_function(module, fnty, func_name)
1025 builder.call(cpow, (pa, pb, pc))
1026
1027 res = builder.load(pc)
1028 return impl_ret_untracked(context, builder, sig.return_type, res)
1029
1030def complex_add_impl(context, builder, sig, args):
1031 [cx, cy] = args
1032 ty = sig.args[0]
1033 x = context.make_complex(builder, ty, value=cx)
1034 y = context.make_complex(builder, ty, value=cy)
1035 z = context.make_complex(builder, ty)
1036 a = x.real
1037 b = x.imag
1038 c = y.real
1039 d = y.imag
1040 z.real = builder.fadd(a, c)
1041 z.imag = builder.fadd(b, d)
1042 res = z._getvalue()
1043 return impl_ret_untracked(context, builder, sig.return_type, res)
1044
1045
1046def complex_sub_impl(context, builder, sig, args):
1047 [cx, cy] = args
1048 ty = sig.args[0]
1049 x = context.make_complex(builder, ty, value=cx)
1050 y = context.make_complex(builder, ty, value=cy)
1051 z = context.make_complex(builder, ty)
1052 a = x.real
1053 b = x.imag
1054 c = y.real
1055 d = y.imag
1056 z.real = builder.fsub(a, c)
1057 z.imag = builder.fsub(b, d)
1058 res = z._getvalue()
1059 return impl_ret_untracked(context, builder, sig.return_type, res)
1060
1061
1062def complex_mul_impl(context, builder, sig, args):
1063 """
1064 (a+bi)(c+di)=(ac-bd)+i(ad+bc)
1065 """
1066 [cx, cy] = args
1067 ty = sig.args[0]
1068 x = context.make_complex(builder, ty, value=cx)
1069 y = context.make_complex(builder, ty, value=cy)
1070 z = context.make_complex(builder, ty)
1071 a = x.real
1072 b = x.imag
1073 c = y.real
1074 d = y.imag
1075 ac = builder.fmul(a, c)
1076 bd = builder.fmul(b, d)
1077 ad = builder.fmul(a, d)
1078 bc = builder.fmul(b, c)
1079 z.real = builder.fsub(ac, bd)
1080 z.imag = builder.fadd(ad, bc)
1081 res = z._getvalue()
1082 return impl_ret_untracked(context, builder, sig.return_type, res)
1083
1084
1085NAN = float('nan')
1086
1087def complex_div_impl(context, builder, sig, args):
1088 def complex_div(a, b):
1089 # This is CPython's algorithm (in _Py_c_quot()).
1090 areal = a.real
1091 aimag = a.imag
1092 breal = b.real
1093 bimag = b.imag
1094 if not breal and not bimag:
1095 raise ZeroDivisionError("complex division by zero")
1096 if abs(breal) >= abs(bimag):
1097 # Divide tops and bottom by b.real
1098 if not breal:
1099 return complex(NAN, NAN)
1100 ratio = bimag / breal
1101 denom = breal + bimag * ratio
1102 return complex(
1103 (areal + aimag * ratio) / denom,
1104 (aimag - areal * ratio) / denom)
1105 else:
1106 # Divide tops and bottom by b.imag
1107 if not bimag:
1108 return complex(NAN, NAN)
1109 ratio = breal / bimag
1110 denom = breal * ratio + bimag
1111 return complex(
1112 (a.real * ratio + a.imag) / denom,
1113 (a.imag * ratio - a.real) / denom)
1114
1115 res = context.compile_internal(builder, complex_div, sig, args)
1116 return impl_ret_untracked(context, builder, sig.return_type, res)
1117
1118
1119def complex_negate_impl(context, builder, sig, args):
1120 from numba.cpython import mathimpl
1121 [typ] = sig.args
1122 [val] = args
1123 cmplx = context.make_complex(builder, typ, value=val)
1124 res = context.make_complex(builder, typ)
1125 res.real = mathimpl.negate_real(builder, cmplx.real)
1126 res.imag = mathimpl.negate_real(builder, cmplx.imag)
1127 res = res._getvalue()
1128 return impl_ret_untracked(context, builder, sig.return_type, res)
1129
1130
1131def complex_positive_impl(context, builder, sig, args):
1132 [val] = args
1133 return impl_ret_untracked(context, builder, sig.return_type, val)
1134
1135
1136def complex_eq_impl(context, builder, sig, args):
1137 [cx, cy] = args
1138 typ = sig.args[0]
1139 x = context.make_complex(builder, typ, value=cx)
1140 y = context.make_complex(builder, typ, value=cy)
1141
1142 reals_are_eq = builder.fcmp_ordered('==', x.real, y.real)
1143 imags_are_eq = builder.fcmp_ordered('==', x.imag, y.imag)
1144 res = builder.and_(reals_are_eq, imags_are_eq)
1145 return impl_ret_untracked(context, builder, sig.return_type, res)
1146
1147
1148def complex_ne_impl(context, builder, sig, args):
1149 [cx, cy] = args
1150 typ = sig.args[0]
1151 x = context.make_complex(builder, typ, value=cx)
1152 y = context.make_complex(builder, typ, value=cy)
1153
1154 reals_are_ne = builder.fcmp_unordered('!=', x.real, y.real)
1155 imags_are_ne = builder.fcmp_unordered('!=', x.imag, y.imag)
1156 res = builder.or_(reals_are_ne, imags_are_ne)
1157 return impl_ret_untracked(context, builder, sig.return_type, res)
1158
1159
1160def complex_abs_impl(context, builder, sig, args):
1161 """
1162 abs(z) := hypot(z.real, z.imag)
1163 """
1164 def complex_abs(z):
1165 return math.hypot(z.real, z.imag)
1166
1167 res = context.compile_internal(builder, complex_abs, sig, args)
1168 return impl_ret_untracked(context, builder, sig.return_type, res)
1169
1170
1171# ty = types.Complex
1172
1173# lower_builtin(operator.add, ty, ty)(complex_add_impl)
1174# lower_builtin(operator.iadd, ty, ty)(complex_add_impl)
1175# lower_builtin(operator.sub, ty, ty)(complex_sub_impl)
1176# lower_builtin(operator.isub, ty, ty)(complex_sub_impl)
1177# lower_builtin(operator.mul, ty, ty)(complex_mul_impl)
1178# lower_builtin(operator.imul, ty, ty)(complex_mul_impl)
1179# lower_builtin(operator.truediv, ty, ty)(complex_div_impl)
1180# lower_builtin(operator.itruediv, ty, ty)(complex_div_impl)
1181# lower_builtin(operator.neg, ty)(complex_negate_impl)
1182# lower_builtin(operator.pos, ty)(complex_positive_impl)
1183# # Complex modulo is deprecated in python3
1184
1185# lower_builtin(operator.eq, ty, ty)(complex_eq_impl)
1186# lower_builtin(operator.ne, ty, ty)(complex_ne_impl)
1187
1188# lower_builtin(abs, ty)(complex_abs_impl)
1189
1190# del ty
1191
1192
1193# @lower_builtin("number.item", types.Boolean)
1194# @lower_builtin("number.item", types.Number)
1195def number_item_impl(context, builder, sig, args):
1196 """
1197 The no-op .item() method on booleans and numbers.
1198 """
1199 return args[0]
1200
1201
1202#------------------------------------------------------------------------------
1203
1204
1205def number_not_impl(context, builder, sig, args):
1206 [typ] = sig.args
1207 [val] = args
1208 istrue = context.cast(builder, val, typ, sig.return_type)
1209 res = builder.not_(istrue)
1210 return impl_ret_untracked(context, builder, sig.return_type, res)
1211
1212# @lower_builtin(bool, types.Boolean)
1213def bool_as_bool(context, builder, sig, args):
1214 [val] = args
1215 return val
1216
1217# @lower_builtin(bool, types.Integer)
1218def int_as_bool(context, builder, sig, args):
1219 [val] = args
1220 return builder.icmp_unsigned('!=', val, Constant(val.type, 0))
1221
1222# @lower_builtin(bool, types.Float)
1223def float_as_bool(context, builder, sig, args):
1224 [val] = args
1225 return builder.fcmp_unordered('!=', val, Constant(val.type, 0.0))
1226
1227# @lower_builtin(bool, types.Complex)
1228def complex_as_bool(context, builder, sig, args):
1229 [typ] = sig.args
1230 [val] = args
1231 cmplx = context.make_complex(builder, typ, val)
1232 real, imag = cmplx.real, cmplx.imag
1233 zero = Constant(real.type, 0.0)
1234 real_istrue = builder.fcmp_unordered('!=', real, zero)
1235 imag_istrue = builder.fcmp_unordered('!=', imag, zero)
1236 return builder.or_(real_istrue, imag_istrue)
1237
1238
1239# for ty in (types.Integer, types.Float, types.Complex):
1240# lower_builtin(operator.not_, ty)(number_not_impl)
1241
1242# lower_builtin(operator.not_, types.boolean)(number_not_impl)
1243
1244
1245#------------------------------------------------------------------------------
1246# Hashing numbers, see hashing.py
1247
1248#-------------------------------------------------------------------------------
1249# Implicit casts between numerics
1250
1251# @lower_cast(types.IntegerLiteral, types.Integer)
1252# @lower_cast(types.IntegerLiteral, types.Float)
1253# @lower_cast(types.IntegerLiteral, types.Complex)
1254def literal_int_to_number(context, builder, fromty, toty, val):
1255 lit = context.get_constant_generic(
1256 builder,
1257 fromty.literal_type,
1258 fromty.literal_value,
1259 )
1260 return context.cast(builder, lit, fromty.literal_type, toty)
1261
1262
1263# @lower_cast(types.Integer, types.Integer)
1264def integer_to_integer(context, builder, fromty, toty, val):
1265 if toty.bitwidth == fromty.bitwidth:
1266 # Just a change of signedness
1267 return val
1268 elif toty.bitwidth < fromty.bitwidth:
1269 # Downcast
1270 return builder.trunc(val, context.get_value_type(toty))
1271 elif fromty.signed:
1272 # Signed upcast
1273 return builder.sext(val, context.get_value_type(toty))
1274 else:
1275 # Unsigned upcast
1276 return builder.zext(val, context.get_value_type(toty))
1277
1278# @lower_cast(types.Integer, types.voidptr)
1279def integer_to_voidptr(context, builder, fromty, toty, val):
1280 return builder.inttoptr(val, context.get_value_type(toty))
1281
1282# @lower_cast(types.Float, types.Float)
1283def float_to_float(context, builder, fromty, toty, val):
1284 lty = context.get_value_type(toty)
1285 if fromty.bitwidth < toty.bitwidth:
1286 return builder.fpext(val, lty)
1287 else:
1288 return builder.fptrunc(val, lty)
1289
1290# @lower_cast(types.Integer, types.Float)
1291def integer_to_float(context, builder, fromty, toty, val):
1292 lty = context.get_value_type(toty)
1293 if fromty.signed:
1294 return builder.sitofp(val, lty)
1295 else:
1296 return builder.uitofp(val, lty)
1297
1298# @lower_cast(types.Float, types.Integer)
1299def float_to_integer(context, builder, fromty, toty, val):
1300 lty = context.get_value_type(toty)
1301 if toty.signed:
1302 return builder.fptosi(val, lty)
1303 else:
1304 return builder.fptoui(val, lty)
1305
1306# @lower_cast(types.Float, types.Complex)
1307# @lower_cast(types.Integer, types.Complex)
1308def non_complex_to_complex(context, builder, fromty, toty, val):
1309 real = context.cast(builder, val, fromty, toty.underlying_float)
1310 imag = context.get_constant(toty.underlying_float, 0)
1311
1312 cmplx = context.make_complex(builder, toty)
1313 cmplx.real = real
1314 cmplx.imag = imag
1315 return cmplx._getvalue()
1316
1317# @lower_cast(types.Complex, types.Complex)
1318def complex_to_complex(context, builder, fromty, toty, val):
1319 srcty = fromty.underlying_float
1320 dstty = toty.underlying_float
1321
1322 src = context.make_complex(builder, fromty, value=val)
1323 dst = context.make_complex(builder, toty)
1324 dst.real = context.cast(builder, src.real, srcty, dstty)
1325 dst.imag = context.cast(builder, src.imag, srcty, dstty)
1326 return dst._getvalue()
1327
1328# @lower_cast(types.Any, types.Boolean)
1329def any_to_boolean(context, builder, fromty, toty, val):
1330 return context.is_true(builder, fromty, val)
1331
1332# @lower_cast(types.Boolean, types.Number)
1333def boolean_to_any(context, builder, fromty, toty, val):
1334 # Casting from boolean to anything first casts to int32
1335 asint = builder.zext(val, ir.IntType(32))
1336 return context.cast(builder, asint, types.int32, toty)
1337
1338# @lower_cast(types.IntegerLiteral, types.Boolean)
1339# @lower_cast(types.BooleanLiteral, types.Boolean)
1340def literal_int_to_boolean(context, builder, fromty, toty, val):
1341 lit = context.get_constant_generic(
1342 builder,
1343 fromty.literal_type,
1344 fromty.literal_value,
1345 )
1346 return context.is_true(builder, fromty.literal_type, lit)
1347
1348#-------------------------------------------------------------------------------
1349# Constants
1350
1351# @lower_constant(types.Complex)
1352def constant_complex(context, builder, ty, pyval):
1353 fty = ty.underlying_float
1354 real = context.get_constant_generic(builder, fty, pyval.real)
1355 imag = context.get_constant_generic(builder, fty, pyval.imag)
1356 return Constant.literal_struct((real, imag))
1357
1358# @lower_constant(types.Integer)
1359# @lower_constant(types.Float)
1360# @lower_constant(types.Boolean)
1361def constant_integer(context, builder, ty, pyval):
1362 # See https://github.com/numba/numba/issues/6979
1363 # llvmlite ir.IntType specialises the formatting of the constant for a
1364 # cpython bool. A NumPy np.bool_ is not a cpython bool so force it to be one
1365 # so that the constant renders correctly!
1366 if isinstance(pyval, np.bool_):
1367 pyval = bool(pyval)
1368 lty = context.get_value_type(ty)
1369 return lty(pyval)
1370
1371
1372#-------------------------------------------------------------------------------
1373# View
1374
1375def scalar_view(scalar, viewty):
1376 """ Typing for the np scalar 'view' method. """
1377 if (isinstance(scalar, (types.Float, types.Integer))
1378 and isinstance(viewty, types.abstract.DTypeSpec)):
1379 if scalar.bitwidth != viewty.dtype.bitwidth:
1380 raise errors.TypingError(
1381 "Changing the dtype of a 0d array is only supported if the "
1382 "itemsize is unchanged")
1383
1384 def impl(scalar, viewty):
1385 return viewer(scalar, viewty)
1386 return impl
1387
1388
1389# overload_method(types.Float, 'view')(scalar_view)
1390# overload_method(types.Integer, 'view')(scalar_view)