Browse Source

Fix bit_field comparison against nil #414

gingerBill 6 năm trước cách đây
mục cha
commit
65d41d4248
3 tập tin đã thay đổi với 44 bổ sung0 xóa
  1. 34 0
      core/runtime/internal.odin
  2. 1 0
      src/checker.cpp
  3. 9 0
      src/ir.cpp

+ 34 - 0
core/runtime/internal.odin

@@ -281,6 +281,40 @@ memory_compare :: proc "contextless" (a, b: rawptr, n: int) -> int #no_bounds_ch
 	return 0;
 }
 
+memory_compare_zero :: proc "contextless" (a: rawptr, n: int) -> int #no_bounds_check {
+	x := uintptr(a);
+	n := uintptr(n);
+
+	SU :: size_of(uintptr);
+	fast := uintptr(n/SU + 1);
+	offset := (fast-1)*SU;
+	curr_block := uintptr(0);
+	if n < SU {
+		fast = 0;
+	}
+
+	for /**/; curr_block < fast; curr_block += 1 {
+		va := (^uintptr)(x + curr_block * size_of(uintptr))^;
+		if va ~ 0 != 0 {
+			for pos := curr_block*SU; pos < n; pos += 1 {
+				a := (^byte)(x+pos)^;
+				if a ~ 0 != 0 {
+					return int(a) < 0 ? -1 : +1;
+				}
+			}
+		}
+	}
+
+	for /**/; offset < n; offset += 1 {
+		a := (^byte)(x+offset)^;
+		if a ~ 0 != 0 {
+			return int(a) < 0 ? -1 : +1;
+		}
+	}
+
+	return 0;
+}
+
 string_eq :: proc "contextless" (a, b: string) -> bool {
 	switch {
 	case len(a) != len(b): return false;

+ 1 - 0
src/checker.cpp

@@ -1615,6 +1615,7 @@ void generate_minimum_dependency_set(Checker *c, Entity *start) {
 		str_lit("udivti3"),
 
 		str_lit("memory_compare"),
+		str_lit("memory_compare_zero"),
 	};
 	for (isize i = 0; i < gb_count_of(required_runtime_entities); i++) {
 		add_dependency_to_set(c, scope_lookup(c->info.runtime_package->scope, required_runtime_entities[i]));

+ 9 - 0
src/ir.cpp

@@ -4017,6 +4017,15 @@ irValue *ir_emit_comp_against_nil(irProcedure *proc, TokenKind op_kind, irValue
 	} else if (is_type_typeid(t)) {
 		irValue *invalid_typeid = ir_value_constant(t_typeid, exact_value_i64(0));
 		return ir_emit_comp(proc, op_kind, x, invalid_typeid);
+	} else if (is_type_bit_field(t)) {
+		auto args = array_make<irValue *>(heap_allocator(), 2);
+		irValue *lhs = ir_address_from_load_or_generate_local(proc, x);
+		args[0] = ir_emit_conv(proc, lhs, t_rawptr);
+		args[1] = ir_const_int(type_size_of(t));
+		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);
+
 	}
 	return nullptr;
 }