diff --git a/core/fmt/fmt.odin b/core/fmt/fmt.odin index 17b11d0c6..459d6e2ce 100644 --- a/core/fmt/fmt.odin +++ b/core/fmt/fmt.odin @@ -96,6 +96,11 @@ write_encoded_rune :: proc(buf: ^String_Buffer, r: rune) { write_byte(buf, '\''); } +write_u64 :: proc(buf: ^String_Buffer, i: u64, base: int) { + b: [129]byte; + s := strconv.append_bits(b[:], u64(i), base, false, 64, strconv.digits, nil); + write_string(buf, s); +} write_i64 :: proc(buf: ^String_Buffer, i: i64, base: int) { b: [129]byte; s := strconv.append_bits(b[:], u64(i), base, true, 64, strconv.digits, nil); @@ -833,6 +838,51 @@ fmt_bit_set :: proc(fi: ^Fmt_Info, v: any, name: string = "") { } } } +fmt_bit_field :: proc(fi: ^Fmt_Info, v: any, name: string = "") { + type_info := type_info_of(v.typeid); + switch info in type_info.variant { + case runtime.Type_Info_Named: + val := v; + val.typeid = info.base.id; + fmt_bit_field(fi, val, info.name); + case runtime.Type_Info_Bit_Field: + data: u64 = 0; + switch type_info.size { + case 1: data = cast(u64) (^u8)(v.data)^; + case 2: data = cast(u64)(^u16)(v.data)^; + case 4: data = cast(u64)(^u32)(v.data)^; + case 8: data = cast(u64)(^u64)(v.data)^; + } + + if name != "" { + write_string(fi.buf, name); + write_byte(fi.buf, '{'); + } else { + write_string(fi.buf, "bit_field{"); + } + for name, i in info.names { + if i > 0 { + write_string(fi.buf, ", "); + } + bits := u64(info.bits[i]); + offset := u64(info.offsets[i]); + write_string(fi.buf, name); + write_string(fi.buf, " = "); + + n := 8*u64(size_of(u64)); + sa := n - bits; + u := data>>offset; + u <<= sa; + u >>= sa; + + write_u64(fi.buf, u, 10); + + } + write_byte(fi.buf, '}'); + case: + write_string(fi.buf, "HERE"); + } +} fmt_value :: proc(fi: ^Fmt_Info, v: any, verb: rune) { if v.data == nil || v.typeid == nil { @@ -887,6 +937,8 @@ fmt_value :: proc(fi: ^Fmt_Info, v: any, verb: rune) { case runtime.Type_Info_Bit_Set: fmt_bit_set(fi, v); + case runtime.Type_Info_Bit_Field: + fmt_bit_field(fi, v); case: fmt_value(fi, any{v.data, typeid_of(info.base)}, verb); } @@ -1052,6 +1104,9 @@ fmt_value :: proc(fi: ^Fmt_Info, v: any, verb: rune) { id := (^typeid)(v.data)^; write_typeid(fi.buf, id); + case runtime.Type_Info_Bit_Field: + fmt_bit_field(fi, v); + case runtime.Type_Info_Bit_Set: fmt_bit_set(fi, v); } diff --git a/core/runtime/core.odin b/core/runtime/core.odin index db908530e..c6ccb7bf4 100644 --- a/core/runtime/core.odin +++ b/core/runtime/core.odin @@ -135,6 +135,39 @@ Type_Info :: struct { }, } +// NOTE(bill): This must match the compiler's +Typeid_Kind :: enum u8 { + Invalid, + Integer, + Rune, + Float, + Complex, + String, + Boolean, + Any, + Type_Id, + Pointer, + Procedure, + Array, + Dynamic_Array, + Slice, + Tuple, + Struct, + Union, + Enum, + Map, + Bit_Field, + Bit_Set, +} + +Typeid_Bit_Field :: bit_field #align align_of(uintptr) { + index: 8*size_of(align_of(uintptr)) - 8, + kind: 5, // Typeid_Kind + named: 1, + special: 1, // signed, cstring, etc + reserved: 1, +} + // NOTE(bill): only the ones that are needed (not all types) // This will be set by the compiler type_table: []Type_Info; @@ -233,7 +266,8 @@ __typeid_of :: proc "contextless" (ti: ^Type_Info) -> typeid { return ti.id; } __type_info_of :: proc "contextless" (id: typeid) -> ^Type_Info { - n := int(transmute(uintptr)id); + data := transmute(Typeid_Bit_Field)id; + n := int(data.index); if n < 0 || n >= len(type_table) { n = 0; } diff --git a/src/ir.cpp b/src/ir.cpp index 4c8ccb6dd..3992f1103 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -3773,12 +3773,95 @@ irValue *ir_type_info(irProcedure *proc, Type *type) { return ir_emit_array_ep(proc, ir_global_type_info_data, ir_const_i32(id)); } +// IMPORTANT NOTE(bill): This must match the same as the in core.odin +enum Typeid_Kind : u8 { + Typeid_Invalid, + Typeid_Integer, + Typeid_Rune, + Typeid_Float, + Typeid_Complex, + Typeid_String, + Typeid_Boolean, + Typeid_Any, + Typeid_Type_Id, + Typeid_Pointer, + Typeid_Procedure, + Typeid_Array, + Typeid_Dynamic_Array, + Typeid_Slice, + Typeid_Tuple, + Typeid_Struct, + Typeid_Union, + Typeid_Enum, + Typeid_Map, + Typeid_Bit_Field, + Typeid_Bit_Set, +}; + + irValue *ir_typeid(irModule *m, Type *type) { type = default_type(type); - isize id = ir_type_info_index(m->info, type); + u64 id = cast(u64)ir_type_info_index(m->info, type); GB_ASSERT(id >= 0); - return ir_value_constant(t_typeid, exact_value_i64(id)); + + u64 kind = Typeid_Invalid; + u64 named = is_type_named(type) && type->kind != Type_Basic; + u64 special = 0; + u64 reserved = 0; + + Type *bt = base_type(type); + TypeKind tk = bt->kind; + switch (tk) { + case Type_Basic: { + u32 flags = bt->Basic.flags; + if (flags & BasicFlag_Boolean) kind = Typeid_Boolean; + if (flags & BasicFlag_Integer) kind = Typeid_Integer; + if (flags & BasicFlag_Unsigned) kind = Typeid_Integer; + if (flags & BasicFlag_Float) kind = Typeid_Float; + if (flags & BasicFlag_Complex) kind = Typeid_Complex; + if (flags & BasicFlag_Pointer) kind = Typeid_Pointer; + if (flags & BasicFlag_String) kind = Typeid_String; + if (flags & BasicFlag_Rune) kind = Typeid_Rune; + } break; + case Type_Pointer: kind = Typeid_Pointer; break; + case Type_Array: kind = Typeid_Array; break; + case Type_Slice: kind = Typeid_Slice; break; + case Type_DynamicArray: kind = Typeid_Dynamic_Array; break; + case Type_Map: kind = Typeid_Map; break; + case Type_Struct: kind = Typeid_Struct; break; + case Type_Enum: kind = Typeid_Enum; break; + case Type_Union: kind = Typeid_Union; break; + case Type_Tuple: kind = Typeid_Tuple; break; + case Type_Proc: kind = Typeid_Procedure; break; + case Type_BitField: kind = Typeid_Bit_Field; break; + case Type_BitSet: kind = Typeid_Bit_Set; break; + } + + if (is_type_cstring(type)) { + special = 1; + } else if (is_type_integer(type) && !is_type_unsigned(type)) { + special = 1; + } + + u64 data = 0; + if (build_context.word_size == 4) { + data |= (id &~ (1u<<24)) << 0u; // index + data |= (kind &~ (1u<<5)) << 24u; // kind + data |= (named &~ (1u<<1)) << 29u; // kind + data |= (special &~ (1u<<1)) << 30u; // kind + data |= (reserved &~ (1u<<1)) << 31u; // kind + } else { + GB_ASSERT(build_context.word_size == 8); + data |= (id &~ (1ull<<56)) << 0ul; // index + data |= (kind &~ (1ull<<5)) << 56ull; // kind + data |= (named &~ (1ull<<1)) << 61ull; // kind + data |= (special &~ (1ull<<1)) << 62ull; // kind + data |= (reserved &~ (1ull<<1)) << 63ull; // kind + } + + + return ir_value_constant(t_typeid, exact_value_u64(data)); }