More work on TB

This commit is contained in:
Christoffer Lerno
2023-01-19 20:32:19 +01:00
parent 1ab304dc64
commit 92507ee388
10 changed files with 1119 additions and 27 deletions

View File

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

View File

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

View File

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

View File

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

View File

@@ -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(&copy);
prototype = &copy;
TB_FunctionPrototype *params_type = NULL;
TB_DataType *params_type = NULL;
tilde_update_prototype_abi(c, prototype, &params_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;
}

View File

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

View File

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

View File

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

View File

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

View File

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