| author | |
| committer | |
| log | 0d117bb0a993b2a0a290f99255c5bf1bf05f187f |
| tree | 54abbc90bb6c31746eb0d9b1c8a3269395190900 |
| parent | 6a98bf3dba6f3ed5b40fe7899899e2a792028be4 |
closes #418
also make clz, ctz return smaller integer bit widths
and use smaller integer bit widths for enum tag types6 files changed, 30 insertions(+), 20 deletions(-)
src/analyze.cpp+8-9| ... | @@ -161,18 +161,17 @@ static TypeTableEntry *new_container_type_entry(TypeTableEntryId id, AstNode *so | ... | @@ -161,18 +161,17 @@ static TypeTableEntry *new_container_type_entry(TypeTableEntryId id, AstNode *so |
| 161 | return entry; | 161 | return entry; |
| 162 | } | 162 | } |
| 163 | 163 | ||
| 164 | static uint8_t log2_u64(uint64_t x) { | ||
| 165 | return (63 - __builtin_clzll(x)); | ||
| 166 | } | ||
| 164 | 167 | ||
| 165 | // TODO no reason to limit to 8/16/32/64 | ||
| 166 | static uint8_t bits_needed_for_unsigned(uint64_t x) { | 168 | static uint8_t bits_needed_for_unsigned(uint64_t x) { |
| 167 | if (x <= UINT8_MAX) { | 169 | if (x == 0) { |
| 168 | return 8; | 170 | return 0; |
| 169 | } else if (x <= UINT16_MAX) { | ||
| 170 | return 16; | ||
| 171 | } else if (x <= UINT32_MAX) { | ||
| 172 | return 32; | ||
| 173 | } else { | ||
| 174 | return 64; | ||
| 175 | } | 171 | } |
| 172 | uint8_t base = log2_u64(x); | ||
| 173 | uint64_t upper = (((uint64_t)1) << base) - 1; | ||
| 174 | return (upper >= x) ? base : (base + 1); | ||
| 176 | } | 175 | } |
| 177 | 176 | ||
| 178 | bool type_is_complete(TypeTableEntry *type_entry) { | 177 | bool type_is_complete(TypeTableEntry *type_entry) { |
src/bigint.cpp+3-1| ... | @@ -95,7 +95,9 @@ static void to_twos_complement(BigInt *dest, const BigInt *op, size_t bit_count) | ... | @@ -95,7 +95,9 @@ static void to_twos_complement(BigInt *dest, const BigInt *op, size_t bit_count) |
| 95 | } | 95 | } |
| 96 | 96 | ||
| 97 | static bool bit_at_index(const BigInt *bi, size_t index) { | 97 | static bool bit_at_index(const BigInt *bi, size_t index) { |
| 98 | size_t digit_index = bi->digit_count - (index / 64) - 1; | 98 | size_t digit_index = index / 64; |
| 99 | if (digit_index >= bi->digit_count) | ||
| 100 | return false; | ||
| 99 | size_t digit_bit_index = index % 64; | 101 | size_t digit_bit_index = index % 64; |
| 100 | const uint64_t *digits = bigint_ptr(bi); | 102 | const uint64_t *digits = bigint_ptr(bi); |
| 101 | uint64_t digit = digits[digit_index]; | 103 | uint64_t digit = digits[digit_index]; |
src/codegen.cpp+8-5| ... | @@ -2440,25 +2440,27 @@ static LLVMValueRef get_int_builtin_fn(CodeGen *g, TypeTableEntry *int_type, Bui | ... | @@ -2440,25 +2440,27 @@ static LLVMValueRef get_int_builtin_fn(CodeGen *g, TypeTableEntry *int_type, Bui |
| 2440 | } | 2440 | } |
| 2441 | 2441 | ||
| 2442 | static LLVMValueRef ir_render_clz(CodeGen *g, IrExecutable *executable, IrInstructionClz *instruction) { | 2442 | static LLVMValueRef ir_render_clz(CodeGen *g, IrExecutable *executable, IrInstructionClz *instruction) { |
| 2443 | TypeTableEntry *int_type = instruction->base.value.type; | 2443 | TypeTableEntry *int_type = instruction->value->value.type; |
| 2444 | LLVMValueRef fn_val = get_int_builtin_fn(g, int_type, BuiltinFnIdClz); | 2444 | LLVMValueRef fn_val = get_int_builtin_fn(g, int_type, BuiltinFnIdClz); |
| 2445 | LLVMValueRef operand = ir_llvm_value(g, instruction->value); | 2445 | LLVMValueRef operand = ir_llvm_value(g, instruction->value); |
| 2446 | LLVMValueRef params[] { | 2446 | LLVMValueRef params[] { |
| 2447 | operand, | 2447 | operand, |
| 2448 | LLVMConstNull(LLVMInt1Type()), | 2448 | LLVMConstNull(LLVMInt1Type()), |
| 2449 | }; | 2449 | }; |
| 2450 | return LLVMBuildCall(g->builder, fn_val, params, 2, ""); | 2450 | LLVMValueRef wrong_size_int = LLVMBuildCall(g->builder, fn_val, params, 2, ""); |
| 2451 | return gen_widen_or_shorten(g, false, int_type, instruction->base.value.type, wrong_size_int); | ||
| 2451 | } | 2452 | } |
| 2452 | 2453 | ||
| 2453 | static LLVMValueRef ir_render_ctz(CodeGen *g, IrExecutable *executable, IrInstructionCtz *instruction) { | 2454 | static LLVMValueRef ir_render_ctz(CodeGen *g, IrExecutable *executable, IrInstructionCtz *instruction) { |
| 2454 | TypeTableEntry *int_type = instruction->base.value.type; | 2455 | TypeTableEntry *int_type = instruction->value->value.type; |
| 2455 | LLVMValueRef fn_val = get_int_builtin_fn(g, int_type, BuiltinFnIdCtz); | 2456 | LLVMValueRef fn_val = get_int_builtin_fn(g, int_type, BuiltinFnIdCtz); |
| 2456 | LLVMValueRef operand = ir_llvm_value(g, instruction->value); | 2457 | LLVMValueRef operand = ir_llvm_value(g, instruction->value); |
| 2457 | LLVMValueRef params[] { | 2458 | LLVMValueRef params[] { |
| 2458 | operand, | 2459 | operand, |
| 2459 | LLVMConstNull(LLVMInt1Type()), | 2460 | LLVMConstNull(LLVMInt1Type()), |
| 2460 | }; | 2461 | }; |
| 2461 | return LLVMBuildCall(g->builder, fn_val, params, 2, ""); | 2462 | LLVMValueRef wrong_size_int = LLVMBuildCall(g->builder, fn_val, params, 2, ""); |
| 2463 | return gen_widen_or_shorten(g, false, int_type, instruction->base.value.type, wrong_size_int); | ||
| 2462 | } | 2464 | } |
| 2463 | 2465 | ||
| 2464 | static LLVMValueRef ir_render_switch_br(CodeGen *g, IrExecutable *executable, IrInstructionSwitchBr *instruction) { | 2466 | 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 | ... | @@ -2545,7 +2547,8 @@ static LLVMValueRef ir_render_enum_tag_name(CodeGen *g, IrExecutable *executable |
| 2545 | 2547 | ||
| 2546 | LLVMValueRef indices[] = { | 2548 | LLVMValueRef indices[] = { |
| 2547 | LLVMConstNull(g->builtin_types.entry_usize->type_ref), | 2549 | LLVMConstNull(g->builtin_types.entry_usize->type_ref), |
| 2548 | enum_tag_value, | 2550 | gen_widen_or_shorten(g, false, enum_tag_type->data.enum_tag.int_type, |
| 2551 | g->builtin_types.entry_usize, enum_tag_value), | ||
| 2549 | }; | 2552 | }; |
| 2550 | return LLVMBuildInBoundsGEP(g->builder, enum_tag_type->data.enum_tag.name_table, indices, 2, ""); | 2553 | return LLVMBuildInBoundsGEP(g->builder, enum_tag_type->data.enum_tag.name_table, indices, 2, ""); |
| 2551 | } | 2554 | } |
src/ir.cpp+8-4| ... | @@ -11359,16 +11359,18 @@ static TypeTableEntry *ir_analyze_instruction_ctz(IrAnalyze *ira, IrInstructionC | ... | @@ -11359,16 +11359,18 @@ static TypeTableEntry *ir_analyze_instruction_ctz(IrAnalyze *ira, IrInstructionC |
| 11359 | if (type_is_invalid(value->value.type)) { | 11359 | if (type_is_invalid(value->value.type)) { |
| 11360 | return ira->codegen->builtin_types.entry_invalid; | 11360 | return ira->codegen->builtin_types.entry_invalid; |
| 11361 | } else if (value->value.type->id == TypeTableEntryIdInt) { | 11361 | } else if (value->value.type->id == TypeTableEntryIdInt) { |
| 11362 | TypeTableEntry *return_type = get_smallest_unsigned_int_type(ira->codegen, | ||
| 11363 | value->value.type->data.integral.bit_count); | ||
| 11362 | if (value->value.special != ConstValSpecialRuntime) { | 11364 | if (value->value.special != ConstValSpecialRuntime) { |
| 11363 | size_t result = bigint_ctz(&value->value.data.x_bigint, | 11365 | size_t result = bigint_ctz(&value->value.data.x_bigint, |
| 11364 | value->value.type->data.integral.bit_count); | 11366 | value->value.type->data.integral.bit_count); |
| 11365 | ConstExprValue *out_val = ir_build_const_from(ira, &ctz_instruction->base); | 11367 | ConstExprValue *out_val = ir_build_const_from(ira, &ctz_instruction->base); |
| 11366 | bigint_init_unsigned(&out_val->data.x_bigint, result); | 11368 | bigint_init_unsigned(&out_val->data.x_bigint, result); |
| 11367 | return value->value.type; | 11369 | return return_type; |
| 11368 | } | 11370 | } |
| 11369 | 11371 | ||
| 11370 | ir_build_ctz_from(&ira->new_irb, &ctz_instruction->base, value); | 11372 | ir_build_ctz_from(&ira->new_irb, &ctz_instruction->base, value); |
| 11371 | return value->value.type; | 11373 | return return_type; |
| 11372 | } else { | 11374 | } else { |
| 11373 | ir_add_error_node(ira, ctz_instruction->base.source_node, | 11375 | ir_add_error_node(ira, ctz_instruction->base.source_node, |
| 11374 | buf_sprintf("expected integer type, found '%s'", buf_ptr(&value->value.type->name))); | 11376 | 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 | ... | @@ -11381,16 +11383,18 @@ static TypeTableEntry *ir_analyze_instruction_clz(IrAnalyze *ira, IrInstructionC |
| 11381 | if (type_is_invalid(value->value.type)) { | 11383 | if (type_is_invalid(value->value.type)) { |
| 11382 | return ira->codegen->builtin_types.entry_invalid; | 11384 | return ira->codegen->builtin_types.entry_invalid; |
| 11383 | } else if (value->value.type->id == TypeTableEntryIdInt) { | 11385 | } else if (value->value.type->id == TypeTableEntryIdInt) { |
| 11386 | TypeTableEntry *return_type = get_smallest_unsigned_int_type(ira->codegen, | ||
| 11387 | value->value.type->data.integral.bit_count); | ||
| 11384 | if (value->value.special != ConstValSpecialRuntime) { | 11388 | if (value->value.special != ConstValSpecialRuntime) { |
| 11385 | size_t result = bigint_clz(&value->value.data.x_bigint, | 11389 | size_t result = bigint_clz(&value->value.data.x_bigint, |
| 11386 | value->value.type->data.integral.bit_count); | 11390 | value->value.type->data.integral.bit_count); |
| 11387 | ConstExprValue *out_val = ir_build_const_from(ira, &clz_instruction->base); | 11391 | ConstExprValue *out_val = ir_build_const_from(ira, &clz_instruction->base); |
| 11388 | bigint_init_unsigned(&out_val->data.x_bigint, result); | 11392 | bigint_init_unsigned(&out_val->data.x_bigint, result); |
| 11389 | return value->value.type; | 11393 | return return_type; |
| 11390 | } | 11394 | } |
| 11391 | 11395 | ||
| 11392 | ir_build_clz_from(&ira->new_irb, &clz_instruction->base, value); | 11396 | ir_build_clz_from(&ira->new_irb, &clz_instruction->base, value); |
| 11393 | return value->value.type; | 11397 | return return_type; |
| 11394 | } else { | 11398 | } else { |
| 11395 | ir_add_error_node(ira, clz_instruction->base.source_node, | 11399 | ir_add_error_node(ira, clz_instruction->base.source_node, |
| 11396 | buf_sprintf("expected integer type, found '%s'", buf_ptr(&value->value.type->name))); | 11400 | buf_sprintf("expected integer type, found '%s'", buf_ptr(&value->value.type->name))); |
std/special/compiler_rt/index.zig+1-1| ... | @@ -139,7 +139,7 @@ export fn __udivmoddi4(a: du_int, b: du_int, maybe_rem: ?&du_int) -> du_int { | ... | @@ -139,7 +139,7 @@ export fn __udivmoddi4(a: du_int, b: du_int, maybe_rem: ?&du_int) -> du_int { |
| 139 | // K X | 139 | // K X |
| 140 | // --- | 140 | // --- |
| 141 | // 0 K | 141 | // 0 K |
| 142 | sr = 1 + n_uword_bits + @clz(su_int(d[low])) - @clz(su_int(n[high])); | 142 | sr = 1 + n_uword_bits + c_uint(@clz(su_int(d[low]))) - c_uint(@clz(su_int(n[high]))); |
| 143 | // 2 <= sr <= n_udword_bits - 1 | 143 | // 2 <= sr <= n_udword_bits - 1 |
| 144 | // q.all = n.all << (n_udword_bits - sr); | 144 | // q.all = n.all << (n_udword_bits - sr); |
| 145 | // r.all = n.all >> sr; | 145 | // r.all = n.all >> sr; |
test/cases/math.zig+2| ... | @@ -66,6 +66,8 @@ fn testClz() { | ... | @@ -66,6 +66,8 @@ fn testClz() { |
| 66 | assert(clz(u8(0b00001010)) == 4); | 66 | assert(clz(u8(0b00001010)) == 4); |
| 67 | assert(clz(u8(0b10001010)) == 0); | 67 | assert(clz(u8(0b10001010)) == 0); |
| 68 | assert(clz(u8(0b00000000)) == 8); | 68 | assert(clz(u8(0b00000000)) == 8); |
| 69 | assert(clz(u128(0xffffffffffffffff)) == 64); | ||
| 70 | assert(clz(u128(0x10000000000000000)) == 63); | ||
| 69 | } | 71 | } |
| 70 | 72 | ||
| 71 | fn clz(x: var) -> usize { | 73 | fn clz(x: var) -> usize { |