def test_array_repr(self): tp = ArrayType(int8, 3) values = [Constant(int8, x) for x in (5, 10, -15)] c = Constant(tp, values) self.assertEqual(str(c), "[3 x i8] [i8 5, i8 10, i8 -15]") c = Constant(tp, bytearray(b"\x01\x02\x03")) self.assertEqual(str(c), '[3 x i8] c"\\01\\02\\03"')
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(ll_ret_type, 0) one = Constant(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 real_sign_impl(context, builder, sig, args): """ np.sign(float) """ [x] = args POS = Constant(x.type, 1) NEG = Constant(x.type, -1) ZERO = Constant(x.type, 0) presult = cgutils.alloca_once(builder, x.type) is_pos = builder.fcmp_ordered('>', x, ZERO) is_neg = builder.fcmp_ordered('<', 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 is_inf(builder, val): """ Return a condition testing whether *val* is an infinite. """ pos_inf = Constant(val.type, float("+inf")) neg_inf = Constant(val.type, float("-inf")) isposinf = builder.fcmp_ordered('==', val, pos_inf) isneginf = builder.fcmp_ordered('==', val, neg_inf) return builder.or_(isposinf, isneginf)
def test_array_repr(): int8 = IntType(8) tp = ArrayType(int8, 3) int8_1 = Constant(int8, 1) tp1 = tp.gep(int8_1) print(tp1, type(tp1)) values = [Constant(int8, x) for x in (5, 10, -15)] c = Constant(tp, values) print(c) assert str(c) == "[3 x i8] [i8 5, i8 10, i8 -15]" c = Constant(tp, bytearray(b"\x01\x02\x03")) print(c) assert str(c) == '[3 x i8] c"\\01\\02\\03"'
def is_leap_year(builder, year_val): """ Return a predicate indicating whether *year_val* (offset by 1970) is a leap year. """ actual_year = builder.add(year_val, Constant(DATETIME64, 1970)) multiple_of_4 = cgutils.is_null( builder, builder.and_(actual_year, Constant(DATETIME64, 3))) not_multiple_of_100 = cgutils.is_not_null( builder, builder.srem(actual_year, Constant(DATETIME64, 100))) multiple_of_400 = cgutils.is_null( builder, builder.srem(actual_year, Constant(DATETIME64, 400))) return builder.and_(multiple_of_4, builder.or_(not_multiple_of_100, multiple_of_400))
def visit_Boolean(self, node: Boolean) -> Constant: """Converts the boolean type to an integer (i1) constant. Args: nodo (Boolean): a token represeting a literal boolean type Returns: Constant: a constant of type IntType (1) representing the Boolean type: 1 = True and 0 = False """ if node.token.type == TokenType.FALSE: return Constant(IntType(1), 0) else: return Constant(IntType(1), 1)
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(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 init_generator_state(self, lower): """ NULL-initialize all generator state variables, to avoid spurious decref's on cleanup. """ lower.builder.store(Constant(self.gen_state_ptr.type.pointee, None), self.gen_state_ptr)
def return_from_generator(self, lower): """ Emit a StopIteration at generator end and mark the generator exhausted. """ indexval = Constant(self.resume_index_ptr.type.pointee, -1) lower.builder.store(indexval, self.resume_index_ptr) self.call_conv.return_stop_iteration(lower.builder)
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(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 __call__(self, value): """ Create a LLVM constant of this type with the given Python value. """ from llvmlite.ir import Constant return Constant(self, value)
def wrap_constant_value(self, values): from . import Value, Constant if not isinstance(values, (list, tuple)): if isinstance(values, Constant): if values.type != self.element: raise TypeError("expected {} for {}".format( self.element, values.type)) return (values, ) * self.count return (Constant(self.element, values), ) * self.count if len(values) != len(self): raise ValueError("wrong constant size for %s: got %d elements" % (self, len(values))) return [ Constant(ty, val) if not isinstance(val, Value) else val for ty, val in zip(self.elements, values) ]
def int_invert_impl(context, builder, sig, args): [typ] = sig.args [val] = args # Invert before upcasting, for unsigned numbers res = builder.xor(val, Constant(val.type, int('1' * val.type.width, 2))) res = context.cast(builder, res, typ, sig.return_type) return impl_ret_untracked(context, builder, sig.return_type, res)
def int_abs_impl(context, builder, sig, args): [x] = args ZERO = Constant(x.type, None) ltz = builder.icmp_signed('<', x, ZERO) negated = builder.neg(x) res = builder.select(ltz, negated, x) return impl_ret_untracked(context, builder, sig.return_type, res)
def visit_Writeln(self, node: Writeln) -> None: """Converts the contents of the command writeln to LLVM ir code and adds the print call to the operating system. Args: node (Writeln): content passed in the command writeln """ self.printf_counter += 1 output_operation_type = "%s" if isinstance(node.content[0], BinaryOperator): self._create_instruct("BinaryOperator", is_printf=True) writeln_content = self.visit(node.content[0]) if isinstance(writeln_content, VarSymbol): content = self.GLOBAL_MEMORY[writeln_content.name] else: content = writeln_content content_type = type(content.type).__name__ if self.builder.block.is_terminated: self._create_instruct(typ=content_type, is_printf=True) if isinstance(content.type, DoubleType): output_operation_type = "%f" output_format = f"{output_operation_type}\n\0" printf_format = Constant( ArrayType(IntType(8), len(output_format)), bytearray(output_format.encode("utf8")), ) fstr = GlobalVariable(self.module, printf_format.type, name=f"fstr_{self.printf_counter}") fstr.linkage = "internal" fstr.global_constant = True fstr.initializer = printf_format writeln_type = FunctionType(IntType(32), [], var_arg=True) writeln = Function( self.module, writeln_type, name=f"printf_{content_type}_{self.printf_counter}", ) body = self.builder.alloca(content.type) temp_loaded = self.builder.load(body) self.builder.store(temp_loaded, body) void_pointer_type = IntType(8).as_pointer() casted_arg = self.builder.bitcast(fstr, void_pointer_type) self.builder.call(writeln, [casted_arg, body]) self.builder.ret_void()
def complex_as_bool(context, builder, sig, args): [typ] = sig.args [val] = args cmplx = context.make_complex(builder, typ, val) real, imag = cmplx.real, cmplx.imag zero = Constant(real.type, 0.0) real_istrue = builder.fcmp_unordered('!=', real, zero) imag_istrue = builder.fcmp_unordered('!=', imag, zero) return builder.or_(real_istrue, imag_istrue)
def insert_const_bytes(self, mod, bytes, name=None): """ Insert constant *byte* (a `bytes` object) into module *mod*. """ stringtype = GENERIC_POINTER name = ".bytes.%s" % (name or hash(bytes)) text = cgutils.make_bytearray(bytes) gv = self.insert_unique_const(mod, name, text) return Constant.bitcast(gv, stringtype)
def insert_const_string(self, mod, string): """ Insert constant *string* (a str object) into module *mod*. """ stringtype = GENERIC_POINTER name = ".const.%s" % string text = cgutils.make_bytearray(string.encode("utf-8") + b"\x00") gv = self.insert_unique_const(mod, name, text) return Constant.bitcast(gv, stringtype)
def visit_Num(self, node: Num) -> Constant: """Set the Double Type to a specific number. Args: node (Num): a token represeting a number (constant) Returns: Constant: a LLVM IR Constant representing the number. """ return Constant(DoubleType(), float(node.value))
def visit_UnaryOperator(self, node: UnaryOperator) -> Constant: """Performs Unary Operations according to the arithmetic operator (PLUS and MINUS) transforming them into a LLVM IR Constant. Args: node (UnaryOperator): node containing the variables (or numbers) and the arithmetic operators (PLUS and MINUS) Returns: Constant: a LLVM IR Constant representing the number or variable. """ operator = node.operator.type if operator == TokenType.PLUS: expression = self.visit(node.expression) return Constant(DoubleType(), float(+expression.constant)) elif operator == TokenType.MINUS: expression = self.visit(node.expression) return Constant(DoubleType(), float(-expression.constant))
def wrap_constant_value(self, values): from . import Value, Constant if not isinstance(values, (list, tuple)): return values if len(values) != len(self): raise ValueError("wrong constant size for %s: got %d elements" % (self, len(values))) return [ Constant(ty, val) if not isinstance(val, Value) else val for ty, val in zip(self.elements, values) ]
def timedelta_sign_impl(context, builder, sig, args): """ np.sign(timedelta64) """ val, = args ret = alloc_timedelta_result(builder) zero = Constant(TIMEDELTA64, 0) with builder.if_else(builder.icmp_signed('>', val, zero)) as (gt_zero, le_zero): with gt_zero: builder.store(Constant(TIMEDELTA64, 1), ret) with le_zero: with builder.if_else(builder.icmp_unsigned('==', val, zero)) as (eq_zero, lt_zero): with eq_zero: builder.store(Constant(TIMEDELTA64, 0), ret) with lt_zero: builder.store(Constant(TIMEDELTA64, -1), ret) res = builder.load(ret) return impl_ret_untracked(context, builder, sig.return_type, res)
def int_sign_impl(context, builder, sig, args): """ np.sign(int) """ [x] = args POS = Constant(x.type, 1) NEG = Constant(x.type, -1) ZERO = Constant(x.type, 0) cmp_zero = builder.icmp_unsigned('==', x, ZERO) cmp_pos = builder.icmp_signed('>', 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 generate_functions(self, functions): type_dict = { 'int': int_type, 'float': float_type, 'byte': byte_type, 'bool': int_type, 'void': void_type } for function in functions: # register function name = function.name if function.name != 'main' else '_gone_main' return_type = type_dict[function.return_type] param_types = [type_dict[t] for t in function.param_types] function_type = FunctionType(return_type, param_types) self.function = Function(self.module, function_type, name=name) self.globals[name] = self.function self.blocks = {} self.block = self.function.append_basic_block('entry') self.blocks['entry'] = self.block self.builder = IRBuilder(self.block) # local scope self.vars = self.vars.new_child() self.temps = {} for n, (param_name, param_type) in enumerate( zip(function.param_names, param_types)): var = self.builder.alloca(param_type, name=param_name) var.initializer = Constant(param_type, 0) self.vars[param_name] = var self.builder.store(self.function.args[n], self.vars[param_name]) # alloc return var / block if function.return_type != 'void': self.vars['return'] = self.builder.alloca(return_type, name='return') self.return_block = self.function.append_basic_block('return') # generate instructions self.generate_code(function) # return if not self.block.is_terminated: self.builder.branch(self.return_block) self.builder.position_at_end(self.return_block) if function.return_type != 'void': self.builder.ret( self.builder.load(self.vars['return'], 'return')) else: self.builder.ret_void() self.vars = self.vars.parents
def visit_String(self, node: String) -> Constant: """Converts the literal string to an array of characters. Args: node (String): a token represeting a string (literal) Returns: Constant: a constant containing a array of characters """ content = node.value return Constant(ArrayType(IntType(8), len(content)), bytearray(content.encode("utf8")))
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(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) res = builder.load(ret) return impl_ret_untracked(context, builder, sig.return_type, res)
def lower_init_func(self, lower): """ Lower the generator's initialization function (which will fill up the passed-by-reference generator structure). """ lower.setup_function(self.fndesc) builder = lower.builder # Insert the generator into the target context in order to allow # calling from other Numba-compiled functions. lower.context.insert_generator(self.gentype, self.gendesc, [self.library]) # Init argument values lower.extract_function_arguments() lower.pre_lower() # Initialize the return structure (i.e. the generator structure). retty = self.context.get_return_type(self.gentype) # Structure index #0: the initial resume index (0 == start of generator) resume_index = self.context.get_constant(types.int32, 0) # Structure index #1: the function arguments argsty = retty.elements[1] statesty = retty.elements[2] lower.debug_print("# low_init_func incref") # Incref all NRT arguments before storing into generator states if self.context.enable_nrt: for argty, argval in zip(self.fndesc.argtypes, lower.fnargs): self.context.nrt.incref(builder, argty, argval) # Filter out omitted arguments argsval = self.arg_packer.as_data(builder, lower.fnargs) # Zero initialize states statesval = Constant(statesty, None) gen_struct = cgutils.make_anonymous_struct(builder, [resume_index, argsval, statesval], retty) retval = self.box_generator_struct(lower, gen_struct) lower.debug_print("# low_init_func before return") self.call_conv.return_value(builder, retval) lower.post_lower()
def details(context, builder, signature, args): [kind_val, char_bytes_val, length_val] = args # fill the struct uni_str_ctor = cgutils.create_struct_proxy(types.unicode_type) uni_str = uni_str_ctor(context, builder) # add null padding character nbytes_val = builder.mul(char_bytes_val, builder.add(length_val, Constant(length_val.type, 1))) uni_str.meminfo = context.nrt.meminfo_alloc(builder, nbytes_val) uni_str.kind = kind_val uni_str.length = length_val uni_str.data = context.nrt.meminfo_data(builder, uni_str.meminfo) # Set parent to NULL uni_str.parent = cgutils.get_null_value(uni_str.parent.type) return uni_str._getvalue()
def details(context, builder, signature, args): [kind_val, char_bytes_val, length_val, is_ascii_val] = args # fill the struct uni_str_ctor = cgutils.create_struct_proxy(types.unicode_type) uni_str = uni_str_ctor(context, builder) # add null padding character nbytes_val = builder.mul(char_bytes_val, builder.add(length_val, Constant(length_val.type, 1))) uni_str.meminfo = context.nrt.meminfo_alloc(builder, nbytes_val) uni_str.kind = kind_val uni_str.is_ascii = is_ascii_val uni_str.length = length_val # empty string has hash value -1 to indicate "need to compute hash" uni_str.hash = context.get_constant(_Py_hash_t, -1) uni_str.data = context.nrt.meminfo_data(builder, uni_str.meminfo) # Set parent to NULL uni_str.parent = cgutils.get_null_value(uni_str.parent.type) return uni_str._getvalue()