Browse Source

Fix #3514 along with `soa.a[i]` bounds checking

gingerBill 1 year ago
parent
commit
32245e93a1
4 changed files with 50 additions and 21 deletions
  1. 2 2
      src/check_expr.cpp
  2. 12 3
      src/check_type.cpp
  3. 35 15
      src/llvm_backend_expr.cpp
  4. 1 1
      src/llvm_backend_general.cpp

+ 2 - 2
src/check_expr.cpp

@@ -7806,8 +7806,8 @@ gb_internal bool check_set_index_data(Operand *o, Type *t, bool indirection, i64
 
 	if (is_type_pointer(original_type) && indirection) {
 		Type *ptr = base_type(original_type);
-		if (ptr->kind == Type_Pointer && o->mode == Addressing_SoaVariable) {
-			o->type = ptr->Pointer.elem;
+		if (ptr->kind == Type_MultiPointer && o->mode == Addressing_SoaVariable) {
+			o->type = ptr->MultiPointer.elem;
 			o->mode = Addressing_Value;
 			return true;
 		}

+ 12 - 3
src/check_type.cpp

@@ -2827,12 +2827,15 @@ gb_internal bool complete_soa_type(Checker *checker, Type *t, bool wait_to_finis
 				GB_ASSERT(soa_count >= 0);
 				field_type = alloc_type_array(old_field->type, soa_count);
 			} else {
-				field_type = alloc_type_pointer(old_field->type);
+				field_type = alloc_type_multi_pointer(old_field->type);
 			}
 			Entity *new_field = alloc_entity_field(scope, old_field->token, field_type, false, old_field->Variable.field_index);
 			t->Struct.fields[i] = new_field;
 			add_entity(scope, new_field);
 			new_field->flags |= EntityFlag_Used;
+			if (t->Struct.soa_kind != StructSoa_Fixed) {
+				new_field->flags |= EntityFlag_SoaPtrField;
+			}
 		} else {
 			t->Struct.fields[i] = old_field;
 		}
@@ -2948,7 +2951,7 @@ gb_internal Type *make_soa_struct_internal(CheckerContext *ctx, Ast *array_typ_e
 				GB_ASSERT(count >= 0);
 				field_type = alloc_type_array(old_array->Array.elem, count);
 			} else {
-				field_type = alloc_type_pointer(old_array->Array.elem);
+				field_type = alloc_type_multi_pointer(old_array->Array.elem);
 			}
 			Token token = {};
 			token.string = params_xyzw[i];
@@ -2957,6 +2960,9 @@ gb_internal Type *make_soa_struct_internal(CheckerContext *ctx, Ast *array_typ_e
 			soa_struct->Struct.fields[i] = new_field;
 			add_entity(ctx, scope, nullptr, new_field);
 			add_entity_use(ctx, nullptr, new_field);
+			if (soa_kind != StructSoa_Fixed) {
+				new_field->flags |= EntityFlag_SoaPtrField;
+			}
 		}
 
 		is_complete = true;
@@ -2980,12 +2986,15 @@ gb_internal Type *make_soa_struct_internal(CheckerContext *ctx, Ast *array_typ_e
 						GB_ASSERT(count >= 0);
 						field_type = alloc_type_array(old_field->type, count);
 					} else {
-						field_type = alloc_type_pointer(old_field->type);
+						field_type = alloc_type_multi_pointer(old_field->type);
 					}
 					Entity *new_field = alloc_entity_field(scope, old_field->token, field_type, false, old_field->Variable.field_index);
 					soa_struct->Struct.fields[i] = new_field;
 					add_entity(ctx, scope, nullptr, new_field);
 					add_entity_use(ctx, nullptr, new_field);
+					if (soa_kind != StructSoa_Fixed) {
+						new_field->flags |= EntityFlag_SoaPtrField;
+					}
 				} else {
 					soa_struct->Struct.fields[i] = old_field;
 				}

+ 35 - 15
src/llvm_backend_expr.cpp

@@ -3851,27 +3851,39 @@ gb_internal lbAddr lb_build_addr_index_expr(lbProcedure *p, Ast *expr) {
 
 	if (ie->expr->tav.mode == Addressing_SoaVariable) {
 		// SOA Structures for slices/dynamic arrays
-		GB_ASSERT(is_type_pointer(type_of_expr(ie->expr)));
+		GB_ASSERT_MSG(is_type_multi_pointer(type_of_expr(ie->expr)), "%s", type_to_string(type_of_expr(ie->expr)));
 
 		lbValue field = lb_build_expr(p, ie->expr);
 		lbValue index = lb_build_expr(p, ie->index);
 
-
 		if (!build_context.no_bounds_check) {
-			// TODO HACK(bill): Clean up this hack to get the length for bounds checking
-			// GB_ASSERT(LLVMIsALoadInst(field.value));
-
-			// lbValue a = {};
-			// a.value = LLVMGetOperand(field.value, 0);
-			// a.type = alloc_type_pointer(field.type);
-
-			// irInstr *b = &a->Instr;
-			// GB_ASSERT(b->kind == irInstr_StructElementPtr);
-			// lbValue base_struct = b->StructElementPtr.address;
+			Ast *se_expr = unparen_expr(ie->expr);
+			if (se_expr->kind == Ast_SelectorExpr) {
+				ast_node(se, SelectorExpr, se_expr);
+				lbValue len = {};
+
+				Type *type = base_type(type_deref(type_of_expr(se->expr)));
+				GB_ASSERT_MSG(is_type_soa_struct(type), "%s", type_to_string(type));
+				if (type->Struct.soa_kind == StructSoa_Fixed) {
+					len = lb_const_int(p->module, t_int, type->Struct.soa_count);
+				} else {
+					lbAddr *found = map_get(&p->selector_addr, se_expr);
+					if (found) {
+						lbAddr addr = *found;
+						lbValue parent = lb_addr_get_ptr(p, addr);
+						if (is_type_pointer(type_deref(parent.type))) {
+							parent = lb_emit_load(p, parent);
+						}
+						len = lb_soa_struct_len(p, parent);
+					}
+				}
 
-			// GB_ASSERT(is_type_soa_struct(type_deref(ir_type(base_struct))));
-			// lbValue len = ir_soa_struct_len(p, base_struct);
-			// lb_emit_bounds_check(p, ast_token(ie->index), index, len);
+				if (len.value) {
+					lb_emit_bounds_check(p, ast_token(ie->index), index, len);
+				}
+			} else {
+				// TODO(bill): how do you even do bounds checking here?
+			}
 		}
 		lbValue val = lb_emit_ptr_offset(p, field, index);
 		return lb_addr(val);
@@ -4218,6 +4230,7 @@ gb_internal lbAddr lb_build_addr_slice_expr(lbProcedure *p, Ast *expr) {
 					lbValue field_dst = lb_emit_struct_ep(p, dst.addr, i);
 					lbValue field_src = lb_emit_struct_ep(p, lb_addr_get_ptr(p, addr), i);
 					field_src = lb_emit_array_ep(p, field_src, low);
+					field_src = lb_emit_conv(p, field_src, type_deref(field_dst.type));
 					lb_emit_store(p, field_dst, field_src);
 				}
 
@@ -4233,6 +4246,7 @@ gb_internal lbAddr lb_build_addr_slice_expr(lbProcedure *p, Ast *expr) {
 						lbValue field_dst = lb_emit_struct_ep(p, dst.addr, i);
 						lbValue field_src = lb_emit_struct_ev(p, base, i);
 						field_src = lb_emit_ptr_offset(p, field_src, low);
+						field_src = lb_emit_conv(p, field_src, type_deref(field_dst.type));
 						lb_emit_store(p, field_dst, field_src);
 					}
 
@@ -4247,6 +4261,7 @@ gb_internal lbAddr lb_build_addr_slice_expr(lbProcedure *p, Ast *expr) {
 					lbValue field_dst = lb_emit_struct_ep(p, dst.addr, i);
 					lbValue field_src = lb_emit_struct_ev(p, base, i);
 					field_src = lb_emit_ptr_offset(p, field_src, low);
+					field_src = lb_emit_conv(p, field_src, type_deref(field_dst.type));
 					lb_emit_store(p, field_dst, field_src);
 				}
 
@@ -4989,6 +5004,11 @@ gb_internal lbAddr lb_build_addr_internal(lbProcedure *p, Ast *expr) {
 					sel.index[0] = addr.swizzle.indices[sel.index[0]];
 				}
 
+				Type *atype = type_deref(lb_addr_type(addr));
+				if (is_type_soa_struct(atype)) {
+					map_set(&p->selector_addr, expr, addr);
+				}
+
 				lbValue a = lb_addr_get_ptr(p, addr);
 				a = lb_emit_deep_field_gep(p, a, sel);
 				return lb_addr(a);

+ 1 - 1
src/llvm_backend_general.cpp

@@ -1324,7 +1324,7 @@ gb_internal lbValue lb_addr_load(lbProcedure *p, lbAddr const &addr) {
 			for (isize i = 0; i < field_count; i++) {
 				Entity *field = t->Struct.fields[i];
 				Type *base_type = field->type;
-				GB_ASSERT(base_type->kind == Type_Pointer);
+				GB_ASSERT(base_type->kind == Type_MultiPointer);
 
 				lbValue dst = lb_emit_struct_ep(p, res.addr, cast(i32)i);
 				lbValue src_ptr = lb_emit_struct_ep(p, addr.addr, cast(i32)i);