Browse Source

If `ir_type_requires_mem_zero` is stored with zero, don't store again with the `zeroinitializer`

gingerBill 4 years ago
parent
commit
d7a5767aa3
2 changed files with 179 additions and 78 deletions
  1. 65 0
      src/check_expr.cpp
  2. 114 78
      src/ir.cpp

+ 65 - 0
src/check_expr.cpp

@@ -10279,6 +10279,71 @@ void check_expr_or_type(CheckerContext *c, Operand *o, Ast *e, Type *type_hint)
 }
 
 
+
+bool is_exact_value_zero(ExactValue const &v) {
+	switch (v.kind) {
+	case ExactValue_Invalid:
+		return true;
+	case ExactValue_Bool:
+		return !v.value_bool;
+	case ExactValue_String:
+		return v.value_string.len == 0;
+	case ExactValue_Integer:
+		return big_int_is_zero(&v.value_integer);
+	case ExactValue_Float:
+		return v.value_float == 0.0;
+	case ExactValue_Complex:
+		if (v.value_complex) {
+			return v.value_complex->real == 0.0 && v.value_complex->imag == 0.0;
+		}
+		return true;
+	case ExactValue_Quaternion:
+		if (v.value_quaternion) {
+			return v.value_quaternion->real == 0.0 &&
+			       v.value_quaternion->imag == 0.0 &&
+			       v.value_quaternion->jmag == 0.0 &&
+			       v.value_quaternion->kmag == 0.0;
+		}
+		return true;
+	case ExactValue_Pointer:
+		return v.value_pointer == 0;
+	case ExactValue_Compound:
+		if (v.value_compound == nullptr) {
+			return true;
+		} else {
+			ast_node(cl, CompoundLit, v.value_compound);
+			if (cl->elems.count == 0) {
+				return true;
+			} else {
+				for_array(i, cl->elems) {
+					Ast *elem = cl->elems[i];
+					if (elem->tav.mode != Addressing_Constant) {
+						// if (elem->tav.value.kind != ExactValue_Invalid) {
+						return false;
+						// }
+					}
+					if (!is_exact_value_zero(elem->tav.value)) {
+						return false;
+					}
+				}
+				return true;
+			}
+		}
+	case ExactValue_Procedure:
+		return v.value_procedure == nullptr;
+	case ExactValue_Typeid:
+		return v.value_typeid == nullptr;
+	}
+	return true;
+
+}
+
+
+
+
+
+
+
 gbString write_expr_to_string(gbString str, Ast *node, bool shorthand);
 
 gbString write_struct_fields_to_string(gbString str, Slice<Ast *> const &params) {

+ 114 - 78
src/ir.cpp

@@ -901,7 +901,7 @@ Array<irValue *> *ir_value_referrers(irValue *v) {
 ////////////////////////////////////////////////////////////////
 
 void     ir_module_add_value    (irModule *m, Entity *e, irValue *v);
-void     ir_emit_zero_init      (irProcedure *p, irValue *address, Ast *expr);
+irValue *ir_emit_zero_init      (irProcedure *p, irValue *address, Ast *expr);
 irValue *ir_emit_comment        (irProcedure *p, String text);
 irValue *ir_emit_store          (irProcedure *p, irValue *address, irValue *value, bool is_volatile=false);
 irValue *ir_emit_load           (irProcedure *p, irValue *address, i64 custom_align=0);
@@ -3091,6 +3091,85 @@ void ir_pop_debug_location(irModule *m) {
 irValue *ir_emit_runtime_call(irProcedure *proc,                            char const *name_, Array<irValue *> args, Ast *expr = nullptr, ProcInlining inlining = ProcInlining_none);
 irValue *ir_emit_package_call(irProcedure *proc, char const *package_name_, char const *name_, Array<irValue *> args, Ast *expr = nullptr, ProcInlining inlining = ProcInlining_none);
 
+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) {
+				Entity *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;
+}
+
+irValue *ir_call_mem_zero(irProcedure *p, irValue *address, Ast *expr = nullptr) {
+	Type *t = type_deref(ir_type(address));
+	// TODO(bill): Is this a good idea?
+	auto args = array_make<irValue *>(ir_allocator(), 2);
+	args[0] = ir_emit_conv(p, address, t_rawptr);
+	args[1] = ir_const_int(type_size_of(t));
+	AstPackage *pkg_runtime = get_core_package(p->module->info, str_lit("runtime"));
+	if (p->entity != nullptr) {
+		String name = p->entity->token.string;
+		if (p->entity->pkg != pkg_runtime && !(name == "mem_zero" || name == "memset")) {
+			ir_emit_comment(p, str_lit("ZeroInit"));
+			return ir_emit_package_call(p, "runtime", "mem_zero", args, expr);
+		}
+	}
+	return nullptr;
+}
 
 irValue *ir_emit_store(irProcedure *p, irValue *address, irValue *value, bool is_volatile) {
 	Type *a = type_deref(ir_type(address));
@@ -3108,6 +3187,35 @@ irValue *ir_emit_store(irProcedure *p, irValue *address, irValue *value, bool is
 	if (!is_type_untyped(b)) {
 		GB_ASSERT_MSG(are_types_identical(core_type(a), core_type(b)), "%s %s", type_to_string(a), type_to_string(b));
 	}
+
+
+	if (value->kind == irValue_Constant) {
+		ExactValue const &v = value->Constant.value;
+		irValue *res = nullptr;
+		switch (v.kind) {
+		case ExactValue_Invalid:
+			res = ir_call_mem_zero(p, address);
+			if (res) {
+				return res;
+			}
+			goto end;
+
+		case ExactValue_Compound:
+			// NOTE(bill): This is to enforce the zeroing of the padding
+			if (ir_type_requires_mem_zero(a)) {
+				res = ir_call_mem_zero(p, address);
+				if (res == nullptr || v.value_compound == nullptr) {
+					goto end;
+				}
+				if (is_exact_value_zero(v)) {
+					return res;
+				}
+			}
+			goto end;
+		}
+	}
+
+end:;
 	return ir_emit(p, ir_instr_store(p, address, value, is_volatile));
 }
 irValue *ir_emit_load(irProcedure *p, irValue *address, i64 custom_align) {
@@ -3162,91 +3270,19 @@ 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) {
-				Entity *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) {
+irValue *ir_emit_zero_init(irProcedure *p, irValue *address, Ast *expr) {
 	gbAllocator a = ir_allocator();
 	Type *t = type_deref(ir_type(address));
 
 	if (address) address->uses += 1;
 
 	if (ir_type_requires_mem_zero(t)) {
-		// TODO(bill): Is this a good idea?
-		auto args = array_make<irValue *>(a, 2);
-		args[0] = ir_emit_conv(p, address, t_rawptr);
-		args[1] = ir_const_int(type_size_of(t));
-		AstPackage *pkg_runtime = get_core_package(p->module->info, str_lit("runtime"));
-		if (p->entity != nullptr) {
-			String name = p->entity->token.string;
-			if (p->entity->pkg != pkg_runtime && !(name == "mem_zero" || name == "memset")) {
-				ir_emit_comment(p, str_lit("ZeroInit"));
-				irValue *v = ir_emit_package_call(p, "runtime", "mem_zero", args, expr);
-				return;
-			}
+		irValue *res = ir_call_mem_zero(p, address, expr);
+		if (res) {
+			return res;
 		}
 	}
-	ir_emit(p, ir_instr_zero_init(p, address));
+	return ir_emit(p, ir_instr_zero_init(p, address));
 }
 
 irValue *ir_emit_comment(irProcedure *p, String text) {