From 65c212620255fa740386813aefb3dc4b3f479778 Mon Sep 17 00:00:00 2001 From: Christoffer Lerno Date: Thu, 8 Aug 2024 12:55:40 +0200 Subject: [PATCH] Removing tb codegen info, because it's sure to have code-rotted by now. --- src/build/build_options.c | 6 - src/compiler/tilde_codegen.c | 658 --------- src/compiler/tilde_codegen_abi.c | 5 - src/compiler/tilde_codegen_expr.c | 1703 ------------------------ src/compiler/tilde_codegen_instr.c | 46 - src/compiler/tilde_codegen_stmt.c | 523 -------- src/compiler/tilde_codegen_storeload.c | 160 --- src/compiler/tilde_codegen_type.c | 501 ------- src/compiler/tilde_codegen_value.c | 172 --- src/compiler/tilde_internal.h | 201 --- 10 files changed, 3975 deletions(-) delete mode 100644 src/compiler/tilde_codegen.c delete mode 100644 src/compiler/tilde_codegen_abi.c delete mode 100644 src/compiler/tilde_codegen_expr.c delete mode 100644 src/compiler/tilde_codegen_instr.c delete mode 100644 src/compiler/tilde_codegen_stmt.c delete mode 100644 src/compiler/tilde_codegen_storeload.c delete mode 100644 src/compiler/tilde_codegen_type.c delete mode 100644 src/compiler/tilde_codegen_value.c delete mode 100644 src/compiler/tilde_internal.h diff --git a/src/build/build_options.c b/src/build/build_options.c index b8600e9c0..deca6c814 100644 --- a/src/build/build_options.c +++ b/src/build/build_options.c @@ -82,7 +82,6 @@ static void usage(void) PRINTF(" project ... Manipulate or view project files."); PRINTF(""); PRINTF("Options:"); - PRINTF(" --tb - Use Tilde Backend for compilation."); PRINTF(" --stdlib - Use this directory as the C3 standard library path."); PRINTF(" --no-entry - Do not generate (or require) a main function."); PRINTF(" --libdir - Add this directory to the C3 library search paths."); @@ -696,11 +695,6 @@ static void parse_option(BuildOptions *options) } break; case '-': - if (match_longopt("tb")) - { - options->backend = BACKEND_TB; - return; - } if (match_longopt("max-mem")) { if (at_end() || next_is_opt()) error_exit("error: --max-mem needs a valid integer."); diff --git a/src/compiler/tilde_codegen.c b/src/compiler/tilde_codegen.c deleted file mode 100644 index 98977b64e..000000000 --- a/src/compiler/tilde_codegen.c +++ /dev/null @@ -1,658 +0,0 @@ -#include "tilde_internal.h" - - - -static TB_System os_to_tilde_system(OsType target) -{ - switch (target) - { - case OS_TYPE_LINUX: - return TB_SYSTEM_LINUX; - case OS_TYPE_MACOSX: - return TB_SYSTEM_MACOS; - case OS_TYPE_WIN32: - return TB_SYSTEM_WINDOWS; - case OS_TYPE_WASI: - case OS_TYPE_EMSCRIPTEN: - return TB_SYSTEM_WEB; - default: - error_exit("Unsupported system for TB compilation, use LLVM."); - } -} -static TB_Arch arch_to_tilde_arch(ArchType target) -{ - switch (target) - { - case ARCH_TYPE_AARCH64: - return TB_ARCH_AARCH64; - case ARCH_TYPE_X86_64: - return TB_ARCH_X86_64; - case ARCH_TYPE_WASM32: - return TB_ARCH_WASM32; - default: - error_exit("Unsupported architecture for TB compilation, use LLVM."); - } - UNREACHABLE -} - -static void tilde_emit_type_decls(TildeContext *c, Decl *decl) -{ - switch (decl->decl_kind) - { - case DECL_POISONED: - UNREACHABLE; - case DECL_FUNC: - // TODO - break; - case DECL_VAR: - // TODO - break; - case DECL_TYPEDEF: - break; - case DECL_ENUM_CONSTANT: - case DECL_FAULTVALUE: - // TODO - break;; - case DECL_DISTINCT: - case DECL_STRUCT: - case DECL_UNION: - case DECL_ENUM: - case DECL_FAULT: - case DECL_BITSTRUCT: - tilde_get_typeid(c, decl->type); - break; - case DECL_BODYPARAM: - case NON_TYPE_DECLS: - UNREACHABLE - } -} - -TB_Reg tilde_get_next_param(TildeContext *c, unsigned *index) -{ - return tb_inst_param(c->f, (*index)++); -} - -static inline void tilde_process_parameter_value(TildeContext *c, Decl *decl, ABIArgInfo *info, unsigned *index) -{ - switch (info->kind) - { - case ABI_ARG_IGNORE: - return; - case ABI_ARG_INDIRECT: - // Indirect is caller copied. - decl->tb_register = tilde_get_next_param(c, index); - return; - /* - case ABI_ARG_EXPAND_COERCE: - { - // Create the expand type: - LLVMTypeRef coerce_type = llvm_get_coerce_type(c, info); - LLVMValueRef temp = LLVMBuildBitCast(c->builder, decl->backend_ref, LLVMPointerType(coerce_type, 0), "coerce"); - llvm_emit_and_set_decl_alloca(c, decl); - - AlignSize alignment = decl->alignment; - AlignSize element_align; - LLVMValueRef gep_first = llvm_emit_struct_gep_raw(c, temp, coerce_type, info->coerce_expand.lo_index, alignment, &element_align); - llvm_store_to_ptr_raw_aligned(c, gep_first, llvm_get_next_param(c, index), element_align); - if (abi_type_is_valid(info->coerce_expand.hi)) - { - LLVMValueRef gep_second = llvm_emit_struct_gep_raw(c, temp, coerce_type, info->coerce_expand.hi_index, alignment, &element_align); - llvm_store_to_ptr_raw_aligned(c, gep_second, llvm_get_next_param(c, index), element_align); - } - break; - } - case ABI_ARG_DIRECT_PAIR: - { - LLVMTypeRef lo = llvm_abi_type(c, info->direct_pair.lo); - LLVMTypeRef hi = llvm_abi_type(c, info->direct_pair.hi); - LLVMTypeRef struct_type = llvm_get_twostruct(c, lo, hi); - AlignSize decl_alignment = decl->alignment; - LLVMValueRef coerce; - if (llvm_store_size(c, struct_type) > type_size(decl->type)) - { - AlignSize struct_alignment = llvm_abi_alignment(c, struct_type); - if (decl_alignment < struct_alignment) decl->alignment = decl_alignment = struct_alignment; - coerce = llvm_emit_alloca(c, struct_type, decl_alignment, ""); - decl->backend_ref = LLVMBuildBitCast(c->builder, coerce, llvm_get_ptr_type(c, decl->type), decl->name ? decl->name : ".anon"); - } - else - { - llvm_emit_and_set_decl_alloca(c, decl); - // Here we do the following transform: - // lo, hi -> { lo, hi } -> struct - // Cast to { lo, hi } - coerce = LLVMBuildBitCast(c->builder, decl->backend_ref, LLVMPointerType(struct_type, 0), "pair"); - } - // Point to the lo value. - AlignSize element_align; - LLVMValueRef lo_ptr = llvm_emit_struct_gep_raw(c, coerce, struct_type, 0, decl_alignment, &element_align); - // Store it in the struct. - llvm_store_to_ptr_raw_aligned(c, lo_ptr, llvm_get_next_param(c, index), element_align); - // Point to the hi value. - LLVMValueRef hi_ptr = llvm_emit_struct_gep_raw(c, coerce, struct_type, 1, decl_alignment, &element_align); - // Store it in the struct. - llvm_store_to_ptr_raw_aligned(c, hi_ptr, llvm_get_next_param(c, index), element_align); - return; - }*/ - - case ABI_ARG_DIRECT: - //DIRECT_FROM_COERCE: - if (!decl->var.is_written && !decl->var.is_addr) - { - decl->tb_register = tilde_get_next_param(c, index); - decl->is_value = true; - return; - } - tilde_emit_and_set_decl_alloca(c, decl); - tilde_store_decl_raw(c, decl, tilde_get_next_param(c, index)); - return; - case ABI_ARG_DIRECT_SPLIT_STRUCT: - { - TODO - /* - // In this case we've been flattening the parameter into multiple registers. - LLVMTypeRef coerce_type = llvm_get_coerce_type(c, info); - llvm_emit_and_set_decl_alloca(c, decl); - - // Cast to the coerce type. - LLVMValueRef cast = LLVMBuildBitCast(c->builder, decl->backend_ref, LLVMPointerType(coerce_type, 0), "coerce"); - - AlignSize decl_alignment = decl->alignment; - // Store each expanded parameter. - for (unsigned idx = 0; idx < info->direct_struct_expand.elements; idx++) - { - AlignSize align; - LLVMValueRef element_ptr = llvm_emit_struct_gep_raw(c, cast, coerce_type, idx, decl_alignment, &align); - LLVMValueRef value = llvm_get_next_param(c, index); - llvm_store_to_ptr_raw_aligned(c, element_ptr, value, align); - } - return;*/ - } - case ABI_ARG_DIRECT_COERCE: - { - TODO - /* - LLVMTypeRef coerce_type = llvm_get_type(c, info->direct_coerce_type); - if (coerce_type == llvm_get_type(c, decl->type)) - { - goto DIRECT_FROM_COERCE; - } - llvm_emit_and_set_decl_alloca(c, decl); - - LLVMValueRef param = llvm_get_next_param(c, index); - // Store it with the alignment of the decl. - llvm_emit_coerce_store(c, decl->backend_ref, decl->alignment, coerce_type, param, llvm_get_type(c, decl->type)); - return;*/ - } - case ABI_ARG_DIRECT_COERCE_INT: - { - TODO - /* TODO - LLVMTypeRef coerce_type = LLVMIntTypeInContext(c->context, type_size(decl->type) * 8); - if (coerce_type == llvm_get_type(c, decl->type)) - { - goto DIRECT_FROM_COERCE; - } - llvm_emit_and_set_decl_alloca(c, decl); - - LLVMValueRef param = llvm_get_next_param(c, index); - // Store it with the alignment of the decl. - llvm_emit_coerce_store(c, decl->backend_ref, decl->alignment, coerce_type, param, llvm_get_type(c, decl->type)); - return; - } - case ABI_ARG_EXPAND: - { - llvm_emit_and_set_decl_alloca(c, decl); - llvm_expand_from_args(c, decl->type, decl->backend_ref, index, decl->alignment); - if (info->expand.padding_type) - { - // Skip the pad. - llvm_get_next_param(c, index); - }*/ - } - default: - TODO - } -} - -static inline void tilde_emit_func_parameter(TildeContext *c, Decl *decl, ABIArgInfo *abi_info, unsigned *index, unsigned real_index) -{ - assert(decl->decl_kind == DECL_VAR && decl->var.kind == VARDECL_PARAM); - - // Allocate room on stack, but do not copy. - tilde_process_parameter_value(c, decl, abi_info, index); - if (tilde_use_debug(c)) - { - TODO - // TODO llvm_emit_debug_parameter(context, decl, real_index); - } -} - -void tilde_emit_body(TildeContext *c, TB_Function *function, const char *module_name, const char *function_name, - FileId file_id, FunctionPrototype *prototype, Signature *signature, Ast *body) -{ - - bool emit_debug = tilde_use_debug(c); - TB_Function *prev_function = c->f; - - c->f = function; - c->opt_var = TB_NULL_REG; - c->catch_block = 0; - - if (!function_name) function_name = "anonymous function"; - if (emit_debug) - { - TODO - /* - c->debug.function = LLVMGetSubprogram(function); - if (c->debug.enable_stacktrace) - { - scratch_buffer_clear(); - scratch_buffer_append(module_name); - scratch_buffer_append("::"); - scratch_buffer_append(function_name); - c->debug.func_name = llvm_emit_string_const(c, scratch_buffer_to_string(), ".funcname"); - - File *file = source_file_by_id(file_id); - c->debug.file_name = llvm_emit_string_const(c, file->name, ".filename"); - }*/ - } - - c->cur_func.name = function_name; - c->cur_func.prototype = prototype; - - - unsigned arg = 0; - - if (emit_debug) - { - TODO /* - llvm_debug_scope_push(c, c->debug.function); - EMIT_LOC(c, body); - if (c->debug.enable_stacktrace) - { - LLVMTypeRef slot_type = c->debug.stack_type; - LLVMTypeRef ptr_to_slot_type = LLVMPointerType(slot_type, 0); - if (!c->debug.last_ptr) - { - const char *name = ".$last_stack"; - LLVMValueRef last_stack = c->debug.last_ptr = llvm_add_global_raw(c, name, ptr_to_slot_type, 0); - LLVMSetThreadLocal(last_stack, true); - LLVMSetInitializer(last_stack, llvm_get_zero_raw(ptr_to_slot_type)); - llvm_set_weak(c, last_stack); - } - AlignSize alignment = llvm_abi_alignment(c, slot_type); - c->debug.stack_slot = llvm_emit_alloca(c, slot_type, alignment, ".$stackslot"); - AlignSize align_to_use; - LLVMValueRef prev_ptr = llvm_emit_struct_gep_raw(c, c->debug.stack_slot, slot_type, 0, alignment, &align_to_use); - llvm_store_to_ptr_raw_aligned(c, - prev_ptr, - LLVMBuildLoad2(c->builder, ptr_to_slot_type, c->debug.last_ptr, ""), - align_to_use); - LLVMValueRef func_name = llvm_emit_struct_gep_raw(c, c->debug.stack_slot, slot_type, 1, alignment, &align_to_use); - llvm_store_to_ptr_raw_aligned(c, func_name, c->debug.func_name, align_to_use); - LLVMValueRef file_name = llvm_emit_struct_gep_raw(c, c->debug.stack_slot, slot_type, 2, alignment, &align_to_use); - llvm_store_to_ptr_raw_aligned(c, file_name, c->debug.file_name, align_to_use); - c->debug.stack_slot_row = llvm_emit_struct_gep_raw(c, c->debug.stack_slot, slot_type, 3, alignment, &align_to_use); - LLVMValueRef last_ptr = NULL; - if (function_name != kw_main && function_name != kw_mainstub) - { - last_ptr = c->debug.last_ptr; - } - else - { - last_ptr = prev_ptr; - } - llvm_store_to_ptr_raw_aligned(c, - last_ptr, - c->debug.stack_slot, - type_alloca_alignment(type_voidptr)); - }*/ - } - - c->optional_out = TB_NULL_REG; - c->return_out = TB_NULL_REG; - if (prototype && prototype->ret_abi_info->kind == ABI_ARG_INDIRECT) - { - if (prototype->is_optional) - { - c->optional_out = tb_inst_param(c->f, arg++); - } - else - { - c->return_out = tb_inst_param(c->f, arg++); - } - } - if (prototype && prototype->ret_by_ref_abi_info) - { - assert(!c->return_out); - c->return_out = tb_inst_param(c->f, arg++); - } - - - if (signature) - { - // Generate LLVMValueRef's for all parameters, so we can use them as local vars in code - FOREACH_BEGIN_IDX(i, Decl *param, signature->params) - tilde_emit_func_parameter(c, param, prototype->abi_args[i], &arg, i); - FOREACH_END(); - } - - /*-- TODO - LLVMSetCurrentDebugLocation2(c->builder, NULL);*/ - - AstId current = body->compound_stmt.first_stmt; - while (current) - { - tilde_emit_stmt(c, ast_next(¤t)); - } - - /* - * TODO - if (c->current_block && llvm_basic_block_is_unused(c->current_block)) - { - LLVMBasicBlockRef prev_block = LLVMGetPreviousBasicBlock(c->current_block); - LLVMDeleteBasicBlock(c->current_block); - c->current_block = prev_block; - LLVMPositionBuilderAtEnd(c->builder, c->current_block); - }*/ - - // Insert a return (and defer) if needed. - if (!tb_basic_block_is_complete(c->f, tb_inst_get_label(c->f))) - { - tilde_emit_return_implicit(c); - } - if (tilde_use_debug(c)) - { - TODO - //llvm_debug_scope_pop(c); - } - - c->f = prev_function; -} - -static void tilde_emit_function_body(TildeContext *c, Decl *decl) -{ - TB_Function *fn = decl->tb_symbol; - vec_add(c->functions, fn); - DEBUG_LOG("Generating function %s.", decl->extname); - assert(decl->backend_ref); - tilde_emit_body(c, - fn, - decl->unit->module->name->module, - decl->name, - decl->span.file_id, - decl->type->function.prototype, - decl->func_decl.attr_naked ? NULL : &decl->func_decl.signature, - astptr(decl->func_decl.body)); -} - -static TildeContext *tilde_gen_module(Module *module, TB_FeatureSet *feature_set) -{ - if (!vec_size(module->units)) return NULL; - TildeContext *context = CALLOCS(TildeContext); - TB_Module *tb_module = tb_module_create(arch_to_tilde_arch(platform_target.arch), - os_to_tilde_system(platform_target.os), - feature_set, false); - codegen_setup_object_names(module, &context->ir_filename, &context->asm_filename, &context->object_filename); - context->module = tb_module; - - FOREACH(CompilationUnit *, unit, module->units) - { - REMINDER("Add debug info"); - /* gencontext_init_file_emit(gen_context, unit); - context->debug.compile_unit = unit->llvm.debug_compile_unit; - gen_context->debug.file = unit->llvm.debug_file;*/ - - FOREACH(Decl *, initializer, unit->xxlizers) - { - REMINDER("Add xxlizer"); - //tilde_emit_xxlizer(gen_context, initializer); - } - - FOREACH(Decl *, method, unit->methods) - { - tilde_emit_function_decl(context, method); - } - - FOREACH(Decl *, type_decl, unit->types) - { - tilde_emit_type_decls(context, type_decl); - } - - FOREACH(Decl *, enum_decl, unit->enums) - { - tilde_emit_type_decls(context, enum_decl); - } - - FOREACH(Decl *, func, unit->functions) - if (func->func_decl.attr_test) - { - if (!active_target.testing) continue; - vec_add(module->tests, func); - } - if (func->func_decl.attr_benchmark) - { - if (!active_target.benchmarking) continue; - vec_add(module->benchmarks, func); - } - tilde_emit_function_decl(context, func); - FOREACH_END(); - - if (active_target.type != TARGET_TYPE_TEST && active_target.type != TARGET_TYPE_BENCHMARK && unit->main_function && unit->main_function->is_synthetic) - { - tilde_emit_function_decl(context, unit->main_function); - } - - FOREACH_END(); - - FOREACH(CompilationUnit *, unit, module->units) - - /*--- TODO - context->debug.compile_unit = unit->llvm.debug_compile_unit; - context->debug.file = unit->llvm.debug_file; -*/ - FOREACH(Decl *, var, unit->vars) - tilde_get_ref(context, var); - FOREACH_END(); - - FOREACH(Decl *, var, unit->vars) - // TODO tilde_emit_global_variable_init(context, var); - FOREACH_END(); - - FOREACH(Decl *, decl, unit->functions) - if (decl->func_decl.attr_test && !active_target.testing) continue; - if (decl->func_decl.body) tilde_emit_function_body(context, decl); - FOREACH_END(); - - if (active_target.type != TARGET_TYPE_TEST && active_target.type != TARGET_TYPE_BENCHMARK && unit->main_function && unit->main_function->is_synthetic) - { - tilde_emit_function_body(context, unit->main_function); - } - - FOREACH(Decl *, decl, unit->methods) - if (decl->func_decl.body) tilde_emit_function_body(context, decl); - FOREACH_END(); - - // gencontext_end_file_emit(gen_context, unit); - - FOREACH_END(); - - /*-- TODO - tilde_emit_constructors_and_destructors(context); */ - - // EmitDeferred() - - /*-- TODO - if (llvm_use_debug(gen_context)) - { - LLVMDIBuilderFinalize(gen_context->debug.builder); - LLVMDisposeDIBuilder(gen_context->debug.builder); - }*/ - - // If it's in test, then we want to serialize the IR before it is optimized. - /*--if (active_target.test_output) - { - gencontext_print_llvm_ir(gen_context); - gencontext_verify_ir(gen_context); - }--*/ - return context; -} - -void **tilde_gen(Module **modules, unsigned module_count) -{ - if (!module_count) return NULL; - TB_FeatureSet feature_set; - switch (platform_target.arch) - { - case ARCH_TYPE_AARCH64: - feature_set.aarch64.bf16 = false; - case ARCH_TYPE_X86_64: - feature_set.x64.avx = platform_target.x64.x86_vector_capability >= X86VECTOR_AVX; - default: - break; - } - TildeContext **contexts = NULL; - for (unsigned i = 0; i < module_count; i++) - { - TildeContext *c = tilde_gen_module(modules[i], &feature_set); - if (c) vec_add(contexts, c); - } - return (void**)contexts; -} - -void tinybackend_codegen_setup() -{ -} - - -static TB_DataType tilde_get_abi_type(AbiType type) -{ - if (abi_type_is_type(type)) return tildetype(type.type); - TODO -} - -TB_DataType tilde_get_int_type_of_bytesize(int byte_size) -{ - switch (byte_size) - { - case 1: - return TB_TYPE_I8; - case 2: - return TB_TYPE_I16; - case 3: - case 4: - return TB_TYPE_I32; - case 5: - case 6: - case 7: - case 8: - return TB_TYPE_I64; - case 16: - return (TB_DataType) { .type = TB_INT, .width = 0, .data = 128 }; - default: - FATAL_ERROR("Unsupported size"); - } - -} -static void param_expand(TB_DataType **params_ref, Type *type) -{ - switch (type->type_kind) - { - case TYPE_TYPEDEF: - UNREACHABLE - case TYPE_ARRAY: - for (ArraySize i = type->array.len; i > 0; i--) - { - param_expand(params_ref, type->array.base); - } - return; - case TYPE_STRUCT: - { - Decl **members = type->decl->strukt.members; - VECEACH(members, i) - { - param_expand(params_ref, members[i]->type); - } - return; - } - case TYPE_ENUM: - case TYPE_ANYFAULT: - case TYPE_FAULTTYPE: - param_expand(params_ref, type_lowering(type)); - return; - case TYPE_UNION: - { - ByteSize largest = 0; - Type *largest_type = NULL; - Decl **members = type->decl->strukt.members; - // Clang: Unions can be here only in degenerative cases - all the fields are same - // after flattening. Thus we have to use the "largest" field. - VECEACH(members, i) - { - if (type_size(type) > largest) - { - largest = type_size(type); - type = type->canonical; - } - } - if (!largest) return; - param_expand(params_ref, largest_type); - return; - } - default: - vec_add(*params_ref, tildetype(type)); - return; - } - -} - -static void callback(void* user_data, const char* fmt, ...) -{ - va_list list; - va_start(list, fmt); - vprintf(fmt, list); - va_end(list); -} - -// Compile module (multi threaded) -const char *tilde_codegen(void *context) -{ - TildeContext *c = (TildeContext *)context; - bool is_win32 = platform_target.os == OS_TYPE_WIN32; - TB_DebugFormat debug_format = is_win32 ? TB_DEBUGFMT_CODEVIEW : TB_DEBUGFMT_DWARF; - if (active_target.debug_info == DEBUG_INFO_NONE) debug_format = TB_DEBUGFMT_NONE; - - FOREACH(TB_Function *, function, c->functions) - if (!tb_module_compile_function(c->module, function, TB_ISEL_FAST)) - { - error_exit("Failed to compile function."); - } - tb_function_print(function, &callback, NULL, true); - FOREACH_END(); - - const char *object_name = NULL; - if (active_target.emit_object_files) - { - if (!tb_exporter_write_files(c->module, TB_FLAVOR_OBJECT, debug_format, 1, &c->object_filename)) - { - error_exit("Failed to create object file %s.", c->object_filename); - } - object_name = c->object_filename; - } - - if (active_target.emit_asm && false) - { - if (!tb_exporter_write_files(c->module, TB_FLAVOR_ASSEMBLY, debug_format, 1, &c->asm_filename)) - { - error_exit("Failed to create asm %s.", c->asm_filename); - } - } - - tb_module_destroy(c->module); - return object_name; - - - return c->object_filename; -} - diff --git a/src/compiler/tilde_codegen_abi.c b/src/compiler/tilde_codegen_abi.c deleted file mode 100644 index d99a50054..000000000 --- a/src/compiler/tilde_codegen_abi.c +++ /dev/null @@ -1,5 +0,0 @@ -// Copyright (c) 2023 Christoffer Lerno. All rights reserved. -// Use of this source code is governed by a LGPLv3.0 -// a copy of which can be found in the LICENSE file. - -#include "tilde_internal.h" diff --git a/src/compiler/tilde_codegen_expr.c b/src/compiler/tilde_codegen_expr.c deleted file mode 100644 index 1a6174603..000000000 --- a/src/compiler/tilde_codegen_expr.c +++ /dev/null @@ -1,1703 +0,0 @@ -// Copyright (c) 2022 Christoffer Lerno. All rights reserved. -// Use of this source code is governed by a LGPLv3.0 -// a copy of which can be found in the LICENSE file. - -#include "tilde_internal.h" - -TB_Reg tilde_get_const_int(TildeContext *c, Type *type, uint64_t i) -{ - return type_is_signed(type) - ? tb_inst_sint(c->f, tildetype(type), (int64_t)i) - : tb_inst_uint(c->f, tildetype(type), i); -} - -TB_Reg tilde_get_const_float(TildeContext *c, Type *type, double d) -{ - return type_size(type) == 4 ? tb_inst_float32(c->f, (float)d) : tb_inst_float64(c->f, d); -} - -TB_Register tilde_get_zero(TildeContext *c, Type *type) -{ - type = type_lowering(type); - TB_DataType data_type = tildetype(type); - switch (data_type.type) - { - case TB_INT: - return type_is_signed(type) ? tb_inst_sint(c->f, data_type, 0) : tb_inst_uint(c->f, data_type, 0); - case TB_FLOAT: - return type->type_kind == TYPE_F32 ? tb_inst_float32(c->f, 0.0f) : tb_inst_float64(c->f, 0.0); - case TB_PTR: - return tb_inst_ptr(c->f, 0); - default: - UNREACHABLE; - } -} - -static void tilde_emit_const_expr(TildeContext *c, TBEValue *value, Expr *expr) -{ - Type *type = type_reduced_from_expr(expr)->canonical; - switch (expr->const_expr.const_kind) - { - - case CONST_BYTES: - TODO - case CONST_INTEGER: - { - Int128 i = expr->const_expr.ixx.i; - switch (expr->const_expr.ixx.type) - { - case TYPE_I128: - case TYPE_U128: - { - uint64_t words[2] = { i.low, i.high }; - TODO - } - default: - value_set(value, tilde_get_const_int(c, type, i.low), type); - return; - } - } - case CONST_FLOAT: - value_set(value, tilde_get_const_float(c, type, expr->const_expr.fxx.f), type); - return; - case CONST_POINTER: - if (!expr->const_expr.ptr) - { - value_set(value, tb_inst_ptr(c->f, 0), type); - } - else - { - value_set(value, tb_inst_ptr(c->f, expr->const_expr.ptr), type); - } - return; - case CONST_BOOL: - value_set(value, tb_inst_bool(c->f, expr->const_expr.b), type_bool); - return; - case CONST_STRING: - { - TODO - /* - Type *str_type = type_lowering(expr->type); - bool is_array = type_flat_is_char_array(str_type); - if (llvm_is_local_eval(c) || !is_array) - { - ArraySize strlen = expr->const_expr.bytes.len; - ArraySize size = expr->const_expr.bytes.len + 1; - if (type_flat_is_char_array(expr->type) && type->array.len > size) size = type->array.len; - LLVMValueRef global_name = llvm_add_global_raw(c, - ".str", - LLVMArrayType(llvm_get_type(c, type_char), size), - 1); - llvm_set_private_linkage(global_name); - LLVMSetUnnamedAddress(global_name, LLVMGlobalUnnamedAddr); - LLVMSetGlobalConstant(global_name, 1); - LLVMValueRef string = llvm_get_zstring(c, expr->const_expr.bytes.ptr, expr->const_expr.bytes.len); - if (size > strlen + 1) - { - LLVMValueRef trailing_zeros = llvm_get_zero_raw(LLVMArrayType(c->byte_type, size - strlen - 1)); - LLVMValueRef values[2] = { string, trailing_zeros }; - string = llvm_get_packed_struct(c, values, 2); - } - LLVMSetInitializer(global_name, string); - if (is_array) - { - global_name = llvm_emit_bitcast_ptr(c, global_name, type); - llvm_value_set_address(be_value, global_name, type, 1); - } - else - { - global_name = llvm_emit_bitcast(c, global_name, type); - llvm_value_set(be_value, global_name, type); - } - return; - } - ArraySize array_len = type->array.len; - ArraySize size = expr->const_expr.bytes.len + 1; - bool zero_terminate = array_len == size; - LLVMValueRef string; - if (array_len <= size) - { - if (zero_terminate) - { - string = llvm_get_zstring(c, expr->const_expr.bytes.ptr, expr->const_expr.bytes.len); - } - else - { - string = llvm_get_bytes(c, expr->const_expr.bytes.ptr, array_len); - } - } - else - { - char *buffer = ccalloc(1, array_len); - memcpy(buffer, expr->const_expr.bytes.ptr, expr->const_expr.bytes.len); - string = llvm_get_bytes(c, buffer, array_len); - } - llvm_value_set(be_value, string, type);*/ - return; - } - case CONST_TYPEID: - TODO - //llvm_emit_typeid(c, be_value, expr->const_expr.typeid); - return; - case CONST_ERR: - { - TODO - /* - Decl *decl = expr->const_expr.enum_err_val; - - LLVMValueRef value; - if (decl) - { - value = LLVMBuildPtrToInt(c->builder, llvm_get_ref(c, decl), llvm_get_type(c, type_anyfault), ""); - } - else - { - value = llvm_get_zero(c, type_anyfault); - } - llvm_value_set(be_value, value, type_anyfault);*/ - return; - } - case CONST_ENUM: - value_set(value, tilde_get_const_int(c, type, expr->const_expr.enum_err_val->enum_constant.ordinal), type); - return; - case CONST_INITIALIZER: - TODO - //llvm_emit_const_initializer_list_expr(c, be_value, expr); - return; - case CONST_MEMBER: - case CONST_UNTYPED_LIST: - UNREACHABLE - } - UNREACHABLE - -} - -void tilde_emit_parameter(TildeContext *c, TB_Reg *args, unsigned *arg_count_ref, ABIArgInfo *info, TBEValue *be_value, Type *type) -{ - type = type_lowering(type); - assert(be_value->type->canonical == type); - switch (info->kind) - { - case ABI_ARG_IGNORE: - // Skip. - return; - case ABI_ARG_INDIRECT: - { - // If we want we could optimize for structs by doing it by reference here. - assert(info->indirect.alignment == type_abi_alignment(type) || info->attributes.realign); - if (info->attributes.by_val && value_is_addr(be_value) && info->indirect.alignment <= be_value->alignment) - { - value_fold_optional(c, be_value); - args[(*arg_count_ref)++] = be_value->reg; - return; - } - TB_Reg indirect = tilde_emit_alloca(c, type, info->indirect.alignment); - tilde_store_to_ptr_aligned(c, indirect, be_value, info->indirect.alignment); - args[(*arg_count_ref)++] = indirect; - return; - } - case ABI_ARG_DIRECT: - args[(*arg_count_ref)++] = tilde_load_value_store(c, be_value); - return; - case ABI_ARG_DIRECT_SPLIT_STRUCT: - { - TODO; /*-- - LLVMTypeRef coerce_type = llvm_get_coerce_type(c, info); - assert(coerce_type && coerce_type != llvm_get_type(c, type)); - AlignSize target_alignment = llvm_abi_alignment(c, coerce_type); - - AlignSize alignment; - LLVMValueRef cast = llvm_emit_coerce_alignment(c, be_value, coerce_type, target_alignment, &alignment); - LLVMTypeRef element = llvm_get_type(c, info->direct_struct_expand.type); - for (unsigned idx = 0; idx < info->direct_struct_expand.elements; idx++) - { - AlignSize load_align; - LLVMValueRef element_ptr = llvm_emit_struct_gep_raw(c, cast, coerce_type, idx, alignment, &load_align); - args[(*arg_count_ref)++] = llvm_load(c, element, element_ptr, load_align, ""); - } - return;*/ - } - case ABI_ARG_DIRECT_COERCE: - { - TODO; /* - LLVMTypeRef coerce_type = llvm_get_type(c, info->direct_coerce_type); - if (coerce_type == llvm_get_type(c, type)) - { - args[(*arg_count_ref)++] = llvm_load_value_store(c, be_value); - return; - } - args[(*arg_count_ref)++] = llvm_emit_coerce(c, coerce_type, be_value, type); - return;--*/ - } - case ABI_ARG_DIRECT_COERCE_INT: - { - TODO; /*-- - LLVMTypeRef coerce_type = LLVMIntTypeInContext(c->context, type_size(type) * 8); - if (coerce_type == llvm_get_type(c, type)) - { - args[(*arg_count_ref)++] = llvm_load_value_store(c, be_value); - return; - } - args[(*arg_count_ref)++] = llvm_emit_coerce(c, coerce_type, be_value, type); - return; --*/ - } - case ABI_ARG_DIRECT_PAIR: - { - TODO; /*- - assert(type_flatten(be_value->type) == be_value->type); - LLVMTypeRef original_type = llvm_get_type(c, be_value->type); - LLVMTypeRef struct_type = llvm_get_coerce_type(c, info); - AlignSize alignment; - if (llvm_types_are_similar(original_type, struct_type)) - { - // Optimization - assert(LLVMGetTypeKind(original_type) == LLVMStructTypeKind && LLVMCountStructElementTypes(original_type) == 2); - if (llvm_value_is_addr(be_value)) - { - LLVMValueRef ptr = llvm_emit_struct_gep_raw(c, be_value->value, original_type, 0, be_value->alignment, &alignment); - args[(*arg_count_ref)++] = llvm_load(c, LLVMStructGetTypeAtIndex(original_type, 0), ptr, alignment, "lo"); - ptr = llvm_emit_struct_gep_raw(c, be_value->value, original_type, 1, be_value->alignment, &alignment); - args[(*arg_count_ref)++] = llvm_load(c, LLVMStructGetTypeAtIndex(original_type, 1), ptr, alignment, "hi"); - return; - } - LLVMValueRef val = be_value->value; - // Maybe it's just created? Let's optimize codegen. - if (!LLVMGetFirstUse(val) && LLVMIsAInsertValueInst(val) && LLVMIsAInsertValueInst( - LLVMGetPreviousInstruction(val))) - { - LLVMValueRef prev = LLVMGetPreviousInstruction(val); - // Isn't this a second insert? - if (LLVMGetOperand(val, 0) != prev) goto NO_OPT; - // Is it used in between? - if (LLVMGetNextUse(LLVMGetFirstUse(prev))) goto NO_OPT; - // No, then we can replace the instructions with the values. - LLVMValueRef first_val = LLVMGetOperand(prev, 1); - LLVMValueRef second_val = LLVMGetOperand(val, 1); - LLVMInstructionEraseFromParent(val); - LLVMInstructionEraseFromParent(prev); - args[(*arg_count_ref)++] = first_val; - args[(*arg_count_ref)++] = second_val; - return; - } - NO_OPT: - args[(*arg_count_ref)++] = llvm_emit_extract_value(c, be_value->value, 0); - args[(*arg_count_ref)++] = llvm_emit_extract_value(c, be_value->value, 1); - return; - } - llvm_value_addr(c, be_value); - REMINDER("Handle invalid alignment"); - // Here we do the following transform: - // struct -> { lo, hi } -> lo, hi - LLVMTypeRef lo = llvm_abi_type(c, info->direct_pair.lo); - LLVMTypeRef hi = llvm_abi_type(c, info->direct_pair.hi); - - AlignSize struct_align; - LLVMValueRef cast = llvm_emit_coerce_alignment(c, be_value, struct_type, llvm_abi_alignment(c, struct_type), &struct_align); - // Get the lo value. - - LLVMValueRef lo_ptr = llvm_emit_struct_gep_raw(c, cast, struct_type, 0, struct_align, &alignment); - args[(*arg_count_ref)++] = llvm_load(c, lo, lo_ptr, alignment, "lo"); - // Get the hi value. - LLVMValueRef hi_ptr = llvm_emit_struct_gep_raw(c, cast, struct_type, 1, struct_align, &alignment); - args[(*arg_count_ref)++] = llvm_load(c, hi, hi_ptr, alignment, "hi"); - return;--*/ - } - case ABI_ARG_EXPAND_COERCE: - { - TODO - - /*-- - // Move this to an address (if needed) - llvm_value_addr(c, be_value); - LLVMTypeRef coerce_type = llvm_get_coerce_type(c, info); - AlignSize alignment; - LLVMValueRef temp = llvm_emit_coerce_alignment(c, be_value, coerce_type, llvm_abi_alignment(c, coerce_type), &alignment); - - AlignSize align; - LLVMValueRef gep_first = llvm_emit_struct_gep_raw(c, temp, coerce_type, info->coerce_expand.lo_index, alignment, &align); - args[(*arg_count_ref)++] = llvm_load(c, llvm_abi_type(c, info->coerce_expand.lo), gep_first, align, ""); - if (abi_type_is_valid(info->coerce_expand.hi)) - { - LLVMValueRef gep_second = llvm_emit_struct_gep_raw(c, temp, coerce_type, info->coerce_expand.hi_index, alignment, &align); - args[(*arg_count_ref)++] = llvm_load(c, llvm_abi_type(c, info->coerce_expand.hi), gep_second, align, ""); - } - return;--*/ - } - case ABI_ARG_EXPAND: - { - // Move this to an address (if needed) - value_addr(c, be_value); - TODO /*--tilde_expand_type_to_args(c, type, be_value.reg, args, arg_count_ref, be_value->alignment); - // Expand the padding here. - if (info->expand.padding_type) - { - args[(*arg_count_ref)++] = TB_NULL_REG; - } - return;--*/ - } - } -} - -void tilde_emit_raw_call(TildeContext *c, TBEValue *result_value, FunctionPrototype *prototype, TB_FunctionPrototype *func_type, - TB_Function *func, TB_Reg func_ptr, TB_Reg *args, unsigned arg_count, int inline_flag, TB_Reg error_var, - bool sret_return, TBEValue *synthetic_return_param) -{ - ABIArgInfo *ret_info = prototype->ret_abi_info; - Type *call_return_type = prototype->abi_ret_type; - - TB_Reg call_value; - if (func_ptr) - { - TODO - } - else - { - call_value = tb_inst_call(c->f, tildetype(call_return_type), (TB_Symbol *)func, arg_count, args); - } - - switch (inline_flag) - { - case -1: - TODO // llvm_attribute_add_call(c, call_value, attribute_id.noinline, -1, 0); - break; - case 1: - TODO // llvm_attribute_add_call(c, call_value, attribute_id.alwaysinline, -1, 0); - break; - default: - break; - } - - assert(!prototype->ret_by_ref || prototype->ret_by_ref_abi_info->kind != ABI_ARG_INDIRECT); - - /* - llvm_add_abi_call_attributes(c, call_value, vec_size(prototype->param_types), prototype->abi_args); - if (prototype->abi_varargs) - { - llvm_add_abi_call_attributes(c, - call_value, - vec_size(prototype->varargs), - prototype->abi_varargs); - }*/ - - // 11. Process the return value. - switch (ret_info->kind) - { - case ABI_ARG_EXPAND: - case ABI_ARG_DIRECT_SPLIT_STRUCT: - UNREACHABLE - case ABI_ARG_IGNORE: - // 12. Basically void returns or empty structs. - // Here we know we don't have an optional or any return value that can be used. - assert(!prototype->is_optional && "Optional should have produced a return value."); - *result_value = (TBEValue) { .type = type_void, .kind = TBE_VALUE }; - return; - case ABI_ARG_INDIRECT: - TODO /* - llvm_attribute_add_call_type(c, call_value, attribute_id.sret, 1, llvm_get_type(c, ret_info->indirect.type)); - llvm_attribute_add_call(c, call_value, attribute_id.align, 1, ret_info->indirect.alignment); - // 13. Indirect, that is passing the result through an out parameter. - - // 13a. In the case of an already present error_var, we don't need to do a load here. - if (error_var || sret_return) break; - - // 13b. If not it will be contained in a be_value that is an address - // so we don't need to do anything more. - assert(result_value->kind == BE_ADDRESS); - - break; --*/ - case ABI_ARG_DIRECT_PAIR: - { - TODO - /* - // 14. A direct pair, in this case the data is stored like { lo, hi } - // For example we might have { int, int, short, short, int }, - // this then gets bitcast to { long, long }, so we recover it by loading - // { long, long } into memory, then performing a bitcast to { int, int, short, short, int } - - // 14a. Generate the type. - LLVMTypeRef lo = llvm_abi_type(c, ret_info->direct_pair.lo); - LLVMTypeRef hi = llvm_abi_type(c, ret_info->direct_pair.hi); - LLVMTypeRef struct_type = llvm_get_twostruct(c, lo, hi); - - // 14b. Use the coerce method to go from the struct to the actual type - // by storing the { lo, hi } struct to memory, then loading it - // again using a bitcast. - llvm_emit_convert_value_from_coerced(c, result_value, struct_type, call_value, call_return_type); - break; --*/ - } - case ABI_ARG_EXPAND_COERCE: - { - TODO - /* - // 15. Expand-coerce, this is similar to "direct pair", but looks like this: - // { lo, hi } set into { pad, lo, pad, hi } -> original type. - - // 15a. Create memory to hold the return type. - LLVMValueRef ret = llvm_emit_alloca_aligned(c, call_return_type, ""); - llvm_value_set_address_abi_aligned(result_value, ret, call_return_type); - - // 15b. "Convert" this return type pointer in memory to our coerce type which is { pad, lo, pad, hi } - LLVMTypeRef coerce_type = llvm_get_coerce_type(c, ret_info); - LLVMValueRef coerce = LLVMBuildBitCast(c->builder, ret, coerce_type, ""); - - // 15d. Find the address to the low value - AlignSize alignment; - LLVMValueRef lo = llvm_emit_struct_gep_raw(c, coerce, coerce_type, ret_info->coerce_expand.lo_index, - type_abi_alignment(call_return_type), &alignment); - - // 15e. If there is only a single field, we simply store the value, - // so { lo } set into { pad, lo, pad } -> original type. - if (!abi_type_is_valid(ret_info->coerce_expand.hi)) - { - // Here we do a store to call -> lo (leaving the rest undefined) - llvm_store_to_ptr_raw_aligned(c, lo, call_value, alignment); - break; - } - - // 15g. We can now extract { lo, hi } to lo_value and hi_value. - LLVMValueRef lo_value = llvm_emit_extract_value(c, call_value, 0); - LLVMValueRef hi_value = llvm_emit_extract_value(c, call_value, 1); - - // 15h. Store lo_value into the { pad, lo, pad, hi } struct. - llvm_store_to_ptr_raw_aligned(c, lo, lo_value, alignment); - - // 15i. Calculate the address to the high value (like for the low in 15d. - LLVMValueRef hi = llvm_emit_struct_gep_raw(c, coerce, coerce_type, ret_info->coerce_expand.hi_index, - type_abi_alignment(call_return_type), &alignment); - - // 15h. Store the high value. - llvm_store_to_ptr_raw_aligned(c, hi, hi_value, alignment); -*/ - break; - } - case ABI_ARG_DIRECT: - value_set(result_value, call_value, call_return_type); - break; - case ABI_ARG_DIRECT_COERCE_INT: - { - // 16. A direct coerce, this is basically "call result" bitcast return type. - - // 16a. Get the type of the return. - TB_DataType coerce = tilde_get_int_type_of_bytesize(type_size(call_return_type)); - - // 16b. If we don't have any coerce type, or the actual LLVM types are the same, we're done. - TB_DataType ret_type = tildetype(call_return_type); - if (coerce.raw == ret_type.raw) - { - // 16c. We just set as a value in be_value. - value_set(result_value, call_value, call_return_type); - break; - } - // 16c. We use a normal bitcast coerce. - TODO // tilde_emit_convert_value_from_coerced(c, result_value, coerce, call_value, call_return_type); - break; - } - case ABI_ARG_DIRECT_COERCE: - { - TODO /*--- - // 16. A direct coerce, this is basically "call result" bitcast return type. - - // 16a. Get the type of the return. - LLVMTypeRef coerce = llvm_get_type(c, ret_info->direct_coerce_type); - - // 16b. If we don't have any coerce type, or the actual LLVM types are the same, we're done. - if (coerce == llvm_get_type(c, call_return_type)) - { - // 16c. We just set as a value in be_value. - llvm_value_set(result_value, call_value, call_return_type); - break; - } - // 16c. We use a normal bitcast coerce. - llvm_emit_convert_value_from_coerced(c, result_value, coerce, call_value, call_return_type); - break; */ - } - } - - // 17. Handle optionals. - if (sret_return) - { - *result_value = (TBEValue) { .type = type_void, .kind = TBE_VALUE }; - return; - } - if (prototype->is_optional) - { - TBEValue no_err; - - // Emit the current stack into the thread local or things will get messed up. - if (c->debug.last_ptr) - tilde_store_to_ptr_raw_aligned(c, - type_voidptr, - c->debug.last_ptr, - c->debug.stack_slot, - type_alloca_alignment(type_voidptr)); - - // 17a. If we used the error var as the indirect recipient, then that will hold the error. - // otherwise it's whatever value in be_value. - TBEValue error_holder = *result_value; - if (error_var) - { - value_set_address_abi_aligned(&error_holder, c->opt_var, type_anyfault); - } - - TB_Reg stored_error; - - if (error_var) - { - stored_error = c->opt_var; - c->opt_var = TB_NULL_REG; - } - tilde_emit_jump_to_optional_exit(c, tilde_load_value(c, &error_holder)); - if (error_var) - { - c->opt_var = stored_error; - } - - - // 17g. If void, be_value contents should be skipped. - if (!prototype->ret_by_ref) - { - *result_value = (TBEValue) { .type = type_void, .kind = TBE_VALUE }; - return; - } - - // 17h. Assign the return param to be_value. - *result_value = *synthetic_return_param; - return; - } - - // Emit the current stack into the thread local or things will get messed up. - if (c->debug.last_ptr) - tilde_store_to_ptr_raw_aligned(c, - type_voidptr, - c->debug.last_ptr, - c->debug.stack_slot, - type_alloca_alignment(type_voidptr)); - - // 17i. The simple case here is where there is a normal return. - // In this case be_value already holds the result -} - -static void tilde_emit_call_expr(TildeContext *c, TBEValue *result_value, Expr *expr, TBEValue *target) -{ - if (expr->call_expr.is_builtin) - { - TODO // llvm_emit_builtin_call(c, result_value, expr); - return; - } - - REMINDER("Debug stack"); - /* - if (c->debug.stack_slot_row) - { - llvm_store_to_ptr_raw_aligned(c, - c->debug.stack_slot_row, - llvm_const_int(c, type_uint, expr->span.row), - type_abi_alignment(type_uint)); - }*/ - - TB_FunctionPrototype *func_type; - TB_Function *func = NULL; - TB_Reg func_ptr = TB_NULL_REG; - TBEValue temp_value; - - bool always_inline = false; - - FunctionPrototype *prototype; - // 1. Call through a pointer. - if (!expr->call_expr.is_func_ref) - { - Expr *function = exprptr(expr->call_expr.function); - - // 1a. Find the pointee type for the function pointer: - Type *type = function->type->canonical->pointer; - - // 1b. Find the type signature using the underlying pointer. - prototype = type->function.prototype; - - // 1c. Evaluate the pointer expression. - TBEValue func_value; - tilde_emit_expr(c, &func_value, function); - - // 1d. Load it as a value - func_ptr = tilde_load_value(c, &func_value); - - // 1e. Calculate the function type - func_type = tilde_get_func_prototype(c, prototype); - } - else - { - // 2a. Get the function declaration - - Decl *function_decl = declptr(expr->call_expr.func_ref); - always_inline = function_decl->func_decl.attr_inline; - - // 2b. Set signature, function and function type - prototype = function_decl->type->function.prototype; - func = tilde_get_function(c, function_decl); - assert(func); - func_type = tilde_get_func_prototype(c, prototype); - } - - TB_Reg arg_values[512]; - unsigned arg_count = 0; - Type **params = prototype->param_types; - ABIArgInfo **abi_args = prototype->abi_args; - unsigned param_count = vec_size(params); - Expr **args = expr->call_expr.arguments; - Expr **varargs = NULL; - Expr *vararg_splat = NULL; - if (prototype->variadic != VARIADIC_NONE) - { - if (expr->call_expr.splat_vararg) - { - vararg_splat = expr->call_expr.splat; - } - else - { - varargs = expr->call_expr.varargs; - } - } - FunctionPrototype copy; - if (prototype->variadic == VARIADIC_RAW) - { - if (varargs || vararg_splat) - { - assert(!vararg_splat); - copy = *prototype; - copy.varargs = NULL; - - foreach(Expr*, varargs) - { - vec_add(copy.varargs, type_flatten(val->type)); - } - copy.ret_abi_info = NULL; - copy.ret_by_ref_abi_info = NULL; - copy.abi_args = NULL; - c_abi_func_create(©); - prototype = © - TB_DataType *params_type = NULL; - tilde_update_prototype_abi(c, prototype, ¶ms_type); - } - } - ABIArgInfo *ret_info = prototype->ret_abi_info; - Type *call_return_type = prototype->abi_ret_type; - - // 5. In the case of an optional, the error is replacing the regular return abi. - TB_Reg error_var = TB_NULL_REG; - - *result_value = (TBEValue){ .kind = TBE_VALUE, .reg = TB_NULL_REG }; - // 6. Generate data for the return value. - bool sret_return = false; - switch (ret_info->kind) - { - case ABI_ARG_INDIRECT: - // 6a. We can use the stored error var if there is no redirect. - if (prototype->is_optional && c->opt_var && !ret_info->attributes.realign) - { - error_var = c->opt_var; - arg_values[arg_count++] = error_var; - break; - } - // 6b. Return true is indirect, in this case we allocate a local, using the desired alignment on the caller side. - assert(ret_info->attributes.realign || ret_info->indirect.alignment == type_abi_alignment(call_return_type)); - AlignSize alignment = ret_info->indirect.alignment; - // If we have a target, then use it. - if (target && alignment <= target->alignment) - { - assert(target->kind == TBE_ADDRESS); - arg_values[arg_count++] = target->reg; - sret_return = true; - break; - } - value_set_address(result_value, - tilde_emit_alloca(c, call_return_type, alignment), - call_return_type, alignment); - - // 6c. Add the pointer to the list of arguments. - arg_values[arg_count++] = result_value->reg; - break; - case ABI_ARG_EXPAND: - case ABI_ARG_DIRECT_SPLIT_STRUCT: - UNREACHABLE - case ABI_ARG_DIRECT_PAIR: - case ABI_ARG_IGNORE: - case ABI_ARG_DIRECT_COERCE_INT: - case ABI_ARG_DIRECT_COERCE: - case ABI_ARG_DIRECT: - case ABI_ARG_EXPAND_COERCE: - break; - } - - - // 7. We might have an optional indirect return and a normal return. - // In this case we need to add it by hand. - TBEValue synthetic_return_param = { 0 }; - if (prototype->ret_by_ref) - { - // 7b. Create the address to hold the return. - Type *actual_return_type = type_lowering(prototype->ret_by_ref_type); - value_set(&synthetic_return_param, tilde_emit_alloca(c, actual_return_type, 0), type_get_ptr(actual_return_type)); - // 7c. Emit it as a parameter as a pointer (will implicitly add it to the value list) - tilde_emit_parameter(c, arg_values, &arg_count, prototype->ret_by_ref_abi_info, &synthetic_return_param, synthetic_return_param.type); - // 7d. Update the be_value to actually be an address. - value_set_address_abi_aligned(&synthetic_return_param, synthetic_return_param.reg, actual_return_type); - } - - - // 8. Add all other arguments. - for (unsigned i = 0; i < param_count; i++) - { - // 8a. Evaluate the expression. - Expr *arg_expr = args[i]; - Type *param = params[i]; - ABIArgInfo *info = abi_args[i]; - - if (arg_expr) - { - tilde_emit_expr(c, &temp_value, arg_expr); - } - else - { - assert(prototype->variadic == VARIADIC_TYPED || prototype->variadic == VARIADIC_ANY); - TODO // tilde_emit_vararg_parameter(c, &temp_value, param, info, varargs, vararg_splat); - } - - // 8b. Emit the parameter according to ABI rules. - tilde_emit_parameter(c, arg_values, &arg_count, info, &temp_value, param); - } - - // 9. Typed varargs - - if (prototype->variadic == VARIADIC_RAW) - { - if (prototype->abi_varargs) - { - // 9. Emit varargs. - unsigned index = 0; - ABIArgInfo **abi_varargs = prototype->abi_varargs; - foreach(Expr*, varargs) - { - tilde_emit_expr(c, &temp_value, val); - ABIArgInfo *info = abi_varargs[index]; - tilde_emit_parameter(c, arg_values, &arg_count, info, &temp_value, prototype->varargs[index]); - index++; - } - } - else - { - // 9. Emit varargs. - foreach(Expr*, varargs) - { - tilde_emit_expr(c, &temp_value, val); - REMINDER("Varargs should be expanded correctly"); - arg_values[arg_count++] = tilde_load_value(c, &temp_value); - } - } - } - - - // 10. Create the actual call (remember to emit a loc, because we might have shifted loc emitting the params) - EMIT_LOC(c, expr); - int inline_flag = 0; - if (expr->call_expr.attr_force_noinline) - { - inline_flag = -1; - } - else - { - inline_flag = expr->call_expr.attr_force_inline || always_inline ? 1 : 0; - } - tilde_emit_raw_call(c, result_value, prototype, func_type, func, func_ptr, arg_values, arg_count, inline_flag, error_var, sret_return, &synthetic_return_param); - - // Emit the current stack into the thread local or things will get messed up. - if (c->debug.last_ptr) - { - tilde_store_to_ptr_raw_aligned(c, type_voidptr, c->debug.last_ptr, c->debug.stack_slot, - type_alloca_alignment(type_voidptr)); - } - - // 17i. The simple case here is where there is a normal return. - // In this case be_value already holds the result - return; -} - -TBEValue tilde_emit_assign_expr(TildeContext *c, TBEValue *ref, Expr *expr, TB_Reg optional) -{ - assert(ref->kind == TBE_ADDRESS || ref->kind == TBE_ADDRESS_OPTIONAL); - - assert(optional || !IS_OPTIONAL(expr)); - // Special optimization of handling of optional - if (expr->expr_kind == EXPR_OPTIONAL) - { - PUSH_OPT(); - - c->opt_var = TB_NULL_REG; - c->catch_block = TB_NULL_REG; - TBEValue result; - // Emit the fault type. - tilde_emit_expr(c, &result, expr->inner_expr); - TB_Reg err_val = result.reg; - // Store it in the optional - tilde_store_to_ptr(c, optional, &result); - // Set the result to an undef value - value_set(&result, TB_NULL_REG, ref->type); - - POP_OPT(); - - // If we had a catch block outside then we want to jump to that exit. - if (c->catch_block) tilde_emit_jump_to_optional_exit(c, err_val); - - // This return value will not be used. - return result; - } - - PUSH_OPT(); - - - TB_Label assign_block = 0; - TB_Label rejump_block = 0; - - if (IS_OPTIONAL(expr)) - { - assign_block = tb_basic_block_create(c->f); - assert(optional); - if (c->opt_var) - { - c->catch_block = rejump_block = tb_basic_block_create(c->f); - } - else - { - c->catch_block = assign_block; - } - c->opt_var = optional; - } - else - { - c->opt_var = 0; - c->catch_block = 0; - } - - TBEValue value; - if (type_flat_is_vector(expr->type)) - { - tilde_emit_expr(c, &value, expr); - tilde_store(c, ref, &value); - } - else if (expr_is_const_initializer(expr)) - { - TODO - //llvm_emit_const_initialize_reference(c, ref, expr); - value = *ref; - } - else if (expr_is_init_list(expr)) - { - TODO - //llvm_emit_initialize_reference(c, ref, expr); - value = *ref; - } - else - { - if (expr->expr_kind == EXPR_CALL) - { - tilde_emit_call_expr(c, &value, expr, ref); - } - else - { - tilde_emit_expr(c, &value, expr); - } - if (value.type != type_void) tilde_store(c, ref, &value); - } - - if (optional) - { - tilde_store_to_ptr_raw(c, optional, tilde_get_zero(c, type_anyfault), type_anyfault); - } - POP_OPT(); - - if (assign_block) - { - tb_inst_goto(c->f, assign_block); - if (rejump_block) - { - tilde_emit_block(c, rejump_block); - TB_Reg error = tilde_load_abi_alignment(c, type_anyfault, optional); - tilde_store_to_ptr_raw(c, c->opt_var, error, type_anyfault); - tb_inst_goto(c->f, c->catch_block); - } - tilde_emit_block(c, assign_block); - } - - return value; - -} - -static inline TB_Reg tilde_emit_add_int(TildeContext *c, Type *type, TB_Reg left, TB_Reg right, SourceSpan loc) -{ - if (active_target.feature.trap_on_wrap) - { - REMINDER("Unable to trap on wrap"); - TODO /*-- - LLVMTypeRef type_to_use = llvm_get_type(c, type->canonical); - LLVMValueRef args[2] = { left, right }; - assert(type->canonical == type); - LLVMValueRef add_res; - if (type_is_unsigned(type)) - { - add_res = llvm_emit_call_intrinsic(c, intrinsic_id.uadd_overflow, &type_to_use, 1, args, 2); - } - else - { - add_res = llvm_emit_call_intrinsic(c, intrinsic_id.sadd_overflow, &type_to_use, 1, args, 2); - } - LLVMValueRef result = llvm_emit_extract_value(c, add_res, 0); - LLVMValueRef ok = llvm_emit_extract_value(c, add_res, 1); - llvm_emit_panic_on_true(c, ok, "Addition overflow", loc); - return result; --*/ - } - - return tb_inst_add(c->f, left, right, (TB_ArithmaticBehavior)0); -} - -static inline TB_Reg tilde_emit_mult_int(TildeContext *c, Type *type, TB_Reg left, TB_Reg right, SourceSpan loc) -{ - if (active_target.feature.trap_on_wrap) - { - TODO /* - LLVMTypeRef type_to_use = llvm_get_type(c, type); - LLVMValueRef args[2] = { left, right }; - LLVMTypeRef types[2] = { type_to_use, type_to_use }; - unsigned operation = type_is_integer_unsigned(type) ? intrinsic_id.umul_overflow - : intrinsic_id.smul_overflow; - LLVMValueRef call_res = llvm_emit_call_intrinsic(c, - operation, - types, - 1, - args, - 2); - LLVMValueRef val = llvm_emit_extract_value(c, call_res, 0); - LLVMValueRef ok = llvm_emit_extract_value(c, call_res, 1); - llvm_emit_panic_on_true(c, ok, "Integer multiplication overflow", loc); - return val;*/ - } - return tb_inst_mul(c->f, left, right, (TB_ArithmaticBehavior)0); -} - -void tilde_emit_int_comp_raw(TildeContext *c, TBEValue *result, Type *lhs_type, Type *rhs_type, TB_Reg lhs_value, TB_Reg rhs_value, BinaryOp binary_op) -{ - bool lhs_signed, rhs_signed; - Type *vector_type = type_vector_type(lhs_type); - if (vector_type) - { - lhs_signed = type_is_signed(vector_type); - rhs_signed = type_is_signed(type_vector_type(rhs_type)); - } - else - { - assert(type_is_integer_or_bool_kind(lhs_type)); - lhs_signed = type_is_signed(lhs_type); - rhs_signed = type_is_signed(rhs_type); - } - if (lhs_signed != rhs_signed) - { - // Swap sides if needed. - if (!lhs_signed) - { - Type *temp = lhs_type; - lhs_type = rhs_type; - rhs_type = temp; - lhs_signed = true; - rhs_signed = false; - TB_Reg temp_val = lhs_value; - lhs_value = rhs_value; - rhs_value = temp_val; - switch (binary_op) - { - case BINARYOP_GE: - binary_op = BINARYOP_LE; - break; - case BINARYOP_GT: - binary_op = BINARYOP_LT; - break; - case BINARYOP_LE: - binary_op = BINARYOP_GE; - break; - case BINARYOP_LT: - binary_op = BINARYOP_GT; - break; - default: - break; - } - } - } - - if (!lhs_signed) - { - assert(lhs_signed == rhs_signed); - // Right and left side are both unsigned. - TB_Reg value; - switch (binary_op) - { - case BINARYOP_EQ: - value = tb_inst_cmp_eq(c->f, lhs_value, rhs_value); - break; - case BINARYOP_NE: - value = tb_inst_cmp_ne(c->f, lhs_value, rhs_value); - break; - case BINARYOP_GE: - value = tb_inst_cmp_ige(c->f, lhs_value, rhs_value, false); - break; - case BINARYOP_GT: - value = tb_inst_cmp_igt(c->f, lhs_value, rhs_value, false); - break; - case BINARYOP_LE: - value = tb_inst_cmp_ile(c->f, lhs_value, rhs_value, false); - break; - case BINARYOP_LT: - value = tb_inst_cmp_ilt(c->f, lhs_value, rhs_value, false); - break; - default: - UNREACHABLE - } - if (vector_type) - { - TODO // llvm_convert_vector_comparison(c, result, value, lhs_type, binary_op == BINARYOP_EQ); - return; - } - value_set(result, value, type_bool); - return; - } - - - // Left side is signed. - TB_Reg comp_value; - TB_Reg check_value; - - switch (binary_op) - { - case BINARYOP_EQ: - comp_value = tb_inst_cmp_eq(c->f, lhs_value, rhs_value); - break; - case BINARYOP_NE: - comp_value = tb_inst_cmp_ne(c->f, lhs_value, rhs_value); - break; - case BINARYOP_GE: - comp_value = tb_inst_cmp_ige(c->f, lhs_value, rhs_value, true); - break; - case BINARYOP_GT: - comp_value = tb_inst_cmp_igt(c->f, lhs_value, rhs_value, true); - break; - case BINARYOP_LE: - comp_value = tb_inst_cmp_ile(c->f, lhs_value, rhs_value, true); - break; - case BINARYOP_LT: - comp_value = tb_inst_cmp_ilt(c->f, lhs_value, rhs_value, true); - break; - default: - UNREACHABLE - } - - // If right side is also signed then this is fine. - if (rhs_signed) - { - if (vector_type) - { - TODO // tilde_convert_vector_comparison(c, result, comp_value, lhs_type, binary_op == BINARYOP_EQ); - return; - } - value_set(result, comp_value, type_bool); - return; - } - - // Otherwise, special handling for left side signed, right side unsigned. - TB_Reg zero = tilde_get_zero(c, lhs_type); - switch (binary_op) - { - case BINARYOP_EQ: - // Only true if lhs >= 0 - check_value = tb_inst_cmp_ige(c->f, lhs_value, zero, true); - comp_value = tb_inst_and(c->f, check_value, comp_value); - break; - case BINARYOP_NE: - // Always true if lhs < 0 - check_value = tb_inst_cmp_ilt(c->f, lhs_value, zero, true); - comp_value = tb_inst_and(c->f, check_value, comp_value); - break; - case BINARYOP_GE: - // Only true if rhs >= 0 when regarded as a signed integer - check_value = tb_inst_cmp_ige(c->f, rhs_value, zero, true); - comp_value = tb_inst_and(c->f, check_value, comp_value); - break; - case BINARYOP_GT: - // Only true if rhs >= 0 when regarded as a signed integer - check_value = tb_inst_cmp_ige(c->f, rhs_value, zero, true); - comp_value = tb_inst_and(c->f, check_value, comp_value); - break; - case BINARYOP_LE: - // Always true if rhs < 0 when regarded as a signed integer - check_value = tb_inst_cmp_ilt(c->f, rhs_value, zero, true); - comp_value = tb_inst_or(c->f, check_value, comp_value); - break; - case BINARYOP_LT: - // Always true if rhs < 0 when regarded as a signed integer - check_value = tb_inst_cmp_ilt(c->f, rhs_value, zero, true); - comp_value = tb_inst_or(c->f, check_value, comp_value); - break; - default: - UNREACHABLE - } - if (vector_type) - { - TODO // tilde_convert_vector_comparison(c, result, comp_value, lhs_type, BINARYOP_EQ == binary_op); - return; - } - value_set(result, comp_value, type_bool); -} - - -void tilde_emit_comp(TildeContext *c, TBEValue *result, TBEValue *lhs, TBEValue *rhs, BinaryOp binary_op) -{ - assert(binary_op >= BINARYOP_GT && binary_op <= BINARYOP_EQ); - value_rvalue(c, lhs); - value_rvalue(c, rhs); - if (type_is_integer_or_bool_kind(lhs->type)) - { - tilde_emit_int_comp_raw(c, result, lhs->type, rhs->type, lhs->reg, rhs->reg, binary_op); - return; - } - if (type_is_pointer(lhs->type)) - { - TODO // tilde_emit_ptr_comparison(c, result, lhs, rhs, binary_op); - return; - } - if (type_is_float(lhs->type)) - { - TODO // tilde_emit_float_comp(c, result, lhs, rhs, binary_op, NULL); - return; - } - if (lhs->type->type_kind == TYPE_INFO_SLICE) - { - TODO // tilde_emit_subarray_comp(c, result, lhs, rhs, binary_op); - return; - } - if (lhs->type->type_kind == TYPE_VECTOR) - { - Type *type = type_vector_type(lhs->type); - if (type_is_float(type)) - { - TODO // tilde_emit_float_comp(c, result, lhs, rhs, binary_op, lhs->type); - } - else - { - TODO // tilde_emit_int_comp_raw(c, result, lhs->type, rhs->type, lhs->reg, rhs->reg, binary_op); - } - return; - } - if (lhs->type->type_kind == TYPE_ARRAY) - { - TODO // tilde_emit_array_comp(c, result, lhs, rhs, binary_op); - return; - } - TODO -} - - -void tilde_emit_binary(TildeContext *c, TBEValue *be_value, Expr *expr, TBEValue *lhs_loaded, BinaryOp binary_op) -{ - // foo ?? bar - if (binary_op == BINARYOP_ELSE) - { - TODO // llvm_emit_else(c, be_value, expr); - return; - } - - // foo || bar and foo && bar - if (binary_op == BINARYOP_AND || binary_op == BINARYOP_OR) - { - TODO // llvm_emit_logical_and_or(c, be_value, expr, binary_op); - return; - } - - // Load if needed, otherwise use the already loaded. - TBEValue lhs; - if (lhs_loaded) - { - lhs = *lhs_loaded; - } - else - { - if (type_is_float(type_flatten(expr->type)) && (binary_op == BINARYOP_ADD || binary_op == BINARYOP_SUB)) - { - TODO // if (tilde_emit_fmuladd_maybe(c, be_value, expr, binary_op)) return; - } - tilde_emit_expr(c, &lhs, exprptr(expr->binary_expr.left)); - } - // We need the rvalue. - value_rvalue(c, &lhs); - - // Evaluate rhs - TBEValue rhs; - tilde_emit_expr(c, &rhs, exprptr(expr->binary_expr.right)); - value_rvalue(c, &rhs); - - EMIT_LOC(c, expr); - // Comparison <=> - if (binary_op >= BINARYOP_GT && binary_op <= BINARYOP_EQ) - { - tilde_emit_comp(c, be_value, &lhs, &rhs, binary_op); - return; - } - - Type *lhs_type = lhs.type; - Type *rhs_type = rhs.type; - Type *vector_type = lhs_type->type_kind == TYPE_VECTOR ? lhs_type->array.base : NULL; - bool is_float = type_is_float(lhs_type) || (vector_type && type_is_float(vector_type)); - TB_Reg val = TB_NULL_REG; - TB_Reg lhs_value = lhs.reg; - TB_Reg rhs_value = rhs.reg; - switch (binary_op) - { - case BINARYOP_ERROR: - UNREACHABLE - case BINARYOP_MULT: - if (is_float) - { - val = tb_inst_fmul(c->f, lhs_value, rhs_value); - break; - } - val = tilde_emit_mult_int(c, lhs_type, lhs_value, rhs_value, expr->span); - break; - case BINARYOP_SUB: - if (lhs_type->type_kind == TYPE_POINTER) - { - TODO /*--- - if (lhs_type == rhs_type) - { - LLVMTypeRef int_type = llvm_get_type(c, type_isz); - val = LLVMBuildSub(c->builder, LLVMBuildPtrToInt(c->builder, lhs_value, int_type, ""), - LLVMBuildPtrToInt(c->builder, rhs_value, int_type, ""), ""); - val = LLVMBuildExactSDiv(c->builder, val, llvm_const_int(c, type_isz, type_abi_alignment(lhs_type->pointer)), ""); - break; - } - rhs_value = LLVMBuildNeg(c->builder, rhs_value, ""); - val = llvm_emit_pointer_gep_raw(c, llvm_get_pointee_type(c, lhs_type), lhs_value, rhs_value); - */ - break; - } - if (is_float) - { - val = tb_inst_fsub(c->f, lhs_value, rhs_value); - break; - } - TODO // val = tilde_emit_sub_int(c, lhs_type, lhs_value, rhs_value, expr->span); - break; - case BINARYOP_ADD: - if (lhs_type->type_kind == TYPE_POINTER) - { - assert(type_is_integer(rhs_type)); - TODO // val = llvm_emit_pointer_gep_raw(c, llvm_get_pointee_type(c, lhs_type), lhs_value, rhs_value); - break; - } - if (is_float) - { - val = tb_inst_fadd(c->f, lhs_value, rhs_value); - break; - } - val = tilde_emit_add_int(c, lhs_type, lhs_value, rhs_value, expr->span); - break; - case BINARYOP_DIV: - TODO // tilde_emit_trap_zero(c, rhs_type, rhs_value, "Division by zero.", expr->span); - if (is_float) - { - val = tb_inst_fdiv(c->f, lhs_value, rhs_value); - break; - } - val = tb_inst_div(c->f, lhs_value, rhs_value, type_is_signed(lhs_type)); - break; - case BINARYOP_MOD: - TODO // tilde_emit_trap_zero(c, rhs_type, rhs_value, "% by zero.", expr->span); - if (type_is_float(lhs_type)) - { - TODO // val = LLVMBuildFRem(c->builder, lhs_value, rhs_value, "fmod"); - break; - } - val = tb_inst_mod(c->f, lhs_value, rhs_value, type_is_signed(lhs_type)); - break; - case BINARYOP_SHR: - TODO /*--- - rhs_value = llvm_zext_trunc(c, rhs_value, LLVMTypeOf(lhs_value)); - llvm_emit_trap_invalid_shift(c, rhs_value, lhs_type, "Shift amount out of range.", expr->span); - val = type_is_unsigned(lhs_type) - ? LLVMBuildLShr(c->builder, lhs_value, rhs_value, "lshr") - : LLVMBuildAShr(c->builder, lhs_value, rhs_value, "ashr"); - val = LLVMBuildFreeze(c->builder, val, ""); --*/ - break; - case BINARYOP_SHL: - /*--- - rhs_value = llvm_zext_trunc(c, rhs_value, LLVMTypeOf(lhs_value)); - llvm_emit_trap_invalid_shift(c, rhs_value, lhs_type, "Shift amount out of range.", expr->span); - val = LLVMBuildShl(c->builder, lhs_value, rhs_value, "shl"); - val = LLVMBuildFreeze(c->builder, val, ""); --*/ - break; - case BINARYOP_BIT_AND: - val = tb_inst_and(c->f, lhs_value, rhs_value); - break; - case BINARYOP_BIT_OR: - val = tb_inst_or(c->f, lhs_value, rhs_value); - break; - case BINARYOP_BIT_XOR: - val = tb_inst_xor(c->f, lhs_value, rhs_value); - break; - case BINARYOP_ELSE: - case BINARYOP_EQ: - case BINARYOP_NE: - case BINARYOP_GE: - case BINARYOP_GT: - case BINARYOP_LE: - case BINARYOP_LT: - case BINARYOP_AND: - case BINARYOP_OR: - case BINARYOP_ASSIGN: - case BINARYOP_MULT_ASSIGN: - case BINARYOP_ADD_ASSIGN: - case BINARYOP_SUB_ASSIGN: - case BINARYOP_DIV_ASSIGN: - case BINARYOP_MOD_ASSIGN: - case BINARYOP_BIT_AND_ASSIGN: - case BINARYOP_BIT_OR_ASSIGN: - case BINARYOP_BIT_XOR_ASSIGN: - case BINARYOP_SHR_ASSIGN: - case BINARYOP_SHL_ASSIGN: - // Handled elsewhere. - UNREACHABLE - } - assert(val); - value_set(be_value, val, expr->type); -} - -static void tilde_emit_binary_expr(TildeContext *c, TBEValue *be_value, Expr *expr) -{ - BinaryOp binary_op = expr->binary_expr.operator; - if (binary_op >= BINARYOP_ASSIGN && expr_is_vector_index(exprptr(expr->binary_expr.left))) - { - TODO // llvm_emit_vector_assign_expr(c, be_value, expr); - return; - } - if (binary_op > BINARYOP_ASSIGN) - { - BinaryOp base_op = binaryop_assign_base_op(binary_op); - assert(base_op != BINARYOP_ERROR); - TBEValue addr; - tilde_emit_expr(c, &addr, exprptr(expr->binary_expr.left)); - value_addr(c, &addr); - tilde_emit_binary(c, be_value, expr, &addr, base_op); - tilde_store(c, &addr, be_value); - return; - } - if (binary_op == BINARYOP_ASSIGN) - { - Expr *left = exprptr(expr->binary_expr.left); - tilde_emit_expr(c, be_value, left); - assert(value_is_addr(be_value)); - TB_Reg optional_ref = TB_NULL_REG; - if (left->expr_kind == EXPR_IDENTIFIER) - { - TODO - /*--- - optional_ref = decl_optional_ref(left->identifier_expr.decl); - be_value->kind = BE_ADDRESS;*/ - } - *be_value = tilde_emit_assign_expr(c, be_value, exprptr(expr->binary_expr.right), optional_ref); - return; - } - - tilde_emit_binary(c, be_value, expr, NULL, binary_op); -} - -void tilde_emit_expr(TildeContext *c, TBEValue *value, Expr *expr) -{ - EMIT_LOC(c, expr); - switch (expr->expr_kind) - { - case NON_RUNTIME_EXPR: - case EXPR_COND: - case EXPR_CT_ARG: - case EXPR_ASM: - case EXPR_VASPLAT: - case EXPR_CT_CHECKS: - case EXPR_BUILTIN: - UNREACHABLE - case EXPR_CONST: - tilde_emit_const_expr(c, value, expr); - return; - case EXPR_BINARY: - tilde_emit_binary_expr(c, value, expr); - return; - case EXPR_NOP: - value_set(value, TB_NULL_REG, type_void); - return; - case EXPR_IDENTIFIER: - value_set_decl(c, value, expr->identifier_expr.decl); - return; - case EXPR_CALL: - tilde_emit_call_expr(c, value, expr, NULL); - return; - - default: - break; - } - TODO -} - -void tilde_emit_cast(TildeContext *c, CastKind cast_kind, Expr *expr, TBEValue *value, Type *to_type, Type *from_type) -{ - Type *to_type_original = to_type; - to_type = type_flatten(to_type); - from_type = type_flatten(from_type); - - switch (cast_kind) - { - case CAST_NUMVEC: - TODO // llvm_emit_num_to_vec_cast(c, value, to_type, from_type); - return; - case CAST_BOOLVECINT: - TODO // llvm_emit_bool_to_intvec_cast(c, value, to_type, from_type); - return; - case CAST_ARRVEC: - TODO // llvm_emit_array_to_vector_cast(c, value, to_type, from_type); - return; - case CAST_PTRANY: - { - value_rvalue(c, value); - TODO /*-- - LLVMValueRef pointer = llvm_emit_bitcast(c, value->value, type_voidptr); - BEValue typeid; - llvm_emit_typeid(c, &typeid, from_type->pointer); - llvm_value_aggregate_two(c, value, to_type, pointer, typeid.value); - return;--*/ - } - case CAST_BSARRY: - TODO - /*-- - llvm_value_addr(c, value); - llvm_value_bitcast(c, value, to_type); - llvm_value_rvalue(c, value);--*/ - return; - /* - case CAST_BSINT: - llvm_value_addr(c, value); - llvm_value_bitcast(c, value, to_type); - llvm_value_rvalue(c, value); - return; - case CAST_EUINT: - case CAST_ERINT: - to_type = type_lowering(to_type); - from_type = type_lowering(from_type); - llvm_value_rvalue(c, value); - if (type_convert_will_trunc(to_type, from_type)) - { - value->value = LLVMBuildTrunc(c->builder, value->value, llvm_get_type(c, to_type), "errinttrunc"); - } - else - { - value->value = type_is_signed(to_type) - ? LLVMBuildSExt(c->builder, value->value, llvm_get_type(c, to_type), "errsiext") - : LLVMBuildZExt(c->builder, value->value, llvm_get_type(c, to_type), "erruiext"); - - } - break; - case CAST_ANYPTR: - llvm_emit_any_pointer(c, value, value); - if (llvm_value_is_addr(value)) - { - value->value = LLVMBuildBitCast(c->builder, value->value, llvm_get_ptr_type(c, to_type), ""); - } - else - { - value->value = LLVMBuildBitCast(c->builder, value->value, llvm_get_type(c, to_type), ""); - } - break; - case CAST_XIERR: - to_type = type_lowering(to_type); - llvm_value_rvalue(c, value); - value->value = llvm_zext_trunc(c, value->value, llvm_get_type(c, to_type)); - break; - case CAST_ERROR: - UNREACHABLE - case CAST_STRPTR: - case CAST_PTRPTR: - llvm_value_rvalue(c, value); - value->value = LLVMBuildPointerCast(c->builder, value->value, llvm_get_type(c, to_type), "ptrptr"); - break; - case CAST_PTRXI: - llvm_value_rvalue(c, value); - value->value = LLVMBuildPtrToInt(c->builder, value->value, llvm_get_type(c, to_type), "ptrxi"); - break; - case CAST_APTSA: - llvm_emit_arr_to_subarray_cast(c, value, to_type); - break; - case CAST_SASA: - assert(type_is_pointer(value->type->array.base)); - llvm_value_addr(c, value); - llvm_value_bitcast(c, value, to_type); - break; - case CAST_SAPTR: - llvm_emit_subarray_pointer(c, value, value); - if (value->type != to_type) - { - if (llvm_value_is_addr(value)) - { - value->value = LLVMBuildPointerCast(c->builder, value->value, llvm_get_ptr_type(c, to_type), "saptr"); - } - else - { - value->value = LLVMBuildPointerCast(c->builder, value->value, llvm_get_ptr_type(c, to_type), "saptr"); - } - } - break; - case CAST_EREU: - // This is a no op. - assert(type_lowering(to_type) == type_lowering(from_type)); - break; - case CAST_VECARR: - llvm_emit_vector_to_array_cast(c, value, to_type, from_type); - break; - case CAST_EUER: - TODO // gencontext_emit_value_bitcast(c, value->value, to_type, from_type); - case CAST_ERBOOL: - case CAST_EUBOOL: - { - BEValue zero; - llvm_value_set_int(c, &zero, type_anyfault, 0); - llvm_emit_int_comp(c, value, value, &zero, BINARYOP_NE); - break; - } - case CAST_PTRBOOL: - llvm_value_rvalue(c, value); - value->value = LLVMBuildIsNotNull(c->builder, value->value, "ptrbool"); - value->kind = BE_BOOLEAN; - break; - case CAST_BOOLINT: - llvm_value_rvalue(c, value); - value->value = LLVMBuildZExt(c->builder, value->value, llvm_get_type(c, to_type), "boolsi"); - value->kind = BE_VALUE; - break; - case CAST_FPBOOL: - llvm_value_rvalue(c, value); - value->value = LLVMBuildFCmp(c->builder, LLVMRealUNE, value->value, llvm_get_zero(c, from_type), "fpbool"); - value->kind = BE_BOOLEAN; - break; - case CAST_BOOLBOOL: - value->value = LLVMBuildTrunc(c->builder, value->value, c->bool_type, "boolbool"); - value->kind = BE_BOOLEAN; - break; - case CAST_BOOLFP: - llvm_value_rvalue(c, value); - value->value = LLVMBuildUIToFP(c->builder, value->value, llvm_get_type(c, to_type), "boolfp"); - value->kind = BE_VALUE; - break; - case CAST_INTBOOL: - llvm_value_rvalue(c, value); - value->value = LLVMBuildICmp(c->builder, LLVMIntNE, value->value, llvm_get_zero(c, from_type), "intbool"); - value->kind = type_kind_is_any_vector(value->type->type_kind) ? BE_BOOLVECTOR : BE_BOOLEAN; - break; - case CAST_FPFP: - llvm_value_rvalue(c, value); - value->value = type_convert_will_trunc(to_type, from_type) - ? LLVMBuildFPTrunc(c->builder, value->value, llvm_get_type(c, to_type), "fpfptrunc") - : LLVMBuildFPExt(c->builder, value->value, llvm_get_type(c, to_type), "fpfpext"); - break; - case CAST_FPSI: - llvm_value_rvalue(c, value); - value->value = LLVMBuildFPToSI(c->builder, value->value, llvm_get_type(c, to_type), "fpsi"); - break; - case CAST_FPUI: - llvm_value_rvalue(c, value); - value->value = LLVMBuildFPToUI(c->builder, value->value, llvm_get_type(c, to_type), "fpui"); - break; - case CAST_SISI: - llvm_value_rvalue(c, value); - value->value = type_convert_will_trunc(to_type, from_type) - ? LLVMBuildTrunc(c->builder, value->value, llvm_get_type(c, to_type), "sisitrunc") - : LLVMBuildSExt(c->builder, value->value, llvm_get_type(c, to_type), "sisiext"); - break; - case CAST_SIUI: - llvm_value_rvalue(c, value); - value->value = type_convert_will_trunc(to_type, from_type) - ? LLVMBuildTrunc(c->builder, value->value, llvm_get_type(c, to_type), "siuitrunc") - : LLVMBuildSExt(c->builder, value->value, llvm_get_type(c, to_type), "siuiext"); - break; - case CAST_SIFP: - llvm_value_rvalue(c, value); - value->value = LLVMBuildSIToFP(c->builder, value->value, llvm_get_type(c, to_type), "sifp"); - break; - case CAST_XIPTR: - llvm_value_rvalue(c, value); - value->value = LLVMBuildIntToPtr(c->builder, value->value, llvm_get_type(c, to_type), "xiptr"); - break; - case CAST_UISI: - llvm_value_rvalue(c, value); - value->value = type_convert_will_trunc(to_type, from_type) - ? LLVMBuildTrunc(c->builder, value->value, llvm_get_type(c, to_type), "uisitrunc") - : LLVMBuildZExt(c->builder, value->value, llvm_get_type(c, to_type), "uisiext"); - break; - case CAST_UIUI: - llvm_value_rvalue(c, value); - value->value = llvm_zext_trunc(c, value->value, llvm_get_type(c, to_type)); - break; - case CAST_UIFP: - llvm_value_rvalue(c, value); - value->value = LLVMBuildUIToFP(c->builder, value->value, llvm_get_type(c, to_type), "uifp"); - break; - case CAST_ENUMLOW: - llvm_value_rvalue(c, value); - break; - case CAST_STST: - llvm_value_addr(c, value); - value->value = LLVMBuildBitCast(c->builder, value->value, llvm_get_ptr_type(c, to_type), ""); - value->type = to_type; - return; - case CAST_INTENUM: - if (active_target.feature.safe_mode && c->builder != c->global_builder) - { - llvm_value_rvalue(c, value); - BEValue check; - Decl *decl = to_type_original->canonical->decl; - unsigned max = vec_size(decl->enums.values); - if (type_is_signed(value->type)) - { - scratch_buffer_clear(); - scratch_buffer_printf("Conversion to enum '%s' failed - tried to convert a negative value.", decl->name); - llvm_emit_int_comp_zero(c, &check, value, BINARYOP_LT); - llvm_emit_panic_on_true(c, check.value, scratch_buffer_to_string(), expr->span); - } - scratch_buffer_clear(); - scratch_buffer_printf("Conversion to enum '%s' failed - the value was greater than %u.", decl->name, max - 1); - LLVMValueRef val = llvm_const_int(c, value->type, max); - llvm_emit_int_comp_raw(c, &check, value->type, value->type, value->value, val, BINARYOP_GE); - llvm_emit_panic_on_true(c, check.value,scratch_buffer_to_string(), expr->span); - } - return; - case CAST_SABOOL: - llvm_value_fold_optional(c, value); - if (llvm_value_is_addr(value)) - { - value->value = llvm_emit_struct_gep_raw(c, - value->value, - llvm_get_type(c, value->type), - 1, - value->alignment, - &value->alignment); - } - else - { - value->value = llvm_emit_extract_value(c, value->value, 1); - } - value->type = type_usz->canonical; - llvm_value_rvalue(c, value); - llvm_emit_int_comp_zero(c, value, value, BINARYOP_NE); - break;*/ - default: - TODO - } - value->type = to_type; -} diff --git a/src/compiler/tilde_codegen_instr.c b/src/compiler/tilde_codegen_instr.c deleted file mode 100644 index 9da7751b0..000000000 --- a/src/compiler/tilde_codegen_instr.c +++ /dev/null @@ -1,46 +0,0 @@ -#include "tilde_internal.h" - - -void tilde_emit_memclear_size_align(TildeContext *c, TB_Register ref, uint64_t size, AlignSize align) -{ - ByteSize min = type_min_alignment(align, size); - TB_Register zero = tb_inst_uint(c->f, TB_TYPE_I8, 0); - TB_Register elements = tb_inst_uint(c->f, size <= UINT32_MAX ? TB_TYPE_I32 : TB_TYPE_I64, size); - tb_inst_memset(c->f, ref, zero, elements, min); -} - -void tilde_emit_cond_br(TildeContext *c, TBEValue *value, TB_Label then_block, TB_Label else_block) -{ - tb_inst_if(c->f, tilde_load_value(c, value), then_block, else_block); -} - -TB_Reg tilde_emit_shl_fixed(TildeContext *c, Type *type, TB_Reg reg, int shift) -{ - assert(shift >= 0); - if (shift == 0) return reg; - BitSize bit_width = type_kind_bitsize(type->type_kind); - if (shift >= bit_width) return tilde_get_zero(c, type); - TB_DataType int_type = tildetype(type); - return tb_inst_shl(c->f, reg, tb_inst_uint(c->f, int_type, (unsigned)shift), type_is_signed(type) ? TB_ARITHMATIC_NSW : TB_ARITHMATIC_NUW); -} - -TB_Reg tilde_emit_lshr_fixed(TildeContext *c, Type *type, TB_Reg reg, int shift) -{ - assert(shift >= 0); - if (shift == 0) return reg; - BitSize bit_width = type_kind_bitsize(type->type_kind); - if (shift >= bit_width) return tilde_get_zero(c, type); - TB_DataType int_type = tildetype(type); - return tb_inst_shr(c->f, reg, tb_inst_uint(c->f, int_type, (unsigned)shift)); -} - -TB_Reg tilde_emit_alloca(TildeContext *c, Type *type, AlignSize alignment) -{ - return tb_inst_local(c->f, type_size(type), alignment ? alignment : type_alloca_alignment(type)); -} - -TB_Reg tilde_emit_is_no_opt(TildeContext *c, TB_Reg error_value) -{ - return tb_inst_cmp_eq(c->f, error_value, tilde_get_zero(c, type_anyfault)); -} - diff --git a/src/compiler/tilde_codegen_stmt.c b/src/compiler/tilde_codegen_stmt.c deleted file mode 100644 index 7023213b1..000000000 --- a/src/compiler/tilde_codegen_stmt.c +++ /dev/null @@ -1,523 +0,0 @@ -// Copyright (c) 2022 Christoffer Lerno. All rights reserved. -// Use of this source code is governed by a LGPLv3.0 -// a copy of which can be found in the LICENSE file. - -#include "tilde_internal.h" - - -bool tilde_emit_goto_if_needed(TildeContext *c, TB_Label jump) -{ - if (tb_basic_block_is_complete(c->f, tb_inst_get_label(c->f))) return false; - tb_inst_goto(c->f, jump); - return true; -} - -INLINE void tilde_emit_statement_chain(TildeContext *c, AstId current) -{ - while (current) - { - tilde_emit_stmt(c, ast_next(¤t)); - } -} - -INLINE void tilde_emit_compound_stmt(TildeContext *c, Ast *ast) -{ - // Push debug scope - tilde_emit_statement_chain(c, ast->compound_stmt.first_stmt); - // Pop debug scope -} - -static void tilde_emit_return_abi(TildeContext *c, TBEValue *return_value, TBEValue *optional) -{ - FunctionPrototype *prototype = c->cur_func.prototype; - - // If there is no prototype, this is a static initializer, so bail. - if (!prototype) - { - tb_inst_ret(c->f, TB_NULL_REG); - return; - } - - ABIArgInfo *info = prototype->ret_abi_info; - - // If we have an optional it's always the return argument, so we need to copy - // the return value into the return value holder. - TB_Reg return_out = c->return_out; - Type *call_return_type = prototype->abi_ret_type; - - TBEValue no_fail; - - // In this case we use the optional as the actual return. - if (prototype->is_optional) - { - if (return_value && return_value->type != type_void) - { - assert(return_value->type); - tilde_store_to_ptr_aligned(c, c->return_out, return_value, type_alloca_alignment(return_value->type)); - } - return_out = c->optional_out; - if (!optional) - { - value_set(&no_fail, tilde_get_zero(c, type_anyfault), type_anyfault); - optional = &no_fail; - } - return_value = optional; - } - assert(return_value || info->kind == ABI_ARG_IGNORE); - - switch (info->kind) - { - case ABI_ARG_INDIRECT: - assert(return_value); - tilde_store_to_ptr_aligned(c, return_out, return_value, info->indirect.alignment); - tb_inst_ret(c->f, TB_NULL_REG); - return; - case ABI_ARG_IGNORE: - tb_inst_ret(c->f, TB_NULL_REG); - return; - case ABI_ARG_DIRECT_SPLIT_STRUCT: - case ABI_ARG_EXPAND: - // Expands to multiple slots - - // Not applicable to return values. - UNREACHABLE - case ABI_ARG_EXPAND_COERCE: - { - TODO - /* - // Pick the return as an address. - value_addr(c, return_value); - // Get the coerce type. - LLVMTypeRef coerce_type = llvm_get_coerce_type(c, info); - // Create the new pointer - assert(return_value); - LLVMValueRef coerce = LLVMBuildBitCast(c->builder, return_value->value, coerce_type, ""); - // We might have only one value, in that case, build a GEP to that one. - LLVMValueRef lo_val; - AlignSize alignment; - LLVMValueRef lo = llvm_emit_struct_gep_raw(c, coerce, coerce_type, info->coerce_expand.lo_index, - return_value->alignment, &alignment); - LLVMTypeRef lo_type = llvm_abi_type(c, info->coerce_expand.lo); - lo_val = llvm_load(c, lo_type, lo, alignment, ""); - - // We're done if there's a single field. - if (!abi_type_is_valid(info->coerce_expand.hi)) - { - llvm_emit_return_value(c, lo_val); - return; - } - - // Let's make a first class aggregate - LLVMValueRef hi = llvm_emit_struct_gep_raw(c, coerce, coerce_type, info->coerce_expand.hi_index, - return_value->alignment, &alignment); - LLVMTypeRef hi_type = llvm_abi_type(c, info->coerce_expand.hi); - LLVMValueRef hi_val = llvm_load(c, hi_type, hi, alignment, ""); - - LLVMTypeRef unpadded_type = llvm_get_twostruct(c, lo_type, hi_type); - LLVMValueRef composite = llvm_get_undef_raw(unpadded_type); - - composite = llvm_emit_insert_value(c, composite, lo_val, 0); - composite = llvm_emit_insert_value(c, composite, hi_val, 1); - - // And return that unpadded result - llvm_emit_return_value(c, composite); - break;*/ - } - case ABI_ARG_DIRECT: - DIRECT_RETURN: - // The normal return - tb_inst_ret(c->f, tilde_load_value_store(c, return_value)); - return; - case ABI_ARG_DIRECT_PAIR: - { - TODO - goto DIRECT_RETURN; - /* - LLVMTypeRef coerce_type = llvm_get_coerce_type(c, info); - if (coerce_type == llvm_get_type(c, call_return_type)) goto DIRECT_RETURN; - llvm_emit_return_value(c, llvm_emit_coerce(c, coerce_type, return_value, call_return_type)); - return;*/ - } - case ABI_ARG_DIRECT_COERCE_INT: - { - TODO - /* - LLVMTypeRef coerce_type = LLVMIntTypeInContext(c->context, type_size(call_return_type) * 8); - if (coerce_type == llvm_get_type(c, call_return_type)) goto DIRECT_RETURN; - llvm_emit_return_value(c, llvm_emit_coerce(c, coerce_type, return_value, call_return_type));*/ - return; - } - case ABI_ARG_DIRECT_COERCE: - { - TODO - /* - LLVMTypeRef coerce_type = llvm_get_type(c, info->direct_coerce_type); - if (coerce_type == llvm_get_type(c, call_return_type)) goto DIRECT_RETURN; - llvm_emit_return_value(c, llvm_emit_coerce(c, coerce_type, return_value, call_return_type));*/ - return; - } - } -} - -void tilde_emit_return_implicit(TildeContext *c) -{ - Type *rtype_real = c->cur_func.prototype ? c->cur_func.prototype->rtype : type_void; - if (type_lowering(type_no_optional(rtype_real)) != type_void) - { - tb_inst_unreachable(c->f); - return; - } - if (type_is_optional(rtype_real)) - { - tilde_emit_return_abi(c, NULL, NULL); - return; - } - TBEValue value; - value_set(&value, tb_inst_ptr(c->f, 0), type_anyfault); - tilde_emit_return_abi(c, NULL, &value); -} - -static void tilde_emit_decl_expr_list(TildeContext *c, TBEValue *be_value, Expr *expr, bool bool_cast) -{ - assert(expr->expr_kind == EXPR_COND); - ByteSize size = vec_size(expr->cond_expr); - ByteSize last_index = size - 1; - for (ByteSize i = 0; i < last_index; i++) - { - TBEValue value; - tilde_emit_expr(c, &value, expr->cond_expr[i]); - } - Expr *last = expr->cond_expr[last_index]; - Type *type = last->type; - tilde_emit_expr(c, be_value, last); - if (last->expr_kind == EXPR_DECL) - { - type = last->decl_expr->var.type_info->type; - - TB_Reg decl_value = tilde_get_ref(c, last->decl_expr); - if (bool_cast && last->decl_expr->var.unwrap) - { - value_set(be_value, tb_inst_bool(c->f, true), type_bool); - return; - } - value_set_address_abi_aligned(be_value, decl_value, type); - } - if (bool_cast) - { - type = type_lowering(type); - if (type->type_kind != TYPE_BOOL) - { - CastKind cast = cast_to_bool_kind(type); - tilde_emit_cast(c, cast, last, be_value, type, type_bool); - } - } -} - -INLINE void tilde_emit_return_stmt(TildeContext *c, Ast *ast) -{ - PUSH_OPT(); - - Expr *expr = ast->return_stmt.expr; - if (expr && expr->expr_kind == EXPR_OPTIONAL) - { - TBEValue be_value; - tilde_emit_expr(c, &be_value, expr->inner_expr); - tilde_emit_statement_chain(c, ast->return_stmt.cleanup); - tilde_emit_return_abi(c, NULL, &be_value); - return; - } - - TB_Label error_return_block = 0; - TB_Reg error_out = TB_NULL_REG; - if (c->cur_func.prototype && type_is_optional(c->cur_func.prototype->rtype)) - { - error_return_block = tb_basic_block_create(c->f); - error_out = tilde_emit_alloca(c, type_anyfault, 0); - c->opt_var = error_out; - c->catch_block = error_return_block; - } - - bool has_return_value = ast->return_stmt.expr != NULL; - TBEValue return_value = { 0 }; - if (has_return_value) - { - tilde_emit_expr(c, &return_value, ast->return_stmt.expr); - value_fold_optional(c, &return_value); - c->retval = return_value; - } - - POP_OPT(); - - tilde_emit_statement_chain(c, ast->return_stmt.cleanup); - - // Are we in an expression block? - if (!has_return_value) - { - tilde_emit_return_implicit(c); - } - else - { - tilde_emit_return_abi(c, &return_value, NULL); - } - if (error_return_block) - { - tilde_emit_block(c, error_return_block); - TBEValue value; - value_set_address_abi_aligned(&value, error_out, type_anyfault); - tilde_emit_return_abi(c, NULL, &value); - } -} - -void tilde_emit_local_decl(TildeContext *c, Decl *decl, TBEValue *value) -{ - // 1. Get the declaration and the LLVM type. - Type *var_type = type_lowering(type_no_optional(decl->type)); - - // 2. In the case we have a static variable, - // then we essentially treat this as a global. - if (decl->var.is_static) - { - TODO - /* - // In defers we might already have generated this variable. - if (decl->backend_ref) - { - llvm_value_set_decl(c, value, decl); - return; - } - void *builder = c->builder; - c->builder = c->global_builder; - decl->backend_ref = llvm_add_global(c, "tempglobal", var_type, decl->alignment); - if (IS_OPTIONAL(decl)) - { - scratch_buffer_clear(); - scratch_buffer_append(decl->extname); - scratch_buffer_append("$f"); - decl->var.optional_ref = llvm_add_global(c, scratch_buffer_to_string(), type_anyfault, 0); - } - llvm_emit_global_variable_init(c, decl); - c->builder = builder; - llvm_value_set_decl(c, value, decl); - return;*/ - } - assert(!decl->backend_ref); - decl->tb_register = tb_inst_local(c->f, type_size(var_type), type_alloca_alignment(var_type)); - Expr *init = decl->var.init_expr; - bool is_optional = IS_OPTIONAL(decl); - if (is_optional) - { - scratch_buffer_clear(); - scratch_buffer_append(decl->name); - scratch_buffer_append(".f"); - decl->var.tb_optional_reg = tb_inst_local(c->f, type_size(type_anyfault), type_alloca_alignment(type_anyfault)); - // Only clear out the result if the assignment isn't an optional. - } - - if (init) - { - value_set_decl_address(c, value, decl); - value->kind = TBE_ADDRESS; - TBEValue val = tilde_emit_assign_expr(c, value, decl->var.init_expr, decl->var.tb_optional_reg); - if (!is_optional) *value = val; - } - else if (decl->var.no_init) - { - value_set(value, tb_inst_poison(c->f), decl->type); - if (decl->var.tb_optional_reg) - { - tilde_store_to_ptr_raw(c, decl->var.tb_optional_reg, tb_inst_poison(c->f), type_anyfault); - } - } - else - { - if (decl->var.tb_optional_reg) - { - tilde_store_zero(c, type_anyfault, decl->var.tb_optional_reg, 0); - } - - Type *type = type_lowering(decl->type); - // Normal case, zero init. - if (type_is_builtin(type->type_kind) || type->type_kind == TYPE_POINTER) - { - tilde_store_zero(c, type_anyfault, decl->tb_register, decl->alignment); - } - else - { - tb_inst_memclr(c->f, decl->tb_register, type_bit_size(type), decl->alignment); - } - } - -} - -static void tilde_emit_expr_stmt(TildeContext *c, Ast *ast) -{ - TBEValue value; - if (IS_OPTIONAL(ast->expr_stmt)) - { - PUSH_OPT(); - TB_Label discard_fail = tb_basic_block_create(c->f); - c->catch_block = discard_fail; - c->opt_var = TB_NULL_REG; - tilde_emit_expr(c, &value, ast->expr_stmt); - value_fold_optional(c, &value); - EMIT_LOC(c, ast); - tilde_emit_goto_if_needed(c, discard_fail); - tilde_emit_block(c, discard_fail); - POP_OPT(); - return; - } - - tilde_emit_expr(c, &value, ast->expr_stmt); -} - -// See llvm_emit_if_stmt -static void tilde_emit_if_stmt(TildeContext *c, Ast *ast) -{ - // We need at least the exit block and the "then" block. - TB_Label exit_block = tb_basic_block_create(c->f); - TB_Label then_block = exit_block; - TB_Label else_block = exit_block; - - Ast *then_body = astptr(ast->if_stmt.then_body); - // Only generate a target if - if (ast_is_not_empty(then_body)) - { - then_block = tb_basic_block_create(c->f); - } - - // We have an optional else block. - AstId else_id = ast->if_stmt.else_body; - Ast *else_body = else_id ? astptr(else_id) : NULL; - if (ast_is_not_empty(else_body)) - { - else_block = tb_basic_block_create(c->f); - } - - Expr *cond = exprptr(ast->if_stmt.cond); - ast->if_stmt.codegen.tb_break_block = exit_block; - - // Output boolean value and switch. - - Decl *label = ast->if_stmt.flow.label; - if (label) - { - label->label.tb_break_target = exit_block; - } - - TBEValue be_value = { 0 }; - - bool exit_in_use = true; - - if (then_body->ast_kind == AST_IF_CATCH_SWITCH_STMT) - { - TODO - /* - tilde_emit_decl_expr_list(c, &be_value, cond, false); - value_rvalue(c, &be_value); - TBEValue comp; - tilde_emit_int_comp_zero(c, &comp, &be_value, BINARYOP_NE); - tb_inst_if(c->f, comp.reg, then_block, else_block); - tb_inst_set_label(c->f, then_block); - tilde_emit_switch_body(c, &be_value, then_body); - tb_inst_goto(c->f, exit_block); - goto EMIT_ELSE;*/ - } - - tilde_emit_decl_expr_list(c, &be_value, cond, true); - - value_rvalue(c, &be_value); - - if (then_block != else_block) - { - tb_inst_if(c->f, be_value.reg, then_block, else_block); - } - - // Emit the 'then' code. - if (then_block != exit_block) - { - tilde_emit_block(c, then_block); - tilde_emit_stmt(c, then_body); - - // Jump to exit. - tilde_emit_goto_if_needed(c, exit_block); - } - - // Emit the 'else' branch if present. - if (else_block != exit_block) - { - tilde_emit_block(c, else_block); - tilde_emit_stmt(c, else_body); - tilde_emit_goto_if_needed(c, exit_block); - } - - tilde_emit_block(c, exit_block); -} - -void tilde_emit_stmt(TildeContext *c, Ast *ast) -{ - switch (ast->ast_kind) - { - case AST_COMPOUND_STMT: - tilde_emit_compound_stmt(c, ast); - return; - case AST_RETURN_STMT: - tilde_emit_return_stmt(c, ast); - return; - case AST_IF_STMT: - tilde_emit_if_stmt(c, ast); - return; - case AST_DECLARE_STMT: - { - TBEValue value; - tilde_emit_local_decl(c, ast->declare_stmt, &value); - return; - } - case AST_EXPR_STMT: - tilde_emit_expr_stmt(c, ast); - return; - default: - TODO - } -} - -void tilde_emit_jump_to_optional_exit(TildeContext *c, TB_Reg opt_value) -{ - assert(c->catch_block && "unexpected emit"); - bool is_constant_opt_zero = tb_node_is_constant_zero(c->f, opt_value); - - // Maybe we don't need to emit anything? - if (is_constant_opt_zero) return; - - bool is_constant_opt = false; - - TB_Label after_block = tb_basic_block_create(c->f); - - // No error variable - if (!c->opt_var) - { - // No error var and a constant error means jumping to the "catch" block - if (is_constant_opt) - { - tb_inst_goto(c->f, c->catch_block); - } - else - { - tb_inst_if(c->f, tilde_emit_is_no_opt(c, opt_value), after_block, c->catch_block); - } - tilde_emit_block(c, after_block); - return; - } - - // If it's not a constant, then jump conditionally - if (!is_constant_opt) - { - TB_Reg was_ok = tilde_emit_is_no_opt(c, opt_value); - TB_Label error_block = tb_basic_block_create(c->f); - tb_inst_if(c->f, was_ok, after_block, error_block); - tilde_emit_block(c, error_block); - } - - tilde_store_to_ptr_raw(c, c->opt_var, opt_value, type_anyfault); - tb_inst_goto(c->f, c->catch_block); - tilde_emit_block(c, after_block); - -} diff --git a/src/compiler/tilde_codegen_storeload.c b/src/compiler/tilde_codegen_storeload.c deleted file mode 100644 index 17a674b4f..000000000 --- a/src/compiler/tilde_codegen_storeload.c +++ /dev/null @@ -1,160 +0,0 @@ -// Copyright (c) 2022 Christoffer Lerno. All rights reserved. -// Use of this source code is governed by a LGPLv3.0 -// a copy of which can be found in the LICENSE file. - -#include "tilde_internal.h" - - - -void tilde_store_to_ptr_raw_aligned(TildeContext *c, Type *type, TB_Reg addr, TB_Reg value, AlignSize alignment) -{ - tilde_store_internal(c, tildetype(type), addr, value, alignment); -} - -void tilde_store_to_ptr_raw(TildeContext *c, TB_Reg addr, TB_Reg value, Type *type) -{ - tilde_store_internal(c, tildetype(type), addr, value, type_abi_alignment(type)); -} - - -void tilde_store_value_raw(TildeContext *c, TBEValue *destination, TB_Reg value) -{ - assert(value_is_addr(destination)); - tilde_store_internal(c, tildetype(destination->type), destination->reg, value, destination->alignment); -} - - -void tilde_store_decl_raw(TildeContext *c, Decl *decl, TB_Reg value) -{ - assert(!decl->is_value); - tilde_store_internal(c, tildetype(decl->type), decl->tb_register, value, decl->alignment); -} - -TB_Reg tilde_load_value_store(TildeContext *c, TBEValue *value) -{ - TB_Reg val = tilde_load_value(c, value); - return val; - /* - if (value->kind == BE_BOOLVECTOR) - { - return LLVMBuildSExt(c->builder, val, llvm_get_type(c, type_get_vector_bool(value->type)), ""); - } - if (value->kind != BE_BOOLEAN) return val; - return LLVMBuildZExt(c->builder, val, c->byte_type, "");*/ -} - -void tilde_store_to_ptr_aligned(TildeContext *c, TB_Reg destination, TBEValue *value, AlignSize alignment) -{ - // If we have an address but not an aggregate, do a load. - assert(alignment); - value_fold_optional(c, value); - if (value->kind == TBE_ADDRESS && !type_is_abi_aggregate(value->type)) - { - value->reg = tilde_load_value_store(c, value); - value->kind = TBE_VALUE; - } - switch (value->kind) - { - /* - case BE_BOOLVECTOR: - value->value = LLVMBuildSExt(c->builder, value->value, llvm_get_type(c, value->type), ""); - value->kind = BE_VALUE; - return llvm_store_to_ptr_raw_aligned(c, destination, value->value, alignment); - case BE_BOOLEAN: - value->value = LLVMBuildZExt(c->builder, value->value, c->byte_type, ""); - value->kind = BE_VALUE; - FALLTHROUGH;*/ - case TBE_VALUE: - tilde_store_to_ptr_raw_aligned(c, value->type, destination, value->reg, alignment); - return; - case TBE_ADDRESS_OPTIONAL: - UNREACHABLE - case TBE_ADDRESS: - tb_inst_memcpy(c->f, destination, value->reg, tb_inst_uint(c->f, TB_TYPE_I32, type_size(value->type)), alignment); - return; - } - UNREACHABLE -} - -void tilde_store_value_aligned(TildeContext *c, TB_Reg destination, TBEValue *value, AlignSize alignment) -{ - assert(alignment); - value_fold_optional(c, value); - // If we have an address but not an aggregate, do a load. - if (value->kind == TBE_ADDRESS && !type_is_abi_aggregate(value->type)) - { - value_rvalue(c, value); - } - switch (value->kind) - { - case TBE_VALUE: - tilde_store_value_raw(c, value, value->reg); - return; - case TBE_ADDRESS_OPTIONAL: - UNREACHABLE - case TBE_ADDRESS: - { - ByteSize size = type_size(value->type); - TB_Reg copy_size = tb_inst_uint(c->f, size <= UINT32_MAX ? TB_TYPE_I32 : TB_TYPE_I64, size); - tb_inst_memcpy(c->f, destination, value->reg, copy_size, type_min_alignment(alignment, value->alignment)); - } - } - UNREACHABLE -} - -void tilde_store(TildeContext *c, TBEValue *dst, TBEValue *value) -{ - if (value->type == type_void) return; - assert(value_is_addr(dst)); - tilde_store_to_ptr_aligned(c, dst->reg, value, dst->alignment); -} - -TB_Reg tilde_load_abi_alignment(TildeContext *c, Type *type, TB_Reg pointer) -{ - return tilde_load(c, tildetype(type), pointer, type_abi_alignment(type)); -} - -TB_Reg tilde_load_value(TildeContext *c, TBEValue *value) -{ - value_fold_optional(c, value); - switch (value->kind) - { - case TBE_VALUE: - return value->reg; - case TBE_ADDRESS_OPTIONAL: - UNREACHABLE - case TBE_ADDRESS: - return tilde_load(c, tildetype(value->type), value->reg, value->alignment); - } - UNREACHABLE -} - -void tilde_store_zero(TildeContext *c, Type *type, TB_Reg addr, AlignSize alignment) -{ - type = type_lowering(type); - if (alignment == 0) alignment = type_alloca_alignment(type); - if (type_is_builtin(type->type_kind) || type->type_kind == TYPE_POINTER) - { - tilde_store_to_ptr_raw_aligned(c, type, addr, tilde_get_zero(c, type), alignment); - return; - } - ByteSize size = type_size(type); - ByteSize min = type_min_alignment(alignment, size); - TB_Register zero = tb_inst_uint(c->f, TB_TYPE_I8, 0); - TB_Register elements = tb_inst_uint(c->f, tildetype(type_usz), size); - tb_inst_memset(c->f, addr, zero, elements, min); -} - -void tilde_store_value_zero(TildeContext *c, TBEValue *to) -{ - assert(to->kind == TBE_ADDRESS); - tilde_store_zero(c, to->type, to->reg, to->alignment); -} - - -void tilde_emit_and_set_decl_alloca(TildeContext *c, Decl *decl) -{ - Type *type = type_lowering(decl->type); - if (type == type_void) return; - decl->tb_register = tilde_emit_alloca(c, type, decl->alignment); -} diff --git a/src/compiler/tilde_codegen_type.c b/src/compiler/tilde_codegen_type.c deleted file mode 100644 index 8ac5ff6f2..000000000 --- a/src/compiler/tilde_codegen_type.c +++ /dev/null @@ -1,501 +0,0 @@ -// Copyright (c) 2022 Christoffer Lerno. All rights reserved. -// Use of this source code is governed by a LGPLv3.0 -// a copy of which can be found in the LICENSE file. - -#include "tilde_internal.h" - -TB_CallingConv calling_conv_from(CallABI abi) -{ - switch (abi) - { - case CALL_X86_STD: - return TB_STDCALL; - case CALL_C: - return TB_CDECL; - case CALL_X86_FAST: - case CALL_X86_THIS: - case CALL_X86_VECTOR: - case CALL_X86_REG: - case CALL_AAPCS: - case CALL_AAPCS_VFP: - REMINDER("Using C decl even though actual calling convention is different."); - return TB_CDECL; - } -} - -TB_DebugType *tilde_get_debug_type(Type *type) -{ - return NULL; -} - -TB_FunctionPrototype *tilde_get_func_prototype(TildeContext *c, FunctionPrototype *prototype) -{ - if (prototype->tb_prototype) return prototype->tb_prototype; - int actual_arg_count = 0; - ABIArgInfo **abi_args = prototype->abi_args; - for (unsigned i = vec_size(prototype->param_types); i > 0; i--) - { - ABIArgInfo *info = abi_args[i - 1]; - switch (info->kind) - { - case ABI_ARG_IGNORE: - continue; - case ABI_ARG_INDIRECT: - case ABI_ARG_DIRECT: - actual_arg_count++; - break; - case ABI_ARG_DIRECT_PAIR: - actual_arg_count += 2; - default: - TODO - } - } - TB_FunctionPrototype *proto = - tb_prototype_create(c->module, - calling_conv_from(prototype->call_abi), - tildetype(prototype->abi_ret_type), - tilde_get_debug_type(prototype->rtype), - actual_arg_count, - prototype->variadic == VARIADIC_RAW); - FOREACH_BEGIN_IDX(i, Decl *param, prototype->param_copy) - ABIArgInfo *abi_info = prototype->abi_args[i]; - switch (abi_info->kind) - { - case ABI_ARG_DIRECT: - if (param->name) - { - tb_prototype_add_param_named(proto, tildetype(param->type), param->name, NULL); - } - else - { - tb_prototype_add_param(proto, tildetype(param->type)); - } - break; - case ABI_ARG_IGNORE: - continue; - case ABI_ARG_INDIRECT: - tb_prototype_add_param(proto, TB_TYPE_PTR); - break; - default: - TODO - } - FOREACH_END(); - prototype->tb_prototype = proto; - return proto; -} - -TB_DataType tilde_abi_type(AbiType type) -{ - if (abi_type_is_type(type)) return tildetype(type.type); - return tilde_get_int_type_of_bytesize((type.int_bits_plus_1 - 1) / 8); -} - -static void param_expand(TildeContext *context, TB_DataType** params_ref, Type *type) -{ - switch (type->type_kind) - { - case TYPE_TYPEDEF: - UNREACHABLE - case TYPE_ARRAY: - for (ArraySize i = type->array.len; i > 0; i--) - { - param_expand(context, params_ref, type->array.base); - } - return; - case TYPE_STRUCT: - { - Decl **members = type->decl->strukt.members; - VECEACH(members, i) - { - param_expand(context, params_ref, members[i]->type); - } - return; - } - case TYPE_ENUM: - case TYPE_ANYFAULT: - case TYPE_FAULTTYPE: - param_expand(context, params_ref, type_lowering(type)); - return; - case TYPE_UNION: - { - ByteSize largest = 0; - Type *largest_type = NULL; - Decl **members = type->decl->strukt.members; - // Clang: Unions can be here only in degenerative cases - all the fields are same - // after flattening. Thus we have to use the "largest" field. - VECEACH(members, i) - { - if (type_size(type) > largest) - { - largest = type_size(type); - type = type->canonical; - } - } - if (!largest) return; - param_expand(context, params_ref, largest_type); - return; - } - default: - // Type complex: return 2; - vec_add(*params_ref, tildetype(type)); - return; - } - -} - -static inline void add_func_type_param(TildeContext *context, Type *param_type, ABIArgInfo *arg_info, TB_DataType **params) -{ - arg_info->param_index_start = (MemberIndex)vec_size(*params); - switch (arg_info->kind) - { - case ABI_ARG_IGNORE: - break; - case ABI_ARG_INDIRECT: - vec_add(*params, TB_TYPE_PTR); - break; - case ABI_ARG_EXPAND_COERCE: - vec_add(*params, tilde_abi_type(arg_info->coerce_expand.lo)); - if (abi_type_is_valid(arg_info->coerce_expand.hi)) - { - vec_add(*params, tilde_abi_type(arg_info->coerce_expand.hi)); - } - break; - case ABI_ARG_EXPAND: - // Expanding a structs - param_expand(context, params, param_type->canonical); - // If we have padding, add it here. - if (arg_info->expand.padding_type) - { - vec_add(*params, tildetype(arg_info->expand.padding_type)); - } - break; - case ABI_ARG_DIRECT: - vec_add(*params, tildetype(param_type)); - break; - case ABI_ARG_DIRECT_SPLIT_STRUCT: - { - // Normal direct. - TB_DataType coerce_type = tildetype(arg_info->direct_struct_expand.type); - for (unsigned idx = 0; idx < arg_info->direct_struct_expand.elements; idx++) - { - vec_add(*params, coerce_type); - } - break; - } - case ABI_ARG_DIRECT_COERCE_INT: - { - // Normal direct. - TB_DataType coerce_type = tilde_get_int_type_of_bytesize(type_size(param_type)); - vec_add(*params, coerce_type); - break; - } - case ABI_ARG_DIRECT_COERCE: - { - // Normal direct. - TB_DataType coerce_type = tildetype(arg_info->direct_coerce_type); - vec_add(*params, coerce_type); - break; - } - case ABI_ARG_DIRECT_PAIR: - // Pairs are passed by param. - vec_add(*params, tilde_abi_type(arg_info->direct_pair.lo)); - vec_add(*params, tilde_abi_type(arg_info->direct_pair.hi)); - break; - } - arg_info->param_index_end = (MemberIndex)vec_size(*params); -} - -TB_DataType tilde_update_prototype_abi(TildeContext *context, FunctionPrototype *prototype, TB_DataType **params) -{ - TB_DataType retval; - Type *call_return_type = prototype->abi_ret_type; - ABIArgInfo *ret_arg_info = prototype->ret_abi_info; - - ret_arg_info->param_index_end = 0; - ret_arg_info->param_index_start = 0; - - switch (ret_arg_info->kind) - { - case ABI_ARG_EXPAND: - UNREACHABLE; - case ABI_ARG_INDIRECT: - vec_add(*params, TB_TYPE_PTR); - retval = TB_TYPE_VOID; - break; - case ABI_ARG_EXPAND_COERCE: - { - TB_DataType lo = tilde_abi_type(ret_arg_info->direct_pair.lo); - if (!abi_type_is_valid(ret_arg_info->direct_pair.hi)) - { - retval = lo; - break; - } - TB_DataType hi = tilde_abi_type(ret_arg_info->direct_pair.hi); - TODO // retval = llvm_get_twostruct(context, lo, hi); - break; - } - case ABI_ARG_IGNORE: - retval = TB_TYPE_VOID; - break; - case ABI_ARG_DIRECT_PAIR: - { - TODO /*--- - LLVMTypeRef lo = llvm_abi_type(context, ret_arg_info->direct_pair.lo); - LLVMTypeRef hi = llvm_abi_type(context, ret_arg_info->direct_pair.hi); - retval = llvm_get_twostruct(context, lo, hi);*/ - break; - } - case ABI_ARG_DIRECT: - retval = tildetype(call_return_type); - break; - case ABI_ARG_DIRECT_SPLIT_STRUCT: - UNREACHABLE - case ABI_ARG_DIRECT_COERCE_INT: - retval = tilde_get_int_type_of_bytesize(type_size(call_return_type)); - break; - case ABI_ARG_DIRECT_COERCE: - retval = tildetype(ret_arg_info->direct_coerce_type); - break; - } - - // If it's optional and it's not void (meaning ret_abi_info will be NULL) - if (prototype->ret_by_ref) - { - add_func_type_param(context, type_get_ptr(type_lowering(prototype->ret_by_ref_type)), prototype->ret_by_ref_abi_info, params); - } - - // Add in all of the required arguments. - VECEACH(prototype->param_types, i) - { - add_func_type_param(context, prototype->param_types[i], prototype->abi_args[i], params); - } - - VECEACH(prototype->varargs, i) - { - add_func_type_param(context, prototype->varargs[i], prototype->abi_varargs[i], params); - } - return retval; -} - -TB_Global *tilde_get_typeid(TildeContext *c, Type *type) -{ - return NULL; - /* - if (type->backend_typeid) return type->backend_typeid; - - switch (type->type_kind) - { - case TYPE_OPTIONAL: - return tilde_generate_introspection_global(c, NULL, type, INTROSPECT_TYPE_OPTIONAL, type->optional, 0, NULL, false); - case TYPE_FLEXIBLE_ARRAY: - return tilde_generate_introspection_global(c, NULL, type, INTROSPECT_TYPE_ARRAY, type->array.base, 0, NULL, false); - case TYPE_VECTOR: - return tilde_generate_introspection_global(c, NULL, type, INTROSPECT_TYPE_VECTOR, type->array.base, type->array.len, NULL, false); - case TYPE_ARRAY: - return tilde_generate_introspection_global(c, NULL, type, INTROSPECT_TYPE_ARRAY, type->array.base, type->array.len, NULL, false); - case TYPE_SUBARRAY: - return tilde_generate_introspection_global(c, NULL, type, INTROSPECT_TYPE_SUBARRAY, type->array.base, 0, NULL, false); - case TYPE_POINTER: - return tilde_generate_introspection_global(c, NULL, type, INTROSPECT_TYPE_POINTER, type->pointer, 0, NULL, false); - case TYPE_DISTINCT: - return tilde_generate_introspection_global(c, NULL, type, INTROSPECT_TYPE_DISTINCT, type->decl->distinct->type, 0, NULL, false); - case TYPE_ENUM: - return tilde_generate_introspection_global(c, type); - case TYPE_FAULTTYPE: - return tilde_generate_introspection_global(c, type); - case TYPE_STRUCT: - case TYPE_UNION: - return tilde_generate_introspection_global(c, type); - case TYPE_FUNC: - if (type->function.prototype->raw_type == type) - { - LLVMValueRef ref = llvm_generate_temp_introspection_global(c, type); - return tilde_generate_introspection_global(c, ref, type, INTROSPECT_TYPE_FUNC, NULL, 0, NULL, false); - } - return llvm_get_typeid(c, type->function.prototype->raw_type); - case TYPE_BITSTRUCT: - { - LLVMValueRef ref = llvm_generate_temp_introspection_global(c, type); - return tilde_generate_introspection_global(c, ref, type, INTROSPECT_TYPE_BITSTRUCT, NULL, 0, NULL, false); - } - case TYPE_TYPEDEF: - return tilde_get_typeid(c, type->canonical); - case TYPE_INFERRED_ARRAY: - case TYPE_INFERRED_VECTOR: - case TYPE_UNTYPED_LIST: - case TYPE_OPTIONAL_ANY: - case TYPE_TYPEINFO: - case TYPE_MEMBER: - UNREACHABLE - case TYPE_VOID: - return tilde_get_introspection_for_builtin_type(c, type, INTROSPECT_TYPE_VOID, 0); - case TYPE_BOOL: - return tilde_get_introspection_for_builtin_type(c, type, INTROSPECT_TYPE_BOOL, 0); - case ALL_SIGNED_INTS: - return tilde_get_introspection_for_builtin_type(c, type, INTROSPECT_TYPE_SIGNED_INT, - type_kind_bitsize(type->type_kind)); - case ALL_UNSIGNED_INTS: - return tilde_get_introspection_for_builtin_type(c, - type, - INTROSPECT_TYPE_UNSIGNED_INT, - type_kind_bitsize(type->type_kind)); - case ALL_FLOATS: - return tilde_get_introspection_for_builtin_type(c, - type, - INTROSPECT_TYPE_FLOAT, - type_kind_bitsize(type->type_kind)); - case TYPE_ANYERR: - return tilde_get_introspection_for_builtin_type(c, type, INTROSPECT_TYPE_ANYERR, 0); - case TYPE_ANY: - return tilde_get_introspection_for_builtin_type(c, type, INTROSPECT_TYPE_ANY, 0); - case TYPE_TYPEID: - return tilde_get_introspection_for_builtin_type(c, type, INTROSPECT_TYPE_TYPEID, 0); - case TYPE_POISONED: - UNREACHABLE - case TYPE_SCALED_VECTOR: - TODO - } - UNREACHABLE*/ -} - -void tilde_emit_function_decl(TildeContext *c, Decl *decl) -{ - assert(decl->decl_kind == DECL_FUNC); - // Resolve function backend type for function. - - TB_Function *fn = tilde_get_function(c, decl); - (void)fn; -/// FunctionPrototype *prototype = decl->type->function.prototype; - - /* - ABIArgInfo *ret_abi_info = prototype->ret_abi_info; - llvm_emit_param_attributes(c, function, ret_abi_info, true, 0, 0); - unsigned params = vec_size(prototype->param_types); - if (prototype->ret_by_ref) - { - ABIArgInfo *info = prototype->ret_by_ref_abi_info; - llvm_emit_param_attributes(c, function, prototype->ret_by_ref_abi_info, false, info->param_index_start + 1, info->param_index_end); - } - for (unsigned i = 0; i < params; i++) - { - ABIArgInfo *info = prototype->abi_args[i]; - llvm_emit_param_attributes(c, function, info, false, info->param_index_start + 1, info->param_index_end); - } - // We ignore decl->func_decl.attr_inline and place it in every call instead. - if (decl->func_decl.attr_noinline) - { - llvm_attribute_add(c, function, attribute_id.noinline, -1); - } - if (decl->func_decl.signature.attrs.noreturn) - { - llvm_attribute_add(c, function, attribute_id.noreturn, -1); - } - if (decl->alignment != type_abi_alignment(decl->type)) - { - llvm_set_alignment(function, decl->alignment); - } - if (decl->section) - { - LLVMSetSection(function, decl->section); - } - llvm_attribute_add(c, function, attribute_id.nounwind, -1); - if (decl->func_decl.attr_naked) - { - llvm_attribute_add(c, function, attribute_id.naked, -1); - } - LLVMSetFunctionCallConv(function, llvm_call_convention_from_call(prototype->call_abi)); - - Visibility visibility = decl->visibility; - if (decl->is_external_visible) visibility = VISIBLE_PUBLIC; - switch (visibility) - { - case VISIBLE_EXTERN: - if (decl->is_weak) - { - LLVMSetLinkage(function, LLVMExternalWeakLinkage); - llvm_set_comdat(c, function); - } - else - { - LLVMSetLinkage(function, LLVMExternalLinkage); - } - LLVMSetVisibility(function, LLVMDefaultVisibility); - if (prototype->call_abi == CALL_X86_STD && platform_target.os == OS_TYPE_WIN32) - { - LLVMSetDLLStorageClass(function, LLVMDLLImportStorageClass); - } - break; - case VISIBLE_PUBLIC: - case VISIBLE_MODULE: - if (decl->is_weak) llvm_set_weak(c, function); - break; - case VISIBLE_LOCAL: - LLVMSetLinkage(function, decl->is_weak ? LLVMLinkerPrivateWeakLinkage : LLVMInternalLinkage); - LLVMSetVisibility(function, LLVMDefaultVisibility); - break;; - } - if (llvm_use_debug(c)) - { - llvm_emit_debug_function(c, decl); - }*/ -} - -TB_DataType tildetype(Type *type) -{ - type = type_lowering(type); - if (type->tb_set) return (TB_DataType) { .raw = type->tb_type }; - TB_DataType tb_type; - switch (type->type_kind) - { - case TYPE_TYPEID: - case TYPE_ANYFAULT: - UNREACHABLE; - case TYPE_FUNC: - TODO - case TYPE_VECTOR: - tb_type = tildetype(type->array.base); - tb_type.width = next_highest_power_of_2(type->array.len); - break; - case TYPE_F32: - tb_type = TB_TYPE_F32; - break; - case TYPE_F64: - tb_type = TB_TYPE_F64; - break; - case TYPE_VOID: - tb_type = TB_TYPE_VOID; - break; - case TYPE_I8: - case TYPE_U8: - tb_type = TB_TYPE_I8; - break; - case TYPE_I16: - case TYPE_U16: - tb_type = TB_TYPE_I16; - break; - case TYPE_I32: - case TYPE_U32: - tb_type = TB_TYPE_I32; - break; - case TYPE_I64: - case TYPE_U64: - tb_type = TB_TYPE_I64; - break; - case TYPE_I128: - case TYPE_U128: - tb_type = (TB_DataType) { { TB_INT, 0, 128 } }; - break; - case TYPE_POINTER: - tb_type = TB_TYPE_PTR; - break; - case TYPE_BOOL: - tb_type = TB_TYPE_BOOL; - break; - case TYPE_ANY: - default: - TODO - } - type->tb_set = 1; - type->tb_type = tb_type.raw; - return tb_type; -} diff --git a/src/compiler/tilde_codegen_value.c b/src/compiler/tilde_codegen_value.c deleted file mode 100644 index 0ac46591c..000000000 --- a/src/compiler/tilde_codegen_value.c +++ /dev/null @@ -1,172 +0,0 @@ -#include "tilde_internal.h" - - -void value_set(TBEValue *value, TB_Reg val, Type *type) -{ - type = type_lowering(type); - assert(val || type == type_void); - value->reg = val; - value->alignment = type_abi_alignment(type); - value->kind = TBE_VALUE; - value->type = type; -} - -void value_set_decl(TildeContext *c, TBEValue *value, Decl *decl) -{ - decl = decl_flatten(decl); - if (decl->is_value) - { - value_set(value, decl->tb_register, decl->type); - return; - } - value_set_decl_address(c, value, decl); -} - - -void value_set_address(TBEValue *value, TB_Reg addr, Type *type, AlignSize alignment) -{ - value->reg = addr; - value->alignment = alignment; - value->kind = TBE_ADDRESS; - value->type = type_lowering(type); -} - -void value_set_address_abi_aligned(TBEValue *value, TB_Reg val, Type *type) -{ - value_set_address(value, val, type, type_abi_alignment(type)); -} - -void value_addr(TildeContext *c, TBEValue *value) -{ - value_fold_optional(c, value); - if (value->kind == TBE_ADDRESS) return; - if (!c->f) - { - TODO - } - else - { - TODO - } -} - -TB_Reg tilde_get_opt_ref(TildeContext *c, Decl *decl) -{ - tilde_get_ref(c, decl); - decl = decl_flatten(decl); - if (decl->decl_kind != DECL_VAR) return TB_NULL_REG; - return decl->var.tb_optional_reg; -} - -TB_Function *tilde_get_function(TildeContext *c, Decl *decl) -{ - assert(decl->decl_kind == DECL_FUNC); - if (decl->tb_symbol && ((TB_Symbol *)decl->tb_symbol)->module == c->module) - { - return decl->tb_symbol; - } - bool is_internal = decl->unit->module == c->code_module && !decl->is_external_visible && !visible_external(decl->visibility); - decl->tb_symbol = tb_function_create(c->module, decl_get_extname(decl), is_internal ? TB_LINKAGE_PRIVATE : TB_LINKAGE_PUBLIC); - tb_function_set_prototype(decl->tb_symbol, tilde_get_func_prototype(c, decl->type->function.prototype)); - return decl->tb_symbol; -} - -TB_Reg tilde_get_ref(TildeContext *c, Decl *decl) -{ - switch (decl->decl_kind) - { - case DECL_VAR: - if (decl_is_local(decl)) - { - return decl->tb_register; - } - if (decl->var.kind == VARDECL_UNWRAPPED) return tilde_get_ref(c, decl->var.alias); - assert(decl->var.kind == VARDECL_GLOBAL || decl->var.kind == VARDECL_CONST); - { - TB_Symbol *symbol = decl->backend_value; - if (symbol->module != c->module || !symbol) - { - TODO - } - return tb_inst_get_symbol_address(c->f, decl->backend_value); - } - case DECL_FUNC: - /* - backend_ref = decl->backend_ref = LLVMAddFunction(c->module, decl_get_extname(decl), llvm_get_type(c, decl->type)); - if (decl->unit->module == c->code_module && !decl->is_external_visible && !visible_external(decl->visibility)) - { - llvm_set_internal_linkage(backend_ref); - } - return backend_ref;*/ - case DECL_DEFINE: - if (decl->define_decl.define_kind != DEFINE_TYPE_GENERIC) return tilde_get_ref(c, decl->define_decl.alias); - UNREACHABLE - case DECL_FAULTVALUE: - /* - if (!decl->backend_ref) - { - llvm_get_typeid(c, declptr(decl->enum_constant.parent)->type); - } - assert(decl->backend_ref); - return decl->backend_ref;*/ - TODO - case DECL_POISONED: - case DECL_ATTRIBUTE: - case DECL_BITSTRUCT: - case DECL_CT_CASE: - case DECL_CT_ELIF: - case DECL_CT_ELSE: - case DECL_CT_IF: - case DECL_CT_SWITCH: - case DECL_CT_ASSERT: - case DECL_DISTINCT: - case DECL_ENUM: - case DECL_ENUM_CONSTANT: - case DECL_FAULT: - case DECL_GENERIC: - case DECL_IMPORT: - case DECL_LABEL: - case DECL_MACRO: - case DECL_STRUCT: - case DECL_TYPEDEF: - case DECL_UNION: - case DECL_DECLARRAY: - case DECL_INITIALIZE: - case DECL_FINALIZE: - case DECL_BODYPARAM: - case DECL_CT_ECHO: - case DECL_CT_INCLUDE: - UNREACHABLE; - } - UNREACHABLE -} - - -void value_set_decl_address(TildeContext *c, TBEValue *value, Decl *decl) -{ - TB_Reg backend_ref = tilde_get_ref(c, decl); - value_set_address(value, backend_ref, decl->type, decl->alignment); - - if ((value->failable = tilde_get_opt_ref(c, decl))) - { - value->kind = TBE_ADDRESS_OPTIONAL; - } -} - -void value_fold_optional(TildeContext *c, TBEValue *value) -{ - if (value->kind == TBE_ADDRESS_OPTIONAL) - { - TODO - //tilde_emit_jump_to_optional_exit(c, tilde_load_natural_alignment(c, type_anyfault, value->optional, "optval")); - value->kind = TBE_ADDRESS; - } -} - -void value_rvalue(TildeContext *c, TBEValue *value) -{ - if (value->kind == TBE_VALUE) return; - value_fold_optional(c, value); - value->reg = tilde_load_value(c, value); - value->kind = TBE_VALUE; -} diff --git a/src/compiler/tilde_internal.h b/src/compiler/tilde_internal.h deleted file mode 100644 index fd68bdac4..000000000 --- a/src/compiler/tilde_internal.h +++ /dev/null @@ -1,201 +0,0 @@ -#pragma once - -#include "codegen_internal.h" - -// Copyright (c) 2022 Christoffer Lerno. All rights reserved. -// Use of this source code is governed by a LGPLv3.0 -// a copy of which can be found in the LICENSE file. - -#undef TB_Reg -#include - - -typedef enum -{ - TBE_VALUE, - TBE_ADDRESS, - TBE_ADDRESS_OPTIONAL, -} TBBackendValueKind; - -typedef struct -{ - TBBackendValueKind kind: 5; - AlignSize alignment; - - Type *type; // Should never be a distinct or canonical type. - - TB_Reg reg; - TB_Reg failable; -} TBEValue; - -typedef struct -{ - Module *code_module; - const char *object_filename; - const char *ir_filename; - const char *asm_filename; - - TB_Function **functions; - TB_Module *module; - TB_FeatureSet features; - - struct - { - const char *name; - FunctionPrototype *prototype; - Type *rtype; - } cur_func; - Decl *curr_func; - TB_Function *f; - TB_Reg opt_var; - TB_Label catch_block; - TBEValue retval; - TB_Reg return_out; - TB_Reg optional_out; - - struct - { - TB_Reg last_ptr; - TB_Reg stack_slot; - CompilationUnit *compile_unit; - } debug; -} TildeContext; - - - - -#define PUSH_OPT() TB_Label _old_catch = c->catch_block; TB_Reg _old_opt_var = c->opt_var -#define POP_OPT() c->catch_block = _old_catch; c->opt_var = _old_opt_var - - -// -- store --- -static inline void tilde_store_internal(TildeContext *c, TB_DataType type, TB_Reg addr, TB_Reg value, AlignSize alignment); -void tilde_store_to_ptr_raw_aligned(TildeContext *c, Type *type, TB_Reg addr, TB_Reg value, AlignSize alignment); -void tilde_store_to_ptr_raw(TildeContext *c, TB_Reg addr, TB_Reg value, Type *type); -void tilde_store_value_raw(TildeContext *c, TBEValue *destination, TB_Reg value); -void tilde_store_to_ptr_aligned(TildeContext *c, TB_Reg destination, TBEValue *value, AlignSize alignment); -void tilde_store_value_aligned(TildeContext *c, TB_Reg destination, TBEValue *value, AlignSize alignment); -void tilde_store(TildeContext *c, TBEValue *dst, TBEValue *value); -void tilde_store_decl_raw(TildeContext *c, Decl *decl, TB_Reg value); -TB_Reg tilde_load_natural_alignment(TildeContext *c, Type *type, TB_Reg pointer); -TB_Reg tilde_load_value_store(TildeContext *c, TBEValue *value); -void tilde_store_zero(TildeContext *c, Type *type, TB_Reg addr, AlignSize alignment); -void tilde_store_value_zero(TildeContext *c, TBEValue *to); -INLINE void tilde_store_to_ptr(TildeContext *c, TB_Reg destination, TBEValue *value); - -// -- load --- -static inline TB_Reg tilde_load(TildeContext *c, TB_DataType type, TB_Reg addr, AlignSize alignment); -TB_Reg tilde_load_abi_alignment(TildeContext *c, Type *type, TB_Reg pointer); -TB_Reg tilde_load_value(TildeContext *c, TBEValue *value); - -// -- value -- -void value_set(TBEValue *value, TB_Reg val, Type *type); -void value_set_address(TBEValue *value, TB_Reg addr, Type *type, AlignSize alignment); -void value_set_address_abi_aligned(TBEValue *value, TB_Reg val, Type *type); -void value_set_decl_address(TildeContext *c, TBEValue *value, Decl *decl); -void value_set_decl(TildeContext *c, TBEValue *value, Decl *decl); -void value_addr(TildeContext *c, TBEValue *value); - -static inline bool value_is_addr(TBEValue *value) { return value->kind == TBE_ADDRESS || value->kind == TBE_ADDRESS_OPTIONAL; } -void value_fold_optional(TildeContext *c, TBEValue *value); -void value_rvalue(TildeContext *c, TBEValue *value); - -TB_Function *tilde_get_function(TildeContext *c, Decl *decl); -TB_Reg tilde_get_ref(TildeContext *c, Decl *decl); -TB_Reg tilde_get_opt_ref(TildeContext *c, Decl *decl); -TB_Reg tilde_get_const_int(TildeContext *c, Type *type, uint64_t i); -TB_Reg tilde_get_const_float(TildeContext *c, Type *type, double d); -TB_Register tilde_get_zero(TildeContext *c, Type *type); - -// -- type --- -TB_DataType tilde_abi_type(AbiType type); -TB_DataType tildetype(Type *type); -TB_Global *tilde_get_typeid(TildeContext *c, Type *type); -TB_DataType tilde_update_prototype_abi(TildeContext *context, FunctionPrototype *prototype, TB_DataType **params); -void tilde_emit_function_decl(TildeContext *c, Decl *decl); - -// -- instructions -- -void tilde_emit_cond_br(TildeContext *c, TBEValue *value, TB_Label then_block, TB_Label else_block); -TB_Reg tilde_emit_lshr_fixed(TildeContext *c, Type *type, TB_Reg reg, int shift); - -// -- stmt --- -void tilde_emit_stmt(TildeContext *c, Ast *ast); -void tilde_emit_return_implicit(TildeContext *c); - -// -- general --- -TB_Register tilde_emit_is_no_error(TildeContext *c, TB_Reg reg); -void tilde_emit_global_initializer(TildeContext *c, Decl *decl); -TB_Reg tilde_emit_alloca(TildeContext *c, Type *type, AlignSize alignment); -void tilde_emit_local_var_alloca(TildeContext *c, Decl *decl); -void tilde_emit_and_set_decl_alloca(TildeContext *c, Decl *decl); -INLINE TB_Linkage tilde_linkage_for_decl(Decl *decl); -void tilde_emit_parameter(TildeContext *c, TB_Reg *args, unsigned *arg_count_ref, ABIArgInfo *info, TBEValue *be_value, Type *type); -INLINE bool tilde_use_debug(TildeContext *context); - - -// -- expr -- -void tilde_emit_expr(TildeContext *c, TBEValue *result, Expr *expr); -TBEValue tilde_emit_assign_expr(TildeContext *c, TBEValue *ref, Expr *expr, TB_Reg optional); -void tilde_emit_cast(TildeContext *c, CastKind cast_kind, Expr *expr, TBEValue *value, Type *to_type, Type *from_type); - -// -- comparisons -- -void tilde_emit_comp(TildeContext *c, TBEValue *result, TBEValue *lhs, TBEValue *rhs, BinaryOp binary_op); -void tilde_emit_int_comp(TildeContext *c, TBEValue *result, TBEValue *lhs, TBEValue *rhs, BinaryOp binary_op); -void tilde_emit_int_comp_zero(TildeContext *c, TBEValue *result, TBEValue *lhs, BinaryOp binary_op); -void tilde_emit_int_comp_raw(TildeContext *c, TBEValue *result, Type *lhs_type, Type *rhs_type, TB_Reg lhs_value, TB_Reg rhs_value, BinaryOp binary_op); - -// -- optional -- -void tilde_emit_jump_to_optional_exit(TildeContext *c, TB_Reg opt_value); -TB_Reg tilde_emit_is_no_opt(TildeContext *c, TB_Reg error_value); - - -// -- jumps --- -bool tilde_emit_goto_if_needed(TildeContext *c, TB_Label jump); -INLINE void tilde_emit_block(TildeContext *c, TB_Label block); - -void tilde_emit_memclear_size_align(TildeContext *c, TB_Register ref, uint64_t size, AlignSize align); - -#define EMIT_LOC(x, y) do { } while(0) - - -static inline void tilde_store_internal(TildeContext *c, TB_DataType type, TB_Reg addr, TB_Reg value, AlignSize alignment) -{ - assert(alignment > 0); - tb_inst_store(c->f, type, addr, value, alignment); -} - -static inline TB_Reg tilde_load(TildeContext *c, TB_DataType type, TB_Reg addr, AlignSize alignment) -{ - assert(alignment > 0); - return tb_inst_load(c->f, type, addr, alignment); -} - -static inline TB_Reg decl_reg(Decl *decl) -{ - if (decl->decl_kind == DECL_VAR && decl->var.kind == VARDECL_UNWRAPPED) return decl_reg(decl->var.alias); - assert(!decl->is_value); - return decl->tb_register; -} - -TB_DataType tilde_get_int_type_of_bytesize(int byte_size); -TB_FunctionPrototype *tilde_get_func_prototype(TildeContext *c, FunctionPrototype *prototype); -INLINE TB_Linkage tilde_linkage_for_decl(Decl *decl) -{ - if (!decl->is_external_visible && decl->visibility == VISIBLE_LOCAL) return TB_LINKAGE_PRIVATE; - return TB_LINKAGE_PUBLIC; -} - -INLINE void tilde_store_to_ptr(TildeContext *c, TB_Reg destination, TBEValue *value) -{ - return tilde_store_to_ptr_aligned(c, destination, value, type_alloca_alignment(value->type)); -} - -INLINE void tilde_emit_block(TildeContext *c, TB_Label block) -{ - tb_inst_set_label(c->f, block); -} - -INLINE bool tilde_use_debug(TildeContext *context) -{ - return false; -} \ No newline at end of file