Browse Source

Improve rules for zeroing types with the ir.cpp backend with `ir_type_requires_mem_zero`

gingerBill 4 years ago
parent
commit
83cd2473f2
1 changed files with 64 additions and 2 deletions
  1. 64 2
      src/ir.cpp

+ 64 - 2
src/ir.cpp

@@ -3162,14 +3162,76 @@ void ir_value_set_debug_location(irProcedure *proc, irValue *v) {
 	}
 	}
 }
 }
 
 
+bool ir_type_requires_mem_zero(Type *t) {
+	t = core_type(t);
+	isize sz = type_size_of(t);
+	if (t->kind == Type_SimdVector) {
+		return false;
+	}
+
+	if (!(gb_is_power_of_two(sz) && sz <= build_context.max_align)) {
+		return true;
+	}
+
+	enum : i64 {LARGE_SIZE = 64};
+	if (sz > LARGE_SIZE) {
+		return true;
+	}
+
+	switch (t->kind) {
+	case Type_Union:
+		return true;
+	case Type_Struct:
+		if (t->Struct.is_raw_union) {
+			return true;
+		}
+		if (t->Struct.is_packed) {
+			return false;
+		} else {
+			i64 packed_sized = 0;
+			for_array(i, t->Struct.fields) {
+				Type *f = t->Struct.fields[i];
+				if (f->kind == Entity_Variable) {
+					packed_sized += type_size_of(f->type);
+				}
+			}
+			return sz != packed_sized;
+		}
+		break;
+	case Type_Tuple:
+		if (t->Tuple.is_packed) {
+			return false;
+		} else {
+			i64 packed_sized = 0;
+			for_array(i, t->Tuple.variables) {
+				Entity *f = t->Tuple.variables[i];
+				if (f->kind == Entity_Variable) {
+					packed_sized += type_size_of(f->type);
+				}
+			}
+			return sz != packed_sized;
+		}
+		break;
+
+	case Type_DynamicArray:
+	case Type_Map:
+	case Type_BitField:
+		return true;
+	case Type_Array:
+		return ir_type_requires_mem_zero(t->Array.elem);
+	case Type_EnumeratedArray:
+		return ir_type_requires_mem_zero(t->EnumeratedArray.elem);
+	}
+	return false;
+}
+
 void ir_emit_zero_init(irProcedure *p, irValue *address, Ast *expr) {
 void ir_emit_zero_init(irProcedure *p, irValue *address, Ast *expr) {
 	gbAllocator a = ir_allocator();
 	gbAllocator a = ir_allocator();
 	Type *t = type_deref(ir_type(address));
 	Type *t = type_deref(ir_type(address));
-	isize sz = type_size_of(t);
 
 
 	if (address) address->uses += 1;
 	if (address) address->uses += 1;
 
 
-	if (!(gb_is_power_of_two(sz) && sz <= build_context.max_align)) {
+	if (ir_type_requires_mem_zero(t)) {
 		// TODO(bill): Is this a good idea?
 		// TODO(bill): Is this a good idea?
 		auto args = array_make<irValue *>(a, 2);
 		auto args = array_make<irValue *>(a, 2);
 		args[0] = ir_emit_conv(p, address, t_rawptr);
 		args[0] = ir_emit_conv(p, address, t_rawptr);