Updated with latest TB.

This commit is contained in:
Christoffer Lerno
2022-01-10 14:38:31 +01:00
parent 4764981708
commit 180b17b213
8 changed files with 182 additions and 129 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

229
tb/tb.h
View File

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