Browse Source

Fix nil comparisons for soa slices and dynamic arrays

gingerBill 5 years ago
parent
commit
7fbe0a6f23
4 changed files with 50 additions and 7 deletions
  1. 4 3
      core/os/os.odin
  2. 1 3
      examples/demo/demo.odin
  3. 38 1
      src/ir.cpp
  4. 7 0
      src/types.cpp

+ 4 - 3
core/os/os.odin

@@ -164,9 +164,10 @@ heap_allocator_proc :: proc(allocator_data: rawptr, mode: mem.Allocator_Mode,
 		return aligned_heap_alloc(size, alignment);
 
 	case .Free:
-		assert(old_memory != nil);
-		ptr := recover_original_pointer(old_memory);
-		heap_free(ptr);
+		if old_memory != nil {
+			ptr := recover_original_pointer(old_memory);
+			heap_free(ptr);
+		}
 		return nil;
 
 	case .Free_All:

+ 1 - 3
examples/demo/demo.odin

@@ -1833,9 +1833,7 @@ main :: proc() {
 		deprecated_attribute();
 		range_statements_with_multiple_return_values();
 		threading_example();
-
-		// TODO(tetra): When bill fixes SOA array comparison to nil in reserve_soa, we can re-enable this.
-		// soa_struct_layout();
+		soa_struct_layout();
 	}
 }
 

+ 38 - 1
src/ir.cpp

@@ -4325,7 +4325,44 @@ irValue *ir_emit_comp_against_nil(irProcedure *proc, TokenKind op_kind, irValue
 		irValue *val = ir_emit_runtime_call(proc, "memory_compare_zero", args);
 		irValue *res = ir_emit_comp(proc, op_kind, val, v_zero);
 		return ir_emit_conv(proc, res, t_bool);
-
+	} else if (is_type_soa_struct(t)) {
+		Type *bt = base_type(t);
+		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);
+			}
+		} 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);
+			}
+		}
 	}
 	return nullptr;
 }

+ 7 - 0
src/types.cpp

@@ -1585,6 +1585,13 @@ bool type_has_nil(Type *t) {
 	case Type_Union:
 		return !t->Union.no_nil;
 	case Type_Struct:
+		if (is_type_soa_struct(t)) {
+			switch (t->Struct.soa_kind) {
+			case StructSoa_Fixed:   return false;
+			case StructSoa_Slice:   return true;
+			case StructSoa_Dynamic: return true;
+			}
+		}
 		return false;
 	case Type_Opaque:
 		return true;