Browse Source

Allow comparisons with bit field values

gingerBill 6 years ago
parent
commit
16f3bc2c0b
3 changed files with 58 additions and 15 deletions
  1. 5 0
      src/check_expr.cpp
  2. 50 15
      src/ir.cpp
  3. 3 0
      src/types.cpp

+ 5 - 0
src/check_expr.cpp

@@ -535,6 +535,11 @@ i64 check_distance_between_types(CheckerContext *c, Operand *operand, Type *type
 		return 1;
 		return 1;
 	}
 	}
 
 
+	if (is_type_bit_field_value(operand->type) && is_type_bit_field_value(type)) {
+		return 1;
+	}
+
+
 
 
 	{
 	{
 		isize subtype_level = check_is_assignable_to_using_subtype(operand->type, type);
 		isize subtype_level = check_is_assignable_to_using_subtype(operand->type, type);

+ 50 - 15
src/ir.cpp

@@ -3521,9 +3521,9 @@ irValue *ir_addr_load(irProcedure *proc, irAddr const &addr) {
 
 
 		Type *int_ptr = alloc_type_pointer(int_type);
 		Type *int_ptr = alloc_type_pointer(int_type);
 
 
+		i32 sa = 8*size_in_bytes - size_in_bits;
 		if (bit_inset == 0) {
 		if (bit_inset == 0) {
-			irValue *v = ir_emit_load(proc, ir_emit_conv(proc, bytes, int_ptr));
-			i32 sa = 8*size_in_bytes - size_in_bits;
+			irValue *v = ir_emit_load(proc, ir_emit_conv(proc, bytes, int_ptr), 1);
 			if (sa > 0) {
 			if (sa > 0) {
 				irValue *shift_amount = ir_const_int(sa);
 				irValue *shift_amount = ir_const_int(sa);
 				v = ir_emit_arith(proc, Token_Shl, v, shift_amount, int_type);
 				v = ir_emit_arith(proc, Token_Shl, v, shift_amount, int_type);
@@ -3534,14 +3534,15 @@ irValue *ir_addr_load(irProcedure *proc, irAddr const &addr) {
 
 
 		GB_ASSERT(8 > bit_inset);
 		GB_ASSERT(8 > bit_inset);
 
 
-		irValue *shift_amount = ir_value_constant(int_type, exact_value_i64(bit_inset));
-		irValue *first_byte = ir_emit_load(proc, bytes);
-		irValue *res = ir_emit_arith(proc, Token_Shr, first_byte, shift_amount, int_type);
-
-		irValue *remaining_bytes = ir_emit_load(proc, ir_emit_conv(proc, ir_emit_ptr_offset(proc, bytes, v_one), int_ptr));
-		remaining_bytes = ir_emit_arith(proc, Token_Shl, remaining_bytes, shift_amount, int_type);
-		return ir_emit_arith(proc, Token_Or, res, remaining_bytes, int_type);
-
+		irValue *ptr = ir_emit_conv(proc, bytes, int_ptr);
+		irValue *v = ir_emit_load(proc, ptr, 1);
+		v = ir_emit_arith(proc, Token_Shr, v, ir_const_int(bit_inset), int_type);
+		if (sa > 0) {
+			irValue *shift_amount = ir_const_int(sa);
+			v = ir_emit_arith(proc, Token_Shl, v, shift_amount, int_type);
+			v = ir_emit_arith(proc, Token_Shr, v, shift_amount, int_type);
+		}
+		return v;
 	} else if (addr.kind == irAddr_Context) {
 	} else if (addr.kind == irAddr_Context) {
 		if (addr.ctx.sel.index.count > 0) {
 		if (addr.ctx.sel.index.count > 0) {
 			irValue *a = addr.addr;
 			irValue *a = addr.addr;
@@ -4020,14 +4021,48 @@ irValue *ir_emit_comp(irProcedure *proc, TokenKind op_kind, irValue *left, irVal
 		right = ir_emit_conv(proc, right, ir_type(left));
 		right = ir_emit_conv(proc, right, ir_type(left));
 	} else {
 	} else {
 		gbAllocator a = ir_allocator();
 		gbAllocator a = ir_allocator();
-		i64 ls = type_size_of(ir_type(left));
-		i64 rs = type_size_of(ir_type(right));
+
+		Type *lt = ir_type(left);
+		Type *rt = ir_type(right);
+
+		if (is_type_bit_set(lt) && is_type_bit_set(rt)) {
+			Type *blt = base_type(lt);
+			Type *brt = base_type(rt);
+			GB_ASSERT(is_type_bit_field_value(blt));
+			GB_ASSERT(is_type_bit_field_value(brt));
+			i64 bits = gb_max(blt->BitFieldValue.bits, brt->BitFieldValue.bits);
+			i64 bytes = bits / 8;
+			switch (bytes) {
+			case 1:
+				left = ir_emit_conv(proc, left, t_u8);
+				right = ir_emit_conv(proc, right, t_u8);
+				break;
+			case 2:
+				left = ir_emit_conv(proc, left, t_u16);
+				right = ir_emit_conv(proc, right, t_u16);
+				break;
+			case 4:
+				left = ir_emit_conv(proc, left, t_u32);
+				right = ir_emit_conv(proc, right, t_u32);
+				break;
+			case 8:
+				left = ir_emit_conv(proc, left, t_u64);
+				right = ir_emit_conv(proc, right, t_u64);
+				break;
+			default: GB_PANIC("Unknown integer size"); break;
+			}
+		}
+
+		lt = ir_type(left);
+		rt = ir_type(right);
+		i64 ls = type_size_of(lt);
+		i64 rs = type_size_of(rt);
 		if (ls < rs) {
 		if (ls < rs) {
-			left = ir_emit_conv(proc, left, ir_type(right));
+			left = ir_emit_conv(proc, left, rt);
 		} else if (ls > rs) {
 		} else if (ls > rs) {
-			right = ir_emit_conv(proc, right, ir_type(left));
+			right = ir_emit_conv(proc, right, lt);
 		} else {
 		} else {
-			right = ir_emit_conv(proc, right, ir_type(left));
+			right = ir_emit_conv(proc, right, lt);
 		}
 		}
 	}
 	}
 
 

+ 3 - 0
src/types.cpp

@@ -1490,6 +1490,9 @@ bool is_type_comparable(Type *t) {
 	case Type_BitSet:
 	case Type_BitSet:
 		return true;
 		return true;
 
 
+	case Type_BitFieldValue:
+		return true;
+
 	case Type_Opaque:
 	case Type_Opaque:
 		return is_type_comparable(t->Opaque.elem);
 		return is_type_comparable(t->Opaque.elem);
 	}
 	}