mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
More work on TB
This commit is contained in:
@@ -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--;
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
Reference in New Issue
Block a user