Add @(deferred_*_by_ptr=<proc>)

This commit is contained in:
gingerBill
2023-04-15 16:04:04 +01:00
parent 7abaf77292
commit dc55e88588
3 changed files with 226 additions and 115 deletions
+108 -17
View File
@@ -3081,6 +3081,54 @@ gb_internal DECL_ATTRIBUTE_PROC(proc_decl_attribute) {
} }
error(elem, "Expected a procedure entity for '%.*s'", LIT(name)); error(elem, "Expected a procedure entity for '%.*s'", LIT(name));
return false; return false;
} else if (name == "deferred_in_by_ptr") {
if (value != nullptr) {
Operand o = {};
check_expr(c, &o, value);
Entity *e = entity_of_node(o.expr);
if (e != nullptr && e->kind == Entity_Procedure) {
if (ac->deferred_procedure.entity != nullptr) {
error(elem, "Previous usage of a 'deferred_*' attribute");
}
ac->deferred_procedure.kind = DeferredProcedure_in_by_ptr;
ac->deferred_procedure.entity = e;
return true;
}
}
error(elem, "Expected a procedure entity for '%.*s'", LIT(name));
return false;
} else if (name == "deferred_out_by_ptr") {
if (value != nullptr) {
Operand o = {};
check_expr(c, &o, value);
Entity *e = entity_of_node(o.expr);
if (e != nullptr && e->kind == Entity_Procedure) {
if (ac->deferred_procedure.entity != nullptr) {
error(elem, "Previous usage of a 'deferred_*' attribute");
}
ac->deferred_procedure.kind = DeferredProcedure_out_by_ptr;
ac->deferred_procedure.entity = e;
return true;
}
}
error(elem, "Expected a procedure entity for '%.*s'", LIT(name));
return false;
} else if (name == "deferred_in_out_by_ptr") {
if (value != nullptr) {
Operand o = {};
check_expr(c, &o, value);
Entity *e = entity_of_node(o.expr);
if (e != nullptr && e->kind == Entity_Procedure) {
if (ac->deferred_procedure.entity != nullptr) {
error(elem, "Previous usage of a 'deferred_*' attribute");
}
ac->deferred_procedure.kind = DeferredProcedure_in_out_by_ptr;
ac->deferred_procedure.entity = e;
return true;
}
}
error(elem, "Expected a procedure entity for '%.*s'", LIT(name));
return false;
} else if (name == "link_name") { } else if (name == "link_name") {
ExactValue ev = check_decl_attribute_value(c, value); ExactValue ev = check_decl_attribute_value(c, value);
@@ -5438,6 +5486,26 @@ gb_internal void add_untyped_expressions(CheckerInfo *cinfo, UntypedExprInfoMap
map_clear(untyped); map_clear(untyped);
} }
gb_internal Type *tuple_to_pointers(Type *ot) {
if (ot == nullptr) {
return nullptr;
}
GB_ASSERT(ot->kind == Type_Tuple);
Type *t = alloc_type_tuple();
t->Tuple.variables = slice_make<Entity *>(heap_allocator(), ot->Tuple.variables.count);
Scope *scope = nullptr;
for_array(i, t->Tuple.variables) {
Entity *e = ot->Tuple.variables[i];
t->Tuple.variables[i] = alloc_entity_variable(scope, e->token, alloc_type_pointer(e->type));
}
t->Tuple.is_packed = ot->Tuple.is_packed;
return t;
}
gb_internal void check_deferred_procedures(Checker *c) { gb_internal void check_deferred_procedures(Checker *c) {
for (Entity *src = nullptr; mpsc_dequeue(&c->procs_with_deferred_to_check, &src); /**/) { for (Entity *src = nullptr; mpsc_dequeue(&c->procs_with_deferred_to_check, &src); /**/) {
GB_ASSERT(src->kind == Entity_Procedure); GB_ASSERT(src->kind == Entity_Procedure);
@@ -5449,18 +5517,13 @@ gb_internal void check_deferred_procedures(Checker *c) {
char const *attribute = "deferred_none"; char const *attribute = "deferred_none";
switch (dst_kind) { switch (dst_kind) {
case DeferredProcedure_none: case DeferredProcedure_none: attribute = "deferred_none"; break;
attribute = "deferred_none"; case DeferredProcedure_in: attribute = "deferred_in"; break;
break; case DeferredProcedure_out: attribute = "deferred_out"; break;
case DeferredProcedure_in: case DeferredProcedure_in_out: attribute = "deferred_in_out"; break;
attribute = "deferred_in"; case DeferredProcedure_in_by_ptr: attribute = "deferred_in_by_ptr"; break;
break; case DeferredProcedure_out_by_ptr: attribute = "deferred_out_by_ptr"; break;
case DeferredProcedure_out: case DeferredProcedure_in_out_by_ptr: attribute = "deferred_in_out_by_ptr"; break;
attribute = "deferred_out";
break;
case DeferredProcedure_in_out:
attribute = "deferred_in_out";
break;
} }
if (is_type_polymorphic(src->type) || is_type_polymorphic(dst->type)) { if (is_type_polymorphic(src->type) || is_type_polymorphic(dst->type)) {
@@ -5474,14 +5537,36 @@ gb_internal void check_deferred_procedures(Checker *c) {
Type *src_results = base_type(src->type)->Proc.results; Type *src_results = base_type(src->type)->Proc.results;
Type *dst_params = base_type(dst->type)->Proc.params; Type *dst_params = base_type(dst->type)->Proc.params;
if (dst_kind == DeferredProcedure_none) { bool by_ptr = false;
switch (dst_kind) {
case DeferredProcedure_in_by_ptr:
by_ptr = true;
src_params = tuple_to_pointers(src_params);
break;
case DeferredProcedure_out_by_ptr:
by_ptr = true;
src_results = tuple_to_pointers(src_results);
break;
case DeferredProcedure_in_out_by_ptr:
by_ptr = true;
src_params = tuple_to_pointers(src_params);
src_results = tuple_to_pointers(src_results);
break;
}
switch (dst_kind) {
case DeferredProcedure_none:
{
if (dst_params == nullptr) { if (dst_params == nullptr) {
// Okay // Okay
continue; continue;
} }
error(src->token, "Deferred procedure '%.*s' must have no input parameters", LIT(dst->token.string)); error(src->token, "Deferred procedure '%.*s' must have no input parameters", LIT(dst->token.string));
} else if (dst_kind == DeferredProcedure_in) { } break;
case DeferredProcedure_in:
case DeferredProcedure_in_by_ptr:
{
if (src_params == nullptr && dst_params == nullptr) { if (src_params == nullptr && dst_params == nullptr) {
// Okay // Okay
continue; continue;
@@ -5508,8 +5593,10 @@ gb_internal void check_deferred_procedures(Checker *c) {
gb_string_free(s); gb_string_free(s);
continue; continue;
} }
} break;
} else if (dst_kind == DeferredProcedure_out) { case DeferredProcedure_out:
case DeferredProcedure_out_by_ptr:
{
if (src_results == nullptr && dst_params == nullptr) { if (src_results == nullptr && dst_params == nullptr) {
// Okay // Okay
continue; continue;
@@ -5536,7 +5623,10 @@ gb_internal void check_deferred_procedures(Checker *c) {
gb_string_free(s); gb_string_free(s);
continue; continue;
} }
} else if (dst_kind == DeferredProcedure_in_out) { } break;
case DeferredProcedure_in_out:
case DeferredProcedure_in_out_by_ptr:
{
if (src_params == nullptr && src_results == nullptr && dst_params == nullptr) { if (src_params == nullptr && src_results == nullptr && dst_params == nullptr) {
// Okay // Okay
continue; continue;
@@ -5586,6 +5676,7 @@ gb_internal void check_deferred_procedures(Checker *c) {
gb_string_free(s); gb_string_free(s);
continue; continue;
} }
} break;
} }
} }
+4
View File
@@ -92,6 +92,10 @@ enum DeferredProcedureKind {
DeferredProcedure_in, DeferredProcedure_in,
DeferredProcedure_out, DeferredProcedure_out,
DeferredProcedure_in_out, DeferredProcedure_in_out,
DeferredProcedure_in_by_ptr,
DeferredProcedure_out_by_ptr,
DeferredProcedure_in_out_by_ptr,
}; };
struct DeferredProcedure { struct DeferredProcedure {
DeferredProcedureKind kind; DeferredProcedureKind kind;
+16
View File
@@ -1169,17 +1169,27 @@ gb_internal lbValue lb_emit_call(lbProcedure *p, lbValue value, Array<lbValue> c
lbValue deferred = lb_find_procedure_value_from_entity(p->module, deferred_entity); lbValue deferred = lb_find_procedure_value_from_entity(p->module, deferred_entity);
bool by_ptr = false;
auto in_args = args; auto in_args = args;
Array<lbValue> result_as_args = {}; Array<lbValue> result_as_args = {};
switch (kind) { switch (kind) {
case DeferredProcedure_none: case DeferredProcedure_none:
break; break;
case DeferredProcedure_in_by_ptr:
by_ptr = true;
/*fallthrough*/
case DeferredProcedure_in: case DeferredProcedure_in:
result_as_args = array_clone(heap_allocator(), in_args); result_as_args = array_clone(heap_allocator(), in_args);
break; break;
case DeferredProcedure_out_by_ptr:
by_ptr = true;
/*fallthrough*/
case DeferredProcedure_out: case DeferredProcedure_out:
result_as_args = lb_value_to_array(p, heap_allocator(), result); result_as_args = lb_value_to_array(p, heap_allocator(), result);
break; break;
case DeferredProcedure_in_out_by_ptr:
by_ptr = true;
/*fallthrough*/
case DeferredProcedure_in_out: case DeferredProcedure_in_out:
{ {
auto out_args = lb_value_to_array(p, heap_allocator(), result); auto out_args = lb_value_to_array(p, heap_allocator(), result);
@@ -1189,6 +1199,12 @@ gb_internal lbValue lb_emit_call(lbProcedure *p, lbValue value, Array<lbValue> c
} }
break; break;
} }
if (by_ptr) {
for_array(i, result_as_args) {
lbValue arg_ptr = lb_address_from_load_or_generate_local(p, result_as_args[i]);
result_as_args[i] = arg_ptr;
}
}
lb_add_defer_proc(p, p->scope_index, deferred, result_as_args); lb_add_defer_proc(p, p->scope_index, deferred, result_as_args);
} }