Removing tb codegen info, because it's sure to have code-rotted by now.

This commit is contained in:
Christoffer Lerno
2024-08-08 12:55:40 +02:00
parent 0ef0f62b69
commit 65c2126202
10 changed files with 0 additions and 3975 deletions

View File

@@ -82,7 +82,6 @@ static void usage(void)
PRINTF(" project <subcommand> ... Manipulate or view project files.");
PRINTF("");
PRINTF("Options:");
PRINTF(" --tb - Use Tilde Backend for compilation.");
PRINTF(" --stdlib <dir> - Use this directory as the C3 standard library path.");
PRINTF(" --no-entry - Do not generate (or require) a main function.");
PRINTF(" --libdir <dir> - 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.");

View File

@@ -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(&current));
}
/*
* 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;
}

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

@@ -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(&current));
}
}
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);
}

View File

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

View File

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

View File

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

View File

@@ -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 <tb.h>
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;
}