aboutsummaryrefslogtreecommitdiff
path: root/src/check_builtin.cpp
diff options
context:
space:
mode:
authorgingerBill <bill@gingerbill.org>2022-09-22 15:17:36 +0100
committergingerBill <bill@gingerbill.org>2022-09-22 15:17:36 +0100
commit6c8aad0afbfab55ed959712e1db4b6c368b4bead (patch)
treee4247ee7e7d1deeaf06c96b9857705fb0953ca57 /src/check_builtin.cpp
parenteb0d7465e2aa4d6119c9219930f9403951df16f0 (diff)
Make `intrinsics.{count_ones, count_zeros, count_trailing_zeros, count_leading_zeros}` work at compile time
Diffstat (limited to 'src/check_builtin.cpp')
-rw-r--r--src/check_builtin.cpp86
1 files changed, 85 insertions, 1 deletions
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;