diff --git a/src/array.cpp b/src/array.cpp index d8e25d25d..5d602cebc 100644 --- a/src/array.cpp +++ b/src/array.cpp @@ -168,6 +168,17 @@ gb_internal gb_inline Slice slice(Slice const &array, isize lo, isize hi) } return out; } +template +gb_internal gb_inline Slice slice(Array const &array, isize lo, isize hi) { + GB_ASSERT(0 <= lo && lo <= hi && hi <= array.count); + Slice out = {}; + isize len = hi-lo; + if (len > 0) { + out.data = array.data+lo; + out.count = len; + } + return out; +} template diff --git a/src/tilde.hpp b/src/tilde.hpp index d548de78e..45eceeb7b 100644 --- a/src/tilde.hpp +++ b/src/tilde.hpp @@ -42,8 +42,9 @@ struct cgValue { cgValueKind kind; Type * type; union { - TB_Symbol *symbol; - TB_Node * node; + // NOTE: any value in this union must be a pointer + TB_Symbol * symbol; + TB_Node * node; cgValueMulti *multi; }; }; @@ -308,4 +309,6 @@ gb_internal cgValue cg_emit_arith(cgProcedure *p, TokenKind op, cgValue lhs, cgV gb_internal bool cg_emit_goto(cgProcedure *p, TB_Node *control_region); -gb_internal TB_Node *cg_control_region(cgProcedure *p, char const *name); \ No newline at end of file +gb_internal TB_Node *cg_control_region(cgProcedure *p, char const *name); + +gb_internal isize cg_append_tuple_values(cgProcedure *p, Array *dst_values, cgValue src_value); \ No newline at end of file diff --git a/src/tilde_const.cpp b/src/tilde_const.cpp index 6e3979637..e066c72a3 100644 --- a/src/tilde_const.cpp +++ b/src/tilde_const.cpp @@ -126,7 +126,7 @@ gb_internal TB_Global *cg_global_const_string(cgModule *m, String const &str, Ty if (global == nullptr) { global = tb_global_create(m->mod, -1, name, cg_debug_type(m, type), TB_LINKAGE_PRIVATE); - tb_global_set_storage(m->mod, tb_module_get_rdata(m->mod), str_global, type_size_of(type), type_align_of(type), 2); + tb_global_set_storage(m->mod, tb_module_get_rdata(m->mod), global, type_size_of(type), type_align_of(type), 2); } tb_global_add_symbol_reloc(m->mod, global, offset+0, cast(TB_Symbol *)str_global); diff --git a/src/tilde_proc.cpp b/src/tilde_proc.cpp index 8f7b1972e..0deb4af45 100644 --- a/src/tilde_proc.cpp +++ b/src/tilde_proc.cpp @@ -355,7 +355,7 @@ gb_internal cgValue cg_build_call_expr(cgProcedure *p, Ast *expr) { return res; } -gb_internal cgValue cg_emit_call(cgProcedure * p, cgValue value, Slice args) { +gb_internal cgValue cg_emit_call(cgProcedure * p, cgValue value, Slice const &args) { if (value.kind == cgValue_Symbol) { value = cg_value(tb_inst_get_symbol_address(p->func, value.symbol), value.type); } @@ -540,6 +540,43 @@ gb_internal cgValue cg_emit_call(cgProcedure * p, cgValue value, Slice return cg_value_multi(multi, pt->results); } + +gb_internal cgValue cg_handle_param_value(cgProcedure *p, Type *parameter_type, ParameterValue const ¶m_value, TokenPos const &pos) { + switch (param_value.kind) { + case ParameterValue_Constant: + if (is_type_constant_type(parameter_type)) { + auto res = cg_const_value(p, parameter_type, param_value.value); + return res; + } else { + ExactValue ev = param_value.value; + cgValue arg = {}; + Type *type = type_of_expr(param_value.original_ast_expr); + if (type != nullptr) { + arg = cg_const_value(p, type, ev); + } else { + arg = cg_const_value(p, parameter_type, param_value.value); + } + return cg_emit_conv(p, arg, parameter_type); + } + + case ParameterValue_Nil: + return cg_const_nil(p, parameter_type); + case ParameterValue_Location: + { + String proc_name = {}; + if (p->entity != nullptr) { + proc_name = p->entity->token.string; + } + GB_PANIC("TODO(bill): cg_emit_source_code_location_as_global"); + // return cg_emit_source_code_location_as_global(p, proc_name, pos); + break; + } + case ParameterValue_Value: + return cg_build_expr(p, param_value.ast_value); + } + return cg_const_nil(p, parameter_type); +} + gb_internal cgValue cg_build_call_expr_internal(cgProcedure *p, Ast *expr) { ast_node(ce, CallExpr, expr); @@ -611,7 +648,151 @@ gb_internal cgValue cg_build_call_expr_internal(cgProcedure *p, Ast *expr) { value = cg_emit_load(p, value); } GB_ASSERT(value.kind == cgValue_Value); + GB_ASSERT(value.node != nullptr); GB_ASSERT(is_type_proc(value.type)); - return cg_emit_call(p, value, {}); + TEMPORARY_ALLOCATOR_GUARD(); + + Type *proc_type_ = base_type(value.type); + GB_ASSERT(proc_type_->kind == Type_Proc); + TypeProc *pt = &proc_type_->Proc; + + GB_ASSERT(ce->split_args != nullptr); + + auto args = array_make(temporary_allocator(), 0, pt->param_count); + + bool vari_expand = (ce->ellipsis.pos.line != 0); + bool is_c_vararg = pt->c_vararg; + + for_array(i, ce->split_args->positional) { + Entity *e = pt->params->Tuple.variables[i]; + if (e->kind == Entity_TypeName) { + continue; + } else if (e->kind == Entity_Constant) { + continue; + } + + GB_ASSERT(e->kind == Entity_Variable); + + if (pt->variadic && pt->variadic_index == i) { + cgValue variadic_args = cg_const_nil(p, e->type); + auto variadic = slice(ce->split_args->positional, pt->variadic_index, ce->split_args->positional.count); + if (variadic.count != 0) { + // variadic call argument generation + Type *slice_type = e->type; + GB_ASSERT(slice_type->kind == Type_Slice); + + if (is_c_vararg) { + GB_ASSERT(!vari_expand); + + Type *elem_type = slice_type->Slice.elem; + + for (Ast *var_arg : variadic) { + cgValue arg = cg_build_expr(p, var_arg); + if (is_type_any(elem_type)) { + array_add(&args, cg_emit_conv(p, arg, default_type(arg.type))); + } else { + array_add(&args, cg_emit_conv(p, arg, elem_type)); + } + } + break; + } else if (vari_expand) { + GB_ASSERT(variadic.count == 1); + variadic_args = cg_build_expr(p, variadic[0]); + variadic_args = cg_emit_conv(p, variadic_args, slice_type); + } else { + Type *elem_type = slice_type->Slice.elem; + + auto var_args = array_make(temporary_allocator(), 0, variadic.count); + for (Ast *var_arg : variadic) { + cgValue v = cg_build_expr(p, var_arg); + cg_append_tuple_values(p, &var_args, v); + } + isize slice_len = var_args.count; + if (slice_len > 0) { + cgAddr slice = cg_add_local(p, slice_type, nullptr, true); + cgAddr base_array = cg_add_local(p, alloc_type_array(elem_type, slice_len), nullptr, true); + + for (isize i = 0; i < var_args.count; i++) { + cgValue addr = cg_emit_array_epi(p, base_array.addr, cast(i32)i); + cgValue var_arg = var_args[i]; + var_arg = cg_emit_conv(p, var_arg, elem_type); + cg_emit_store(p, addr, var_arg); + } + + cgValue base_elem = cg_emit_array_epi(p, base_array.addr, 0); + cgValue len = cg_const_int(p, t_int, slice_len); + GB_PANIC("TODO(bill): cg_fill_slice"); + // cg_fill_slice(p, slice, base_elem, len); + + variadic_args = cg_addr_load(p, slice); + } + } + } + array_add(&args, variadic_args); + + break; + } else { + cgValue value = cg_build_expr(p, ce->split_args->positional[i]); + cg_append_tuple_values(p, &args, value); + } + } + + if (!is_c_vararg) { + array_resize(&args, pt->param_count); + } + + for (Ast *arg : ce->split_args->named) { + ast_node(fv, FieldValue, arg); + GB_ASSERT(fv->field->kind == Ast_Ident); + String name = fv->field->Ident.token.string; + gb_unused(name); + isize param_index = lookup_procedure_parameter(pt, name); + GB_ASSERT(param_index >= 0); + + cgValue value = cg_build_expr(p, fv->value); + GB_ASSERT(!is_type_tuple(value.type)); + args[param_index] = value; + } + + TokenPos pos = ast_token(ce->proc).pos; + + + if (pt->params != nullptr) { + isize min_count = pt->params->Tuple.variables.count; + if (is_c_vararg) { + min_count -= 1; + } + GB_ASSERT(args.count >= min_count); + for_array(arg_index, pt->params->Tuple.variables) { + Entity *e = pt->params->Tuple.variables[arg_index]; + if (pt->variadic && arg_index == pt->variadic_index) { + if (!is_c_vararg && args[arg_index].node == nullptr) { + args[arg_index] = cg_const_nil(p, e->type); + } + continue; + } + + cgValue arg = args[arg_index]; + if (arg.node == nullptr) { + switch (e->kind) { + case Entity_TypeName: + case Entity_Constant: + break; + case Entity_Variable: + args[arg_index] = cg_handle_param_value(p, e->type, e->Variable.param_value, pos); + break; + default: + GB_PANIC("Unknown entity kind %.*s\n", LIT(entity_strings[e->kind])); + } + } else { + args[arg_index] = cg_emit_conv(p, arg, e->type); + } + } + } + + isize final_count = is_c_vararg ? args.count : pt->param_count; + auto call_args = slice(args, 0, final_count); + + return cg_emit_call(p, value, call_args); }