Browse Source

Calculate size and alignment, and reuse memory for all variadic calls within a procedure body

gingerBill 1 year ago
parent
commit
6959554040
5 changed files with 34 additions and 12 deletions
  1. 9 0
      src/check_decl.cpp
  2. 2 0
      src/checker.cpp
  3. 3 1
      src/checker.hpp
  4. 3 3
      src/llvm_backend.hpp
  5. 17 8
      src/llvm_backend_proc.cpp

+ 9 - 0
src/check_decl.cpp

@@ -1869,5 +1869,14 @@ gb_internal bool check_proc_body(CheckerContext *ctx_, Token token, DeclInfo *de
 
 	add_deps_from_child_to_parent(decl);
 
+	for (VariadicReuseData const &vr : decl->variadic_reuses) {
+		GB_ASSERT(vr.slice_type->kind == Type_Slice);
+		Type *elem = vr.slice_type->Slice.elem;
+		i64 size = type_size_of(elem);
+		i64 align = type_align_of(elem);
+		decl->variadic_reuse_max_bytes = gb_max(decl->variadic_reuse_max_bytes, size*vr.max_count);
+		decl->variadic_reuse_max_align = gb_max(decl->variadic_reuse_max_align, align);
+	}
+
 	return true;
 }

+ 2 - 0
src/checker.cpp

@@ -185,6 +185,8 @@ gb_internal void init_decl_info(DeclInfo *d, Scope *scope, DeclInfo *parent) {
 	ptr_set_init(&d->type_info_deps, 0);
 	d->labels.allocator = heap_allocator();
 	d->variadic_reuses.allocator = heap_allocator();
+	d->variadic_reuse_max_bytes = 0;
+	d->variadic_reuse_max_align = 1;
 }
 
 gb_internal DeclInfo *make_decl_info(Scope *scope, DeclInfo *parent) {

+ 3 - 1
src/checker.hpp

@@ -183,7 +183,7 @@ char const *ProcCheckedState_strings[ProcCheckedState_COUNT] {
 
 struct VariadicReuseData {
 	Type *slice_type; // ..elem_type
-	isize max_count;
+	i64 max_count;
 };
 
 // DeclInfo is used to store information of certain declarations to allow for "any order" usage
@@ -225,6 +225,8 @@ struct DeclInfo {
 	Array<BlockLabel> labels;
 
 	Array<VariadicReuseData> variadic_reuses;
+	i64 variadic_reuse_max_bytes;
+	i64 variadic_reuse_max_align;
 
 	// NOTE(bill): this is to prevent a race condition since these procedure literals can be created anywhere at any time
 	struct lbModule *code_gen_module;

+ 3 - 3
src/llvm_backend.hpp

@@ -296,9 +296,8 @@ enum lbProcedureFlag : u32 {
 	lbProcedureFlag_DebugAllocaCopy = 1<<1,
 };
 
-struct lbVariadicReuseData {
+struct lbVariadicReuseSlices {
 	Type *slice_type;
-	lbAddr base_array;
 	lbAddr slice_addr;
 };
 
@@ -342,7 +341,8 @@ struct lbProcedure {
 	bool             in_multi_assignment;
 	Array<LLVMValueRef> raw_input_parameters;
 
-	Array<lbVariadicReuseData> variadic_reuses;
+	Array<lbVariadicReuseSlices> variadic_reuses;
+	lbAddr variadic_reuse_base_array_ptr;
 
 	LLVMValueRef temp_callee_return_struct_memory;
 	Ast *curr_stmt;

+ 17 - 8
src/llvm_backend_proc.cpp

@@ -3456,39 +3456,48 @@ gb_internal lbValue lb_build_call_expr_internal(lbProcedure *p, Ast *expr) {
 					}
 					isize slice_len = var_args.count;
 					if (slice_len > 0) {
-						lbAddr base_array = {};
 						lbAddr slice = {};
 
 						for (auto const &vr : p->variadic_reuses) {
 							if (are_types_identical(vr.slice_type, slice_type)) {
-								base_array = vr.base_array;
 								slice = vr.slice_addr;
 								break;
 							}
 						}
+
 						DeclInfo *d = decl_info_of_entity(p->entity);
-						if (d != nullptr && base_array.addr.value == nullptr) {
+						if (d != nullptr && slice.addr.value == nullptr) {
 							for (auto const &vr : d->variadic_reuses) {
 								if (are_types_identical(vr.slice_type, slice_type)) {
-									base_array = lb_add_local_generated(p, alloc_type_array(elem_type, vr.max_count), true);
 									slice = lb_add_local_generated(p, slice_type, true);
-									array_add(&p->variadic_reuses, lbVariadicReuseData{slice_type, base_array, slice});
+									array_add(&p->variadic_reuses, lbVariadicReuseSlices{slice_type, slice});
 									break;
 								}
 							}
 						}
-						GB_ASSERT(base_array.addr.value != nullptr);
+
+						lbValue base_array_ptr = p->variadic_reuse_base_array_ptr.addr;
+						if (d != nullptr && base_array_ptr.value == nullptr) {
+							i64 max_bytes = d->variadic_reuse_max_bytes;
+							i64 max_align = gb_max(d->variadic_reuse_max_align, 16);
+							p->variadic_reuse_base_array_ptr = lb_add_local_generated(p, alloc_type_array(t_u8, max_bytes), true);
+							lb_try_update_alignment(p->variadic_reuse_base_array_ptr.addr, cast(unsigned)max_align);
+							base_array_ptr = p->variadic_reuse_base_array_ptr.addr;
+						}
+
+						GB_ASSERT(base_array_ptr.value != nullptr);
 						GB_ASSERT(slice.addr.value != nullptr);
 
+						base_array_ptr = lb_emit_conv(p, base_array_ptr, alloc_type_pointer(alloc_type_array(elem_type, slice_len)));
 
 						for (isize i = 0; i < var_args.count; i++) {
-							lbValue addr = lb_emit_array_epi(p, base_array.addr, cast(i32)i);
+							lbValue addr = lb_emit_array_epi(p, base_array_ptr, cast(i32)i);
 							lbValue var_arg = var_args[i];
 							var_arg = lb_emit_conv(p, var_arg, elem_type);
 							lb_emit_store(p, addr, var_arg);
 						}
 
-						lbValue base_elem = lb_emit_array_epi(p, base_array.addr, 0);
+						lbValue base_elem = lb_emit_array_epi(p, base_array_ptr, 0);
 						lbValue len = lb_const_int(p->module, t_int, slice_len);
 						lb_fill_slice(p, slice, base_elem, len);