From 6035cb460021060eeed1e2479a520b11b6832eec Mon Sep 17 00:00:00 2001 From: Christoffer Lerno Date: Sat, 21 May 2022 19:57:11 +0200 Subject: [PATCH] Update TB --- src/compiler/tb_codegen.c | 119 ++-- src/compiler/tilde_codegen_expr.c | 141 +++-- src/compiler/tilde_codegen_stmt.c | 38 +- src/compiler/tilde_codegen_value.c | 4 +- src/compiler/tilde_internal.h | 3 +- tb/tb.h | 945 +++++++++++++++++++++++------ 6 files changed, 902 insertions(+), 348 deletions(-) diff --git a/src/compiler/tb_codegen.c b/src/compiler/tb_codegen.c index 61359e35d..269b6c25d 100644 --- a/src/compiler/tb_codegen.c +++ b/src/compiler/tb_codegen.c @@ -4,6 +4,10 @@ static void tinybackend_emit_expr(TbContext *c, TBEValue *value, Expr *expr); static inline void tilde_emit_block(TbContext *c, TB_Label label); +static inline void tinybackend_emit_exprid(TbContext *c, TBEValue *value, ExprId id) +{ + tinybackend_emit_expr(c, value, exprptr(id)); +} static TB_Register tilde_value_rvalue_get(TbContext *c, TBEValue *value); static void TBE_VALUE_set_reg(TBEValue *value, TB_Register reg, Type *type); @@ -36,8 +40,8 @@ TB_DataType tbtype(Type *type) uint8_t elements = 1; if (type->type_kind == TYPE_VECTOR) { - elements = (uint8_t)type->vector.len; - switch (type->vector.base->type_kind) + elements = (uint8_t)type->array.len; + switch (type->array.base->type_kind) { case TYPE_U8: case TYPE_I8: @@ -111,6 +115,23 @@ static TB_DataType tilde_get_abi_type(AbiType 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 4: + return TB_TYPE_I32; + case 8: + return TB_TYPE_I64; + default: + FATAL_ERROR("Unsupported size"); + } + +} static void param_expand(TB_DataType **params_ref, Type *type) { switch (type->type_kind) @@ -192,24 +213,24 @@ static inline void add_func_type_param(Type *param_type, ABIArgInfo *arg_info, T case ABI_ARG_DIRECT: vec_add(*params, tbtype(param_type)); break; + case ABI_ARG_DIRECT_SPLIT_STRUCT: + { + // Normal direct. + TB_DataType coerce_type = tbtype(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: + vec_add(*params, tilde_get_int_type_of_bytesize(type_size(param_type))); + break; case ABI_ARG_DIRECT_COERCE: { // Normal direct. - if (!abi_type_is_valid(arg_info->direct_coerce.type)) - { - vec_add(*params, tbtype(param_type)); - break; - } - TB_DataType coerce_type = tilde_get_abi_type(arg_info->direct_coerce.type); - if (!abi_info_should_flatten(arg_info)) - { - vec_add(*params, coerce_type); - break; - } - for (unsigned idx = 0; idx < arg_info->direct_coerce.elements; idx++) - { - vec_add(*params, coerce_type); - } + TB_DataType coerce_type = tbtype(arg_info->direct_coerce_type); + vec_add(*params, coerce_type); break; } case ABI_ARG_DIRECT_PAIR: @@ -268,13 +289,13 @@ static TB_FunctionPrototype *tilde_get_function_type(TB_Module *module, Function case ABI_ARG_DIRECT: return_type = tbtype(call_return_type); break; + case ABI_ARG_DIRECT_SPLIT_STRUCT: + UNREACHABLE + case ABI_ARG_DIRECT_COERCE_INT: + return_type = tilde_get_int_type_of_bytesize(type_size(call_return_type)); + break; case ABI_ARG_DIRECT_COERCE: - assert(!abi_info_should_flatten(ret_arg_info)); - - TODO - /* - return_type = llvm_get_coerce_type(context, ret_arg_info); - if (!return_type) return_type = llvm_get_type(context, call_return_type);*/ + return_type = tbtype(ret_arg_info->direct_coerce_type); break; } @@ -508,12 +529,12 @@ void tinybackend_emit_binary(TbContext *c, TBEValue *TBE_VALUE, Expr *expr, TBEV } else { - tinybackend_emit_expr(c, &lhs, expr->binary_expr.left); + tinybackend_emit_exprid(c, &lhs, expr->binary_expr.left); } value_rvalue(c, &lhs); TBEValue rhs; - tinybackend_emit_expr(c, &rhs, expr->binary_expr.right); + tinybackend_emit_exprid(c, &rhs, expr->binary_expr.right); value_rvalue(c, &rhs); /*EMIT_LOC(c, expr); @@ -525,7 +546,7 @@ void tinybackend_emit_binary(TbContext *c, TBEValue *TBE_VALUE, Expr *expr, TBEV Type *lhs_type = lhs.type; Type *rhs_type = rhs.type; - Type *vector_type = lhs_type->type_kind == TYPE_VECTOR ? lhs_type->vector.base : NULL; + Type *vector_type = lhs_type->type_kind == TYPE_VECTOR ? lhs_type->array.base : NULL; bool is_float = type_is_float(lhs_type) || (vector_type && type_is_float(vector_type)); TB_Register val = TB_NULL_REG; @@ -638,6 +659,9 @@ void tinybackend_emit_binary(TbContext *c, TBEValue *TBE_VALUE, Expr *expr, TBEV case BINARYOP_SHR_ASSIGN: case BINARYOP_SHL_ASSIGN: UNREACHABLE + case BINARYOP_OR_ERR: + TODO + break; } assert(val); TBE_VALUE_set(TBE_VALUE, val, expr->type); @@ -658,7 +682,7 @@ static void tinybackend_emit_binary_expr(TbContext *c, TBEValue *TBE_VALUE, Expr BinaryOp base_op = binaryop_assign_base_op(binary_op); assert(base_op != BINARYOP_ERROR); TBEValue addr; - tinybackend_emit_expr(c, &addr, expr->binary_expr.left); + tinybackend_emit_exprid(c, &addr, expr->binary_expr.left); value_rvalue(c, &addr); tinybackend_emit_binary(c, TBE_VALUE, expr, &addr, base_op); tinybackend_store_value(c, &addr, TBE_VALUE); @@ -667,11 +691,10 @@ static void tinybackend_emit_binary_expr(TbContext *c, TBEValue *TBE_VALUE, Expr printf("B\n"); if (binary_op == BINARYOP_ASSIGN) { - Expr *left = expr->binary_expr.left; - tinybackend_emit_expr(c, TBE_VALUE, expr->binary_expr.left); + tinybackend_emit_exprid(c, TBE_VALUE, expr->binary_expr.left); assert(tinybackend_value_is_addr(TBE_VALUE)); - *TBE_VALUE = tilde_emit_assign_expr(c, TBE_VALUE, expr->binary_expr.right, TB_NULL_REG /* failable_ref */); + *TBE_VALUE = tilde_emit_assign_expr(c, TBE_VALUE, exprptr(expr->binary_expr.right), TB_NULL_REG /* failable_ref */); return; } @@ -694,7 +717,6 @@ static void tinybackend_emit_expr(TbContext *c, TBEValue *value, Expr *expr) tinybackend_emit_binary_expr(c, value, expr); return; case EXPR_IDENTIFIER: - case EXPR_CONST_IDENTIFIER: value_set_decl(value, expr->identifier_expr.decl); return; default: @@ -724,13 +746,15 @@ static TB_Register tilde_emit_local_decl(TbContext *c, Decl *decl) if (IS_FAILABLE(decl)) { scratch_buffer_clear(); - scratch_buffer_append(decl->external_name); + scratch_buffer_append(decl_get_extname(decl)); scratch_buffer_append(".f"); TB_InitializerID initializer = tb_initializer_create(c->module, type_size(type_anyerr), type_alloca_alignment(type_anyerr), 1); - decl->var.tb_failable_reg = tb_global_create(c->module, initializer, scratch_buffer_to_string(), TB_LINKAGE_PRIVATE); + decl->var.tb_failable_reg = tb_global_create(c->module, scratch_buffer_to_string(), TB_STORAGE_DATA, TB_LINKAGE_PRIVATE); + tb_global_set_initializer(c->module, decl->var.tb_failable_reg, initializer); } TB_InitializerID static_initializer = tb_initializer_create(c->module, type_size(var_type), type_alloca_alignment(var_type), 1); - decl->tb_register = tb_global_create(c->module, static_initializer, "tempglobal", TB_LINKAGE_PRIVATE); + decl->tb_register = tb_global_create(c->module, "tempglobal", TB_STORAGE_DATA, TB_LINKAGE_PRIVATE); + tb_global_set_initializer(c->module, decl->tb_register, static_initializer); tilde_emit_global_initializer(c, decl); return decl->tb_register; } @@ -750,14 +774,9 @@ static TB_Register tilde_emit_local_decl(TbContext *c, Decl *decl) value_set_decl(&value, decl); if (init) { - // If we don't have undef, then make an assign. - if (init->expr_kind != EXPR_UNDEF) - { - tilde_emit_assign_expr(c, &value, decl->var.init_expr, decl->var.tb_failable_reg); - } - // TODO trap on undef in debug mode. + tilde_emit_assign_expr(c, &value, decl->var.init_expr, decl->var.tb_failable_reg); } - else + else if (!decl->var.no_init) { if (decl->var.tb_failable_reg) { @@ -774,15 +793,15 @@ static TB_Register tilde_emit_local_decl(TbContext *c, Decl *decl) static void tilde_emit_function_body(TbContext *c, Decl *decl) { - printf("Function: %s\n", decl->external_name); + printf("Function: %s\n", decl_get_extname(decl)); c->current_func_decl = decl; TB_FunctionPrototype *prototype = tilde_get_function_type(c->module, decl->type->func.prototype); - TB_Function *function = tb_prototype_build(c->module, prototype, decl->external_name, TB_LINKAGE_PUBLIC); + TB_Function *function = tb_prototype_build(c->module, prototype, decl_get_extname(decl), TB_LINKAGE_PUBLIC); c->f = function; - AstId current = decl->func_decl.body->compound_stmt.first_stmt; + AstId current = astptr(decl->func_decl.body)->compound_stmt.first_stmt; while (current) { tilde_emit_stmt(c, ast_next(¤t)); @@ -816,7 +835,7 @@ static void tilde_emit_function_body(TbContext *c, Decl *decl) context->function = prev_function; */ - tb_function_print(c->f, stdout); +// tb_function_print(c->f, stdout); // TODO } @@ -861,10 +880,13 @@ void *tinybackend_gen(Module *module) TbContext *c = ccalloc(sizeof(TbContext), 1); c->code_module = module; - c->module = tb_module_create(tilde_get_arch(), tilde_get_system(), &c->features); + c->module = tb_module_create(tilde_get_arch(), tilde_get_system(), TB_DEBUGFMT_NONE, &c->features); const char *result = module_create_object_file_name(module); - c->object_filename = strformat("%s%s", result, get_object_extension()); + + scratch_buffer_clear(); + scratch_buffer_printf("%s%s", result, get_object_extension()); + c->object_filename = scratch_buffer_copy(); printf("Module: %.*s\n", module->name->len, module->name->module); // Forward decls @@ -887,7 +909,8 @@ void *tinybackend_gen(Module *module) } } - tb_module_compile(c->module); +// tb_module_compile(c->module); +TODO return c; } diff --git a/src/compiler/tilde_codegen_expr.c b/src/compiler/tilde_codegen_expr.c index 00c64d7b2..429c7befa 100644 --- a/src/compiler/tilde_codegen_expr.c +++ b/src/compiler/tilde_codegen_expr.c @@ -95,6 +95,25 @@ static void tilde_emit_parameter(TbContext *c, TB_Reg **args, ABIArgInfo *info, case ABI_ARG_IGNORE: // Skip. return; + case ABI_ARG_DIRECT_SPLIT_STRUCT: + { + TODO + /* + LLVMTypeRef coerce_type = llvm_get_coerce_type(c, info); + assert(coerce_type && coerce_type != llvm_get_type(c, type)); + AlignSize target_alignment = llvm_abi_alignment(c, coerce_type); + + AlignSize alignment; + LLVMValueRef cast = llvm_emit_coerce_alignment(c, be_value, coerce_type, target_alignment, &alignment); + LLVMTypeRef element = llvm_get_type(c, info->direct_struct_expand.type); + for (unsigned idx = 0; idx < info->direct_struct_expand.elements; idx++) + { + AlignSize load_align; + LLVMValueRef element_ptr = llvm_emit_struct_gep_raw(c, cast, coerce_type, idx, alignment, &load_align); + vec_add(*args, llvm_load(c, element, element_ptr, load_align, "")); + } + return;*/ + } case ABI_ARG_INDIRECT: { // If we want we could optimize for structs by doing it by reference here. @@ -109,40 +128,31 @@ static void tilde_emit_parameter(TbContext *c, TB_Reg **args, ABIArgInfo *info, return; case ABI_ARG_DIRECT_COERCE: { - if (!abi_type_is_type(info->direct_coerce.type)) + TB_DataType coerce_type = tbtype(info->direct_coerce_type); + if (coerce_type.type == tbtype(type).type) { vec_add(*args, tilde_load_value(c, be_value)); + return; } TODO - vec_add(*args, tilde_load_value(c, be_value)); - return; - /* - LLVMTypeRef coerce_type = llvm_get_coerce_type(c, info); - if (!coerce_type || coerce_type == llvm_get_type(c, type)) + //vec_add(*args, llvm_emit_coerce(c, coerce_type, be_value, type)); + //return; + } + case ABI_ARG_DIRECT_COERCE_INT: + { + TB_DataType coerce_type = tilde_get_int_type_of_bytesize(type_size(type)); + if (coerce_type.type == tbtype(type).type) { - vec_add(*args, llvm_load_value_store(c, be_value)); + vec_add(*args, tilde_load_value(c, be_value)); return; } - if (!abi_info_should_flatten(info)) - { - vec_add(*args, llvm_emit_coerce(c, coerce_type, be_value, type)); - return; - } - AlignSize target_alignment = llvm_abi_alignment(c, coerce_type); - - AlignSize alignment; - LLVMValueRef cast = llvm_emit_coerce_alignment(c, be_value, coerce_type, target_alignment, &alignment); - LLVMTypeRef element = llvm_abi_type(c, info->direct_coerce.type); - for (unsigned idx = 0; idx < info->direct_coerce.elements; idx++) - { - AlignSize load_align; - LLVMValueRef element_ptr = llvm_emit_struct_gep_raw(c, cast, coerce_type, idx, alignment, &load_align); - vec_add(*args, llvm_load(c, element, element_ptr, load_align, "")); - }*/ - return; + TODO + //vec_add(*args, llvm_emit_coerce(c, coerce_type, be_value, type)); + //return; } case ABI_ARG_DIRECT_PAIR: { + TODO /* llvm_value_addr(c, be_value); REMINDER("Handle invalid alignment"); @@ -153,11 +163,7 @@ static void tilde_emit_parameter(TbContext *c, TB_Reg **args, ABIArgInfo *info, LLVMTypeRef struct_type = llvm_get_coerce_type(c, info); AlignSize struct_align; - LLVMValueRef cast = llvm_emit_coerce_alignment(c, - be_value, - struct_type, - llvm_abi_alignment(c, struct_type), - &struct_align); + LLVMValueRef cast = llvm_emit_coerce_alignment(c, be_value, struct_type, llvm_abi_alignment(c, struct_type), &struct_align); // Get the lo value. AlignSize alignment; @@ -170,50 +176,36 @@ static void tilde_emit_parameter(TbContext *c, TB_Reg **args, ABIArgInfo *info, } case ABI_ARG_EXPAND_COERCE: { - // Move this to an address (if needed) - value_addr(c, be_value); /* + // Create the expand type: LLVMTypeRef coerce_type = llvm_get_coerce_type(c, info); - AlignSize alignment; - LLVMValueRef temp = llvm_emit_coerce_alignment(c, - be_value, - coerce_type, - llvm_abi_alignment(c, coerce_type), - &alignment); + LLVMValueRef temp = LLVMBuildBitCast(c->builder, decl->backend_ref, LLVMPointerType(coerce_type, 0), "coerce"); + llvm_emit_and_set_decl_alloca(c, decl); - AlignSize align; - LLVMValueRef gep_first = llvm_emit_struct_gep_raw(c, - temp, - coerce_type, - info->coerce_expand.lo_index, - alignment, - &align); - vec_add(*args, llvm_load(c, llvm_abi_type(c, info->coerce_expand.lo), gep_first, align, "")); + 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(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, - &align); - vec_add(*args, llvm_load(c, llvm_abi_type(c, info->coerce_expand.hi), gep_second, align, "")); - }*/ - return; - } - case ABI_ARG_EXPAND: - { - // Move this to an address (if needed) - value_addr(c, be_value); - TODO - /* - llvm_expand_type_to_args(c, type, be_value->value, args, be_value->alignment); - // Expand the padding here. - if (info->expand.padding_type) + LLVMValueRef gep_second = llvm_emit_struct_gep_raw(c, temp, coerce_type, info->coerce_expand.hi_index, alignment, &element_align); + llvm_store(c, gep_second, llvm_get_next_param(c, index), element_align); + } + break;*/ + case ABI_ARG_EXPAND: { - vec_add(*args, LLVMGetUndef(llvm_get_type(c, info->expand.padding_type))); - }*/ - return; + TODO + /* + // Move this to an address (if needed) + llvm_value_addr(c, be_value); + llvm_expand_type_to_args(c, type, be_value->value, args, be_value->alignment); + // Expand the padding here. + if (info->expand.padding_type) + { + vec_add(*args, LLVMGetUndef(llvm_get_type(c, info->expand.padding_type))); + } + return;*/ + } } } @@ -237,7 +229,7 @@ void tilde_emit_call_expr(TbContext *c, TBEValue *result_value, Expr *expr) // 1. Call through a pointer. if (expr->call_expr.is_pointer_call) { - Expr *function = expr->call_expr.function; + Expr *function = exprptr(expr->call_expr.function); // 1a. Find the pointee type for the function pointer: Type *type = function->type->canonical->pointer; @@ -247,7 +239,7 @@ void tilde_emit_call_expr(TbContext *c, TBEValue *result_value, Expr *expr) // 1c. Evaluate the pointer expression. TBEValue func_value; - tilde_emit_expr(c, &func_value, expr->call_expr.function); + tilde_emit_expr(c, &func_value, function); // 1d. Load it as a value func = tilde_load_value(c, &func_value); @@ -259,7 +251,7 @@ void tilde_emit_call_expr(TbContext *c, TBEValue *result_value, Expr *expr) { // 2a. Get the function declaration - Decl *function_decl = expr->call_expr.func_ref; + Decl *function_decl = declptr(expr->call_expr.func_ref); always_inline = function_decl->func_decl.attr_inline; // 2b. Set signature, function and function type @@ -269,6 +261,7 @@ void tilde_emit_call_expr(TbContext *c, TBEValue *result_value, Expr *expr) func_type = tbtype(function_decl->type); } + (void)func_type; TB_Reg *values = NULL; Type **params = prototype->params; ABIArgInfo **abi_args = prototype->abi_args; @@ -308,7 +301,9 @@ void tilde_emit_call_expr(TbContext *c, TBEValue *result_value, Expr *expr) case ABI_ARG_DIRECT_COERCE: case ABI_ARG_DIRECT: case ABI_ARG_EXPAND_COERCE: - break; + case ABI_ARG_DIRECT_COERCE_INT: + case ABI_ARG_DIRECT_SPLIT_STRUCT: + TODO } @@ -424,13 +419,13 @@ void tilde_emit_call_expr(TbContext *c, TBEValue *result_value, Expr *expr) { // LLVMSetInstructionCallConv(call_value, llvm_call_convention_from_call(prototype->call_abi, platform_target.arch, platform_target.os)); } - if (expr->call_expr.force_noinline) + if (expr->call_expr.attr_force_noinline) { // llvm_attribute_add_call(c, call_value, attribute_id.noinline, -1, 0); } else { - if (expr->call_expr.force_inline || always_inline) + if (expr->call_expr.attr_force_inline || always_inline) { // llvm_attribute_add_call(c, call_value, attribute_id.alwaysinline, -1, 0); } diff --git a/src/compiler/tilde_codegen_stmt.c b/src/compiler/tilde_codegen_stmt.c index 1e251c46b..9336d6adb 100644 --- a/src/compiler/tilde_codegen_stmt.c +++ b/src/compiler/tilde_codegen_stmt.c @@ -14,12 +14,11 @@ void tilde_emit_compound_stmt(TbContext *context, Ast *ast) { tilde_emit_stmt(context, ast_next(¤t)); } - tilde_emit_defer(context, ast->compound_stmt.defer_list.start, ast->compound_stmt.defer_list.end); } static void llvm_emit_ct_compound_stmt(TbContext *context, Ast *ast) { - assert(ast->ast_kind == AST_CT_COMPOUND_STMT); + assert(ast->ast_kind == AST_COMPOUND_STMT); AstId current = ast->compound_stmt.first_stmt; while (current) { @@ -39,13 +38,15 @@ TB_Reg tilde_emit_local_decl(TbContext *c, Decl *decl) if (IS_FAILABLE(decl)) { scratch_buffer_clear(); - scratch_buffer_append(decl->external_name); + scratch_buffer_append(decl_get_extname(decl)); scratch_buffer_append(".f"); TB_InitializerID initializer = tb_initializer_create(c->module, type_size(type_anyerr), type_alloca_alignment(type_anyerr), 1); - decl->var.tb_failable_reg = tb_global_create(c->module, initializer, scratch_buffer_to_string(), TB_LINKAGE_PRIVATE); + decl->var.tb_failable_reg = tb_global_create(c->module, scratch_buffer_to_string(), TB_STORAGE_DATA, TB_LINKAGE_PRIVATE); + tb_global_set_initializer(c->module, decl->var.tb_failable_reg, initializer); } + decl->tb_register = tb_global_create(c->module, decl_get_extname(decl), TB_STORAGE_DATA, TB_LINKAGE_PRIVATE); TB_InitializerID static_initializer = tb_initializer_create(c->module, type_size(var_type), type_alloca_alignment(var_type), 1); - decl->tb_register = tb_global_create(c->module, static_initializer, "tempglobal", TB_LINKAGE_PRIVATE); + tb_global_set_initializer(c->module, decl->tb_register, static_initializer); tilde_emit_global_initializer(c, decl); return decl->tb_register; } @@ -65,14 +66,9 @@ TB_Reg tilde_emit_local_decl(TbContext *c, Decl *decl) value_set_decl(&value, decl); if (init) { - // If we don't have undef, then make an assign. - if (init->expr_kind != EXPR_UNDEF) - { - tilde_emit_assign_expr(c, &value, decl->var.init_expr, decl->var.tb_failable_reg); - } - // TODO trap on undef in debug mode. + tilde_emit_assign_expr(c, &value, decl->var.init_expr, decl->var.tb_failable_reg); } - else + else if (!decl->var.no_init) { if (decl->var.tb_failable_reg) { @@ -84,24 +80,6 @@ TB_Reg tilde_emit_local_decl(TbContext *c, Decl *decl) } -void tilde_emit_defer(TbContext *c, AstId defer_start, AstId defer_end) -{ - if (defer_start == defer_end) return; - AstId defer = defer_start; - while (defer && defer != defer_end) - { - Ast *def = astptr(defer); - TB_Label exit = tb_inst_new_label_id(c->f); - Ast *body = def->defer_stmt.body; - def->defer_stmt.codegen.exit_val = exit; - tilde_emit_stmt(c, body); - tb_inst_goto(c->f, exit); - tb_inst_label(c->f, exit); - defer = def->defer_stmt.prev_defer; - } -} - - void tilde_emit_stmt(TbContext *c, Ast *ast) { diff --git a/src/compiler/tilde_codegen_value.c b/src/compiler/tilde_codegen_value.c index ff835fbc5..74a24d488 100644 --- a/src/compiler/tilde_codegen_value.c +++ b/src/compiler/tilde_codegen_value.c @@ -34,9 +34,11 @@ void value_addr(TbContext *c, TBEValue *value) TODO // TB_Register val = value_rvalue_get(c, value); // TODO check whether new names must be added + TB_Register val = tb_global_create(c->module, ".taddr", TB_STORAGE_DATA, TB_LINKAGE_PRIVATE); TB_InitializerID initializer_id = tb_initializer_create(c->module, type_size(value->type), type_alloca_alignment(value->type), 0); - tb_global_create(c->module, initializer_id, ".taddr", TB_LINKAGE_PRIVATE); + tb_global_set_initializer(c->module, val, initializer_id); + TODO // TODO set linkage /* llvm_set_private_linkage(ref); diff --git a/src/compiler/tilde_internal.h b/src/compiler/tilde_internal.h index e41887561..d38bd6c17 100644 --- a/src/compiler/tilde_internal.h +++ b/src/compiler/tilde_internal.h @@ -90,7 +90,6 @@ TB_Reg tilde_emit_alloca(TbContext *c, Type *type); // -- stmt --- void tilde_emit_stmt(TbContext *c, Ast *ast); -void tilde_emit_defer(TbContext *c, AstId defer_start, AstId defer_end); // -- general --- TB_Register tilde_emit_is_no_error(TbContext *c, TB_Reg reg); @@ -124,4 +123,6 @@ static inline TB_Reg decl_reg(Decl *decl) return decl->tb_register; } +TB_DataType tilde_get_int_type_of_bytesize(int byte_size); + #endif // TB_BACKEND \ No newline at end of file diff --git a/tb/tb.h b/tb/tb.h index 4f77942f8..54a58cddb 100644 --- a/tb/tb.h +++ b/tb/tb.h @@ -16,19 +16,19 @@ extern "C" { #endif - // Windows likes it's secure functions, i kinda do too - // but only sometimes and this isn't one of them -#ifndef _CRT_SECURE_NO_WARNINGS +// Windows likes it's secure functions, i kinda do too +// but only sometimes and this isn't one of them +#if defined(_WIN32) && !defined(_CRT_SECURE_NO_WARNINGS) #define _CRT_SECURE_NO_WARNINGS #endif -#include #include +#include +#include #include +#include #include #include -#include -#include // https://semver.org/ #define TB_VERSION_MAJOR 0 @@ -51,7 +51,7 @@ extern "C" { #define TB_API extern #define TB_HOST_UNKNOWN 0 -#define TB_HOST_X86_64 1 +#define TB_HOST_X86_64 1 // If on, the labels aren't marked in the object file // might save on performance at the cost of some assembly @@ -64,10 +64,7 @@ extern "C" { #define TB_HOST_ARCH TB_HOST_UNKNOWN #endif -#define TB_NULL_REG ((TB_Register)0) -#define TB_REG_MAX ((TB_Register)INT_MAX) - -typedef enum TB_ArithmaticBehavior { +typedef enum { // No overflow will assume the value does not // overflow and if it does this can be considered // undefined behavior with unknown consequences. @@ -90,12 +87,24 @@ typedef enum TB_ArithmaticBehavior { TB_SATURATED_SIGNED } TB_ArithmaticBehavior; -typedef enum TB_Arch { +typedef enum { + TB_DEBUGFMT_NONE, + + TB_DEBUGFMT_DWARF, + TB_DEBUGFMT_CODEVIEW, + + TB_DEBUGFMT_COLINPILLED +} TB_DebugFormat; + +typedef enum { + TB_ARCH_UNKNOWN, + TB_ARCH_X86_64, + // unsupported but planned TB_ARCH_AARCH64 } TB_Arch; -typedef enum TB_System { +typedef enum { TB_SYSTEM_WINDOWS, TB_SYSTEM_LINUX, @@ -104,73 +113,11 @@ typedef enum TB_System { TB_SYSTEM_ANDROID } TB_System; -typedef enum TB_CallingConv { +typedef enum { TB_CDECL, TB_STDCALL } TB_CallingConv; -typedef enum TB_BranchHint { - TB_BRANCH_HINT_NONE, - TB_BRANCH_HINT_LIKELY, - TB_BRANCH_HINT_UNLIKELY -} TB_BranchHint; - -typedef enum TB_Linkage { - TB_LINKAGE_PUBLIC, - TB_LINKAGE_PRIVATE -} TB_Linkage; - -typedef enum TB_MemoryOrder { - TB_MEM_ORDER_RELAXED, - TB_MEM_ORDER_CONSUME, - TB_MEM_ORDER_ACQUIRE, - TB_MEM_ORDER_RELEASE, - TB_MEM_ORDER_ACQ_REL, - TB_MEM_ORDER_SEQ_CST, - } TB_MemoryOrder; - -typedef enum TB_OptLevel { - // no optimizer run - TB_OPT_O0, - - // run optimizer with all optimizations - TB_OPT_O1, - - // same as O1 but favors size, will aggresively deduplicate - // (at least that's the plan :P) - TB_OPT_SIZE, - - // same as O1 but favors speed, will aggresively unroll - // sometimes (at least that's the plan :P) - TB_OPT_SPEED, - } TB_OptLevel; - -typedef enum TB_DataTypeEnum { - TB_VOID, - // Boolean - TB_BOOL, - // Integers - TB_I8, TB_I16, TB_I32, TB_I64, - // IEEE 754 Floating point - TB_F32, TB_F64, - // Pointers - TB_PTR, - - TB_MAX_TYPES -} TB_DataTypeEnum; - -#define TB_IS_INTEGER_TYPE(x) ((x) >= TB_I8 && (x) <= TB_I64) -#define TB_IS_FLOAT_TYPE(x) ((x) >= TB_F32 && (x) <= TB_F64) -#define TB_IS_POINTER_TYPE(x) ((x) == TB_PTR) - -typedef struct TB_DataType { - TB_DataTypeEnum type : 8; - - // 2^N where N is the width value. - // Only integers and floats can be wide. - uint8_t width; -} TB_DataType; - typedef struct TB_FeatureSet { struct { bool sse3 : 1; @@ -194,35 +141,547 @@ typedef struct TB_FeatureSet { } aarch64; } TB_FeatureSet; +typedef enum +{ + TB_BRANCH_HINT_NONE, + TB_BRANCH_HINT_LIKELY, + TB_BRANCH_HINT_UNLIKELY +} TB_BranchHint; + +typedef enum +{ + TB_LINKAGE_PUBLIC, + TB_LINKAGE_PRIVATE +} TB_Linkage; + +typedef enum +{ + // data is the default way to handle storage, this is usually + // passed onto the .data section + TB_STORAGE_DATA, + + // Thread local storage will have the values defined per thread + // and only accessible within that thread + TB_STORAGE_TLS +} TB_StorageClass; + +typedef enum +{ + TB_MEM_ORDER_RELAXED, + TB_MEM_ORDER_CONSUME, + TB_MEM_ORDER_ACQUIRE, + TB_MEM_ORDER_RELEASE, + TB_MEM_ORDER_ACQ_REL, + TB_MEM_ORDER_SEQ_CST, +} TB_MemoryOrder; + +typedef enum +{ + // no optimizer run + TB_OPT_O0, + + // run optimizer with all optimizations + TB_OPT_O1, + + // same as O1 but favors size, will aggresively deduplicate + // (at least that's the plan :P) + TB_OPT_SIZE, + + // same as O1 but favors speed, will aggresively unroll + // sometimes (at least that's the plan :P) + TB_OPT_SPEED, +} TB_OptLevel; + +typedef enum +{ + // FastISel + TB_ISEL_FAST, + TB_ISEL_COMPLEX +} TB_ISelMode; + +typedef enum +{ + TB_VOID, + // Boolean + TB_BOOL, + // Integers + TB_I8, + TB_I16, + TB_I32, + TB_I64, + // IEEE 754 Floating point + TB_F32, + TB_F64, + // Pointers + TB_PTR, + + TB_MAX_TYPES +} TB_DataTypeEnum; + +typedef enum +{ + TB_NULL = 0, + + /* metadata */ + TB_LINE_INFO, + TB_KEEPALIVE, + TB_POISON, + + TB_ICALL, /* internal use only, inline call */ + TB_CALL, /* standard function call */ + TB_VCALL, /* virtual call */ + TB_ECALL, /* extern call */ + + /* Memory operations */ + TB_STORE, + + TB_MEMCLR, + TB_MEMCPY, + TB_MEMSET, + TB_MEMCMP, + TB_INITIALIZE, + + /* Atomics */ + TB_ATOMIC_TEST_AND_SET, + TB_ATOMIC_CLEAR, + + TB_ATOMIC_XCHG, + TB_ATOMIC_ADD, + TB_ATOMIC_SUB, + TB_ATOMIC_AND, + TB_ATOMIC_XOR, + TB_ATOMIC_OR, + + TB_ATOMIC_CMPXCHG, /* These are always bundled together */ + TB_ATOMIC_CMPXCHG2, + TB_DEBUGBREAK, + + /* Terminators */ + TB_LABEL, + TB_GOTO, + TB_SWITCH, + TB_IF, + TB_RET, + TB_TRAP, + TB_UNREACHABLE, + + /* Load */ + TB_LOAD, + + /* Pointers */ + TB_RESTRICT, + TB_LOCAL, + TB_PARAM_ADDR, + + TB_PARAM, + TB_FUNC_ADDRESS, + TB_EXTERN_ADDRESS, + TB_GLOBAL_ADDRESS, + + TB_MEMBER_ACCESS, + TB_ARRAY_ACCESS, + + /* Immediates */ + TB_UNSIGNED_CONST, + TB_SIGNED_CONST, + TB_FLOAT_CONST, + TB_STRING_CONST, + + /* Conversions */ + TB_TRUNCATE, + TB_FLOAT_EXT, + TB_SIGN_EXT, + TB_ZERO_EXT, + TB_INT2PTR, + TB_PTR2INT, + TB_INT2FLOAT, + TB_FLOAT2INT, + TB_BITCAST, + + /* Select */ + TB_SELECT, + + /* Unary operations */ + TB_NOT, + TB_NEG, + + /* Integer arithmatic */ + TB_AND, + TB_OR, + TB_XOR, + TB_ADD, + TB_SUB, + TB_MUL, + + TB_SHL, + TB_SHR, + TB_SAR, + TB_UDIV, + TB_SDIV, + TB_UMOD, + TB_SMOD, + + /* Float arithmatic */ + TB_FADD, + TB_FSUB, + TB_FMUL, + TB_FDIV, + + /* Comparisons */ + TB_CMP_EQ, + TB_CMP_NE, + TB_CMP_SLT, + TB_CMP_SLE, + TB_CMP_ULT, + TB_CMP_ULE, + TB_CMP_FLT, + TB_CMP_FLE, + + /* PHI */ + // NOTE(NeGate): phi1 and phi2 are just to avoid + // using extra space for the common cases + TB_PHI1, + TB_PHI2, + TB_PHIN, + + // NOTE(NeGate): only used internally, if you + // see one in normal IR things went wrong in + // an optimization pass + TB_PASS, + + // variadic + TB_VA_START, + + // x86 intrinsics + TB_X86INTRIN_SQRT, + TB_X86INTRIN_RSQRT, +} TB_NodeTypeEnum; +typedef uint8_t TB_NodeType; + +#define TB_IS_NODE_SIDE_EFFECT(type) ((type) >= TB_LINE_INFO && (type) <= TB_DEBUGBREAK) +#define TB_IS_NODE_TERMINATOR(type) ((type) >= TB_LABEL && (type) <= TB_RET) + +#define TB_IS_INTEGER_TYPE(x) ((x) >= TB_I8 && (x) <= TB_I64) +#define TB_IS_FLOAT_TYPE(x) ((x) >= TB_F32 && (x) <= TB_F64) +#define TB_IS_POINTER_TYPE(x) ((x) == TB_PTR) + +typedef struct { + uint8_t type; + + // 2^N where N is the width value. + // Only integers and floats can be wide. + uint8_t width; +} TB_DataType; + typedef int TB_Label; -typedef struct TB_SwitchEntry { - uint32_t key; +typedef struct { + int32_t key; TB_Label value; } TB_SwitchEntry; -typedef int TB_Register; -typedef int TB_Reg; // short-hand +// just represents some region of bytes, usually in file parsing crap +typedef struct { + size_t length; + uint8_t* data; +} TB_Slice; // represents byte counts typedef uint32_t TB_CharUnits; +typedef unsigned int TB_AttributeID; typedef unsigned int TB_FileID; typedef unsigned int TB_FunctionID; -typedef unsigned int TB_ExternalID; +typedef unsigned int TB_ExternalID; // 0 means NULL typedef unsigned int TB_GlobalID; typedef unsigned int TB_InitializerID; -typedef struct TB_Module TB_Module; -typedef struct TB_Function TB_Function; +typedef struct TB_Module TB_Module; +typedef struct TB_Function TB_Function; +typedef struct TB_AttribList TB_AttribList; typedef struct TB_FunctionPrototype TB_FunctionPrototype; +// references to a node within a TB_Function +// these are virtual registers so they don't necessarily +// map to any hardware but instead represent some operation +typedef int TB_Reg, TB_Register; + +#define TB_NULL_REG ((TB_Reg)0) +#define TB_REG_MAX ((TB_Reg)INT_MAX) + +typedef struct TB_Node { + TB_NodeType type; + TB_DataType dt; + TB_Reg next; + TB_AttribList* first_attrib; + + union { + struct TB_NodeUint { + uint64_t value; + } uint; + struct TB_NodeSint { + int64_t value; + } sint; + struct TB_NodeFloat { + double value; + } flt; + struct TB_NodeString { + size_t length; + const char* data; + } string; + struct TB_NodeFunction { + const TB_Function* value; + } func; + struct TB_NodeExtern { + TB_ExternalID value; + } external; + struct TB_NodeGlobal { + TB_GlobalID value; + } global; + struct TB_NodeLine { + TB_FileID file; + int line; + } line_info; + struct TB_NodeMemberAccess { + TB_Reg base; + int32_t offset; + } member_access; + struct TB_NodeArrayAccess { + TB_Reg base; + TB_Reg index; + TB_CharUnits stride; + } array_access; + struct TB_NodePtrdiff { + TB_Reg a; + TB_Reg b; + TB_CharUnits stride; + } ptrdiff; + struct TB_NodeParam { + uint32_t id; + TB_CharUnits size; + } param; + struct TB_NodeParamAddr { + TB_Reg param; + + TB_CharUnits size; + TB_CharUnits alignment; + } param_addr; + struct TB_NodeLocal { + TB_CharUnits size; + TB_CharUnits alignment; + } local; + struct TB_NodeUnary { + TB_Reg src; + } unary; + struct TB_NodeIArith { + TB_Reg a; + TB_Reg b; + TB_ArithmaticBehavior arith_behavior; + } i_arith; + struct TB_NodeFArith { + TB_Reg a; + TB_Reg b; + } f_arith; + struct TB_NodeCompare { + TB_Reg a; + TB_Reg b; + TB_DataType dt; + } cmp; + struct TB_NodeSelect { + TB_Reg a; + TB_Reg b; + TB_Reg cond; + } select; + struct TB_NodeLoad { + TB_Reg address; + // this is only here to make load and store + // payloads match in data layout... just because + TB_Reg _; + TB_CharUnits alignment; + bool is_volatile; + } load; + struct TB_NodeStore { + TB_Reg address; + TB_Reg value; + TB_CharUnits alignment; + bool is_volatile; + } store; + struct TB_NodeAtomicRMW { + TB_Reg addr; + TB_Reg src; + TB_MemoryOrder order; + + // NOTE(NeGate): this is used for fail + TB_MemoryOrder order2; + } atomic; + struct TB_NodeReturn { + TB_Reg value; + } ret; + struct TB_NodePass { + TB_Reg value; + } pass; + struct TB_NodePhi1 { + TB_Reg a_label; + TB_Reg a; + } phi1; + struct TB_NodePhi2 { + TB_Reg a_label; + TB_Reg a; + TB_Reg b_label; + TB_Reg b; + } phi2; + struct TB_NodePhi { + int param_start, param_end; + } phin; + struct TB_NodeLabel { + TB_Label id; + TB_Reg terminator; + } label; + struct TB_NodeIf { + TB_Reg cond; + TB_Label if_true; + TB_Label if_false; + } if_; + struct TB_NodeGoto { + TB_Label label; + } goto_; + struct TB_NodeExternCall { + int param_start, param_end; + TB_ExternalID target; + } ecall; + struct TB_NodeDynamicCall { + int param_start, param_end; + TB_Reg target; + } vcall; + struct TB_NodeFunctionCall { + int param_start, param_end; + const TB_Function* target; + } call; + struct TB_NodeSwitch { + TB_Reg key; + TB_Label default_label; + int entries_start, entries_end; + } switch_; + struct TB_NodeMemoryOp { + TB_Reg dst; + TB_Reg src; + TB_Reg size; + TB_CharUnits align; + } mem_op; + struct TB_NodeMemoryClear { + TB_Reg dst; + TB_CharUnits size; + TB_CharUnits align; + } clear; + struct TB_NodeInitialize { + TB_Reg addr; + TB_InitializerID id; + } init; + }; +} TB_Node; +static_assert(sizeof(TB_Node) <= 32, "sizeof(TB_Node) <= 32"); + // represents the atomic cmpxchg result since it's two values -typedef struct TB_CmpXchgResult { - TB_Register success; - TB_Register old_value; +typedef struct { + TB_Reg success; + TB_Reg old_value; } TB_CmpXchgResult; +typedef struct { + size_t count; + struct TB_Loop { + int parent_loop; + + // the terminator of the header will exit + TB_Register header; + + // this is where the contents of the loop begin + TB_Register body; + + // this is not part of the loop but instead where + // the loop goes on exit + TB_Register exit; + } loops[]; +} TB_LoopInfo; + +typedef enum { + TB_OBJECT_RELOC_NONE, // how? + + // Target independent + TB_OBJECT_RELOC_ADDR32, + TB_OBJECT_RELOC_ADDR64, // unsupported on 32bit platforms + TB_OBJECT_RELOC_SECREL, + TB_OBJECT_RELOC_SECTION, + + // x64 only + TB_OBJECT_RELOC_REL32, // relative 32bit displacement + TB_OBJECT_RELOC_REL32_1, // plus 1 + TB_OBJECT_RELOC_REL32_2, // plus 2 + TB_OBJECT_RELOC_REL32_3, // and so on + TB_OBJECT_RELOC_REL32_4, // ... + TB_OBJECT_RELOC_REL32_5, + + // Aarch64 only + TB_OBJECT_RELOC_BRANCH26, // 26bit displacement for B and BL instructions + TB_OBJECT_RELOC_REL21, // for ADR instructions + + // TODO(NeGate): fill in the rest of this later +} TB_ObjectRelocType; + +typedef struct { + TB_ObjectRelocType type; + uint32_t symbol_index; + size_t virtual_address; +} TB_ObjectReloc; + +typedef struct { + TB_Slice name; + + size_t virtual_address; + size_t virtual_size; + + // You can have a virtual size without having a raw + // data size, that's how the BSS section works + TB_Slice raw_data; + + size_t relocation_count; + TB_ObjectReloc* relocations; +} TB_ObjectSection; + +typedef enum { + TB_OBJECT_SYMBOL_SECTION +} TB_ObjectSymbolType; + +typedef struct { + TB_Slice name; +} TB_ObjectSymbol; + +typedef enum { + TB_OBJECT_FILE_UNKNOWN, + + TB_OBJECT_FILE_COFF, + TB_OBJECT_FILE_ELF64 +} TB_ObjectFileType; + +typedef struct { + TB_ObjectFileType type; + TB_Arch arch; + + size_t symbol_count; + TB_ObjectSymbol* symbols; + + size_t section_count; + TB_ObjectSection sections[]; +} TB_ObjectFile; + +typedef struct { + size_t object_file_count; + + // Name table maps to the object files directly + char** object_file_names; + TB_Slice object_files[]; +} TB_ArchiveFile; + // ******************************* // Public macros // ******************************* @@ -243,43 +702,48 @@ typedef struct TB_CmpXchgResult { #else #define TB_TYPE_VOID (TB_DataType){ TB_VOID, 0 } +#define TB_TYPE_I8 (TB_DataType){ TB_I8, 0 } +#define TB_TYPE_I16 (TB_DataType){ TB_I16, 0 } +#define TB_TYPE_I32 (TB_DataType){ TB_I32, 0 } +#define TB_TYPE_I64 (TB_DataType){ TB_I64, 0 } -#define TB_TYPE_I8 (TB_DataType){ TB_I8, 0 } -#define TB_TYPE_I16 (TB_DataType){ TB_I16, 0 } -#define TB_TYPE_I32 (TB_DataType){ TB_I32, 0 } -#define TB_TYPE_I64 (TB_DataType){ TB_I64, 0 } - -#define TB_TYPE_F32 (TB_DataType){ TB_F32, 0 } -#define TB_TYPE_F64 (TB_DataType){ TB_F64, 0 } - +#define TB_TYPE_F32 (TB_DataType){ TB_F32, 0 } +#define TB_TYPE_F64 (TB_DataType){ TB_F64, 0 } #define TB_TYPE_BOOL (TB_DataType){ TB_BOOL, 0 } -#define TB_TYPE_PTR (TB_DataType){ TB_PTR, 0 } +#define TB_TYPE_PTR (TB_DataType){ TB_PTR, 0 } #endif +typedef void (*TB_PrintCallback)(void* user_data, const char* fmt, ...); + //////////////////////////////// // Module management //////////////////////////////// // Creates a module with the correct target and settings -TB_API TB_Module* tb_module_create(TB_Arch target_arch, TB_System target_system, const TB_FeatureSet* features); +TB_API TB_Module* tb_module_create(TB_Arch target_arch, TB_System target_system, TB_DebugFormat debug_fmt, const TB_FeatureSet* features); // Validates IR & compiles the function into machine code. +// For isel_mode, TB_ISEL_FAST will compile faster but worse codegen +// TB_ISEL_COMPLEX will compile slower but better codegen +// // returns false if it fails. -TB_API bool tb_module_compile_func(TB_Module* m, TB_Function* f); +TB_API bool tb_module_compile_func(TB_Module* m, TB_Function* f, TB_ISelMode isel_mode); -// NOTE: Don't use this it's for testing purposes. -TB_API size_t tb_DEBUG_module_get_full_node_count(TB_Module* m); - -// Frees all resources for the TB_Module and it's functions, globals and compiled code. +// Frees all resources for the TB_Module and it's functions, globals and +// compiled code. TB_API void tb_module_destroy(TB_Module* m); -// Waits for the machine code generation to finish before continuing. -TB_API bool tb_module_compile(TB_Module* m); +// When targetting windows & thread local storage, you'll need to bind a tls index +// which is usually just a global that the runtime support has initialized, if you +// dont and the tls_index is used, it'll crash +TB_API void tb_module_set_tls_index(TB_Module* m, TB_ExternalID e); // Exports an object file with all the machine code and symbols generated. TB_API bool tb_module_export(TB_Module* m, const char* path); -TB_API void tb_module_export_jit(TB_Module* m); +// For isel_mode, TB_ISEL_FAST will compile faster but worse codegen +// TB_ISEL_COMPLEX will compile slower but better codegen +TB_API void tb_module_export_jit(TB_Module* m, TB_ISelMode isel_mode); TB_API void* tb_module_get_jit_func_by_name(TB_Module* m, const char* name); TB_API void* tb_module_get_jit_func_by_id(TB_Module* m, size_t i); @@ -289,7 +753,7 @@ TB_API void* tb_module_get_jit_func(TB_Module* m, TB_Function* f); TB_API bool tb_jit_import(TB_Module* m, const char* name, void* address); TB_API TB_ExternalID tb_extern_create(TB_Module* m, const char* name); -TB_API TB_FileID tb_file_create(TB_Module* m, const char* path); +TB_API TB_FileID tb_file_create(TB_Module* m, const char* path); //////////////////////////////// // Function Prototypes @@ -298,8 +762,8 @@ TB_API TB_FileID tb_file_create(TB_Module* m, const char* path); // return type. // // function prototypes do not get freed individually and last for the entire run -// of the backend, they can also be reused for multiple functions which have matching -// signatures. +// of the backend, they can also be reused for multiple functions which have +// matching signatures. TB_API TB_FunctionPrototype* tb_prototype_create(TB_Module* m, TB_CallingConv conv, TB_DataType return_dt, int num_params, bool has_varargs); // adds a parameter to the function prototype, TB doesn't support struct @@ -322,109 +786,156 @@ TB_API TB_Function* tb_prototype_build(TB_Module* m, TB_FunctionPrototype* p, co // number used. TB_API TB_InitializerID tb_initializer_create(TB_Module* m, size_t size, size_t align, size_t max_objects); -// returns a buffer which the user can fill to then have represented in the initializer +// returns a buffer which the user can fill to then have represented in the +// initializer TB_API void* tb_initializer_add_region(TB_Module* m, TB_InitializerID id, size_t offset, size_t size); +// places a relocation for a global at offset, the size of the relocation +// depends on the pointer size +TB_API void tb_initializer_add_global(TB_Module* m, TB_InitializerID id, size_t offset, TB_GlobalID global); +TB_API void tb_initializer_add_function(TB_Module* m, TB_InitializerID id, size_t offset, TB_FunctionID func); +TB_API void tb_initializer_add_extern(TB_Module* m, TB_InitializerID id, size_t offset, TB_ExternalID external); + //////////////////////////////// // Constant Initializers //////////////////////////////// -TB_API TB_GlobalID tb_global_create(TB_Module* m, TB_InitializerID initializer, const char* name, TB_Linkage linkage); +TB_API TB_GlobalID tb_global_create(TB_Module* m, const char* name, TB_StorageClass storage, TB_Linkage linkage); +TB_API void tb_global_set_initializer(TB_Module* m, TB_GlobalID global, TB_InitializerID initializer); + +//////////////////////////////// +// Function Attributes +//////////////////////////////// +// These are parts of a function that describe metadata for instructions + +// restrict is applied onto loads and store operations meaning that the pointer +// being accessed doesn't alias with any of the other pointers within the scope +TB_API TB_AttributeID tb_function_attrib_restrict(TB_Function* f, TB_AttributeID scope); + +// This defines a some scope which can have a set of restrict pointers defined +// in it +TB_API TB_AttributeID tb_function_attrib_scope(TB_Function* f, TB_AttributeID parent_scope); + +// places an attribute on a function, note that there's no limit to how many +// registers can share an attribute +TB_API void tb_function_append_attrib(TB_Function* f, TB_Reg r, TB_AttributeID a); //////////////////////////////// // Function IR Generation //////////////////////////////// +// the user_data is expected to be a valid FILE* +TB_API void tb_default_print_callback(void* user_data, const char* fmt, ...); + // this only allows for power of two vector types TB_API TB_DataType tb_vector_type(TB_DataTypeEnum type, int width); TB_API TB_Function* tb_function_clone(TB_Module* m, TB_Function* f, const char* name); -TB_API void tb_function_print(TB_Function* f, FILE* out); +TB_API void tb_function_print(TB_Function* f, TB_PrintCallback callback, void* user_data); + +// Prints out the IR in the GraphViz format +TB_API void tb_function_print_cfg(TB_Function* f, TB_PrintCallback callback, void* user_data); TB_API void tb_function_free(TB_Function* f); TB_API TB_Label tb_inst_get_current_label(TB_Function* f); TB_API void tb_inst_loc(TB_Function* f, TB_FileID file, int line); -TB_API TB_Register tb_inst_param(TB_Function* f, int param_id); -TB_API TB_Register tb_inst_param_addr(TB_Function* f, int param_id); +TB_API void tb_inst_set_scope(TB_Function* f, TB_AttributeID scope); +TB_API TB_AttributeID tb_inst_get_scope(TB_Function* f); -TB_API TB_Register tb_inst_fpxt(TB_Function* f, TB_Register src, TB_DataType dt); -TB_API TB_Register tb_inst_sxt(TB_Function* f, TB_Register src, TB_DataType dt); -TB_API TB_Register tb_inst_zxt(TB_Function* f, TB_Register src, TB_DataType dt); -TB_API TB_Register tb_inst_trunc(TB_Function* f, TB_Register src, TB_DataType dt); -TB_API TB_Register tb_inst_int2ptr(TB_Function* f, TB_Register src); -TB_API TB_Register tb_inst_ptr2int(TB_Function* f, TB_Register src, TB_DataType dt); +TB_API void tb_inst_debugbreak(TB_Function* f); -TB_API TB_Register tb_inst_local(TB_Function* f, uint32_t size, TB_CharUnits align); -TB_API TB_Register tb_inst_load(TB_Function* f, TB_DataType dt, TB_Register addr, TB_CharUnits align); -TB_API void tb_inst_store(TB_Function* f, TB_DataType dt, TB_Register addr, TB_Register val, TB_CharUnits align); +TB_API TB_Reg tb_inst_param(TB_Function* f, int param_id); +TB_API TB_Reg tb_inst_param_addr(TB_Function* f, int param_id); -TB_API TB_Register tb_inst_volatile_load(TB_Function* f, TB_DataType dt, TB_Register addr, TB_CharUnits alignment); -TB_API void tb_inst_volatile_store(TB_Function* f, TB_DataType dt, TB_Register addr, TB_Register val, TB_CharUnits alignment); +TB_API TB_Reg tb_inst_fpxt(TB_Function* f, TB_Reg src, TB_DataType dt); +TB_API TB_Reg tb_inst_sxt(TB_Function* f, TB_Reg src, TB_DataType dt); +TB_API TB_Reg tb_inst_zxt(TB_Function* f, TB_Reg src, TB_DataType dt); +TB_API TB_Reg tb_inst_trunc(TB_Function* f, TB_Reg src, TB_DataType dt); +TB_API TB_Reg tb_inst_int2ptr(TB_Function* f, TB_Reg src); +TB_API TB_Reg tb_inst_ptr2int(TB_Function* f, TB_Reg src, TB_DataType dt); +TB_API TB_Reg tb_inst_int2float(TB_Function* f, TB_Reg src, TB_DataType dt); +TB_API TB_Reg tb_inst_float2int(TB_Function* f, TB_Reg src, TB_DataType dt); +TB_API TB_Reg tb_inst_bitcast(TB_Function* f, TB_Reg src, TB_DataType dt); -TB_API TB_Register tb_inst_bool(TB_Function* f, bool imm); -TB_API TB_Register tb_inst_ptr(TB_Function* f, uint64_t imm); -TB_API TB_Register tb_inst_sint(TB_Function* f, TB_DataType dt, int64_t imm); -TB_API TB_Register tb_inst_uint(TB_Function* f, TB_DataType dt, uint64_t imm); -TB_API TB_Register tb_inst_float(TB_Function* f, TB_DataType dt, double imm); -TB_API TB_Register tb_inst_cstring(TB_Function* f, const char* str); -TB_API TB_Register tb_inst_string(TB_Function* f, size_t len, const char* str); +TB_API TB_Reg tb_inst_local(TB_Function* f, uint32_t size, TB_CharUnits align); +TB_API TB_Reg tb_inst_load(TB_Function* f, TB_DataType dt, TB_Reg addr, TB_CharUnits align); +TB_API void tb_inst_store(TB_Function* f, TB_DataType dt, TB_Reg addr, TB_Reg val, TB_CharUnits align); + +TB_API TB_Reg tb_inst_volatile_load(TB_Function* f, TB_DataType dt, TB_Reg addr, TB_CharUnits alignment); +TB_API void tb_inst_volatile_store(TB_Function* f, TB_DataType dt, TB_Reg addr, TB_Reg val, TB_CharUnits alignment); + +TB_API TB_Reg tb_inst_bool(TB_Function* f, bool imm); +TB_API TB_Reg tb_inst_ptr(TB_Function* f, uint64_t imm); +TB_API TB_Reg tb_inst_sint(TB_Function* f, TB_DataType dt, int64_t imm); +TB_API TB_Reg tb_inst_uint(TB_Function* f, TB_DataType dt, uint64_t imm); +TB_API TB_Reg tb_inst_float(TB_Function* f, TB_DataType dt, double imm); +TB_API TB_Reg tb_inst_cstring(TB_Function* f, const char* str); +TB_API TB_Reg tb_inst_string(TB_Function* f, size_t len, const char* str); // Applies an initializer to a memory region -TB_API void tb_inst_initialize_mem(TB_Function* f, TB_Register addr, TB_InitializerID src); +TB_API void tb_inst_initialize_mem(TB_Function* f, TB_Reg addr, TB_InitializerID src); // Broadcasts 'val' across 'count' elements starting 'dst' -TB_API void tb_inst_memset(TB_Function* f, TB_Register dst, TB_Register val, TB_Register count, TB_CharUnits align); +TB_API void tb_inst_memset(TB_Function* f, TB_Reg dst, TB_Reg val, TB_Reg count, TB_CharUnits align); // performs a copy of 'count' elements from one memory location to another // both locations cannot overlap. -TB_API void tb_inst_memcpy(TB_Function* f, TB_Register dst, TB_Register src, TB_Register count, TB_CharUnits align); +TB_API void tb_inst_memcpy(TB_Function* f, TB_Reg dst, TB_Reg src, TB_Reg count, TB_CharUnits align); // Clears a memory region to zeroes -TB_API void tb_inst_memclr(TB_Function* f, TB_Register addr, TB_CharUnits size, TB_CharUnits align); +TB_API void tb_inst_memclr(TB_Function* f, TB_Reg addr, TB_CharUnits size, TB_CharUnits align); // result = base + (index * stride) -TB_API TB_Register tb_inst_array_access(TB_Function* f, TB_Register base, TB_Register index, uint32_t stride); +TB_API TB_Reg tb_inst_array_access(TB_Function* f, TB_Reg base, TB_Reg index, uint32_t stride); // result = base + offset // where base is a pointer -TB_API TB_Register tb_inst_member_access(TB_Function* f, TB_Register base, int32_t offset); +TB_API TB_Reg tb_inst_member_access(TB_Function* f, TB_Reg base, int32_t offset); -TB_API TB_Register tb_inst_get_func_address(TB_Function* f, const TB_Function* target); -TB_API TB_Register tb_inst_get_extern_address(TB_Function* f, TB_ExternalID target); -TB_API TB_Register tb_inst_get_global_address(TB_Function* f, TB_GlobalID target); +TB_API TB_Reg tb_inst_get_func_address(TB_Function* f, const TB_Function* target); +TB_API TB_Reg tb_inst_get_extern_address(TB_Function* f, TB_ExternalID target); +TB_API TB_Reg tb_inst_get_global_address(TB_Function* f, TB_GlobalID target); + +// Performs a conditional select between two values, if the operation is +// performed wide then the cond is expected to be the same type as a and b where +// the condition is resolved as true if the MSB (per component) is 1. +// +// result = cond ? a : b +// a, b must match in type +TB_API TB_Reg tb_inst_select(TB_Function* f, TB_Reg cond, TB_Reg a, TB_Reg b); // Integer arithmatic -TB_API TB_Register tb_inst_add(TB_Function* f, TB_Register a, TB_Register b, TB_ArithmaticBehavior arith_behavior); -TB_API TB_Register tb_inst_sub(TB_Function* f, TB_Register a, TB_Register b, TB_ArithmaticBehavior arith_behavior); -TB_API TB_Register tb_inst_mul(TB_Function* f, TB_Register a, TB_Register b, TB_ArithmaticBehavior arith_behavior); -TB_API TB_Register tb_inst_div(TB_Function* f, TB_Register a, TB_Register b, bool signedness); -TB_API TB_Register tb_inst_mod(TB_Function* f, TB_Register a, TB_Register b, bool signedness); +TB_API TB_Reg tb_inst_add(TB_Function* f, TB_Reg a, TB_Reg b, TB_ArithmaticBehavior arith_behavior); +TB_API TB_Reg tb_inst_sub(TB_Function* f, TB_Reg a, TB_Reg b, TB_ArithmaticBehavior arith_behavior); +TB_API TB_Reg tb_inst_mul(TB_Function* f, TB_Reg a, TB_Reg b, TB_ArithmaticBehavior arith_behavior); +TB_API TB_Reg tb_inst_div(TB_Function* f, TB_Reg a, TB_Reg b, bool signedness); +TB_API TB_Reg tb_inst_mod(TB_Function* f, TB_Reg a, TB_Reg b, bool signedness); // Bitwise operations -TB_API TB_Register tb_inst_not(TB_Function* f, TB_Register n); -TB_API TB_Register tb_inst_neg(TB_Function* f, TB_Register n); -TB_API TB_Register tb_inst_and(TB_Function* f, TB_Register a, TB_Register b); -TB_API TB_Register tb_inst_or(TB_Function* f, TB_Register a, TB_Register b); -TB_API TB_Register tb_inst_xor(TB_Function* f, TB_Register a, TB_Register b); -TB_API TB_Register tb_inst_sar(TB_Function* f, TB_Register a, TB_Register b); -TB_API TB_Register tb_inst_shl(TB_Function* f, TB_Register a, TB_Register b, TB_ArithmaticBehavior arith_behavior); -TB_API TB_Register tb_inst_shr(TB_Function* f, TB_Register a, TB_Register b); +TB_API TB_Reg tb_inst_not(TB_Function* f, TB_Reg n); +TB_API TB_Reg tb_inst_neg(TB_Function* f, TB_Reg n); +TB_API TB_Reg tb_inst_and(TB_Function* f, TB_Reg a, TB_Reg b); +TB_API TB_Reg tb_inst_or(TB_Function* f, TB_Reg a, TB_Reg b); +TB_API TB_Reg tb_inst_xor(TB_Function* f, TB_Reg a, TB_Reg b); +TB_API TB_Reg tb_inst_sar(TB_Function* f, TB_Reg a, TB_Reg b); +TB_API TB_Reg tb_inst_shl(TB_Function* f, TB_Reg a, TB_Reg b, TB_ArithmaticBehavior arith_behavior); +TB_API TB_Reg tb_inst_shr(TB_Function* f, TB_Reg a, TB_Reg b); // Atomics // By default you can use TB_MEM_ORDER_SEQ_CST for the memory order to get // correct but possibly slower results on certain platforms (those with relaxed // memory models). -TB_API TB_Register tb_inst_atomic_test_and_set(TB_Function* f, TB_Register addr, TB_MemoryOrder order); -TB_API TB_Register tb_inst_atomic_clear(TB_Function* f, TB_Register addr, TB_MemoryOrder order); +TB_API TB_Reg tb_inst_atomic_test_and_set(TB_Function* f, TB_Reg addr, TB_MemoryOrder order); +TB_API TB_Reg tb_inst_atomic_clear(TB_Function* f, TB_Reg addr, TB_MemoryOrder order); // All atomic operations here return the old value and the operations are // performed in the same data type as 'src' with alignment of 'addr' being // the natural alignment of 'src' -TB_API TB_Register tb_inst_atomic_xchg(TB_Function* f, TB_Register addr, TB_Register src, TB_MemoryOrder order); -TB_API TB_Register tb_inst_atomic_add(TB_Function* f, TB_Register addr, TB_Register src, TB_MemoryOrder order); -TB_API TB_Register tb_inst_atomic_sub(TB_Function* f, TB_Register addr, TB_Register src, TB_MemoryOrder order); -TB_API TB_Register tb_inst_atomic_and(TB_Function* f, TB_Register addr, TB_Register src, TB_MemoryOrder order); -TB_API TB_Register tb_inst_atomic_xor(TB_Function* f, TB_Register addr, TB_Register src, TB_MemoryOrder order); -TB_API TB_Register tb_inst_atomic_or(TB_Function* f, TB_Register addr, TB_Register src, TB_MemoryOrder order); +TB_API TB_Reg tb_inst_atomic_xchg(TB_Function* f, TB_Reg addr, TB_Reg src, TB_MemoryOrder order); +TB_API TB_Reg tb_inst_atomic_add(TB_Function* f, TB_Reg addr, TB_Reg src, TB_MemoryOrder order); +TB_API TB_Reg tb_inst_atomic_sub(TB_Function* f, TB_Reg addr, TB_Reg src, TB_MemoryOrder order); +TB_API TB_Reg tb_inst_atomic_and(TB_Function* f, TB_Reg addr, TB_Reg src, TB_MemoryOrder order); +TB_API TB_Reg tb_inst_atomic_xor(TB_Function* f, TB_Reg addr, TB_Reg src, TB_MemoryOrder order); +TB_API TB_Reg tb_inst_atomic_or(TB_Function* f, TB_Reg addr, TB_Reg src, TB_MemoryOrder order); // if (*addr == expected) { // old_value = atomic_xchg(addr, desired); @@ -432,51 +943,70 @@ TB_API TB_Register tb_inst_atomic_or(TB_Function* f, TB_Register addr, TB_Regist // } else { // return { false }; // } -TB_API TB_CmpXchgResult tb_inst_atomic_cmpxchg(TB_Function* f, TB_Register addr, TB_Register expected, TB_Register desired, TB_MemoryOrder succ, TB_MemoryOrder fail); +TB_API TB_CmpXchgResult tb_inst_atomic_cmpxchg(TB_Function* f, TB_Reg addr, TB_Reg expected, TB_Reg desired, TB_MemoryOrder succ, TB_MemoryOrder fail); // Float math -TB_API TB_Register tb_inst_fadd(TB_Function* f, TB_Register a, TB_Register b); -TB_API TB_Register tb_inst_fsub(TB_Function* f, TB_Register a, TB_Register b); -TB_API TB_Register tb_inst_fmul(TB_Function* f, TB_Register a, TB_Register b); -TB_API TB_Register tb_inst_fdiv(TB_Function* f, TB_Register a, TB_Register b); +TB_API TB_Reg tb_inst_fadd(TB_Function* f, TB_Reg a, TB_Reg b); +TB_API TB_Reg tb_inst_fsub(TB_Function* f, TB_Reg a, TB_Reg b); +TB_API TB_Reg tb_inst_fmul(TB_Function* f, TB_Reg a, TB_Reg b); +TB_API TB_Reg tb_inst_fdiv(TB_Function* f, TB_Reg a, TB_Reg b); // Comparisons -TB_API TB_Register tb_inst_cmp_eq(TB_Function* f, TB_Register a, TB_Register b); -TB_API TB_Register tb_inst_cmp_ne(TB_Function* f, TB_Register a, TB_Register b); +TB_API TB_Reg tb_inst_cmp_eq(TB_Function* f, TB_Reg a, TB_Reg b); +TB_API TB_Reg tb_inst_cmp_ne(TB_Function* f, TB_Reg a, TB_Reg b); -TB_API TB_Register tb_inst_cmp_ilt(TB_Function* f, TB_Register a, TB_Register b, bool signedness); -TB_API TB_Register tb_inst_cmp_ile(TB_Function* f, TB_Register a, TB_Register b, bool signedness); -TB_API TB_Register tb_inst_cmp_igt(TB_Function* f, TB_Register a, TB_Register b, bool signedness); -TB_API TB_Register tb_inst_cmp_ige(TB_Function* f, TB_Register a, TB_Register b, bool signedness); +TB_API TB_Reg tb_inst_cmp_ilt(TB_Function* f, TB_Reg a, TB_Reg b, bool signedness); +TB_API TB_Reg tb_inst_cmp_ile(TB_Function* f, TB_Reg a, TB_Reg b, bool signedness); +TB_API TB_Reg tb_inst_cmp_igt(TB_Function* f, TB_Reg a, TB_Reg b, bool signedness); +TB_API TB_Reg tb_inst_cmp_ige(TB_Function* f, TB_Reg a, TB_Reg b, bool signedness); -TB_API TB_Register tb_inst_cmp_flt(TB_Function* f, TB_Register a, TB_Register b); -TB_API TB_Register tb_inst_cmp_fle(TB_Function* f, TB_Register a, TB_Register b); -TB_API TB_Register tb_inst_cmp_fgt(TB_Function* f, TB_Register a, TB_Register b); -TB_API TB_Register tb_inst_cmp_fge(TB_Function* f, TB_Register a, TB_Register b); +TB_API TB_Reg tb_inst_cmp_flt(TB_Function* f, TB_Reg a, TB_Reg b); +TB_API TB_Reg tb_inst_cmp_fle(TB_Function* f, TB_Reg a, TB_Reg b); +TB_API TB_Reg tb_inst_cmp_fgt(TB_Function* f, TB_Reg a, TB_Reg b); +TB_API TB_Reg tb_inst_cmp_fge(TB_Function* f, TB_Reg a, TB_Reg b); + +TB_API TB_Reg tb_inst_restrict(TB_Function* f, TB_Reg value); + +// General intrinsics +TB_API TB_Reg tb_inst_va_start(TB_Function* f, TB_Reg a); + +// x86 Intrinsics +TB_API TB_Reg tb_inst_x86_sqrt(TB_Function* f, TB_Reg a); +TB_API TB_Reg tb_inst_x86_rsqrt(TB_Function* f, TB_Reg a); // Control flow -TB_API TB_Register tb_inst_call(TB_Function* f, TB_DataType dt, const TB_Function* target, size_t param_count, const TB_Register* params); -TB_API TB_Register tb_inst_vcall(TB_Function* f, TB_DataType dt, TB_Register target, size_t param_count, const TB_Register* params); -TB_API TB_Register tb_inst_ecall(TB_Function* f, TB_DataType dt, const TB_ExternalID target, size_t param_count, const TB_Register* params); +TB_API TB_Reg tb_inst_call(TB_Function* f, TB_DataType dt, const TB_Function* target, size_t param_count, const TB_Reg* params); +TB_API TB_Reg tb_inst_vcall(TB_Function* f, TB_DataType dt, TB_Reg target, size_t param_count, const TB_Reg* params); +TB_API TB_Reg tb_inst_ecall(TB_Function* f, TB_DataType dt, const TB_ExternalID target, size_t param_count, const TB_Reg* params); TB_API TB_Label tb_inst_new_label_id(TB_Function* f); -TB_API TB_Register tb_inst_phi2(TB_Function* f, TB_Label a_label, TB_Register a, TB_Label b_label, TB_Register b); -TB_API TB_Register tb_inst_label(TB_Function* f, TB_Label id); +TB_API TB_Reg tb_inst_phi2(TB_Function* f, TB_Label a_label, TB_Reg a, TB_Label b_label, TB_Reg b); +TB_API TB_Reg tb_inst_label(TB_Function* f, TB_Label id); TB_API void tb_inst_goto(TB_Function* f, TB_Label id); -TB_API TB_Register tb_inst_if(TB_Function* f, TB_Register cond, TB_Label if_true, TB_Label if_false); -TB_API void tb_inst_switch(TB_Function* f, TB_DataType dt, TB_Register key, TB_Label default_label, size_t entry_count, const TB_SwitchEntry* entries); -TB_API void tb_inst_ret(TB_Function* f, TB_Register value); +TB_API TB_Reg tb_inst_if(TB_Function* f, TB_Reg cond, TB_Label if_true, TB_Label if_false); +TB_API void tb_inst_switch(TB_Function* f, TB_DataType dt, TB_Reg key, TB_Label default_label, size_t entry_count, const TB_SwitchEntry* entries); +TB_API void tb_inst_ret(TB_Function* f, TB_Reg value); //////////////////////////////// // Optimizer //////////////////////////////// -TB_API void tb_function_optimize(TB_Function* f, TB_OptLevel opt); +// Applies single function optimizations until it runs out +TB_API bool tb_function_optimize(TB_Function* f); +// Applies whole program optimizations until it runs out +TB_API bool tb_module_optimize(TB_Module* m); + +// analysis +TB_API TB_LoopInfo* tb_function_get_loop_info(TB_Function* f); + +// passes TB_API bool tb_opt_mem2reg(TB_Function* f); +TB_API bool tb_opt_subexpr_elim(TB_Function* f); TB_API bool tb_opt_dead_expr_elim(TB_Function* f); TB_API bool tb_opt_dead_block_elim(TB_Function* f); TB_API bool tb_opt_fold(TB_Function* f); TB_API bool tb_opt_load_elim(TB_Function* f); +TB_API bool tb_opt_hoist_invariants(TB_Function* f); TB_API bool tb_opt_inline(TB_Function* f); TB_API bool tb_opt_hoist_locals(TB_Function* f); TB_API bool tb_opt_canonicalize(TB_Function* f); @@ -486,35 +1016,60 @@ TB_API bool tb_opt_strength_reduction(TB_Function* f); TB_API bool tb_opt_compact_dead_regs(TB_Function* f); TB_API bool tb_opt_copy_elision(TB_Function* f); +// analysis +TB_API TB_LoopInfo* tb_function_get_loop_info(TB_Function* f); + //////////////////////////////// // IR access //////////////////////////////// TB_API TB_FunctionID tb_function_get_id(TB_Module* m, TB_Function* f); TB_API TB_Function* tb_function_from_id(TB_Module* m, TB_FunctionID id); -TB_API TB_Register tb_node_get_last_register(TB_Function* f); -TB_API TB_DataType tb_node_get_data_type(TB_Function* f, TB_Register r); +TB_API TB_Reg tb_node_get_last_register(TB_Function* f); + +TB_API TB_Node* tb_function_get_node(TB_Function* f, TB_Reg r); + +// either an unsigned or signed constant +TB_API bool tb_node_is_constant_int(TB_Function* f, TB_Reg r, uint64_t imm); + +// returns true if it's a signed or unsigned constant +// in which case *imm is the raw bits and *is_signed is +// signedness +// +// notes: +// imm cannot be NULL +// is_signed can be NULL +TB_API bool tb_node_get_constant_int(TB_Function* f, TB_Reg r, uint64_t* imm, bool* is_signed); // Returns the size and alignment of a LOCAL node, both must // be valid addresses -TB_API void tb_get_function_get_local_info(TB_Function* f, TB_Register r, int* size, int* align); +TB_API void tb_get_function_get_local_info(TB_Function* f, TB_Reg r, int* size, int* align); // is an IF node? -TB_API bool tb_node_is_conditional(TB_Function* f, TB_Register r); +TB_API bool tb_node_is_conditional(TB_Function* f, TB_Reg r); // is an IF, GOTO, RET, SWITCH, or LABEL node? -TB_API bool tb_node_is_terminator(TB_Function* f, TB_Register r); +TB_API bool tb_node_is_terminator(TB_Function* f, TB_Reg r); -TB_API bool tb_node_is_label(TB_Function* f, TB_Register r); +TB_API bool tb_node_is_label(TB_Function* f, TB_Reg r); -TB_API TB_Register tb_node_store_get_address(TB_Function* f, TB_Register r); -TB_API TB_Register tb_node_store_get_value(TB_Function* f, TB_Register r); +TB_API TB_Reg tb_node_store_get_address(TB_Function* f, TB_Reg r); +TB_API TB_Reg tb_node_store_get_value(TB_Function* f, TB_Reg r); -TB_API TB_Register tb_node_load_get_address(TB_Function* f, TB_Register r); +TB_API TB_Reg tb_node_load_get_address(TB_Function* f, TB_Reg r); // These work for any floating point, comparison, or integer arithmatic ops -TB_API TB_Register tb_node_arith_get_left(TB_Function* f, TB_Register r); -TB_API TB_Register tb_node_arith_get_right(TB_Function* f, TB_Register r); +TB_API TB_Reg tb_node_arith_get_left(TB_Function* f, TB_Reg r); +TB_API TB_Reg tb_node_arith_get_right(TB_Function* f, TB_Reg r); + +//////////////////////////////// +// Objects +//////////////////////////////// +TB_ArchiveFile* tb_archive_parse_lib(const TB_Slice file); +void tb_archive_free(TB_ArchiveFile* archive); + +TB_ObjectFile* tb_object_parse_coff(const TB_Slice file); +void tb_object_free(TB_ObjectFile* obj); #ifdef __cplusplus }