Update Tilde for the new TB_Passes approach

This commit is contained in:
gingerBill
2023-07-28 14:57:04 +01:00
parent f6d1724835
commit c39a360372
10 changed files with 344 additions and 125 deletions

View File

@@ -1,9 +1,6 @@
//+private
//+build windows
package runtime
import "core:intrinsics"
foreign import kernel32 "system:Kernel32.lib"
@(private="file")
@@ -102,12 +99,12 @@ _windows_default_alloc_or_resize :: proc "contextless" (size, alignment: int, ol
allocated_mem: rawptr
if old_ptr != nil {
original_old_ptr := intrinsics.ptr_offset((^rawptr)(old_ptr), -1)^
original_old_ptr := ([^]rawptr)(old_ptr)[-1]
allocated_mem = heap_resize(original_old_ptr, space+size_of(rawptr))
} else {
allocated_mem = heap_alloc(space+size_of(rawptr), zero_memory)
}
aligned_mem := rawptr(intrinsics.ptr_offset((^u8)(allocated_mem), size_of(rawptr)))
aligned_mem := ([^]u8)(allocated_mem)[size_of(rawptr):]
ptr := uintptr(aligned_mem)
aligned_ptr := (ptr - 1 + uintptr(a)) & -uintptr(a)
@@ -116,10 +113,10 @@ _windows_default_alloc_or_resize :: proc "contextless" (size, alignment: int, ol
return nil, .Out_Of_Memory
}
aligned_mem = rawptr(aligned_ptr)
intrinsics.ptr_offset((^rawptr)(aligned_mem), -1)^ = allocated_mem
aligned_mem = ([^]byte)(aligned_ptr)
([^]rawptr)(aligned_mem)[-1] = allocated_mem
return byte_slice(aligned_mem, size), nil
return aligned_mem[:size], nil
}
_windows_default_alloc :: proc "contextless" (size, alignment: int, zero_memory := true) -> ([]byte, Allocator_Error) {
@@ -129,7 +126,7 @@ _windows_default_alloc :: proc "contextless" (size, alignment: int, zero_memory
_windows_default_free :: proc "contextless" (ptr: rawptr) {
if ptr != nil {
heap_free(intrinsics.ptr_offset((^rawptr)(ptr), -1)^)
heap_free(([^]rawptr)(ptr)[-1])
}
}

View File

@@ -8,6 +8,11 @@ _INTEGER_DIGITS_VAR := _INTEGER_DIGITS
when !ODIN_NO_RTTI {
print_any_single :: proc "contextless" (arg: any) {
x := arg
if x.data == nil {
print_string("nil")
return
}
if loc, ok := x.(Source_Code_Location); ok {
print_caller_location(loc)
return
@@ -48,6 +53,7 @@ when !ODIN_NO_RTTI {
case int: print_int(v)
case uint: print_uint(v)
case uintptr: print_uintptr(v)
case rawptr: print_uintptr(uintptr(v))
case bool: print_string("true" if v else "false")
case b8: print_string("true" if v else "false")
@@ -58,7 +64,7 @@ when !ODIN_NO_RTTI {
case:
ti := type_info_of(x.id)
#partial switch v in ti.variant {
case Type_Info_Pointer:
case Type_Info_Pointer, Type_Info_Multi_Pointer:
print_uintptr((^uintptr)(x.data)^)
return
}
@@ -67,7 +73,9 @@ when !ODIN_NO_RTTI {
}
}
println_any :: proc "contextless" (args: ..any) {
context = default_context()
loop: for arg, i in args {
assert(arg.id != nil)
if i != 0 {
print_string(" ")
}

View File

@@ -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;

View File

@@ -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);

View File

@@ -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);

Binary file not shown.

76
src/tilde/tb_arena.h Normal file
View File

@@ -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);

View File

@@ -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)) {

View File

@@ -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;
TB_Passes *opt = tb_pass_enter(p->func, cg_arena());
defer (tb_pass_exit(opt));
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;
// 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;
}

View File

@@ -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;