From 6c8aad0afbfab55ed959712e1db4b6c368b4bead Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 22 Sep 2022 15:17:36 +0100 Subject: [PATCH] Make `intrinsics.{count_ones, count_zeros, count_trailing_zeros, count_leading_zeros}` work at compile time --- src/check_builtin.cpp | 86 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 85 insertions(+), 1 deletion(-) diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp index c835801ac..09294c93a 100644 --- a/src/check_builtin.cpp +++ b/src/check_builtin.cpp @@ -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;