mirror of
https://github.com/ziglang/zig.git
synced 2024-11-15 00:26:57 +00:00
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
This commit is contained in:
parent
6a98bf3dba
commit
0d117bb0a9
@ -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) {
|
||||
|
@ -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];
|
||||
|
@ -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, "");
|
||||
}
|
||||
|
12
src/ir.cpp
12
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)));
|
||||
|
@ -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;
|
||||
|
@ -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 {
|
||||
|
Loading…
Reference in New Issue
Block a user