Browse Source

Mock out `#no_capture` for future use

gingerBill 1 year ago
parent
commit
3dff83f3dc
7 changed files with 54 additions and 39 deletions
  1. 6 7
      src/check_expr.cpp
  2. 24 8
      src/check_type.cpp
  3. 1 1
      src/checker.cpp
  4. 2 2
      src/checker.hpp
  5. 6 0
      src/llvm_abi.cpp
  6. 2 2
      src/llvm_backend.hpp
  7. 13 19
      src/llvm_backend_proc.cpp

+ 6 - 7
src/check_expr.cpp

@@ -6034,19 +6034,18 @@ gb_internal CallArgumentError check_call_arguments_internal(CheckerContext *c, A
 					Entity *vt = pt->params->Tuple.variables[pt->variadic_index];
 					o.type = vt->type;
 
-					// NOTE(bill, 2024-07-14): minimize the stack usage for variadic parameter that use `#no_capture`
-					// on the variadic parameter
-					if (c->decl && (vt->flags & EntityFlag_NoCapture)) {
+					// NOTE(bill, 2024-07-14): minimize the stack usage for variadic parameters with the backing array
+					if (c->decl) {
 						bool found = false;
-						for (NoCaptureData &nc : c->decl->no_captures) {
-							if (are_types_identical(vt->type, nc.slice_type)) {
-								nc.max_count = gb_max(nc.max_count, variadic_operands.count);
+						for (auto &vr : c->decl->variadic_reuses) {
+							if (are_types_identical(vt->type, vr.slice_type)) {
+								vr.max_count = gb_max(vr.max_count, variadic_operands.count);
 								found = true;
 								break;
 							}
 						}
 						if (!found) {
-							array_add(&c->decl->no_captures, NoCaptureData{vt->type, variadic_operands.count});
+							array_add(&c->decl->variadic_reuses, VariadicReuseData{vt->type, variadic_operands.count});
 						}
 					}
 

+ 24 - 8
src/check_type.cpp

@@ -1954,7 +1954,7 @@ gb_internal Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_para
 					p->flags &= ~FieldFlag_by_ptr;
 				}
 				if (p->flags&FieldFlag_no_capture) {
-					error(name, "'#no_capture' can only be applied to variable variadic fields");
+					error(name, "'#no_capture' can only be applied to variable fields");
 					p->flags &= ~FieldFlag_no_capture;
 				}
 
@@ -2059,16 +2059,32 @@ gb_internal Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_para
 					}
 				}
 				if (p->flags&FieldFlag_no_capture) {
-					if (!(is_variadic && variadic_index == variables.count)) {
-						error(name, "'#no_capture' can only be applied to a variadic parameter");
-						p->flags &= ~FieldFlag_no_capture;
-					} else if (p->flags & FieldFlag_c_vararg) {
-						error(name, "'#no_capture' cannot be applied to a #c_vararg parameter");
-						p->flags &= ~FieldFlag_no_capture;
+					if (is_variadic && variadic_index == variables.count) {
+						if (p->flags & FieldFlag_c_vararg) {
+							error(name, "'#no_capture' cannot be applied to a #c_vararg parameter");
+							p->flags &= ~FieldFlag_no_capture;
+						} else {
+							error(name, "'#no_capture' is already implied on all variadic parameter");
+						}
+					} else if (is_type_polymorphic(type)) {
+						// ignore
 					} else {
-						error(name, "'#no_capture' is already implied on all variadic parameter");
+						if (is_type_internally_pointer_like(type)) {
+							// okay
+						} else if (is_type_slice(type) || is_type_string(type)) {
+							// okay
+						} else if (is_type_dynamic_array(type)) {
+							// okay
+						} else {
+							ERROR_BLOCK();
+							error(name, "'#no_capture' can only be applied to pointer-like types, slices, strings, and dynamic arrays");
+							error_line("\t'#no_capture' does not currently do anything useful\n");
+							p->flags &= ~FieldFlag_no_capture;
+						}
 					}
 				}
+
+
 				if (is_poly_name) {
 					if (p->flags&FieldFlag_no_alias) {
 						error(name, "'#no_alias' can only be applied to non constant values");

+ 1 - 1
src/checker.cpp

@@ -184,7 +184,7 @@ gb_internal void init_decl_info(DeclInfo *d, Scope *scope, DeclInfo *parent) {
 	ptr_set_init(&d->deps, 0);
 	ptr_set_init(&d->type_info_deps, 0);
 	d->labels.allocator = heap_allocator();
-	d->no_captures.allocator = heap_allocator();
+	d->variadic_reuses.allocator = heap_allocator();
 }
 
 gb_internal DeclInfo *make_decl_info(Scope *scope, DeclInfo *parent) {

+ 2 - 2
src/checker.hpp

@@ -181,7 +181,7 @@ char const *ProcCheckedState_strings[ProcCheckedState_COUNT] {
 	"Checked",
 };
 
-struct NoCaptureData {
+struct VariadicReuseData {
 	Type *slice_type; // ..elem_type
 	isize max_count;
 };
@@ -224,7 +224,7 @@ struct DeclInfo {
 
 	Array<BlockLabel> labels;
 
-	Array<NoCaptureData> no_captures;
+	Array<VariadicReuseData> variadic_reuses;
 
 	// 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;

+ 6 - 0
src/llvm_abi.cpp

@@ -15,6 +15,7 @@ struct lbArgType {
 	LLVMAttributeRef align_attribute; // Optional
 	i64 byval_alignment;
 	bool is_byval;
+	bool no_capture;
 };
 
 
@@ -159,6 +160,11 @@ gb_internal void lb_add_function_type_attributes(LLVMValueRef fn, lbFunctionType
 			LLVMAddAttributeAtIndex(fn, arg_index+1, arg->align_attribute);
 		}
 
+		if (arg->no_capture) {
+			LLVMAddAttributeAtIndex(fn, arg_index+1, nocapture_attr);
+		}
+
+
 		if (ft->multiple_return_original_type) {
 			if (ft->original_arg_count <= i) {
 				LLVMAddAttributeAtIndex(fn, arg_index+1, noalias_attr);

+ 2 - 2
src/llvm_backend.hpp

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

+ 13 - 19
src/llvm_backend_proc.cpp

@@ -517,7 +517,7 @@ gb_internal void lb_begin_procedure_body(lbProcedure *p) {
 	lb_start_block(p, p->entry_block);
 
 	map_init(&p->direct_parameters);
-	p->no_captures.allocator = heap_allocator();
+	p->variadic_reuses.allocator = heap_allocator();
 
 	GB_ASSERT(p->type != nullptr);
 
@@ -3452,28 +3452,22 @@ 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 = {};
-						if (e->flags & EntityFlag_NoCapture) {
-							for (lbNoCaptureData const &nc : p->no_captures) {
-								if (are_types_identical(nc.slice_type, slice_type)) {
-									base_array = nc.base_array;
-									break;
-								}
+						for (auto const &vr : p->variadic_reuses) {
+							if (are_types_identical(vr.slice_type, slice_type)) {
+								base_array = vr.base_array;
+								break;
 							}
-							DeclInfo *d = decl_info_of_entity(p->entity);
-							if (d != nullptr && base_array.addr.value == nullptr) {
-								for (NoCaptureData const &nc : d->no_captures) {
-									if (are_types_identical(nc.slice_type, slice_type)) {
-										base_array = lb_add_local_generated(p, alloc_type_array(elem_type, nc.max_count), true);
-										array_add(&p->no_captures, lbNoCaptureData{slice_type, base_array});
-										break;
-									}
+						}
+						DeclInfo *d = decl_info_of_entity(p->entity);
+						if (d != nullptr && base_array.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);
+									array_add(&p->variadic_reuses, lbVariadicReuseData{slice_type, base_array});
+									break;
 								}
 							}
 						}
-
-						if (base_array.addr.value == nullptr) {
-							base_array = lb_add_local_generated(p, alloc_type_array(elem_type, slice_len), true);
-						}
 						GB_ASSERT(base_array.addr.value != nullptr);
 
 						lbAddr slice = lb_add_local_generated(p, slice_type, true);