diff --git a/src/compiler/tb_codegen.c b/src/compiler/tb_codegen.c index 07413e354..06ec94365 100644 --- a/src/compiler/tb_codegen.c +++ b/src/compiler/tb_codegen.c @@ -41,23 +41,23 @@ TB_DataType tbtype(Type *type) { case TYPE_U8: case TYPE_I8: - return TB_TYPE_VEC_I8(elements); + return tb_vector_type(TB_I8, elements); case TYPE_U16: case TYPE_I16: - return TB_TYPE_VEC_I16(elements); + return tb_vector_type(TB_I16, elements); case TYPE_U32: case TYPE_I32: - return TB_TYPE_VEC_I32(elements); + return tb_vector_type(TB_I32, elements); case TYPE_U64: case TYPE_I64: - return TB_TYPE_VEC_I64(elements); + return tb_vector_type(TB_I64, elements); case TYPE_I128: case TYPE_U128: FATAL_ERROR("Unsupported int128"); - case TYPE_F64: - return TB_TYPE_VEC_F64(elements); case TYPE_F32: - return TB_TYPE_VEC_F32(elements); + return tb_vector_type(TB_F32, elements); + case TYPE_F64: + return tb_vector_type(TB_F64, elements); case TYPE_F16: FATAL_ERROR("Unsupported f16"); case TYPE_F128: @@ -340,9 +340,9 @@ void tinybackend_store_value(TbContext *c, TBEValue *destination, TBEValue *valu { // Here we do an optimized(?) memcopy. ByteSize size = type_size(value->type); - TB_Register copy_size = tb_inst_iconst(c->f, - size <= UINT32_MAX ? TB_TYPE_I32 : TB_TYPE_I64, - size); + TB_Register copy_size = tb_inst_uint(c->f, + size <= UINT32_MAX ? TB_TYPE_I32 : TB_TYPE_I64, + size); alignment = type_min_alignment(destination->alignment, value->alignment); tb_inst_memcpy(c->f, destination->reg, value->reg, copy_size, alignment); @@ -371,7 +371,7 @@ static void tinybackend_emit_const_expr(TbContext *c, TBEValue *value, Expr *exp switch (expr->const_expr.const_kind) { case CONST_FLOAT: - TBE_VALUE_set(value, tb_inst_fconst(c->f, tbtype(type), expr->const_expr.fxx.f), type); + TBE_VALUE_set(value, tb_inst_float(c->f, tbtype(type), expr->const_expr.fxx.f), type); return; case CONST_INTEGER: { @@ -390,7 +390,7 @@ static void tinybackend_emit_const_expr(TbContext *c, TBEValue *value, Expr *exp //reg = tb_inst_iconst128(c->function, dt, (TB_Int128){ .lo = i.low, .hi = i.high }); break; default: - reg = tb_inst_iconst(c->f, dt, i.low); + reg = type_kind_is_signed(expr->const_expr.ixx.type) ? tb_inst_sint(c->f, dt, i.low) : tb_inst_uint(c->f, dt, i.low); break; } TBE_VALUE_set(value, reg, type); @@ -539,12 +539,12 @@ void tinybackend_emit_binary(TbContext *c, TBEValue *TBE_VALUE, Expr *expr, TBEV case BINARYOP_MULT: if (is_float) { - val = tb_inst_fmul(c->f, dt, lhs_value, rhs_value); + val = tb_inst_fmul(c->f, lhs_value, rhs_value); break; } // TODO(NeGate): review this later, maybe it shouldn't be NO_WRAP - val = tb_inst_mul(c->f, dt, lhs_value, rhs_value, TB_ASSUME_NUW); + val = tb_inst_mul(c->f, lhs_value, rhs_value, TB_ASSUME_NUW); break; case BINARYOP_SUB: if (lhs_type->type_kind == TYPE_POINTER) @@ -564,10 +564,10 @@ void tinybackend_emit_binary(TbContext *c, TBEValue *TBE_VALUE, Expr *expr, TBEV } if (is_float) { - val = tb_inst_fsub(c->f, dt, lhs_value, rhs_value); + val = tb_inst_fsub(c->f, lhs_value, rhs_value); break; } - val = tb_inst_mul(c->f, dt, lhs_value, rhs_value, tinybackend_get_arith_behavior(lhs_type)); + val = tb_inst_mul(c->f, lhs_value, rhs_value, tinybackend_get_arith_behavior(lhs_type)); break; case BINARYOP_ADD: if (lhs_type->type_kind == TYPE_POINTER) @@ -576,20 +576,20 @@ void tinybackend_emit_binary(TbContext *c, TBEValue *TBE_VALUE, Expr *expr, TBEV } if (is_float) { - val = tb_inst_fadd(c->f, dt, lhs_value, rhs_value); + val = tb_inst_fadd(c->f, lhs_value, rhs_value); break; } - val = tb_inst_add(c->f, dt, lhs_value, rhs_value, tinybackend_get_arith_behavior(lhs_type)); + val = tb_inst_add(c->f, lhs_value, rhs_value, tinybackend_get_arith_behavior(lhs_type)); break; case BINARYOP_DIV: //llvm_emit_trap_zero(c, rhs_type, rhs_value, "% by zero", TOKLOC(expr->span.loc)); if (is_float) { - val = tb_inst_fdiv(c->f, dt, lhs_value, rhs_value); + val = tb_inst_fdiv(c->f, lhs_value, rhs_value); break; } - val = tb_inst_div(c->f, dt, lhs_value, rhs_value, !type_is_unsigned(lhs_type)); + val = tb_inst_div(c->f, lhs_value, rhs_value, !type_is_unsigned(lhs_type)); break; case BINARYOP_MOD: { @@ -598,20 +598,20 @@ void tinybackend_emit_binary(TbContext *c, TBEValue *TBE_VALUE, Expr *expr, TBEV case BINARYOP_SHR: if (type_is_unsigned(lhs_type)) { - val = tb_inst_shr(c->f, dt, lhs_value, rhs_value); + val = tb_inst_shr(c->f, lhs_value, rhs_value); return; } - val = tb_inst_sar(c->f, dt, lhs_value, rhs_value); + val = tb_inst_sar(c->f, lhs_value, rhs_value); break; case BINARYOP_SHL: - val = tb_inst_shl(c->f, dt, lhs_value, rhs_value, TB_ASSUME_NUW); + val = tb_inst_shl(c->f, lhs_value, rhs_value, TB_ASSUME_NUW); break; case BINARYOP_BIT_AND: - val = tb_inst_and(c->f, dt, lhs_value, rhs_value); + val = tb_inst_and(c->f, lhs_value, rhs_value); break; case BINARYOP_BIT_OR: - val = tb_inst_or(c->f, dt, lhs_value, rhs_value); + val = tb_inst_or(c->f, lhs_value, rhs_value); break; case BINARYOP_BIT_XOR: TODO @@ -726,10 +726,10 @@ static TB_Register tilde_emit_local_decl(TbContext *c, Decl *decl) scratch_buffer_append(decl->external_name); 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, scratch_buffer_to_string(), initializer); + decl->var.tb_failable_reg = tb_global_create(c->module, initializer, scratch_buffer_to_string(), 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, "tempglobal", static_initializer); + decl->tb_register = tb_global_create(c->module, static_initializer, "tempglobal", TB_LINKAGE_PRIVATE); tilde_emit_global_initializer(c, decl); return decl->tb_register; } @@ -778,7 +778,7 @@ static void tilde_emit_function_body(TbContext *c, Decl *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_Function *function = tb_prototype_build(c->module, prototype, decl->external_name, TB_LINKAGE_PUBLIC); c->f = function; AstId current = decl->func_decl.body->compound_stmt.first_stmt; diff --git a/src/compiler/tilde_codegen.c b/src/compiler/tilde_codegen.c index 92b0cb0ee..ed88c9e29 100644 --- a/src/compiler/tilde_codegen.c +++ b/src/compiler/tilde_codegen.c @@ -8,7 +8,7 @@ static void tbcontext_destroy(TbContext *context) TB_Register tilde_emit_is_no_error(TbContext *c, TB_Reg reg) { - return tb_inst_cmp_eq(c->f, tbtype(type_anyerr), reg, tilde_get_zero(c, type_anyerr)); + return tb_inst_cmp_eq(c->f, reg, tilde_get_zero(c, type_anyerr)); } void tilde_emit_global_initializer(TbContext *c, Decl *decl) diff --git a/src/compiler/tilde_codegen_expr.c b/src/compiler/tilde_codegen_expr.c index d9ef7ad0d..600e645f1 100644 --- a/src/compiler/tilde_codegen_expr.c +++ b/src/compiler/tilde_codegen_expr.c @@ -12,9 +12,9 @@ TB_Register tilde_get_zero(TbContext *c, Type *type) TB_DataType data_type = tbtype(type); if (type_is_float(type)) { - return tb_inst_fconst(c->f, data_type, 0); + return tb_inst_float(c->f, data_type, 0); } - return tb_inst_iconst(c->f, data_type, 0); + return type_is_signed(type) ? tb_inst_sint(c->f, data_type, 0) : tb_inst_uint(c->f, data_type, 0); } TBEValue tilde_emit_assign_expr(TbContext *c, TBEValue *ref, Expr *expr, TB_Reg failable) diff --git a/src/compiler/tilde_codegen_instr.c b/src/compiler/tilde_codegen_instr.c index 87b8d1fb5..6ed61aa39 100644 --- a/src/compiler/tilde_codegen_instr.c +++ b/src/compiler/tilde_codegen_instr.c @@ -5,8 +5,8 @@ void tilde_emit_memclear_size_align(TbContext *c, TB_Register ref, uint64_t size, AlignSize align) { ByteSize min = type_min_alignment(align, size); - TB_Register zero = tb_inst_iconst(c->f, TB_TYPE_I8, 0); - TB_Register elements = tb_inst_iconst(c->f, size <= UINT32_MAX ? TB_TYPE_I32 : TB_TYPE_I64, size); + TB_Register zero = tb_inst_uint(c->f, TB_TYPE_I8, 0); + TB_Register elements = tb_inst_uint(c->f, size <= UINT32_MAX ? TB_TYPE_I32 : TB_TYPE_I64, size); tb_inst_memset(c->f, ref, zero, elements, min); } @@ -22,7 +22,7 @@ TB_Reg tilde_emit_shl_fixed(TbContext *c, Type *type, TB_Reg reg, int shift) BitSize bit_width = type_kind_bitsize(type->type_kind); if (shift >= bit_width) return tilde_get_zero(c, type); TB_DataType int_type = tbtype(type); - return tb_inst_shl(c->f, int_type, reg, tb_inst_iconst(c->f, int_type, (unsigned)shift), type_is_signed(type) ? TB_ASSUME_NSW : TB_ASSUME_NUW); + return tb_inst_shl(c->f, reg, tb_inst_uint(c->f, int_type, (unsigned)shift), type_is_signed(type) ? TB_ASSUME_NSW : TB_ASSUME_NUW); } TB_Reg tilde_emit_lshr_fixed(TbContext *c, Type *type, TB_Reg reg, int shift) @@ -32,7 +32,7 @@ TB_Reg tilde_emit_lshr_fixed(TbContext *c, Type *type, TB_Reg reg, int shift) BitSize bit_width = type_kind_bitsize(type->type_kind); if (shift >= bit_width) return tilde_get_zero(c, type); TB_DataType int_type = tbtype(type); - return tb_inst_shr(c->f, int_type, reg, tb_inst_iconst(c->f, int_type, (unsigned)shift)); + return tb_inst_shr(c->f, reg, tb_inst_uint(c->f, int_type, (unsigned)shift)); } TB_Reg tilde_emit_alloca(TbContext *c, Type *type) diff --git a/src/compiler/tilde_codegen_stmt.c b/src/compiler/tilde_codegen_stmt.c index 80c21d9ae..1e251c46b 100644 --- a/src/compiler/tilde_codegen_stmt.c +++ b/src/compiler/tilde_codegen_stmt.c @@ -42,10 +42,10 @@ TB_Reg tilde_emit_local_decl(TbContext *c, Decl *decl) scratch_buffer_append(decl->external_name); 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, scratch_buffer_to_string(), initializer); + decl->var.tb_failable_reg = tb_global_create(c->module, initializer, scratch_buffer_to_string(), 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, "tempglobal", static_initializer); + decl->tb_register = tb_global_create(c->module, static_initializer, "tempglobal", TB_LINKAGE_PRIVATE); tilde_emit_global_initializer(c, decl); return decl->tb_register; } diff --git a/src/compiler/tilde_codegen_storeload.c b/src/compiler/tilde_codegen_storeload.c index 52672272d..3dfa0ec86 100644 --- a/src/compiler/tilde_codegen_storeload.c +++ b/src/compiler/tilde_codegen_storeload.c @@ -48,7 +48,7 @@ void tilde_store_value_aligned(TbContext *c, TB_Reg destination, TBEValue *value case TBE_ADDRESS: { ByteSize size = type_size(value->type); - TB_Reg copy_size = tb_inst_iconst(c->f, size <= UINT32_MAX ? TB_TYPE_I32 : TB_TYPE_I64, size); + TB_Reg copy_size = tb_inst_uint(c->f, size <= UINT32_MAX ? TB_TYPE_I32 : TB_TYPE_I64, size); tb_inst_memcpy(c->f, destination, value->reg, copy_size, type_min_alignment(alignment, value->alignment)); } } @@ -91,8 +91,8 @@ void tilde_store_zero(TbContext *c, Type *type, TB_Reg addr, AlignSize alignment } ByteSize size = type_size(type); ByteSize min = type_min_alignment(alignment, size); - TB_Register zero = tb_inst_iconst(c->f, TB_TYPE_I8, 0); - TB_Register elements = tb_inst_iconst(c->f, tbtype(type_usize), size); + TB_Register zero = tb_inst_uint(c->f, TB_TYPE_I8, 0); + TB_Register elements = tb_inst_uint(c->f, tbtype(type_usize), size); tb_inst_memset(c->f, addr, zero, elements, min); } diff --git a/src/compiler/tilde_codegen_value.c b/src/compiler/tilde_codegen_value.c index c492b8b5b..ff835fbc5 100644 --- a/src/compiler/tilde_codegen_value.c +++ b/src/compiler/tilde_codegen_value.c @@ -36,7 +36,7 @@ void value_addr(TbContext *c, TBEValue *value) // TODO check whether new names must be added TB_InitializerID initializer_id = tb_initializer_create(c->module, type_size(value->type), type_alloca_alignment(value->type), 0); - tb_global_create(c->module, ".taddr", initializer_id); + tb_global_create(c->module, initializer_id, ".taddr", TB_LINKAGE_PRIVATE); // TODO set linkage /* llvm_set_private_linkage(ref); diff --git a/tb/tb.h b/tb/tb.h index 783fdfad2..4f77942f8 100644 --- a/tb/tb.h +++ b/tb/tb.h @@ -32,7 +32,7 @@ extern "C" { // https://semver.org/ #define TB_VERSION_MAJOR 0 -#define TB_VERSION_MINOR 1 +#define TB_VERSION_MINOR 2 #define TB_VERSION_PATCH 0 #ifndef TB_MAX_THREADS @@ -115,6 +115,20 @@ typedef enum TB_BranchHint { 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, @@ -151,7 +165,10 @@ typedef enum TB_DataTypeEnum { typedef struct TB_DataType { TB_DataTypeEnum type : 8; - uint8_t count; // 0 is illegal, except on VOID, it doesn't matter there + + // 2^N where N is the width value. + // Only integers and floats can be wide. + uint8_t width; } TB_DataType; typedef struct TB_FeatureSet { @@ -187,6 +204,9 @@ typedef struct TB_SwitchEntry { typedef int TB_Register; typedef int TB_Reg; // short-hand +// represents byte counts +typedef uint32_t TB_CharUnits; + typedef unsigned int TB_FileID; typedef unsigned int TB_FunctionID; typedef unsigned int TB_ExternalID; @@ -197,52 +217,43 @@ typedef struct TB_Module TB_Module; typedef struct TB_Function TB_Function; typedef struct TB_FunctionPrototype TB_FunctionPrototype; +// represents the atomic cmpxchg result since it's two values +typedef struct TB_CmpXchgResult { + TB_Register success; + TB_Register old_value; +} TB_CmpXchgResult; + // ******************************* // Public macros // ******************************* #ifdef __cplusplus -#define TB_TYPE_VOID TB_DataType{ TB_VOID, 1 } +#define TB_TYPE_VOID TB_DataType{ TB_VOID } -#define TB_TYPE_I8 TB_DataType{ TB_I8, 1 } -#define TB_TYPE_I16 TB_DataType{ TB_I16, 1 } -#define TB_TYPE_I32 TB_DataType{ TB_I32, 1 } -#define TB_TYPE_I64 TB_DataType{ TB_I64, 1 } +#define TB_TYPE_I8 TB_DataType{ TB_I8 } +#define TB_TYPE_I16 TB_DataType{ TB_I16 } +#define TB_TYPE_I32 TB_DataType{ TB_I32 } +#define TB_TYPE_I64 TB_DataType{ TB_I64 } -#define TB_TYPE_F32 TB_DataType{ TB_F32, 1 } -#define TB_TYPE_F64 TB_DataType{ TB_F64, 1 } +#define TB_TYPE_F32 TB_DataType{ TB_F32 } +#define TB_TYPE_F64 TB_DataType{ TB_F64 } -#define TB_TYPE_BOOL TB_DataType{ TB_BOOL, 1 } -#define TB_TYPE_PTR TB_DataType{ TB_PTR, 1 } - -#define TB_TYPE_VEC_I8(c) TB_DataType{ TB_I8, c } -#define TB_TYPE_VEC_I16(c) TB_DataType{ TB_I16, c } -#define TB_TYPE_VEC_I32(c) TB_DataType{ TB_I32, c } -#define TB_TYPE_VEC_I64(c) TB_DataType{ TB_I64, c } -#define TB_TYPE_VEC_F32(c) TB_DataType{ TB_F32, c } -#define TB_TYPE_VEC_F64(c) TB_DataType{ TB_F64, c } -#define TB_TYPE_VEC_BOOL(c) TB_DataType{ TB_BOOL, c } +#define TB_TYPE_BOOL TB_DataType{ TB_BOOL } +#define TB_TYPE_PTR TB_DataType{ TB_PTR } #else -#define TB_TYPE_VOID (TB_DataType){ TB_VOID, 1 } +#define TB_TYPE_VOID (TB_DataType){ TB_VOID, 0 } -#define TB_TYPE_I8 (TB_DataType){ TB_I8, 1 } -#define TB_TYPE_I16 (TB_DataType){ TB_I16, 1 } -#define TB_TYPE_I32 (TB_DataType){ TB_I32, 1 } -#define TB_TYPE_I64 (TB_DataType){ TB_I64, 1 } +#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, 1 } -#define TB_TYPE_F64 (TB_DataType){ TB_F64, 1 } +#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, 1 } -#define TB_TYPE_PTR (TB_DataType){ TB_PTR, 1 } - -#define TB_TYPE_VEC_I8(c) (TB_DataType){ TB_I8, c } -#define TB_TYPE_VEC_I16(c) (TB_DataType){ TB_I16, c } -#define TB_TYPE_VEC_I32(c) (TB_DataType){ TB_I32, c } -#define TB_TYPE_VEC_I64(c) (TB_DataType){ TB_I64, c } -#define TB_TYPE_VEC_F32(c) (TB_DataType){ TB_F32, c } -#define TB_TYPE_VEC_F64(c) (TB_DataType){ TB_F64, c } +#define TB_TYPE_BOOL (TB_DataType){ TB_BOOL, 0 } +#define TB_TYPE_PTR (TB_DataType){ TB_PTR, 0 } #endif @@ -302,7 +313,7 @@ TB_API void tb_prototype_add_params(TB_FunctionPrototype* p, size_t count, const // adds a parameter to the function prototype, TB doesn't support struct // parameters so the frontend must lower them to pointers or any other type // depending on their preferred ABI. -TB_API TB_Function* tb_prototype_build(TB_Module* m, TB_FunctionPrototype* p, const char* name); +TB_API TB_Function* tb_prototype_build(TB_Module* m, TB_FunctionPrototype* p, const char* name, TB_Linkage linkage); //////////////////////////////// // Constant Initializers @@ -317,11 +328,14 @@ TB_API void* tb_initializer_add_region(TB_Module* m, TB_InitializerID id, size_t //////////////////////////////// // Constant Initializers //////////////////////////////// -TB_API TB_GlobalID tb_global_create(TB_Module* m, const char* name, TB_InitializerID initializer); +TB_API TB_GlobalID tb_global_create(TB_Module* m, TB_InitializerID initializer, const char* name, TB_Linkage linkage); //////////////////////////////// // Function IR Generation //////////////////////////////// +// 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_free(TB_Function* f); @@ -339,75 +353,114 @@ 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 TB_Register tb_inst_local(TB_Function* f, uint32_t size, uint32_t alignment); -TB_API TB_Register tb_inst_load(TB_Function* f, TB_DataType dt, TB_Register addr, uint32_t alignment); -TB_API void tb_inst_store(TB_Function* f, TB_DataType dt, TB_Register addr, TB_Register val, uint32_t alignment); +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_Register tb_inst_volatile_load(TB_Function* f, TB_DataType dt, TB_Register addr, uint32_t alignment); -TB_API void tb_inst_volatile_store(TB_Function* f, TB_DataType dt, TB_Register addr, TB_Register val, uint32_t alignment); +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_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); + +// 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 TB_Register tb_inst_iconst(TB_Function* f, TB_DataType dt, uint64_t imm); -TB_API TB_Register tb_inst_fconst(TB_Function* f, TB_DataType dt, double imm); +// 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); -// string is a UTF-8 null terminated string -TB_API TB_Register tb_inst_const_cstr(TB_Function* f, const char* str); +// 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); -// string is a slice of bytes -TB_API TB_Register tb_inst_const_string(TB_Function* f, const char* str, size_t len); +// Clears a memory region to zeroes +TB_API void tb_inst_memclr(TB_Function* f, TB_Register 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); + +// 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_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); +// 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); + +// 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); + +// 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); + +// 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); + +// if (*addr == expected) { +// old_value = atomic_xchg(addr, desired); +// return { true, old_value }; +// } 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); + +// 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); + +// 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_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_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); + +// 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 void tb_inst_memset(TB_Function* f, TB_Register dst, TB_Register val, TB_Register size, int align); -TB_API void tb_inst_memcpy(TB_Function* f, TB_Register dst, TB_Register src, TB_Register size, int align); - -TB_API TB_Register tb_inst_not(TB_Function* f, TB_DataType dt, TB_Register n); -TB_API TB_Register tb_inst_neg(TB_Function* f, TB_DataType dt, TB_Register n); - -TB_API TB_Register tb_inst_and(TB_Function* f, TB_DataType dt, TB_Register a, TB_Register b); -TB_API TB_Register tb_inst_or(TB_Function* f, TB_DataType dt, TB_Register a, TB_Register b); -TB_API TB_Register tb_inst_xor(TB_Function* f, TB_DataType dt, TB_Register a, TB_Register b); -TB_API TB_Register tb_inst_add(TB_Function* f, TB_DataType dt, TB_Register a, TB_Register b, TB_ArithmaticBehavior arith_behavior); -TB_API TB_Register tb_inst_sub(TB_Function* f, TB_DataType dt, TB_Register a, TB_Register b, TB_ArithmaticBehavior arith_behavior); -TB_API TB_Register tb_inst_mul(TB_Function* f, TB_DataType dt, TB_Register a, TB_Register b, TB_ArithmaticBehavior arith_behavior); -TB_API TB_Register tb_inst_div(TB_Function* f, TB_DataType dt, TB_Register a, TB_Register b, bool signedness); - -TB_API TB_Register tb_inst_shl(TB_Function* f, TB_DataType dt, TB_Register a, TB_Register b, TB_ArithmaticBehavior arith_behavior); -TB_API TB_Register tb_inst_sar(TB_Function* f, TB_DataType dt, TB_Register a, TB_Register b); -TB_API TB_Register tb_inst_shr(TB_Function* f, TB_DataType dt, TB_Register a, TB_Register b); - -TB_API TB_Register tb_inst_fadd(TB_Function* f, TB_DataType dt, TB_Register a, TB_Register b); -TB_API TB_Register tb_inst_fsub(TB_Function* f, TB_DataType dt, TB_Register a, TB_Register b); -TB_API TB_Register tb_inst_fmul(TB_Function* f, TB_DataType dt, TB_Register a, TB_Register b); -TB_API TB_Register tb_inst_fdiv(TB_Function* f, TB_DataType dt, TB_Register a, TB_Register b); - -TB_API TB_Register tb_inst_cmp_eq(TB_Function* f, TB_DataType dt, TB_Register a, TB_Register b); -TB_API TB_Register tb_inst_cmp_ne(TB_Function* f, TB_DataType dt, TB_Register a, TB_Register b); - -TB_API TB_Register tb_inst_cmp_ilt(TB_Function* f, TB_DataType dt, TB_Register a, TB_Register b, bool signedness); -TB_API TB_Register tb_inst_cmp_ile(TB_Function* f, TB_DataType dt, TB_Register a, TB_Register b, bool signedness); -TB_API TB_Register tb_inst_cmp_igt(TB_Function* f, TB_DataType dt, TB_Register a, TB_Register b, bool signedness); -TB_API TB_Register tb_inst_cmp_ige(TB_Function* f, TB_DataType dt, TB_Register a, TB_Register b, bool signedness); - -TB_API TB_Register tb_inst_cmp_flt(TB_Function* f, TB_DataType dt, TB_Register a, TB_Register b); -TB_API TB_Register tb_inst_cmp_fle(TB_Function* f, TB_DataType dt, TB_Register a, TB_Register b); -TB_API TB_Register tb_inst_cmp_fgt(TB_Function* f, TB_DataType dt, TB_Register a, TB_Register b); -TB_API TB_Register tb_inst_cmp_fge(TB_Function* f, TB_DataType dt, TB_Register a, TB_Register b); - -// Gives you a reference to a local label, doesn't place it anywhere. TB_API TB_Label tb_inst_new_label_id(TB_Function* f); - -TB_API TB_Register tb_inst_phi2(TB_Function* f, TB_DataType dt, TB_Label a_label, TB_Register a, TB_Label b_label, TB_Register b); +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 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); @@ -437,7 +490,7 @@ TB_API bool tb_opt_copy_elision(TB_Function* f); // IR access //////////////////////////////// TB_API TB_FunctionID tb_function_get_id(TB_Module* m, TB_Function* f); -TB_API TB_Function* tb_get_function_by_id(TB_Module* m, TB_FunctionID id); +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);