Browse Source

Fix bit sets with custom endian underlying type

gingerBill 6 years ago
parent
commit
17b0e3a1a1
4 changed files with 56 additions and 13 deletions
  1. 36 4
      core/fmt/fmt.odin
  2. 4 5
      src/ir.cpp
  3. 8 0
      src/ir_print.cpp
  4. 8 4
      src/types.cpp

+ 36 - 4
core/fmt/fmt.odin

@@ -834,6 +834,25 @@ enum_value_to_u64 :: proc(ev: runtime.Type_Info_Enum_Value) -> u64 {
 }
 
 fmt_bit_set :: proc(fi: ^Fmt_Info, v: any, name: string = "") {
+	is_bit_set_different_endian_to_platform :: proc(ti: ^runtime.Type_Info, ) -> bool {
+		if ti == nil {
+			return false;
+		}
+		ti = runtime.type_info_base(ti);
+		switch info in ti.variant {
+		case runtime.Type_Info_Integer:
+			using runtime.Type_Info_Endianness;
+			switch info.endianness {
+			case Platform: return false;
+			case Little:   return ODIN_ENDIAN != "little";
+			case Big:      return ODIN_ENDIAN != "big";
+			}
+		}
+		return false;
+	}
+
+	byte_swap :: bits.byte_swap;
+
 	type_info := type_info_of(v.id);
 	switch info in type_info.variant {
 	case runtime.Type_Info_Named:
@@ -845,12 +864,25 @@ fmt_bit_set :: proc(fi: ^Fmt_Info, v: any, name: string = "") {
 		bits: u64;
 		bit_size := u64(8*type_info.size);
 
+		do_byte_swap := is_bit_set_different_endian_to_platform(info.underlying);
+
 		switch bit_size {
 		case  0: bits = 0;
-		case  8: bits = u64( (^u8)(v.data)^);
-		case 16: bits = u64((^u16)(v.data)^);
-		case 32: bits = u64((^u32)(v.data)^);
-		case 64: bits = u64((^u64)(v.data)^);
+		case  8:
+			x := (^u8)(v.data)^;
+			bits = u64(x);
+		case 16:
+			x := (^u16)(v.data)^;
+			if do_byte_swap do x = byte_swap(x);
+			bits = u64(x);
+		case 32:
+			x := (^u32)(v.data)^;
+			if do_byte_swap do x = byte_swap(x);
+			bits = u64(x);
+		case 64:
+			x := (^u64)(v.data)^;
+			if do_byte_swap do x = byte_swap(x);
+			bits = u64(x);
 		case: panic("unknown bit_size size");
 		}
 

+ 4 - 5
src/ir.cpp

@@ -6250,13 +6250,13 @@ irValue *ir_build_expr_internal(irProcedure *proc, Ast *expr) {
 
 					Type *key_type = rt->BitSet.elem;
 					GB_ASSERT(are_types_identical(ir_type(left), key_type));
+
 					Type *it = bit_set_to_int(rt);
-					left = ir_emit_conv(proc, left, it);
 
 					irValue *lower = ir_value_constant(it, exact_value_i64(rt->BitSet.lower));
-					irValue *key = ir_emit_arith(proc, Token_Sub, left, lower, it);
-					irValue *bit = ir_emit_arith(proc, Token_Shl, v_one, key, it);
-
+					irValue *key = ir_emit_arith(proc, Token_Sub, left, lower, ir_type(left));
+					irValue *bit = ir_emit_arith(proc, Token_Shl, v_one, key, ir_type(left));
+					bit = ir_emit_conv(proc, bit, it);
 
 					irValue *old_value = ir_emit_bitcast(proc, right, it);
 					irValue *new_value = ir_emit_arith(proc, Token_And, old_value, bit, it);
@@ -7228,7 +7228,6 @@ irAddr ir_build_addr(irProcedure *proc, Ast *expr) {
 		}
 
 		case Type_BitSet: {
-
 			i64 sz = type_size_of(type);
 			if (cl->elems.count > 0 && sz > 0) {
 				ir_emit_store(proc, v, ir_add_module_constant(proc->module, type, exact_value_compound(expr)));

+ 8 - 0
src/ir_print.cpp

@@ -890,6 +890,14 @@ void ir_print_exact_value(irFileBuffer *f, irModule *m, ExactValue value, Type *
 				i64 lower = type->BitSet.lower;
 				bits |= 1ull<<cast(u64)(v-lower);
 			}
+			if (is_type_different_to_arch_endianness(type)) {
+				i64 size = type_size_of(type);
+				switch (size) {
+				case 2: bits = cast(u64)gb_endian_swap16(cast(u16)bits); break;
+				case 4: bits = cast(u64)gb_endian_swap32(cast(u32)bits); break;
+				case 8: bits = cast(u64)gb_endian_swap64(cast(u64)bits); break;
+				}
+			}
 			ir_write_u64(f, bits);
 		} else {
 			ir_write_str_lit(f, "zeroinitializer");

+ 8 - 4
src/types.cpp

@@ -500,7 +500,7 @@ i64      type_align_of              (Type *t);
 i64      type_offset_of             (Type *t, i32 index);
 gbString type_to_string             (Type *type);
 void     init_map_internal_types(Type *type);
-
+Type *   bit_set_to_int(Type *t);
 
 
 Type *base_type(Type *t) {
@@ -1037,7 +1037,7 @@ bool is_type_integer_endian_big(Type *t) {
 		}
 		return build_context.endian_kind == TargetEndian_Big;
 	} else if (t->kind == Type_BitSet) {
-		return is_type_integer_endian_big(t->BitSet.elem);
+		return is_type_integer_endian_big(bit_set_to_int(t));
 	} else {
 		GB_PANIC("Unsupported type: %s", type_to_string);
 	}
@@ -1054,7 +1054,7 @@ bool is_type_integer_endian_little(Type *t) {
 		}
 		return build_context.endian_kind == TargetEndian_Little;
 	} else if (t->kind == Type_BitSet) {
-		return is_type_integer_endian_little(t->BitSet.elem);
+		return is_type_integer_endian_little(bit_set_to_int(t));
 	} else {
 		GB_PANIC("Unsupported type: %s", type_to_string);
 	}
@@ -1074,7 +1074,7 @@ bool is_type_different_to_arch_endianness(Type *t) {
 Type *integer_endian_type_to_platform_type(Type *t) {
 	t = core_type(t);
 	if (t->kind == Type_BitSet) {
-		t = core_type(t->BitSet.elem);
+		t = bit_set_to_int(t);
 	}
 	GB_ASSERT(t->kind == Type_Basic);
 
@@ -2919,6 +2919,10 @@ gbString write_type_to_string(gbString str, Type *type) {
 	case Type_BitSet:
 		str = gb_string_appendc(str, "bit_set[");
 		str = write_type_to_string(str, type->BitSet.elem);
+		if (type->BitSet.underlying != nullptr) {
+			str = gb_string_appendc(str, "; ");
+			str = write_type_to_string(str, type->BitSet.underlying);
+		}
 		str = gb_string_appendc(str, "]");
 		break;
 	}