Add #no_capture args: ..T to reuse the backing array stack memory

This commit is contained in:
gingerBill
2024-07-14 11:39:05 +01:00
parent f98a7b84df
commit edc793d7c1
12 changed files with 136 additions and 57 deletions
+17
View File
@@ -6033,6 +6033,23 @@ 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)) {
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);
found = true;
break;
}
}
if (!found) {
array_add(&c->decl->no_captures, NoCaptureData{vt->type, variadic_operands.count});
}
}
} else {
dummy_argument_count += 1;
o.type = t_untyped_nil;
+17
View File
@@ -1953,6 +1953,10 @@ gb_internal Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_para
error(name, "'#by_ptr' can only be applied to variable fields");
p->flags &= ~FieldFlag_by_ptr;
}
if (p->flags&FieldFlag_no_capture) {
error(name, "'#no_capture' can only be applied to variable variadic fields");
p->flags &= ~FieldFlag_no_capture;
}
param = alloc_entity_type_name(scope, name->Ident.token, type, EntityState_Resolved);
param->TypeName.is_type_alias = true;
@@ -2054,6 +2058,15 @@ gb_internal Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_para
p->flags &= ~FieldFlag_by_ptr; // Remove the flag
}
}
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_poly_name) {
if (p->flags&FieldFlag_no_alias) {
@@ -2115,6 +2128,10 @@ gb_internal Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_para
if (p->flags&FieldFlag_by_ptr) {
param->flags |= EntityFlag_ByPtr;
}
if (p->flags&FieldFlag_no_capture) {
param->flags |= EntityFlag_NoCapture;
}
param->state = EntityState_Resolved; // NOTE(bill): This should have be resolved whilst determining it
add_entity(ctx, scope, name, param);
+1
View File
@@ -184,6 +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();
}
gb_internal DeclInfo *make_decl_info(Scope *scope, DeclInfo *parent) {
+7
View File
@@ -181,6 +181,11 @@ char const *ProcCheckedState_strings[ProcCheckedState_COUNT] {
"Checked",
};
struct NoCaptureData {
Type *slice_type; // ..elem_type
isize max_count;
};
// DeclInfo is used to store information of certain declarations to allow for "any order" usage
struct DeclInfo {
DeclInfo * parent; // NOTE(bill): only used for procedure literals at the moment
@@ -219,6 +224,8 @@ struct DeclInfo {
Array<BlockLabel> labels;
Array<NoCaptureData> no_captures;
// 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;
};
+1 -1
View File
@@ -45,7 +45,7 @@ enum EntityFlag : u64 {
EntityFlag_Value = 1ull<<11,
EntityFlag_BitFieldField = 1ull<<12,
EntityFlag_NoCapture = 1ull<<13, // #no_capture
EntityFlag_PolyConst = 1ull<<15,
EntityFlag_NotExported = 1ull<<16,
+7
View File
@@ -296,6 +296,11 @@ enum lbProcedureFlag : u32 {
lbProcedureFlag_DebugAllocaCopy = 1<<1,
};
struct lbNoCaptureData {
Type *slice_type;
lbAddr base_array;
};
struct lbProcedure {
u32 flags;
u16 state_flags;
@@ -336,6 +341,8 @@ struct lbProcedure {
bool in_multi_assignment;
Array<LLVMValueRef> raw_input_parameters;
Array<lbNoCaptureData> no_captures;
LLVMValueRef temp_callee_return_struct_memory;
Ast *curr_stmt;
+26 -1
View File
@@ -517,6 +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();
GB_ASSERT(p->type != nullptr);
@@ -3450,8 +3451,32 @@ 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;
}
}
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;
}
}
}
}
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);
lbAddr base_array = lb_add_local_generated(p, alloc_type_array(elem_type, slice_len), true);
for (isize i = 0; i < var_args.count; i++) {
lbValue addr = lb_emit_array_epi(p, base_array.addr, cast(i32)i);
+1
View File
@@ -4014,6 +4014,7 @@ struct ParseFieldPrefixMapping {
gb_global ParseFieldPrefixMapping const parse_field_prefix_mappings[] = {
{str_lit("using"), Token_using, FieldFlag_using},
{str_lit("no_alias"), Token_Hash, FieldFlag_no_alias},
{str_lit("no_capture"), Token_Hash, FieldFlag_no_capture},
{str_lit("c_vararg"), Token_Hash, FieldFlag_c_vararg},
{str_lit("const"), Token_Hash, FieldFlag_const},
{str_lit("any_int"), Token_Hash, FieldFlag_any_int},
+6 -2
View File
@@ -330,9 +330,10 @@ enum FieldFlag : u32 {
FieldFlag_subtype = 1<<7,
FieldFlag_by_ptr = 1<<8,
FieldFlag_no_broadcast = 1<<9, // disallow array programming
FieldFlag_no_capture = 1<<10,
// Internal use by the parser only
FieldFlag_Tags = 1<<10,
FieldFlag_Tags = 1<<11,
FieldFlag_Results = 1<<16,
@@ -340,7 +341,10 @@ enum FieldFlag : u32 {
FieldFlag_Invalid = 1u<<31,
// Parameter List Restrictions
FieldFlag_Signature = FieldFlag_ellipsis|FieldFlag_using|FieldFlag_no_alias|FieldFlag_c_vararg|FieldFlag_const|FieldFlag_any_int|FieldFlag_by_ptr|FieldFlag_no_broadcast,
FieldFlag_Signature = FieldFlag_ellipsis|FieldFlag_using|FieldFlag_no_alias|FieldFlag_c_vararg|
FieldFlag_const|FieldFlag_any_int|FieldFlag_by_ptr|FieldFlag_no_broadcast|
FieldFlag_no_capture,
FieldFlag_Struct = FieldFlag_using|FieldFlag_subtype|FieldFlag_Tags,
};