diff --git a/src/compiler/llvm_codegen_expr.c b/src/compiler/llvm_codegen_expr.c index 59429e081..9a0e19339 100644 --- a/src/compiler/llvm_codegen_expr.c +++ b/src/compiler/llvm_codegen_expr.c @@ -5352,7 +5352,6 @@ static inline void llvm_emit_return_block(GenContext *c, BEValue *be_value, Type } LLVMValueRef old_ret_out = c->return_out; - c->in_block++; LLVMValueRef error_out = c->opt_var; LLVMBasicBlockRef error_block = c->catch_block; @@ -5446,7 +5445,6 @@ DONE: c->return_out = old_ret_out; c->catch_block = error_block; c->opt_var = error_out; - c->in_block--; } diff --git a/src/compiler/llvm_codegen_function.c b/src/compiler/llvm_codegen_function.c index f3ff18323..675f8f11c 100644 --- a/src/compiler/llvm_codegen_function.c +++ b/src/compiler/llvm_codegen_function.c @@ -461,7 +461,6 @@ void llvm_emit_body(GenContext *c, LLVMValueRef function, const char *module_nam LLVMBasicBlockRef entry = LLVMAppendBasicBlockInContext(c->context, c->function, "entry"); c->current_block = entry; c->current_block_is_target = true; - c->in_block = 0; c->builder = LLVMCreateBuilderInContext(c->context); LLVMPositionBuilderAtEnd(c->builder, entry); diff --git a/src/compiler/llvm_codegen_internal.h b/src/compiler/llvm_codegen_internal.h index 538b6a629..1c50f2c2c 100644 --- a/src/compiler/llvm_codegen_internal.h +++ b/src/compiler/llvm_codegen_internal.h @@ -107,7 +107,6 @@ typedef struct GenContext_ LLVMValueRef return_out; LLVMValueRef optional_out; BEValue retval; - int in_block; bool current_block_is_target : 1; LLVMTypeRef type_data_definitions[TYPE_KINDS]; SourceSpan last_emitted_loc; diff --git a/src/compiler/tilde_codegen.c b/src/compiler/tilde_codegen.c index 8862aa430..72cc27bd3 100644 --- a/src/compiler/tilde_codegen.c +++ b/src/compiler/tilde_codegen.c @@ -35,19 +35,356 @@ static TB_Arch arch_to_tilde_arch(ArchType target) 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 = tb_function_create(c->module, decl_get_extname(decl), tilde_linkage_for_decl(decl)); - decl->backend_value = fn; - tb_function_set_prototype(fn, (TB_FunctionPrototype*)tilde_get_func_prototype(c, decl->type->function.prototype)); + TB_Function *fn = decl->tb_symbol; vec_add(c->functions, fn); - c->curr_func = decl; - c->cur_func.prototype = decl->type->function.prototype; - c->cur_func.rtype = decl->type->function.prototype->rtype; - c->cur_func.name = decl->name; - c->f = fn; - if (decl->func_decl.body) tilde_emit_stmt(c, astptr(decl->func_decl.body)); + 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) @@ -62,13 +399,94 @@ static TildeContext *tilde_gen_module(Module *module, TB_FeatureSet *feature_set FOREACH_BEGIN(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_BEGIN(Decl *initializer, unit->xxlizers) + REMINDER("Add xxlizer"); + //tilde_emit_xxlizer(gen_context, initializer); + FOREACH_END(); + + FOREACH_BEGIN(Decl *method, unit->methods) + tilde_emit_function_decl(context, method); + FOREACH_END(); + + FOREACH_BEGIN(Decl *type_decl, unit->types) + tilde_emit_type_decls(context, type_decl); + FOREACH_END(); + + FOREACH_BEGIN(Decl *enum_decl, unit->enums) + tilde_emit_type_decls(context, enum_decl); + FOREACH_END(); + + FOREACH_BEGIN(Decl *func, unit->functions) + if (func->func_decl.attr_test) + { + if (!active_target.testing) continue; + vec_add(module->tests, func); + } + tilde_emit_function_decl(context, func); + FOREACH_END(); + + if (active_target.type != TARGET_TYPE_TEST && unit->main_function && unit->main_function->is_synthetic) + { + tilde_emit_function_decl(context, unit->main_function); + } + + FOREACH_END(); + + FOREACH_BEGIN(CompilationUnit *unit, module->units) + + /*--- TODO + context->debug.compile_unit = unit->llvm.debug_compile_unit; + context->debug.file = unit->llvm.debug_file; +*/ + FOREACH_BEGIN(Decl *var, unit->vars) + tilde_get_ref(context, var); + FOREACH_END(); + + FOREACH_BEGIN(Decl *var, unit->vars) + // TODO tilde_emit_global_variable_init(context, var); + FOREACH_END(); + FOREACH_BEGIN(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 && unit->main_function && unit->main_function->is_synthetic) + { + tilde_emit_function_body(context, unit->main_function); + } + + FOREACH_BEGIN(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; } @@ -113,10 +531,16 @@ TB_DataType tilde_get_int_type_of_bytesize(int byte_size) 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"); } diff --git a/src/compiler/tilde_codegen_expr.c b/src/compiler/tilde_codegen_expr.c index 251f912e8..6880bba1b 100644 --- a/src/compiler/tilde_codegen_expr.c +++ b/src/compiler/tilde_codegen_expr.c @@ -338,6 +338,245 @@ void tilde_emit_parameter(TildeContext *c, TB_Reg *args, unsigned *arg_count_ref } } +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_anyerr); + } + + 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) @@ -356,10 +595,9 @@ static void tilde_emit_call_expr(TildeContext *c, TBEValue *result_value, Expr * type_abi_alignment(type_uint)); }*/ - TODO - /* TB_FunctionPrototype *func_type; - TB_Function *func; + TB_Function *func = NULL; + TB_Reg func_ptr = TB_NULL_REG; TBEValue temp_value; bool always_inline = false; @@ -381,7 +619,7 @@ static void tilde_emit_call_expr(TildeContext *c, TBEValue *result_value, Expr * tilde_emit_expr(c, &func_value, function); // 1d. Load it as a value - func = tilde_load_value(c, &func_value); + func_ptr = tilde_load_value(c, &func_value); // 1e. Calculate the function type func_type = tilde_get_func_prototype(c, prototype); @@ -437,7 +675,7 @@ static void tilde_emit_call_expr(TildeContext *c, TBEValue *result_value, Expr * copy.abi_args = NULL; c_abi_func_create(©); prototype = © - TB_FunctionPrototype *params_type = NULL; + TB_DataType *params_type = NULL; tilde_update_prototype_abi(c, prototype, ¶ms_type); } } @@ -569,8 +807,7 @@ static void tilde_emit_call_expr(TildeContext *c, TBEValue *result_value, Expr * { inline_flag = expr->call_expr.attr_force_inline || always_inline ? 1 : 0; } - TODO - // tilde_emit_raw_call(c, result_value, prototype, func_type, func, arg_values, arg_count, inline_flag, error_var, sret_return, &synthetic_return_param); + 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) @@ -581,7 +818,7 @@ static void tilde_emit_call_expr(TildeContext *c, TBEValue *result_value, Expr * // 17i. The simple case here is where there is a normal return. // In this case be_value already holds the result - return;*/ + return; } TBEValue tilde_emit_assign_expr(TildeContext *c, TBEValue *ref, Expr *expr, TB_Reg optional) @@ -1201,6 +1438,10 @@ void tilde_emit_expr(TildeContext *c, TBEValue *value, Expr *expr) 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; } diff --git a/src/compiler/tilde_codegen_stmt.c b/src/compiler/tilde_codegen_stmt.c index dbdb6d115..b8194ed5b 100644 --- a/src/compiler/tilde_codegen_stmt.c +++ b/src/compiler/tilde_codegen_stmt.c @@ -158,7 +158,7 @@ static void tilde_emit_return_abi(TildeContext *c, TBEValue *return_value, TBEVa } } -static void tilde_emit_return_implicit(TildeContext *c) +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) diff --git a/src/compiler/tilde_codegen_storeload.c b/src/compiler/tilde_codegen_storeload.c index 500163eaa..9dbfa8c27 100644 --- a/src/compiler/tilde_codegen_storeload.c +++ b/src/compiler/tilde_codegen_storeload.c @@ -151,3 +151,10 @@ void tilde_store_value_zero(TildeContext *c, TBEValue *to) 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 index a89a47ac2..0dd0c4d9f 100644 --- a/src/compiler/tilde_codegen_type.c +++ b/src/compiler/tilde_codegen_type.c @@ -27,23 +27,419 @@ 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), + tildetype(prototype->abi_ret_type), tilde_get_debug_type(prototype->rtype), - vec_size(prototype->param_types), + actual_arg_count, prototype->variadic == VARIADIC_RAW); - FOREACH_BEGIN(AbiType *param, prototype->abi_args) - tb_prototype_add_param_named(proto, tildetype(param->type), "foek", NULL); + 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_ANYERR: + 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_decl.base_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); diff --git a/src/compiler/tilde_codegen_value.c b/src/compiler/tilde_codegen_value.c index f46a92e37..5fb387ef5 100644 --- a/src/compiler/tilde_codegen_value.c +++ b/src/compiler/tilde_codegen_value.c @@ -58,6 +58,19 @@ TB_Reg tilde_get_opt_ref(TildeContext *c, Decl *decl) 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) diff --git a/src/compiler/tilde_internal.h b/src/compiler/tilde_internal.h index 9b3205a25..fd68bdac4 100644 --- a/src/compiler/tilde_internal.h +++ b/src/compiler/tilde_internal.h @@ -52,15 +52,17 @@ typedef struct TBEValue retval; TB_Reg return_out; TB_Reg optional_out; + struct { TB_Reg last_ptr; TB_Reg stack_slot; + CompilationUnit *compile_unit; } debug; } TildeContext; -TB_DataType tildetype(Type *type); + #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 @@ -98,6 +100,7 @@ static inline bool value_is_addr(TBEValue *value) { return value->kind == TBE_AD 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); @@ -105,6 +108,11 @@ 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); @@ -112,6 +120,7 @@ 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); @@ -121,6 +130,7 @@ 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 -- @@ -184,3 +194,8 @@ 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