diff --git a/src/analyze.cpp b/src/analyze.cpp index 1cb36682f9..263c04f6e4 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -161,18 +161,17 @@ static TypeTableEntry *new_container_type_entry(TypeTableEntryId id, AstNode *so return entry; } +static uint8_t log2_u64(uint64_t x) { + return (63 - __builtin_clzll(x)); +} -// TODO no reason to limit to 8/16/32/64 static uint8_t bits_needed_for_unsigned(uint64_t x) { - if (x <= UINT8_MAX) { - return 8; - } else if (x <= UINT16_MAX) { - return 16; - } else if (x <= UINT32_MAX) { - return 32; - } else { - return 64; + if (x == 0) { + return 0; } + uint8_t base = log2_u64(x); + uint64_t upper = (((uint64_t)1) << base) - 1; + return (upper >= x) ? base : (base + 1); } bool type_is_complete(TypeTableEntry *type_entry) { diff --git a/src/bigint.cpp b/src/bigint.cpp index 5679d2041a..5c68b18a81 100644 --- a/src/bigint.cpp +++ b/src/bigint.cpp @@ -95,7 +95,9 @@ static void to_twos_complement(BigInt *dest, const BigInt *op, size_t bit_count) } static bool bit_at_index(const BigInt *bi, size_t index) { - size_t digit_index = bi->digit_count - (index / 64) - 1; + size_t digit_index = index / 64; + if (digit_index >= bi->digit_count) + return false; size_t digit_bit_index = index % 64; const uint64_t *digits = bigint_ptr(bi); uint64_t digit = digits[digit_index]; diff --git a/src/codegen.cpp b/src/codegen.cpp index a7695d4d5f..7581ee271c 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -2440,25 +2440,27 @@ static LLVMValueRef get_int_builtin_fn(CodeGen *g, TypeTableEntry *int_type, Bui } static LLVMValueRef ir_render_clz(CodeGen *g, IrExecutable *executable, IrInstructionClz *instruction) { - TypeTableEntry *int_type = instruction->base.value.type; + TypeTableEntry *int_type = instruction->value->value.type; LLVMValueRef fn_val = get_int_builtin_fn(g, int_type, BuiltinFnIdClz); LLVMValueRef operand = ir_llvm_value(g, instruction->value); LLVMValueRef params[] { operand, LLVMConstNull(LLVMInt1Type()), }; - return LLVMBuildCall(g->builder, fn_val, params, 2, ""); + LLVMValueRef wrong_size_int = LLVMBuildCall(g->builder, fn_val, params, 2, ""); + return gen_widen_or_shorten(g, false, int_type, instruction->base.value.type, wrong_size_int); } static LLVMValueRef ir_render_ctz(CodeGen *g, IrExecutable *executable, IrInstructionCtz *instruction) { - TypeTableEntry *int_type = instruction->base.value.type; + TypeTableEntry *int_type = instruction->value->value.type; LLVMValueRef fn_val = get_int_builtin_fn(g, int_type, BuiltinFnIdCtz); LLVMValueRef operand = ir_llvm_value(g, instruction->value); LLVMValueRef params[] { operand, LLVMConstNull(LLVMInt1Type()), }; - return LLVMBuildCall(g->builder, fn_val, params, 2, ""); + LLVMValueRef wrong_size_int = LLVMBuildCall(g->builder, fn_val, params, 2, ""); + return gen_widen_or_shorten(g, false, int_type, instruction->base.value.type, wrong_size_int); } static LLVMValueRef ir_render_switch_br(CodeGen *g, IrExecutable *executable, IrInstructionSwitchBr *instruction) { @@ -2545,7 +2547,8 @@ static LLVMValueRef ir_render_enum_tag_name(CodeGen *g, IrExecutable *executable LLVMValueRef indices[] = { LLVMConstNull(g->builtin_types.entry_usize->type_ref), - enum_tag_value, + gen_widen_or_shorten(g, false, enum_tag_type->data.enum_tag.int_type, + g->builtin_types.entry_usize, enum_tag_value), }; return LLVMBuildInBoundsGEP(g->builder, enum_tag_type->data.enum_tag.name_table, indices, 2, ""); } diff --git a/src/ir.cpp b/src/ir.cpp index 875be38654..57b7f07c20 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -11359,16 +11359,18 @@ static TypeTableEntry *ir_analyze_instruction_ctz(IrAnalyze *ira, IrInstructionC if (type_is_invalid(value->value.type)) { return ira->codegen->builtin_types.entry_invalid; } else if (value->value.type->id == TypeTableEntryIdInt) { + TypeTableEntry *return_type = get_smallest_unsigned_int_type(ira->codegen, + value->value.type->data.integral.bit_count); if (value->value.special != ConstValSpecialRuntime) { size_t result = bigint_ctz(&value->value.data.x_bigint, value->value.type->data.integral.bit_count); ConstExprValue *out_val = ir_build_const_from(ira, &ctz_instruction->base); bigint_init_unsigned(&out_val->data.x_bigint, result); - return value->value.type; + return return_type; } ir_build_ctz_from(&ira->new_irb, &ctz_instruction->base, value); - return value->value.type; + return return_type; } else { ir_add_error_node(ira, ctz_instruction->base.source_node, buf_sprintf("expected integer type, found '%s'", buf_ptr(&value->value.type->name))); @@ -11381,16 +11383,18 @@ static TypeTableEntry *ir_analyze_instruction_clz(IrAnalyze *ira, IrInstructionC if (type_is_invalid(value->value.type)) { return ira->codegen->builtin_types.entry_invalid; } else if (value->value.type->id == TypeTableEntryIdInt) { + TypeTableEntry *return_type = get_smallest_unsigned_int_type(ira->codegen, + value->value.type->data.integral.bit_count); if (value->value.special != ConstValSpecialRuntime) { size_t result = bigint_clz(&value->value.data.x_bigint, value->value.type->data.integral.bit_count); ConstExprValue *out_val = ir_build_const_from(ira, &clz_instruction->base); bigint_init_unsigned(&out_val->data.x_bigint, result); - return value->value.type; + return return_type; } ir_build_clz_from(&ira->new_irb, &clz_instruction->base, value); - return value->value.type; + return return_type; } else { ir_add_error_node(ira, clz_instruction->base.source_node, buf_sprintf("expected integer type, found '%s'", buf_ptr(&value->value.type->name))); diff --git a/std/special/compiler_rt/index.zig b/std/special/compiler_rt/index.zig index c2486a3d59..0d2e1325ab 100644 --- a/std/special/compiler_rt/index.zig +++ b/std/special/compiler_rt/index.zig @@ -139,7 +139,7 @@ export fn __udivmoddi4(a: du_int, b: du_int, maybe_rem: ?&du_int) -> du_int { // K X // --- // 0 K - sr = 1 + n_uword_bits + @clz(su_int(d[low])) - @clz(su_int(n[high])); + sr = 1 + n_uword_bits + c_uint(@clz(su_int(d[low]))) - c_uint(@clz(su_int(n[high]))); // 2 <= sr <= n_udword_bits - 1 // q.all = n.all << (n_udword_bits - sr); // r.all = n.all >> sr; diff --git a/test/cases/math.zig b/test/cases/math.zig index 82773f077a..5707e40607 100644 --- a/test/cases/math.zig +++ b/test/cases/math.zig @@ -66,6 +66,8 @@ fn testClz() { assert(clz(u8(0b00001010)) == 4); assert(clz(u8(0b10001010)) == 0); assert(clz(u8(0b00000000)) == 8); + assert(clz(u128(0xffffffffffffffff)) == 64); + assert(clz(u128(0x10000000000000000)) == 63); } fn clz(x: var) -> usize {