aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorgingerBill <bill@gingerbill.org>2023-07-28 14:57:04 +0100
committergingerBill <bill@gingerbill.org>2023-07-28 14:57:04 +0100
commitc39a3603720917d6970026e5c0595d468ea9b372 (patch)
tree47f9b81d6a37007aee82834df91bec311742ec9f /src
parentf6d1724835489120ae4a3805495dafc97c86db80 (diff)
Update Tilde for the new TB_Passes approach
Diffstat (limited to 'src')
-rw-r--r--src/tilde.cpp44
-rw-r--r--src/tilde.hpp12
-rw-r--r--src/tilde/tb.h106
-rw-r--r--src/tilde/tb.libbin4162224 -> 4177320 bytes
-rw-r--r--src/tilde/tb_arena.h76
-rw-r--r--src/tilde_expr.cpp42
-rw-r--r--src/tilde_proc.cpp158
-rw-r--r--src/tilde_stmt.cpp8
8 files changed, 330 insertions, 116 deletions
diff --git a/src/tilde.cpp b/src/tilde.cpp
index fc51a1156..0cbc975c4 100644
--- a/src/tilde.cpp
+++ b/src/tilde.cpp
@@ -1,16 +1,16 @@
#include "tilde.hpp"
-gb_global Slice<TB_Arena *> global_tb_arenas;
+gb_global Slice<TB_Arena> global_tb_arenas;
gb_internal TB_Arena *cg_arena(void) {
- return global_tb_arenas[current_thread_index()];
+ return &global_tb_arenas[current_thread_index()];
}
gb_internal void cg_global_arena_init(void) {
- global_tb_arenas = slice_make<TB_Arena *>(permanent_allocator(), global_thread_pool.threads.count);
+ 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();
+ tb_arena_create(&global_tb_arenas[i], 2ull<<20);
}
}
@@ -426,14 +426,15 @@ gb_internal cgModule *cg_module_create(Checker *c) {
map_init(&m->values);
map_init(&m->symbols);
-
map_init(&m->file_id_map);
-
map_init(&m->debug_type_map);
map_init(&m->proc_debug_type_map);
map_init(&m->proc_proto_map);
-
map_init(&m->anonymous_proc_lits_map);
+ map_init(&m->equal_procs);
+ map_init(&m->hasher_procs);
+ map_init(&m->map_get_procs);
+ map_init(&m->map_set_procs);
array_init(&m->single_threaded_procedure_queue, heap_allocator());
@@ -456,6 +457,10 @@ gb_internal void cg_module_destroy(cgModule *m) {
map_destroy(&m->proc_debug_type_map);
map_destroy(&m->proc_proto_map);
map_destroy(&m->anonymous_proc_lits_map);
+ map_destroy(&m->equal_procs);
+ map_destroy(&m->hasher_procs);
+ map_destroy(&m->map_get_procs);
+ map_destroy(&m->map_set_procs);
array_free(&m->single_threaded_procedure_queue);
@@ -751,6 +756,19 @@ gb_internal bool cg_generate_code(Checker *c, LinkerData *linker_data) {
array_add(&procedures_to_generate, p);
}
}
+ for (cgProcedure *p : procedures_to_generate) {
+ cg_add_procedure_to_queue(p);
+ }
+
+ if (!m->do_threading) {
+ for (isize i = 0; i < m->single_threaded_procedure_queue.count; i++) {
+ cgProcedure *p = m->single_threaded_procedure_queue[i];
+ cg_procedure_generate(p);
+ }
+ }
+
+ thread_pool_wait();
+
{
cgProcedure *p = cg_startup_runtime_proc;
cg_procedure_begin(p);
@@ -765,18 +783,6 @@ gb_internal bool cg_generate_code(Checker *c, LinkerData *linker_data) {
cg_procedure_end(p);
}
- for (cgProcedure *p : procedures_to_generate) {
- cg_add_procedure_to_queue(p);
- }
-
- if (!m->do_threading) {
- for (isize i = 0; i < m->single_threaded_procedure_queue.count; i++) {
- cgProcedure *p = m->single_threaded_procedure_queue[i];
- cg_procedure_generate(p);
- }
- }
-
- thread_pool_wait();
TB_DebugFormat debug_format = TB_DEBUGFMT_NONE;
diff --git a/src/tilde.hpp b/src/tilde.hpp
index 6ff5602b5..a70d03a6c 100644
--- a/src/tilde.hpp
+++ b/src/tilde.hpp
@@ -6,6 +6,7 @@
#endif
#include "tilde/tb.h"
+#include "tilde/tb_arena.h"
#define TB_TYPE_F16 TB_DataType{ { TB_INT, 0, 16 } }
#define TB_TYPE_I128 TB_DataType{ { TB_INT, 0, 128 } }
@@ -230,6 +231,12 @@ struct cgModule {
BlockingMutex anonymous_proc_lits_mutex;
PtrMap<Ast *, cgProcedure *> anonymous_proc_lits_map;
+ RecursiveMutex generated_procs_mutex;
+ PtrMap<Type *, cgProcedure *> equal_procs;
+ PtrMap<Type *, cgProcedure *> hasher_procs;
+ PtrMap<Type *, cgProcedure *> map_get_procs;
+ PtrMap<Type *, cgProcedure *> map_set_procs;
+
// NOTE(bill): no need to protect this with a mutex
PtrMap<uintptr, TB_FileID> file_id_map; // Key: AstFile.id (i32 cast to uintptr)
@@ -319,6 +326,7 @@ gb_internal cgValue cg_build_call_expr(cgProcedure *p, Ast *expr);
gb_internal void cg_build_return_stmt(cgProcedure *p, Slice<Ast *> const &return_results);
gb_internal void cg_build_return_stmt_internal(cgProcedure *p, Slice<cgValue> const &results);
+gb_internal void cg_build_return_stmt_internal_single(cgProcedure *p, cgValue result);
gb_internal void cg_build_range_stmt(cgProcedure *p, Ast *node);
gb_internal cgValue cg_find_value_from_entity(cgModule *m, Entity *e);
@@ -341,6 +349,10 @@ gb_internal cgValue cg_emit_conv(cgProcedure *p, cgValue value, Type *t);
gb_internal cgValue cg_emit_comp_against_nil(cgProcedure *p, TokenKind op_kind, cgValue x);
gb_internal cgValue cg_emit_comp(cgProcedure *p, TokenKind op_kind, cgValue left, cgValue right);
gb_internal cgValue cg_emit_arith(cgProcedure *p, TokenKind op, cgValue lhs, cgValue rhs, Type *type);
+gb_internal cgValue cg_emit_unary_arith(cgProcedure *p, TokenKind op, cgValue x, Type *type);
+
+gb_internal cgProcedure *cg_equal_proc_for_type(cgModule *m, Type *type);
+
gb_internal cgValue cg_emit_call(cgProcedure * p, cgValue value, Slice<cgValue> const &args);
gb_internal cgValue cg_emit_runtime_call(cgProcedure *p, char const *name, Slice<cgValue> const &args);
diff --git a/src/tilde/tb.h b/src/tilde/tb.h
index a68f06554..b20b98b35 100644
--- a/src/tilde/tb.h
+++ b/src/tilde/tb.h
@@ -15,20 +15,21 @@
#define TB_VERSION_MINOR 2
#define TB_VERSION_PATCH 0
-#ifdef __cplusplus
-#define TB_EXTERN extern "C"
-#else
-#define TB_EXTERN
-#endif
-
-#ifdef TB_DLL
-# ifdef TB_IMPORT_DLL
-# define TB_API TB_EXTERN __declspec(dllimport)
+#ifndef TB_API
+# ifdef __cplusplus
+# define TB_EXTERN extern "C"
# else
-# define TB_API TB_EXTERN __declspec(dllexport)
+# define TB_EXTERN
+# endif
+# ifdef TB_DLL
+# ifdef TB_IMPORT_DLL
+# define TB_API TB_EXTERN __declspec(dllimport)
+# else
+# define TB_API TB_EXTERN __declspec(dllexport)
+# endif
+# else
+# define TB_API TB_EXTERN
# endif
-#else
-# define TB_API TB_EXTERN
#endif
// These are flags
@@ -171,7 +172,6 @@ typedef enum TB_FloatFormat {
typedef union TB_DataType {
struct {
uint8_t type;
- // 2^N where N is the width value.
// Only integers and floats can be wide.
uint8_t width;
// for integers it's the bitwidth
@@ -406,8 +406,6 @@ typedef struct TB_Symbol {
typedef int TB_Reg;
-#define TB_NULL_REG NULL
-
typedef struct TB_Node TB_Node;
struct TB_Node {
TB_NodeType type;
@@ -586,29 +584,13 @@ typedef struct {
typedef void (*TB_PrintCallback)(void* user_data, const char* fmt, ...);
-////////////////////////////////
-// Arena
-////////////////////////////////
-// the goal is to move more things to transparent arenas, for now it's just function
-// IR which is a big one if you're interested in freeing them in whatever organization
-// you please.
-
-// allocations can make no guarentees about being sequential
-// tho it would be greatly appreciated at least to some degree.
+// defined in common/arena.h
typedef struct TB_Arena TB_Arena;
-struct TB_Arena {
- // alignment never goes past max_align_t
- void* (*alloc)(TB_Arena* arena, size_t size, size_t align);
- // clearing but we're not done with it yet, cheap
- void (*clear)(TB_Arena* arena);
-
- // frees everything within the arena, potentially expensive
- void (*free)(TB_Arena* arena);
-};
-
-// allocates in 16MiB chunks and does linear allocation in 'em
-TB_API TB_Arena* tb_default_arena(void);
+// 0 for default
+TB_API void tb_arena_create(TB_Arena* restrict arena, size_t chunk_size);
+TB_API void tb_arena_destroy(TB_Arena* restrict arena);
+TB_API bool tb_arena_is_empty(TB_Arena* arena);
////////////////////////////////
// Module management
@@ -651,8 +633,7 @@ struct TB_Assembly {
// 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, bool emit_asm);
+TB_API void tb_output_print_asm(TB_FunctionOutput* out, FILE* fp);
TB_API uint8_t* tb_output_get_code(TB_FunctionOutput* out, size_t* out_length);
@@ -865,6 +846,9 @@ TB_API TB_DebugType* tb_debug_create_func(TB_Module* m, TB_CallingConv cc, size_
TB_API TB_DebugType* tb_debug_field_type(TB_DebugType* type);
+TB_API size_t tb_debug_func_return_count(TB_DebugType* type);
+TB_API size_t tb_debug_func_param_count(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);
@@ -895,9 +879,6 @@ TB_API void tb_default_print_callback(void* user_data, const char* fmt, ...);
TB_API void tb_inst_set_location(TB_Function* f, TB_FileID file, int line);
-// this only allows for power of two vector types
-TB_API TB_DataType tb_vector_type(TB_DataTypeEnum type, int width);
-
// if section is NULL, default to .text
TB_API TB_Function* tb_function_create(TB_Module* m, ptrdiff_t len, const char* name, TB_Linkage linkage, TB_ComdatType comdat);
@@ -1073,25 +1054,40 @@ TB_API void tb_inst_branch(TB_Function* f, TB_DataType dt, TB_Node* key, TB_Node
TB_API void tb_inst_ret(TB_Function* f, size_t count, TB_Node** values);
////////////////////////////////
-// Optimizer
+// Passes
////////////////////////////////
// Function analysis, optimizations, and codegen are all part of this
-typedef struct TB_FuncOpt TB_FuncOpt;
+typedef struct TB_Passes TB_Passes;
-// the arena is used to allocate the nodes
-TB_API TB_FuncOpt* tb_funcopt_enter(TB_Function* f, TB_Arena* arena);
-TB_API void tb_funcopt_exit(TB_FuncOpt* opt);
+// the arena is used to allocate the nodes while passes are being done.
+TB_API TB_Passes* tb_pass_enter(TB_Function* f, TB_Arena* arena);
+TB_API void tb_pass_exit(TB_Passes* opt);
-TB_API bool tb_funcopt_peephole(TB_FuncOpt* opt);
-TB_API bool tb_funcopt_mem2reg(TB_FuncOpt* opt);
-TB_API bool tb_funcopt_loop(TB_FuncOpt* opt);
+// transformation passes:
+// peephole: runs most simple reductions on the code,
+// should be run after any bigger passes (it's incremental
+// so it's not that bad)
+//
+// mem2reg: lowers TB_LOCALs into SSA values, this makes more
+// data flow analysis possible on the code and allows to codegen
+// to place variables into registers.
+//
+// loop: NOT READY
+//
+TB_API bool tb_pass_peephole(TB_Passes* opt);
+TB_API bool tb_pass_mem2reg(TB_Passes* opt);
+TB_API bool tb_pass_loop(TB_Passes* opt);
-// isn't an optimization, just does the name flat form of IR printing
-TB_API bool tb_funcopt_print(TB_FuncOpt* opt);
+// analysis
+// print: prints IR in a flattened text form.
+TB_API bool tb_pass_print(TB_Passes* opt);
-TB_API void tb_funcopt_kill(TB_FuncOpt* opt, TB_Node* n);
-TB_API bool tb_funcopt_mark(TB_FuncOpt* opt, TB_Node* n);
-TB_API void tb_funcopt_mark_users(TB_FuncOpt* opt, TB_Node* n);
+// codegen
+TB_API TB_FunctionOutput* tb_pass_codegen(TB_Passes* opt, bool emit_asm);
+
+TB_API void tb_pass_kill_node(TB_Passes* opt, TB_Node* n);
+TB_API bool tb_pass_mark(TB_Passes* opt, TB_Node* n);
+TB_API void tb_pass_mark_users(TB_Passes* opt, TB_Node* n);
////////////////////////////////
// IR access
@@ -1099,8 +1095,6 @@ TB_API void tb_funcopt_mark_users(TB_FuncOpt* opt, TB_Node* n);
TB_API const char* tb_node_get_name(TB_Node* n);
TB_API TB_Node* tb_get_parent_region(TB_Node* n);
-TB_API bool tb_has_effects(TB_Node* n);
-
TB_API bool tb_node_is_constant_non_zero(TB_Node* n);
TB_API bool tb_node_is_constant_zero(TB_Node* n);
diff --git a/src/tilde/tb.lib b/src/tilde/tb.lib
index 43e477536..b0886ebfb 100644
--- a/src/tilde/tb.lib
+++ b/src/tilde/tb.lib
Binary files differ
diff --git a/src/tilde/tb_arena.h b/src/tilde/tb_arena.h
new file mode 100644
index 000000000..d50e777da
--- /dev/null
+++ b/src/tilde/tb_arena.h
@@ -0,0 +1,76 @@
+#pragma once
+#include <stddef.h>
+#include <stdbool.h>
+
+#ifndef TB_API
+# ifdef __cplusplus
+# define TB_EXTERN extern "C"
+# else
+# define TB_EXTERN
+# endif
+# ifdef TB_DLL
+# ifdef TB_IMPORT_DLL
+# define TB_API TB_EXTERN __declspec(dllimport)
+# else
+# define TB_API TB_EXTERN __declspec(dllexport)
+# endif
+# else
+# define TB_API TB_EXTERN
+# endif
+#endif
+
+enum {
+ TB_ARENA_SMALL_CHUNK_SIZE = 4 * 1024,
+ TB_ARENA_MEDIUM_CHUNK_SIZE = 512 * 1024,
+ TB_ARENA_LARGE_CHUNK_SIZE = 2 * 1024 * 1024,
+
+ TB_ARENA_ALIGNMENT = 16,
+};
+
+typedef struct TB_ArenaChunk TB_ArenaChunk;
+struct TB_ArenaChunk {
+ TB_ArenaChunk* next;
+ size_t pad;
+ char data[];
+};
+
+typedef struct TB_Arena {
+ size_t chunk_size;
+ TB_ArenaChunk* base;
+ TB_ArenaChunk* top;
+
+ // top of the allocation space
+ char* watermark;
+ char* high_point; // &top->data[chunk_size]
+} TB_Arena;
+
+typedef struct TB_ArenaSavepoint {
+ TB_ArenaChunk* top;
+ char* watermark;
+} TB_ArenaSavepoint;
+
+#define TB_ARENA_FOR(it, arena) for (TB_ArenaChunk* it = (arena)->base; it != NULL; it = it->next)
+
+#define TB_ARENA_ALLOC(arena, T) tb_arena_alloc(arena, sizeof(T))
+#define TB_ARENA_ARR_ALLOC(arena, count, T) tb_arena_alloc(arena, (count) * sizeof(T))
+
+TB_API void tb_arena_create(TB_Arena* restrict arena, size_t chunk_size);
+TB_API void tb_arena_destroy(TB_Arena* restrict arena);
+
+TB_API void* tb_arena_unaligned_alloc(TB_Arena* restrict arena, size_t size);
+TB_API void* tb_arena_alloc(TB_Arena* restrict arena, size_t size);
+
+// asserts if ptr+size != watermark
+TB_API void tb_arena_pop(TB_Arena* restrict arena, void* ptr, size_t size);
+
+// in case you wanna mix unaligned and aligned arenas
+TB_API void tb_arena_realign(TB_Arena* restrict arena);
+
+TB_API bool tb_arena_is_empty(TB_Arena* arena);
+
+// savepoints
+TB_API TB_ArenaSavepoint tb_arena_save(TB_Arena* arena);
+TB_API void tb_arena_restore(TB_Arena* arena, TB_ArenaSavepoint sp);
+
+// resets to only having one chunk
+TB_API void tb_arena_clear(TB_Arena* arena);
diff --git a/src/tilde_expr.cpp b/src/tilde_expr.cpp
index 1966dcd8e..fdd26e3db 100644
--- a/src/tilde_expr.cpp
+++ b/src/tilde_expr.cpp
@@ -304,6 +304,42 @@ gb_internal cgValue cg_emit_byte_swap(cgProcedure *p, cgValue value, Type *end_t
return cg_emit_transmute(p, value, end_type);
}
+gb_internal cgValue cg_emit_comp_records(cgProcedure *p, TokenKind op_kind, cgValue left, cgValue right, Type *type) {
+ GB_ASSERT((is_type_struct(type) || is_type_union(type)) && is_type_comparable(type));
+ cgValue left_ptr = cg_address_from_load_or_generate_local(p, left);
+ cgValue right_ptr = cg_address_from_load_or_generate_local(p, right);
+ cgValue res = {};
+ if (type_size_of(type) == 0) {
+ switch (op_kind) {
+ case Token_CmpEq:
+ return cg_const_bool(p, t_bool, true);
+ case Token_NotEq:
+ return cg_const_bool(p, t_bool, false);
+ }
+ GB_PANIC("invalid operator");
+ }
+ TEMPORARY_ALLOCATOR_GUARD();
+ if (is_type_simple_compare(type)) {
+ // TODO(bill): Test to see if this is actually faster!!!!
+ auto args = slice_make<cgValue>(temporary_allocator(), 3);
+ args[0] = cg_emit_conv(p, left_ptr, t_rawptr);
+ args[1] = cg_emit_conv(p, right_ptr, t_rawptr);
+ args[2] = cg_const_int(p, t_int, type_size_of(type));
+ res = cg_emit_runtime_call(p, "memory_equal", args);
+ } else {
+ cgProcedure *equal_proc = cg_equal_proc_for_type(p->module, type);
+ cgValue value = cg_value(tb_inst_get_symbol_address(p->func, equal_proc->symbol), equal_proc->type);
+ auto args = slice_make<cgValue>(temporary_allocator(), 2);
+ args[0] = cg_emit_conv(p, left_ptr, t_rawptr);
+ args[1] = cg_emit_conv(p, right_ptr, t_rawptr);
+ res = cg_emit_call(p, value, args);
+ }
+ if (op_kind == Token_NotEq) {
+ res = cg_emit_unary_arith(p, Token_Not, res, res.type);
+ }
+ return res;
+}
+
gb_internal cgValue cg_emit_comp(cgProcedure *p, TokenKind op_kind, cgValue left, cgValue right) {
GB_ASSERT(gb_is_between(op_kind, Token__ComparisonBegin+1, Token__ComparisonEnd-1));
@@ -440,13 +476,11 @@ gb_internal cgValue cg_emit_comp(cgProcedure *p, TokenKind op_kind, cgValue left
}
if ((is_type_struct(a) || is_type_union(a)) && is_type_comparable(a)) {
- GB_PANIC("TODO(bill): cg_compare_records");
- // return cg_compare_records(p, op_kind, left, right, a);
+ return cg_emit_comp_records(p, op_kind, left, right, a);
}
if ((is_type_struct(b) || is_type_union(b)) && is_type_comparable(b)) {
- GB_PANIC("TODO(bill): cg_compare_records");
- // return cg_compare_records(p, op_kind, left, right, b);
+ return cg_emit_comp_records(p, op_kind, left, right, b);
}
if (is_type_string(a)) {
diff --git a/src/tilde_proc.cpp b/src/tilde_proc.cpp
index 8cfc564a7..26c70b508 100644
--- a/src/tilde_proc.cpp
+++ b/src/tilde_proc.cpp
@@ -368,22 +368,17 @@ gb_internal void cg_procedure_begin(cgProcedure *p) {
gb_internal WORKER_TASK_PROC(cg_procedure_compile_worker_proc) {
cgProcedure *p = cast(cgProcedure *)data;
- bool emit_asm = false;
-
- if (false &&
- string_starts_with(p->name, str_lit("bug@main"))) {
- TB_Arena *arena = cg_arena();
- TB_FuncOpt *opt = tb_funcopt_enter(p->func, arena);
- defer (tb_funcopt_exit(opt));
-
- tb_funcopt_peephole(opt);
- tb_funcopt_mem2reg(opt);
- tb_funcopt_peephole(opt);
-
- emit_asm = true;
+ TB_Passes *opt = tb_pass_enter(p->func, cg_arena());
+ defer (tb_pass_exit(opt));
+
+ // optimization passes
+ if (false) {
+ tb_pass_peephole(opt);
+ tb_pass_mem2reg(opt);
+ tb_pass_peephole(opt);
}
-
+ bool emit_asm = false;
if (
// string_starts_with(p->name, str_lit("runtime@_windows_default_alloc_or_resize")) ||
false
@@ -391,12 +386,27 @@ gb_internal WORKER_TASK_PROC(cg_procedure_compile_worker_proc) {
emit_asm = true;
}
- TB_FunctionOutput *output = tb_module_compile_function(p->module->mod, p->func, TB_ISEL_FAST, emit_asm);
+ // emit ir
+ if (
+ // string_starts_with(p->name, str_lit("bug@main")) ||
+ // p->name == str_lit("runtime@_windows_default_alloc_or_resize") ||
+ false
+ ) { // IR Printing
+ TB_Arena *arena = cg_arena();
+ TB_Passes *passes = tb_pass_enter(p->func, arena);
+ defer (tb_pass_exit(passes));
+
+ tb_pass_print(passes);
+ fprintf(stdout, "\n");
+ }
+ if (false) { // GraphViz printing
+ tb_function_print(p->func, tb_default_print_callback, stdout);
+ }
+
+ // compile
+ TB_FunctionOutput *output = tb_pass_codegen(opt, emit_asm);
if (emit_asm) {
- TB_Assembly *assembly = tb_output_get_asm(output);
- for (TB_Assembly *node = assembly; node != nullptr; node = node->next) {
- fprintf(stdout, "%.*s", cast(int)node->length, node->data);
- }
+ tb_output_print_asm(output, stdout);
fprintf(stdout, "\n");
}
@@ -427,27 +437,9 @@ gb_internal void cg_procedure_generate(cgProcedure *p) {
return;
}
-
cg_procedure_begin(p);
cg_build_stmt(p, p->body);
cg_procedure_end(p);
-
-
- if (
- // string_starts_with(p->name, str_lit("runtime@_windows_default_alloc")) ||
- // p->name == str_lit("runtime@_windows_default_alloc_or_resize") ||
- false
- ) { // IR Printing
- 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);
- fprintf(stdout, "\n");
- }
- if (false) { // GraphViz printing
- tb_function_print(p->func, tb_default_print_callback, stdout);
- }
}
gb_internal void cg_build_nested_proc(cgProcedure *p, AstProcLit *pd, Entity *e) {
@@ -989,3 +981,95 @@ gb_internal cgValue cg_build_call_expr_internal(cgProcedure *p, Ast *expr) {
return cg_emit_call(p, value, call_args);
}
+
+
+
+
+gb_internal cgProcedure *cg_equal_proc_for_type(cgModule *m, Type *type) {
+ type = base_type(type);
+ GB_ASSERT(is_type_comparable(type));
+
+ mutex_lock(&m->generated_procs_mutex);
+ defer (mutex_unlock(&m->generated_procs_mutex));
+
+ cgProcedure **found = map_get(&m->equal_procs, type);
+ if (found) {
+ return *found;
+ }
+
+ static std::atomic<u32> proc_index;
+
+ char buf[32] = {};
+ isize n = gb_snprintf(buf, 32, "__$equal%u", 1+proc_index.fetch_add(1));
+ char *str = gb_alloc_str_len(permanent_allocator(), buf, n-1);
+ String proc_name = make_string_c(str);
+
+
+ cgProcedure *p = cg_procedure_create_dummy(m, proc_name, t_equal_proc);
+ map_set(&m->equal_procs, type, p);
+
+ cg_procedure_begin(p);
+
+ TB_Node *x = tb_inst_param(p->func, 0);
+ TB_Node *y = tb_inst_param(p->func, 1);
+ GB_ASSERT(x->dt.type == TB_PTR);
+ GB_ASSERT(y->dt.type == TB_PTR);
+
+ TB_DataType ret_dt = TB_PROTOTYPE_RETURNS(p->proto)->dt;
+
+ TB_Node *node_true = tb_inst_uint(p->func, ret_dt, true);
+ TB_Node *node_false = tb_inst_uint(p->func, ret_dt, false);
+
+ TB_Node *same_ptr_region = cg_control_region(p, "same_ptr");
+ TB_Node *diff_ptr_region = cg_control_region(p, "diff_ptr");
+
+ TB_Node *is_same_ptr = tb_inst_cmp_eq(p->func, x, y);
+ tb_inst_if(p->func, is_same_ptr, same_ptr_region, diff_ptr_region);
+
+ tb_inst_set_control(p->func, same_ptr_region);
+ tb_inst_ret(p->func, 1, &node_true);
+
+ tb_inst_set_control(p->func, diff_ptr_region);
+
+ Type *pt = alloc_type_pointer(type);
+ cgValue lhs = cg_value(x, pt);
+ cgValue rhs = cg_value(y, pt);
+
+ if (type->kind == Type_Struct) {
+ type_set_offsets(type);
+
+ TB_Node *false_region = cg_control_region(p, "bfalse");
+ cgValue res = cg_const_bool(p, t_bool, true);
+
+ for_array(i, type->Struct.fields) {
+ TB_Node *next_region = cg_control_region(p, "btrue");
+
+ cgValue plhs = cg_emit_struct_ep(p, lhs, i);
+ cgValue prhs = cg_emit_struct_ep(p, rhs, i);
+ cgValue left = cg_emit_load(p, plhs);
+ cgValue right = cg_emit_load(p, prhs);
+ cgValue ok = cg_emit_comp(p, Token_CmpEq, left, right);
+
+ cg_emit_if(p, ok, next_region, false_region);
+
+ cg_emit_goto(p, next_region);
+ tb_inst_set_control(p->func, next_region);
+ }
+
+ tb_inst_ret(p->func, 1, &node_true);
+ tb_inst_set_control(p->func, false_region);
+ tb_inst_ret(p->func, 1, &node_false);
+
+ } else if (type->kind == Type_Union) {
+ GB_PANIC("TODO(bill): union comparison");
+ } else {
+ cgValue left = cg_lvalue_addr(x, type);
+ cgValue right = cg_lvalue_addr(y, type);
+ cgValue ok = cg_emit_comp(p, Token_CmpEq, left, right);
+ cg_build_return_stmt_internal_single(p, ok);
+ }
+
+ cg_procedure_end(p);
+
+ return p;
+} \ No newline at end of file
diff --git a/src/tilde_stmt.cpp b/src/tilde_stmt.cpp
index 0b5f122d4..382b4c02d 100644
--- a/src/tilde_stmt.cpp
+++ b/src/tilde_stmt.cpp
@@ -1047,6 +1047,14 @@ gb_internal void cg_build_assign_stmt(cgProcedure *p, AstAssignStmt *as) {
}
}
+gb_internal void cg_build_return_stmt_internal_single(cgProcedure *p, cgValue result) {
+ Slice<cgValue> results = {};
+ results.data = &result;
+ results.count = 1;
+ cg_build_return_stmt_internal(p, results);
+}
+
+
gb_internal void cg_build_return_stmt_internal(cgProcedure *p, Slice<cgValue> const &results) {
TypeTuple *tuple = &p->type->Proc.results->Tuple;
isize return_count = p->type->Proc.result_count;