Browse Source

`runtime.Typeid_Bit_Field` layout to store more information into the typeid

gingerBill 7 years ago
parent
commit
3365baee8f
3 changed files with 175 additions and 3 deletions
  1. 55 0
      core/fmt/fmt.odin
  2. 35 1
      core/runtime/core.odin
  3. 85 2
      src/ir.cpp

+ 55 - 0
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);
 	}

+ 35 - 1
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;
 	}

+ 85 - 2
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));
 }