mirror of
https://github.com/odin-lang/Odin.git
synced 2026-01-06 04:57:55 +00:00
Make intrinsics.{count_ones, count_zeros, count_trailing_zeros, count_leading_zeros} work at compile time
This commit is contained in:
@@ -3685,8 +3685,92 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
|
||||
gb_string_free(xts);
|
||||
}
|
||||
|
||||
Type *type = default_type(x.type);
|
||||
operand->mode = Addressing_Value;
|
||||
operand->type = default_type(x.type);
|
||||
operand->type = type;
|
||||
|
||||
if (id == BuiltinProc_reverse_bits) {
|
||||
// make runtime only for the time being
|
||||
} else if (x.mode == Addressing_Constant && x.value.kind == ExactValue_Integer) {
|
||||
convert_to_typed(c, &x, type);
|
||||
if (x.mode == Addressing_Invalid) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ExactValue res = {};
|
||||
|
||||
i64 sz = type_size_of(x.type);
|
||||
u64 bit_size = sz*8;
|
||||
u64 rop64[4] = {}; // 2 u64 is the maximum we will ever need, so doubling it will ne fine
|
||||
u8 *rop = cast(u8 *)rop64;
|
||||
|
||||
size_t max_count = 0;
|
||||
size_t written = 0;
|
||||
size_t size = 1;
|
||||
size_t nails = 0;
|
||||
mp_endian endian = MP_LITTLE_ENDIAN;
|
||||
|
||||
max_count = mp_pack_count(&x.value.value_integer, nails, size);
|
||||
GB_ASSERT(sz >= cast(i64)max_count);
|
||||
|
||||
mp_err err = mp_pack(rop, max_count, &written, MP_LSB_FIRST, size, endian, nails, &x.value.value_integer);
|
||||
GB_ASSERT(err == MP_OKAY);
|
||||
|
||||
if (id == BuiltinProc_reverse_bits) {
|
||||
// TODO(bill): Should this even be allowed at compile time?
|
||||
} else {
|
||||
u64 v = 0;
|
||||
switch (id) {
|
||||
case BuiltinProc_count_ones:
|
||||
case BuiltinProc_count_zeros:
|
||||
switch (sz) {
|
||||
case 1: v = bit_set_count(cast(u32)rop[0]); break;
|
||||
case 2: v = bit_set_count(cast(u32)*(u16 *)rop); break;
|
||||
case 4: v = bit_set_count(*(u32 *)rop); break;
|
||||
case 8: v = bit_set_count(rop64[0]); break;
|
||||
case 16:
|
||||
v += bit_set_count(rop64[0]);
|
||||
v += bit_set_count(rop64[1]);
|
||||
break;
|
||||
default: GB_PANIC("Unhandled sized");
|
||||
}
|
||||
if (id == BuiltinProc_count_zeros) {
|
||||
// flip the result
|
||||
v = bit_size - v;
|
||||
}
|
||||
break;
|
||||
case BuiltinProc_count_trailing_zeros:
|
||||
for (u64 i = 0; i < bit_size; i++) {
|
||||
u8 b = cast(u8)(i & 7);
|
||||
u8 j = cast(u8)(i >> 3);
|
||||
if (rop[j] & (1 << b)) {
|
||||
break;
|
||||
}
|
||||
v += 1;
|
||||
}
|
||||
break;
|
||||
case BuiltinProc_count_leading_zeros:
|
||||
for (u64 i = bit_size-1; i < bit_size; i--) {
|
||||
u8 b = cast(u8)(i & 7);
|
||||
u8 j = cast(u8)(i >> 3);
|
||||
if (rop[j] & (1 << b)) {
|
||||
break;
|
||||
}
|
||||
v += 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
res = exact_value_u64(v);
|
||||
}
|
||||
|
||||
if (res.kind != ExactValue_Invalid) {
|
||||
operand->mode = Addressing_Constant;
|
||||
operand->value = res;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user