Update Tilde to get procedure passing rules

This commit is contained in:
gingerBill
2023-07-22 07:56:13 +01:00
parent ec0a9a5f8a
commit e5f9458905
6 changed files with 217 additions and 115 deletions
+12 -83
View File
@@ -1,5 +1,12 @@
#include "tilde.hpp"
gb_global Slice<TB_Arena *> global_tb_arenas;
gb_internal TB_Arena *cg_arena(void) {
return global_tb_arenas[current_thread_index()];
}
// returns TB_TYPE_VOID if not trivially possible
gb_internal TB_DataType cg_data_type(Type *t) {
GB_ASSERT(t != nullptr);
@@ -672,6 +679,11 @@ gb_internal bool cg_generate_code(Checker *c) {
CheckerInfo *info = &c->info;
gb_unused(info);
global_tb_arenas = slice_make<TB_Arena *>(permanent_allocator(), global_thread_pool.threads.count);
for_array(i, global_tb_arenas) {
global_tb_arenas[i] = tb_default_arena();
}
cgModule *m = cg_module_create(c);
defer (cg_module_destroy(m));
@@ -750,89 +762,6 @@ gb_internal bool cg_generate_code(Checker *c) {
char const *path = "W:/Odin/tilde_main.obj";
GB_ASSERT(tb_export_buffer_to_file(export_buffer, path));
////////////////////////////////////////////////////////////////////////////////////
// TB_Arena *arena = tb_default_arena();
// TB_Global *str = nullptr;
// {
// TB_Global *str_data = nullptr;
// {
// str_data = tb_global_create(m->mod, "csb$1", nullptr, TB_LINKAGE_PRIVATE);
// tb_global_set_storage(m->mod, tb_module_get_rdata(m->mod), str_data, 8, 1, 1);
// void *region = tb_global_add_region(m->mod, str_data, 0, 8);
// memcpy(region, "Hellope\x00", 8);
// }
// str = tb_global_create(m->mod, "global$str", nullptr, TB_LINKAGE_PRIVATE);
// tb_global_set_storage(m->mod, tb_module_get_rdata(m->mod), str, 16, 8, 2);
// tb_global_add_symbol_reloc(m->mod, str, 0, cast(TB_Symbol *)str_data);
// void *len = tb_global_add_region(m->mod, str, 8, 8);
// *cast(i64 *)len = 7;
// }
// {
// TB_PrototypeParam printf_ret = {TB_TYPE_I32};
// TB_PrototypeParam printf_params = {TB_TYPE_PTR};
// TB_FunctionPrototype *printf_proto = tb_prototype_create(m->mod, TB_STDCALL, 1, &printf_params, 1, &printf_ret, true);
// TB_External *printf_proc = tb_extern_create(m->mod, "printf", TB_EXTERNAL_SO_LOCAL);
// TB_PrototypeParam main_ret = {TB_TYPE_I32};
// TB_FunctionPrototype *main_proto = tb_prototype_create(m->mod, TB_STDCALL, 0, nullptr, 1, &main_ret, false);
// TB_Function * p = tb_function_create(m->mod, "main", TB_LINKAGE_PUBLIC, TB_COMDAT_NONE);
// tb_function_set_prototype(p, main_proto, arena);
// auto str_ptr = tb_inst_get_symbol_address(p, cast(TB_Symbol *)str);
// auto str_data_ptr_ptr = tb_inst_member_access(p, str_ptr, 0);
// auto str_data_ptr = tb_inst_load(p, TB_TYPE_PTR, str_data_ptr_ptr, 1, false);
// auto str_len_ptr = tb_inst_member_access(p, str_ptr, 8);
// auto str_len = tb_inst_load(p, TB_TYPE_I64, str_len_ptr, 8, false);
// TB_Node *params[4] = {};
// params[0] = tb_inst_cstring(p, "%.*s %s!\n");
// params[1] = tb_inst_trunc(p, str_len, TB_TYPE_I32);
// params[2] = str_data_ptr;
// params[3] = tb_inst_cstring(p, "World");
// TB_MultiOutput output = tb_inst_call(p, printf_proto, tb_inst_get_symbol_address(p, cast(TB_Symbol *)printf_proc), gb_count_of(params), params);
// gb_unused(output);
// TB_Node *printf_return_value = output.single;
// TB_Node *zero = tb_inst_uint(p, TB_TYPE_I32, 0);
// TB_Node *one = tb_inst_uint(p, TB_TYPE_I32, 1);
// TB_Node *prev_case = tb_inst_get_control(p);
// TB_Node *true_case = tb_inst_region(p);
// TB_Node *false_case = tb_inst_region(p);
// TB_Node *cond = tb_inst_cmp_igt(p, printf_return_value, zero, true);
// tb_inst_if(p, cond, true_case, false_case);
// tb_inst_set_control(p, true_case);
// tb_inst_ret(p, 1, &zero);
// tb_inst_set_control(p, false_case);
// tb_inst_ret(p, 1, &one);
// tb_inst_set_control(p, prev_case);
// tb_module_compile_function(m->mod, p, TB_ISEL_FAST);
// tb_function_print(p, tb_default_print_callback, stdout);
// TB_DebugFormat debug_format = TB_DEBUGFMT_NONE;
// TB_ExportBuffer export_buffer = tb_module_object_export(m->mod, debug_format);
// defer (tb_export_buffer_free(export_buffer));
// char const *path = "W:/Odin/tilde_main.obj";
// GB_ASSERT(tb_export_buffer_to_file(export_buffer, path));
// }
return true;
}
+3
View File
@@ -248,6 +248,9 @@ gb_global isize cg_global_type_info_member_offsets_index = 0;
gb_global isize cg_global_type_info_member_usings_index = 0;
gb_global isize cg_global_type_info_member_tags_index = 0;
gb_internal TB_Arena *cg_arena(void);
gb_internal cgValue cg_value(TB_Global * g, Type *type);
gb_internal cgValue cg_value(TB_External *e, Type *type);
gb_internal cgValue cg_value(TB_Function *f, Type *type);
+43 -19
View File
@@ -210,9 +210,6 @@ typedef enum TB_NodeTypeEnum {
// projection
TB_PROJ,
// metadata
TB_KEEPALIVE,
TB_CALL, // normal call
TB_SCALL, // system call
@@ -640,14 +637,32 @@ TB_API void tb_module_set_tls_index(TB_Module* m, ptrdiff_t len, const char* nam
TB_API void tb_module_layout_sections(TB_Module* m);
////////////////////////////////
// Exporter
// Compiled code introspection
////////////////////////////////
enum { TB_ASSEMBLY_CHUNK_CAP = 4*1024 - sizeof(size_t[2]) };
typedef struct TB_Assembly TB_Assembly;
struct TB_Assembly {
TB_Assembly* next;
// nice chunk of text here
size_t length;
char data[];
};
// this is where the machine code and other relevant pieces go.
typedef struct TB_FunctionOutput TB_FunctionOutput;
// returns NULL if it fails
TB_API TB_FunctionOutput* tb_module_compile_function(TB_Module* m, TB_Function* f, TB_ISelMode isel_mode);
TB_API TB_FunctionOutput* tb_module_compile_function(TB_Module* m, TB_Function* f, TB_ISelMode isel_mode, bool emit_asm);
TB_API uint8_t* tb_output_get_code(TB_FunctionOutput* out, size_t* out_length);
// returns NULL if no assembly was generated
TB_API TB_Assembly* tb_output_get_asm(TB_FunctionOutput* out);
// this is relative to the start of the function (the start of the prologue)
TB_API TB_Safepoint* tb_safepoint_get(TB_Function* f, uint32_t relative_ip);
////////////////////////////////
// Exporter
@@ -780,6 +795,27 @@ struct TB_FunctionPrototype {
// matching signatures.
TB_API TB_FunctionPrototype* tb_prototype_create(TB_Module* m, TB_CallingConv cc, size_t param_count, const TB_PrototypeParam* params, size_t return_count, const TB_PrototypeParam* returns, bool has_varargs);
// same as tb_function_set_prototype except it will handle lowering from types like the TB_DebugType
// into the correct ABI and exposing sane looking nodes to the parameters.
//
// returns the parameters
TB_API TB_Node** tb_function_set_prototype_from_dbg(TB_Function* f, TB_DebugType* dbg, TB_Arena* arena, size_t* out_param_count);
TB_API TB_FunctionPrototype* tb_prototype_from_dbg(TB_Module* m, TB_DebugType* dbg);
// used for ABI parameter passing
typedef enum {
// needs a direct value
TB_PASSING_DIRECT,
// needs an address to the value
TB_PASSING_INDIRECT,
// doesn't use this parameter
TB_PASSING_IGNORE,
} TB_PassingRule;
TB_API TB_PassingRule tb_get_passing_rule_from_dbg(TB_Module* mod, TB_DebugType* param_type, bool is_return);
////////////////////////////////
// Globals
////////////////////////////////
@@ -829,6 +865,8 @@ TB_API void tb_debug_record_end(TB_DebugType* type, TB_CharUnits size, TB_CharUn
TB_API TB_DebugType* tb_debug_create_func(TB_Module* m, TB_CallingConv cc, size_t param_count, size_t return_count, bool has_varargs);
TB_API TB_DebugType* tb_debug_field_type(TB_DebugType* type);
// you'll need to fill these if you make a function
TB_API TB_DebugType** tb_debug_func_params(TB_DebugType* type);
TB_API TB_DebugType** tb_debug_func_returns(TB_DebugType* type);
@@ -839,12 +877,6 @@ TB_API TB_DebugType** tb_debug_func_returns(TB_DebugType* type);
// it is an index to the input
#define TB_FOR_INPUT_IN_NODE(it, parent) for (TB_Node **it = parent->inputs, **__end = it + (parent)->input_count; it != __end; it++)
////////////////////////////////
// Compiled code introspection
////////////////////////////////
// this is relative to the start of the function (the start of the prologue)
TB_API TB_Safepoint* tb_safepoint_get(TB_Function* f, uint32_t relative_ip);
////////////////////////////////
// Symbols
////////////////////////////////
@@ -879,13 +911,6 @@ TB_API void tb_symbol_set_name(TB_Symbol* s, ptrdiff_t len, const char* name);
TB_API void tb_symbol_bind_ptr(TB_Symbol* s, void* ptr);
TB_API const char* tb_symbol_get_name(TB_Symbol* s);
// same as tb_function_set_prototype except it will handle lowering from types like the TB_DebugType
// into the correct ABI and exposing sane looking nodes to the parameters.
//
// returns the parameters
TB_API TB_Node** tb_function_set_prototype_from_dbg(TB_Function* f, TB_DebugType* dbg, TB_Arena* arena, size_t* out_param_count);
TB_API TB_FunctionPrototype* tb_prototype_from_dbg(TB_Module* m, TB_DebugType* dbg);
// if arena is NULL, defaults to module arena which is freed on tb_free_thread_resources
TB_API void tb_function_set_prototype(TB_Function* f, TB_FunctionPrototype* p, TB_Arena* arena);
TB_API TB_FunctionPrototype* tb_function_get_prototype(TB_Function* f);
@@ -903,7 +928,6 @@ TB_API void tb_inst_set_region_name(TB_Node* n, ptrdiff_t len, const char* name)
TB_API void tb_inst_unreachable(TB_Function* f);
TB_API void tb_inst_debugbreak(TB_Function* f);
TB_API void tb_inst_trap(TB_Function* f);
TB_API void tb_inst_keep_alive(TB_Function* f, TB_Node* src);
TB_API TB_Node* tb_inst_poison(TB_Function* f);
TB_API TB_Node* tb_inst_param(TB_Function* f, int param_id);
BIN
View File
Binary file not shown.
+120 -12
View File
@@ -87,12 +87,11 @@ gb_internal cgProcedure *cg_procedure_create(cgModule *m, Entity *entity, bool i
}
if (p->symbol == nullptr) {
TB_Arena *arena = tb_default_arena();
p->func = tb_function_create(m->mod, link_name.len, cast(char const *)link_name.text, linkage, TB_COMDAT_NONE);
size_t out_param_count = 0;
p->debug_type = cg_debug_type_for_proc(m, p->type);
TB_Node **params = tb_function_set_prototype_from_dbg(p->func, p->debug_type, arena, &out_param_count);
TB_Node **params = tb_function_set_prototype_from_dbg(p->func, p->debug_type, cg_arena(), &out_param_count);
p->param_nodes = {params, cast(isize)out_param_count};
p->proto = tb_function_get_prototype(p->func);
@@ -141,12 +140,11 @@ gb_internal cgProcedure *cg_procedure_create_dummy(cgModule *m, String const &li
TB_Linkage linkage = TB_LINKAGE_PRIVATE;
TB_Arena *arena = tb_default_arena();
p->func = tb_function_create(m->mod, link_name.len, cast(char const *)link_name.text, linkage, TB_COMDAT_NONE);
size_t out_param_count = 0;
p->debug_type = cg_debug_type_for_proc(m, p->type);
TB_Node **params = tb_function_set_prototype_from_dbg(p->func, p->debug_type, arena, &out_param_count);
TB_Node **params = tb_function_set_prototype_from_dbg(p->func, p->debug_type, cg_arena(), &out_param_count);
p->param_nodes = {params, cast(isize)out_param_count};
p->proto = tb_function_get_prototype(p->func);
@@ -275,17 +273,32 @@ gb_internal void cg_procedure_end(cgProcedure *p) {
if (tb_inst_get_control(p->func)) {
tb_inst_ret(p->func, 0, nullptr);
}
bool emit_asm = false;
// if (p->name == "main") {
if (p->name == "bug" ABI_PKG_NAME_SEPARATOR "main") {
if (
// p->name == "bug" ABI_PKG_NAME_SEPARATOR "main" ||
p->name == "main" ||
false
) {
TB_Arena *arena = tb_default_arena();
defer (arena->free(arena));
TB_FuncOpt *opt = tb_funcopt_enter(p->func, arena);
defer (tb_funcopt_exit(opt));
tb_funcopt_print(opt);
// emit_asm = true;
// GraphViz printing
// tb_function_print(p->func, tb_default_print_callback, stdout);
}
tb_module_compile_function(p->module->mod, p->func, TB_ISEL_FAST);
TB_FunctionOutput *output = tb_module_compile_function(p->module->mod, p->func, TB_ISEL_FAST, emit_asm);
if (emit_asm) {
TB_Assembly *assembly = tb_output_get_asm(output);
for (TB_Assembly *node = assembly; node != nullptr; node = node->next) {
gb_printf_err("%.*s", cast(int)node->length, node->data);
}
gb_printf_err("\n");
}
}
gb_internal void cg_procedure_generate(cgProcedure *p) {
@@ -332,7 +345,9 @@ gb_internal cgValue cg_build_call_expr(cgProcedure *p, Ast *expr) {
cgValue res = cg_build_call_expr_internal(p, expr);
if (ce->optional_ok_one) { // TODO(bill): Minor hack for #optional_ok procedures
GB_PANIC("Handle optional_ok_one");
GB_ASSERT(res.kind == cgValue_Multi);
GB_ASSERT(res.multi->values.count == 2);
return res.multi->values[0];
// GB_ASSERT(is_type_tuple(res.type));
// GB_ASSERT(res.type->Tuple.variables.count == 2);
// return cg_emit_struct_ev(p, res, 0);
@@ -345,18 +360,111 @@ gb_internal cgValue cg_emit_call(cgProcedure * p, cgValue value, Slice<cgValue>
value = cg_value(tb_inst_get_symbol_address(p->func, value.symbol), value.type);
}
GB_ASSERT(value.kind == cgValue_Value);
TEMPORARY_ALLOCATOR_GUARD();
// TODO(bill): abstract out the function prototype stuff so that you handle the ABI correctly (at least for win64 at the moment)
TB_FunctionPrototype *proto = cg_procedure_type_as_prototype(p->module, value.type);
TB_Module *m = p->module->mod;
Type *type = base_type(value.type);
GB_ASSERT(type->kind == Type_Proc);
TypeProc *pt = &type->Proc;
gb_unused(pt);
TB_FunctionPrototype *proto = cg_procedure_type_as_prototype(p->module, type);
TB_Node *target = value.node;
auto params = slice_make<TB_Node *>(temporary_allocator(), 0 /*proto->param_count*/);
for_array(i, params) {
// params[i] = proto
auto params = slice_make<TB_Node *>(temporary_allocator(), proto->param_count);
GB_ASSERT(build_context.metrics.os == TargetOs_windows);
// TODO(bill): Support more than Win64 ABI
bool is_odin_like_cc = is_calling_convention_odin(pt->calling_convention);
GB_ASSERT(is_odin_like_cc);
bool return_is_indirect = false;
isize param_index = 0;
if (pt->result_count != 0) {
Type *last_result = pt->results->Tuple.variables[pt->results->Tuple.variables.count-1]->type;
TB_DebugType *dbg = cg_debug_type(p->module, last_result);
TB_PassingRule rule = tb_get_passing_rule_from_dbg(m, dbg, true);
if (rule == TB_PASSING_INDIRECT) {
return_is_indirect = true;
TB_CharUnits size = cast(TB_CharUnits)type_size_of(last_result);
TB_CharUnits align = cast(TB_CharUnits)type_align_of(last_result);
params[param_index++] = tb_inst_local(p->func, size, align);
}
}
for (cgValue arg : args) {
Type *param_type = pt->params->Tuple.variables[param_index]->type;
arg = cg_emit_conv(p, arg, param_type);
arg = cg_flatten_value(p, arg);
TB_Node *param = nullptr;
TB_DebugType *dbg = cg_debug_type(p->module, param_type);
TB_PassingRule rule = tb_get_passing_rule_from_dbg(m, dbg, false);
switch (rule) {
case TB_PASSING_DIRECT:
GB_ASSERT(arg.kind == cgValue_Value);
param = arg.node;
break;
case TB_PASSING_INDIRECT:
{
// indirect
cgValue arg_ptr = cg_address_from_load_or_generate_local(p, arg);
GB_ASSERT(arg_ptr.kind == cgValue_Value);
param = arg_ptr.node;
}
break;
case TB_PASSING_IGNORE:
continue;
}
params[param_index++] = param;
}
// Split returns
for (isize i = 0; i < pt->result_count-1; i++) {
Type *result = pt->results->Tuple.variables[i]->type;
TB_CharUnits size = cast(TB_CharUnits)type_size_of(result);
TB_CharUnits align = cast(TB_CharUnits)type_align_of(result);
params[param_index++] = tb_inst_local(p->func, size, align);
}
if (pt->calling_convention == ProcCC_Odin) {
cgValue ctx_ptr = cg_find_or_generate_context_ptr(p).addr;
GB_ASSERT(ctx_ptr.kind == cgValue_Value);
params[param_index++] = ctx_ptr.node;
}
GB_ASSERT_MSG(param_index == params.count, "%td vs %td\n %s %u %u",
param_index, params.count,
type_to_string(type),
proto->return_count,
proto->param_count);
for (TB_Node *param : params) {
GB_ASSERT(param != nullptr);
}
GB_ASSERT(target != nullptr);
TB_MultiOutput multi_output = tb_inst_call(p->func, proto, target, params.count, params.data);
gb_unused(multi_output);
switch (pt->result_count) {
case 0:
return {};
case 1:
if (return_is_indirect) {
return cg_lvalue_addr(params[0], pt->results->Tuple.variables[0]->type);
}
GB_ASSERT(multi_output.count == 1);
return cg_value(multi_output.single, pt->results->Tuple.variables[0]->type);
}
return {};
}
+39 -1
View File
@@ -252,7 +252,45 @@ gb_internal void cg_addr_store(cgProcedure *p, cgAddr addr, cgValue value) {
} else if (addr.kind == cgAddr_Map) {
GB_PANIC("TODO(bill): cgAddr_Map");
} else if (addr.kind == cgAddr_Context) {
GB_PANIC("TODO(bill): cgAddr_Context");
cgAddr old_addr = cg_find_or_generate_context_ptr(p);
bool create_new = true;
for_array(i, p->context_stack) {
cgContextData *ctx_data = &p->context_stack[i];
if (ctx_data->ctx.addr.node == old_addr.addr.node) {
if (ctx_data->uses > 0) {
create_new = true;
} else if (p->scope_index > ctx_data->scope_index) {
create_new = true;
} else {
// gb_printf_err("%.*s (curr:%td) (ctx:%td) (uses:%td)\n", LIT(p->name), p->scope_index, ctx_data->scope_index, ctx_data->uses);
create_new = false;
}
break;
}
}
cgValue next = {};
if (create_new) {
cgValue old = cg_addr_load(p, old_addr);
cgAddr next_addr = cg_add_local(p, t_context, nullptr, true);
cg_addr_store(p, next_addr, old);
cg_push_context_onto_stack(p, next_addr);
next = next_addr.addr;
} else {
next = old_addr.addr;
}
if (addr.ctx.sel.index.count > 0) {
cgValue lhs = cg_emit_deep_field_gep(p, next, addr.ctx.sel);
cgValue rhs = cg_emit_conv(p, value, type_deref(lhs.type));
cg_emit_store(p, lhs, rhs);
} else {
cgValue lhs = next;
cgValue rhs = cg_emit_conv(p, value, cg_addr_type(addr));
cg_emit_store(p, lhs, rhs);
}
return;
} else if (addr.kind == cgAddr_SoaVariable) {
GB_PANIC("TODO(bill): cgAddr_SoaVariable");
} else if (addr.kind == cgAddr_Swizzle) {