From 9e698b720f4f26341db81b70ea5f70f5bdfd9e3a Mon Sep 17 00:00:00 2001 From: gingerBill Date: Sun, 12 Apr 2020 10:41:44 +0100 Subject: [PATCH] Change behaviour for zero-sized value types of array-related types; Fix make behaviour to always zero memory --- core/mem/alloc.odin | 8 +++-- core/runtime/core.odin | 26 ++++++++++----- src/ir.cpp | 65 ++++++------------------------------ src/llvm_backend.cpp | 76 +++++++++++++++--------------------------- 4 files changed, 60 insertions(+), 115 deletions(-) diff --git a/core/mem/alloc.odin b/core/mem/alloc.odin index 767e59183..fda7862c3 100644 --- a/core/mem/alloc.odin +++ b/core/mem/alloc.odin @@ -111,7 +111,10 @@ make_slice :: inline proc($T: typeid/[]$E, auto_cast len: int, allocator := cont make_aligned :: proc($T: typeid/[]$E, auto_cast len: int, alignment: int, allocator := context.allocator, loc := #caller_location) -> T { runtime.make_slice_error_loc(loc, len); data := alloc(size_of(E)*len, alignment, allocator, loc); - if data == nil do return nil; + if data == nil && size_of(E) != 0 { + return nil; + } + zero(data, size_of(E)*len); s := Raw_Slice{data, len}; return transmute(T)s; } @@ -125,9 +128,10 @@ make_dynamic_array_len_cap :: proc($T: typeid/[dynamic]$E, auto_cast len: int, a runtime.make_dynamic_array_error_loc(loc, len, cap); data := alloc(size_of(E)*cap, align_of(E), allocator, loc); s := Raw_Dynamic_Array{data, len, cap, allocator}; - if data == nil { + if data == nil && size_of(E) != 0 { s.len, s.cap = 0, 0; } + zero(data, size_of(E)*len); return transmute(T)s; } make_map :: proc($T: typeid/map[$K]$E, auto_cast cap: int = 16, allocator := context.allocator, loc := #caller_location) -> T { diff --git a/core/runtime/core.odin b/core/runtime/core.odin index d906c28b7..b66f43788 100644 --- a/core/runtime/core.odin +++ b/core/runtime/core.odin @@ -609,7 +609,10 @@ new_clone :: inline proc(data: $T, allocator := context.allocator, loc := #calle make_aligned :: proc($T: typeid/[]$E, auto_cast len: int, alignment: int, allocator := context.allocator, loc := #caller_location) -> T { make_slice_error_loc(loc, len); data := mem_alloc(size_of(E)*len, alignment, allocator, loc); - if data == nil do return nil; + if data == nil && size_of(E) != 0 { + return nil; + } + mem_zero(data, size_of(E)*len); s := Raw_Slice{data, len}; return transmute(T)s; } @@ -634,9 +637,10 @@ make_dynamic_array_len_cap :: proc($T: typeid/[dynamic]$E, auto_cast len: int, a make_dynamic_array_error_loc(loc, len, cap); data := mem_alloc(size_of(E)*cap, align_of(E), allocator, loc); s := Raw_Dynamic_Array{data, len, cap, allocator}; - if data == nil { + if data == nil && size_of(E) != 0 { s.len, s.cap = 0, 0; } + mem_zero(data, size_of(E)*cap); return transmute(T)s; } @@ -697,10 +701,12 @@ append_elem :: proc(array: ^$T/[dynamic]$E, arg: E, loc := #caller_location) { arg_len = min(cap(array)-len(array), arg_len); if arg_len > 0 { a := (^Raw_Dynamic_Array)(array); - data := (^E)(a.data); - assert(data != nil); - val := arg; - mem_copy(ptr_offset(data, a.len), &val, size_of(E)); + if size_of(E) != 0 { + data := (^E)(a.data); + assert(data != nil); + val := arg; + mem_copy(ptr_offset(data, a.len), &val, size_of(E)); + } a.len += arg_len; } } @@ -719,9 +725,11 @@ append_elems :: proc(array: ^$T/[dynamic]$E, args: ..E, loc := #caller_location) arg_len = min(cap(array)-len(array), arg_len); if arg_len > 0 { a := (^Raw_Dynamic_Array)(array); - data := (^E)(a.data); - assert(data != nil); - mem_copy(ptr_offset(data, a.len), &args[0], size_of(E) * arg_len); + if size_of(E) != 0 { + data := (^E)(a.data); + assert(data != nil); + mem_copy(ptr_offset(data, a.len), &args[0], size_of(E) * arg_len); + } a.len += arg_len; } } diff --git a/src/ir.cpp b/src/ir.cpp index 9b8eac02f..c01876b5d 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -4414,6 +4414,7 @@ irValue *ir_emit_comp_against_nil(irProcedure *proc, TokenKind op_kind, irValue irValue *ptr = ir_emit_conv(proc, x, t_u8_ptr); return ir_emit_comp(proc, op_kind, ptr, v_raw_nil); } else if (is_type_any(t)) { + // TODO(bill): is this correct behaviour for nil comparison for any? irValue *data = ir_emit_struct_ev(proc, x, 0); irValue *ti = ir_emit_struct_ev(proc, x, 1); if (op_kind == Token_CmpEq) { @@ -4426,32 +4427,14 @@ irValue *ir_emit_comp_against_nil(irProcedure *proc, TokenKind op_kind, irValue return ir_emit_arith(proc, Token_And, a, b, t_bool); } } else if (is_type_slice(t)) { - irValue *data = ir_emit_struct_ev(proc, x, 0); - irValue *cap = ir_emit_struct_ev(proc, x, 1); - if (op_kind == Token_CmpEq) { - irValue *a = ir_emit_comp(proc, Token_CmpEq, data, v_raw_nil); - irValue *b = ir_emit_comp(proc, Token_CmpEq, cap, v_zero); - return ir_emit_arith(proc, Token_Or, a, b, t_bool); - } else if (op_kind == Token_NotEq) { - irValue *a = ir_emit_comp(proc, Token_NotEq, data, v_raw_nil); - irValue *b = ir_emit_comp(proc, Token_NotEq, cap, v_zero); - return ir_emit_arith(proc, Token_And, a, b, t_bool); - } - } else if (is_type_dynamic_array(t)) { - irValue *data = ir_emit_struct_ev(proc, x, 0); - irValue *cap = ir_emit_struct_ev(proc, x, 2); - if (op_kind == Token_CmpEq) { - irValue *a = ir_emit_comp(proc, Token_CmpEq, data, v_raw_nil); - irValue *b = ir_emit_comp(proc, Token_CmpEq, cap, v_zero); - return ir_emit_arith(proc, Token_Or, a, b, t_bool); - } else if (op_kind == Token_NotEq) { - irValue *a = ir_emit_comp(proc, Token_NotEq, data, v_raw_nil); - irValue *b = ir_emit_comp(proc, Token_NotEq, cap, v_zero); - return ir_emit_arith(proc, Token_And, a, b, t_bool); - } - } else if (is_type_map(t)) { - irValue *len = ir_map_len(proc, x); + irValue *len = ir_emit_struct_ev(proc, x, 1); return ir_emit_comp(proc, op_kind, len, v_zero); + } else if (is_type_dynamic_array(t)) { + irValue *cap = ir_emit_struct_ev(proc, x, 2); + return ir_emit_comp(proc, op_kind, cap, v_zero); + } else if (is_type_map(t)) { + irValue *cap = ir_map_cap(proc, x); + return ir_emit_comp(proc, op_kind, cap, v_zero); } else if (is_type_union(t)) { if (type_size_of(t) == 0) { return ir_emit_comp(proc, op_kind, v_zero, v_zero); @@ -4481,38 +4464,12 @@ irValue *ir_emit_comp_against_nil(irProcedure *proc, TokenKind op_kind, irValue if (bt->Struct.soa_kind == StructSoa_Slice) { ir_emit_comment(proc, str_lit("soa-slice-nil-comp")); irValue *len = ir_soa_struct_len(proc, x); - if (bt->Struct.fields.count > 1) { - irValue *data = ir_emit_struct_ev(proc, x, 0); - if (op_kind == Token_CmpEq) { - irValue *a = ir_emit_comp(proc, Token_CmpEq, data, v_raw_nil); - irValue *b = ir_emit_comp(proc, Token_CmpEq, len, v_zero); - return ir_emit_arith(proc, Token_Or, a, b, t_bool); - } else if (op_kind == Token_NotEq) { - irValue *a = ir_emit_comp(proc, Token_NotEq, data, v_raw_nil); - irValue *b = ir_emit_comp(proc, Token_NotEq, len, v_zero); - return ir_emit_arith(proc, Token_And, a, b, t_bool); - } - } else { - return ir_emit_comp(proc, op_kind, len, v_zero); - } + return ir_emit_comp(proc, op_kind, len, v_zero); } else if (bt->Struct.soa_kind == StructSoa_Dynamic) { ir_emit_comment(proc, str_lit("soa-dynamic-array-nil-comp")); - irValue *cap = ir_soa_struct_len(proc, x); - if (bt->Struct.fields.count > 1) { - irValue *data = ir_emit_struct_ev(proc, x, 0); - if (op_kind == Token_CmpEq) { - irValue *a = ir_emit_comp(proc, Token_CmpEq, data, v_raw_nil); - irValue *b = ir_emit_comp(proc, Token_CmpEq, cap, v_zero); - return ir_emit_arith(proc, Token_Or, a, b, t_bool); - } else if (op_kind == Token_NotEq) { - irValue *a = ir_emit_comp(proc, Token_NotEq, data, v_raw_nil); - irValue *b = ir_emit_comp(proc, Token_NotEq, cap, v_zero); - return ir_emit_arith(proc, Token_And, a, b, t_bool); - } - } else { - return ir_emit_comp(proc, op_kind, cap, v_zero); - } + irValue *cap = ir_soa_struct_cap(proc, x); + return ir_emit_comp(proc, op_kind, cap, v_zero); } } return nullptr; diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index 68d288799..c308f5746 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -7952,6 +7952,7 @@ lbValue lb_emit_comp_against_nil(lbProcedure *p, TokenKind op_kind, lbValue x) { } return res; } else if (is_type_any(t)) { + // TODO(bill): is this correct behaviour for nil comparison for any? lbValue data = lb_emit_struct_ev(p, x, 0); lbValue ti = lb_emit_struct_ev(p, x, 1); if (op_kind == Token_CmpEq) { @@ -7966,31 +7967,21 @@ lbValue lb_emit_comp_against_nil(lbProcedure *p, TokenKind op_kind, lbValue x) { return res; } } else if (is_type_slice(t)) { - lbValue data = lb_emit_struct_ev(p, x, 0); - lbValue cap = lb_emit_struct_ev(p, x, 1); + lbValue len = lb_emit_struct_ev(p, x, 1); if (op_kind == Token_CmpEq) { - LLVMValueRef a = LLVMBuildIsNull(p->builder, data.value, ""); - LLVMValueRef b = LLVMBuildIsNull(p->builder, cap.value, ""); - res.value = LLVMBuildOr(p->builder, a, b, ""); + res.value = LLVMBuildIsNull(p->builder, len.value, ""); return res; } else if (op_kind == Token_NotEq) { - LLVMValueRef a = LLVMBuildIsNotNull(p->builder, data.value, ""); - LLVMValueRef b = LLVMBuildIsNotNull(p->builder, cap.value, ""); - res.value = LLVMBuildAnd(p->builder, a, b, ""); + res.value = LLVMBuildIsNotNull(p->builder, len.value, ""); return res; } } else if (is_type_dynamic_array(t)) { - lbValue data = lb_emit_struct_ev(p, x, 0); lbValue cap = lb_emit_struct_ev(p, x, 2); if (op_kind == Token_CmpEq) { - LLVMValueRef a = LLVMBuildIsNull(p->builder, data.value, ""); - LLVMValueRef b = LLVMBuildIsNull(p->builder, cap.value, ""); - res.value = LLVMBuildOr(p->builder, a, b, ""); + res.value = LLVMBuildIsNull(p->builder, cap.value, ""); return res; } else if (op_kind == Token_NotEq) { - LLVMValueRef a = LLVMBuildIsNotNull(p->builder, data.value, ""); - LLVMValueRef b = LLVMBuildIsNotNull(p->builder, cap.value, ""); - res.value = LLVMBuildAnd(p->builder, a, b, ""); + res.value = LLVMBuildIsNotNull(p->builder, cap.value, ""); return res; } } else if (is_type_map(t)) { @@ -8019,41 +8010,26 @@ lbValue lb_emit_comp_against_nil(lbProcedure *p, TokenKind op_kind, lbValue x) { lbValue res = lb_emit_comp(p, op_kind, val, lb_const_int(p->module, t_int, 0)); return res; } else if (is_type_soa_struct(t)) { - GB_PANIC("#soa struct nil comparison"); - // Type *bt = base_type(t); - // if (bt->Struct.soa_kind == StructSoa_Slice) { - // lbValue len = lb_soa_struct_len(p, x); - // if (bt->Struct.fields.count > 1) { - // lbValue data = lb_emit_struct_ev(p, x, 0); - // if (op_kind == Token_CmpEq) { - // lbValue a = lb_emit_comp(p, Token_CmpEq, data, v_raw_nil); - // lbValue b = lb_emit_comp(p, Token_CmpEq, len, v_zero); - // return lb_emit_arith(p, Token_Or, a, b, t_bool); - // } else if (op_kind == Token_NotEq) { - // lbValue a = lb_emit_comp(p, Token_NotEq, data, v_raw_nil); - // lbValue b = lb_emit_comp(p, Token_NotEq, len, v_zero); - // return lb_emit_arith(p, Token_And, a, b, t_bool); - // } - // } else { - // return lb_emit_comp(p, op_kind, len, v_zero); - // } - // } else if (bt->Struct.soa_kind == StructSoa_Dynamic) { - // lbValue cap = lb_soa_struct_len(p, x); - // if (bt->Struct.fields.count > 1) { - // lbValue data = lb_emit_struct_ev(p, x, 0); - // if (op_kind == Token_CmpEq) { - // lbValue a = lb_emit_comp(p, Token_CmpEq, data, v_raw_nil); - // lbValue b = lb_emit_comp(p, Token_CmpEq, cap, v_zero); - // return lb_emit_arith(p, Token_Or, a, b, t_bool); - // } else if (op_kind == Token_NotEq) { - // lbValue a = lb_emit_comp(p, Token_NotEq, data, v_raw_nil); - // lbValue b = lb_emit_comp(p, Token_NotEq, cap, v_zero); - // return lb_emit_arith(p, Token_And, a, b, t_bool); - // } - // } else { - // return lb_emit_comp(p, op_kind, cap, v_zero); - // } - // } + Type *bt = base_type(t); + if (bt->Struct.soa_kind == StructSoa_Slice) { + lbValue len = lb_soa_struct_len(p, x); + if (op_kind == Token_CmpEq) { + res.value = LLVMBuildIsNull(p->builder, len.value, ""); + return res; + } else if (op_kind == Token_NotEq) { + res.value = LLVMBuildIsNotNull(p->builder, len.value, ""); + return res; + } + } else if (bt->Struct.soa_kind == StructSoa_Dynamic) { + lbValue cap = lb_soa_struct_cap(p, x); + if (op_kind == Token_CmpEq) { + res.value = LLVMBuildIsNull(p->builder, cap.value, ""); + return res; + } else if (op_kind == Token_NotEq) { + res.value = LLVMBuildIsNotNull(p->builder, cap.value, ""); + return res; + } + } } return {}; }