From d7a5767aa3497f9b4b6f0ced955ce31fb019ef80 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Tue, 8 Dec 2020 15:43:57 +0000 Subject: [PATCH] If `ir_type_requires_mem_zero` is stored with zero, don't store again with the `zeroinitializer` --- src/check_expr.cpp | 65 ++++++++++++++ src/ir.cpp | 208 ++++++++++++++++++++++++++------------------- 2 files changed, 187 insertions(+), 86 deletions(-) diff --git a/src/check_expr.cpp b/src/check_expr.cpp index ea460ce09..15380e55c 100644 --- a/src/check_expr.cpp +++ b/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 const ¶ms) { diff --git a/src/ir.cpp b/src/ir.cpp index 34b64562f..f69b25494 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -901,7 +901,7 @@ Array *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,77 +3091,6 @@ void ir_pop_debug_location(irModule *m) { irValue *ir_emit_runtime_call(irProcedure *proc, char const *name_, Array args, Ast *expr = nullptr, ProcInlining inlining = ProcInlining_none); irValue *ir_emit_package_call(irProcedure *proc, char const *package_name_, char const *name_, Array args, Ast *expr = nullptr, ProcInlining inlining = ProcInlining_none); - -irValue *ir_emit_store(irProcedure *p, irValue *address, irValue *value, bool is_volatile) { - Type *a = type_deref(ir_type(address)); - - if (is_type_boolean(a)) { - // NOTE(bill): There are multiple sized booleans, thus force a conversion (if necessarily) - value = ir_emit_conv(p, value, a); - } - - if (address) address->uses += 1; - if (value) value->uses += 1; - - - Type *b = ir_type(value); - 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)); - } - return ir_emit(p, ir_instr_store(p, address, value, is_volatile)); -} -irValue *ir_emit_load(irProcedure *p, irValue *address, i64 custom_align) { - GB_ASSERT(address != nullptr); - Type *t = type_deref(ir_type(address)); - // if (is_type_boolean(t)) { - // return ir_emit(p, ir_instr_load_bool(p, address)); - // } - if (address) address->uses += 1; - auto instr = ir_instr_load(p, address); - instr->Instr.Load.custom_align = custom_align; - return ir_emit(p, instr); -} -irValue *ir_emit_select(irProcedure *p, irValue *cond, irValue *t, irValue *f) { - if (cond) cond->uses += 1; - if (t) t->uses += 1; - if (f) f->uses += 1; - - return ir_emit(p, ir_instr_select(p, cond, t, f)); -} - -void ir_value_set_debug_location(irProcedure *proc, irValue *v) { - GB_ASSERT_NOT_NULL(proc); - GB_ASSERT_NOT_NULL(v); - - if (v->loc != nullptr) { - return; // Already set - } - - if (proc->is_startup) { - // ignore startup procedures - return; - } - - irModule *m = proc->module; - GB_ASSERT(m->debug_location_stack.count > 0); - v->loc = *array_end_ptr(&m->debug_location_stack); - - if (v->loc == nullptr && proc->entity != nullptr) { - if (proc->is_entry_point || (string_compare(proc->name, str_lit(IR_STARTUP_RUNTIME_PROC_NAME)) == 0)) { - // NOTE(lachsinc): Entry point (main()) and runtime_startup are the only ones where null location is considered valid. - } else { - if (v->kind == irValue_Instr) { - auto *instr = &v->Instr; - gb_printf_err("Instruction kind: %.*s\n", LIT(ir_instr_strings[instr->kind])); - if (instr->kind == irInstr_DebugDeclare) { - gb_printf_err("\t%.*s\n", LIT(instr->DebugDeclare.entity->token.string)); - } - } - GB_PANIC("Value without debug location: %.*s %p; %p :: %s", LIT(proc->name), proc->entity, v, type_to_string(proc->type)); - } - } -} - bool ir_type_requires_mem_zero(Type *t) { t = core_type(t); isize sz = type_size_of(t); @@ -3225,28 +3154,135 @@ bool ir_type_requires_mem_zero(Type *t) { return false; } -void ir_emit_zero_init(irProcedure *p, irValue *address, Ast *expr) { +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(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)); + + if (is_type_boolean(a)) { + // NOTE(bill): There are multiple sized booleans, thus force a conversion (if necessarily) + value = ir_emit_conv(p, value, a); + } + + if (address) address->uses += 1; + if (value) value->uses += 1; + + + Type *b = ir_type(value); + 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) { + GB_ASSERT(address != nullptr); + Type *t = type_deref(ir_type(address)); + // if (is_type_boolean(t)) { + // return ir_emit(p, ir_instr_load_bool(p, address)); + // } + if (address) address->uses += 1; + auto instr = ir_instr_load(p, address); + instr->Instr.Load.custom_align = custom_align; + return ir_emit(p, instr); +} +irValue *ir_emit_select(irProcedure *p, irValue *cond, irValue *t, irValue *f) { + if (cond) cond->uses += 1; + if (t) t->uses += 1; + if (f) f->uses += 1; + + return ir_emit(p, ir_instr_select(p, cond, t, f)); +} + +void ir_value_set_debug_location(irProcedure *proc, irValue *v) { + GB_ASSERT_NOT_NULL(proc); + GB_ASSERT_NOT_NULL(v); + + if (v->loc != nullptr) { + return; // Already set + } + + if (proc->is_startup) { + // ignore startup procedures + return; + } + + irModule *m = proc->module; + GB_ASSERT(m->debug_location_stack.count > 0); + v->loc = *array_end_ptr(&m->debug_location_stack); + + if (v->loc == nullptr && proc->entity != nullptr) { + if (proc->is_entry_point || (string_compare(proc->name, str_lit(IR_STARTUP_RUNTIME_PROC_NAME)) == 0)) { + // NOTE(lachsinc): Entry point (main()) and runtime_startup are the only ones where null location is considered valid. + } else { + if (v->kind == irValue_Instr) { + auto *instr = &v->Instr; + gb_printf_err("Instruction kind: %.*s\n", LIT(ir_instr_strings[instr->kind])); + if (instr->kind == irInstr_DebugDeclare) { + gb_printf_err("\t%.*s\n", LIT(instr->DebugDeclare.entity->token.string)); + } + } + GB_PANIC("Value without debug location: %.*s %p; %p :: %s", LIT(proc->name), proc->entity, v, type_to_string(proc->type)); + } + } +} + +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(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) {