authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-08-17 17:14:35-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-08-17 17:14:35-04:00
log0d117bb0a993b2a0a290f99255c5bf1bf05f187f
tree54abbc90bb6c31746eb0d9b1c8a3269395190900
parent6a98bf3dba6f3ed5b40fe7899899e2a792028be4

fix wrong value for clz, ctz at compile time

closes #418 also make clz, ctz return smaller integer bit widths and use smaller integer bit widths for enum tag types

6 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}
163163
164static uint8_t log2_u64(uint64_t x) {
165 return (63 - __builtin_clzll(x));
166}
164167
165// TODO no reason to limit to 8/16/32/64
166static uint8_t bits_needed_for_unsigned(uint64_t x) {168static 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}
177176
178bool type_is_complete(TypeTableEntry *type_entry) {177bool 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}
9696
97static bool bit_at_index(const BigInt *bi, size_t index) {97static 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}
24412441
2442static LLVMValueRef ir_render_clz(CodeGen *g, IrExecutable *executable, IrInstructionClz *instruction) {2442static 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}
24522453
2453static LLVMValueRef ir_render_ctz(CodeGen *g, IrExecutable *executable, IrInstructionCtz *instruction) {2454static 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}
24632465
2464static LLVMValueRef ir_render_switch_br(CodeGen *g, IrExecutable *executable, IrInstructionSwitchBr *instruction) {2466static 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
25452547
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 }
1136911371
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 }
1139111395
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 X139 // K X
140 // ---140 // ---
141 // 0 K141 // 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 - 1143 // 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}
7072
71fn clz(x: var) -> usize {73fn clz(x: var) -> usize {