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

This commit is contained in:
gingerBill
2020-12-08 15:43:57 +00:00
parent 15bf57e4e1
commit d7a5767aa3
2 changed files with 187 additions and 86 deletions

View File

@@ -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) {

View File

@@ -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,77 +3091,6 @@ 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);
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<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));
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<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) {