mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-06 07:38:48 +00:00
Make intrinsics.{count_ones, count_zeros, count_trailing_zeros, count_leading_zeros} work at compile time
This commit is contained in:
+85
-1
@@ -3685,8 +3685,92 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
|
|||||||
gb_string_free(xts);
|
gb_string_free(xts);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Type *type = default_type(x.type);
|
||||||
operand->mode = Addressing_Value;
|
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;
|
break;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user