#ifndef __SPL_IR_H__ #define __SPL_IR_H__ #include "../stage0/include/utils.h" #include "spl_dbg.h" #include "spl_type.h" /* clang-format off */ #define SPL_IR_FN_TABLE \ X(arith.add, V0, SPL_IR_ARITH_ADD) \ X(arith.sub, V0, SPL_IR_ARITH_SUB) \ X(arith.mul, V0, SPL_IR_ARITH_MUL) \ X(arith.div, V0, SPL_IR_ARITH_DIV) \ X(arith.rem, V0, SPL_IR_ARITH_REM) \ X(arith.neg, V0, SPL_IR_ARITH_NEG) \ X(arith.abs, V0, SPL_IR_ARITH_ABS) \ X(arith.and, V0, SPL_IR_ARITH_AND) \ X(arith.or, V0, SPL_IR_ARITH_OR) \ X(arith.xor, V0, SPL_IR_ARITH_XOR) \ X(arith.shl, V0, SPL_IR_ARITH_SHL) \ X(arith.shr, V0, SPL_IR_ARITH_SHR) \ X(arith.not, V0, SPL_IR_ARITH_NOT) \ X(cmp.eq, V0, SPL_IR_CMP_EQ) \ X(cmp.ne, V0, SPL_IR_CMP_NE) \ X(cmp.lt, V0, SPL_IR_CMP_LT) \ X(cmp.le, V0, SPL_IR_CMP_LE) \ X(cmp.gt, V0, SPL_IR_CMP_GT) \ X(cmp.ge, V0, SPL_IR_CMP_GE) \ X(cast.trunc, V0, SPL_IR_CAST_TRUNC) \ X(cast.zext, V0, SPL_IR_CAST_ZEXT) \ X(cast.sext, V0, SPL_IR_CAST_SEXT) \ X(cast.fext, V0, SPL_IR_CAST_FEXT) \ X(cast.ftrunc, V0, SPL_IR_CAST_FTRUNC) \ X(cast.bitcast, V0, SPL_IR_CAST_BITCAST) \ X(cast.ptr2int, V0, SPL_IR_CAST_PTR2INT) \ X(cast.int2ptr, V0, SPL_IR_CAST_INT2PTR) \ X(cast.bool2int, V0, SPL_IR_CAST_BOOL2INT) \ X(case.int2float, V0, SPL_IR_CASE_INT2FLOAT) \ X(case.float2int, V0, SPL_IR_CASE_FLOAT2INT) \ X(mem.alloca, V0, SPL_IR_MEM_ALLOCA) \ X(mem.global_alloc, V0, SPL_IR_MEM_GLOBAL_ALLOC) \ X(mem.load, V0, SPL_IR_MEM_LOAD) \ X(mem.store, V0, SPL_IR_MEM_STORE) \ X(mem.offset, V0, SPL_IR_MEM_OFFSET) \ X(mem.field, V0, SPL_IR_MEM_FIELD_PTR) \ X(mem.copy, V0, SPL_IR_MEM_COPY) \ X(mem.set, V0, SPL_IR_MEM_SET) \ X(type.const, V0, SPL_IR_TYPE_CONST) \ X(type.bitsizeof, V0, SPL_IR_TYPE_BITSIZEOF) \ X(type.sizeof, V0, SPL_IR_TYPE_SIZEOF) \ X(type.alignof, V0, SPL_IR_TYPE_ALIGNOF) \ X(type.offsetof, V0, SPL_IR_TYPE_OFFSETOF) \ X(type.field_count, V0, SPL_IR_TYPE_FIELD_COUNT) \ X(agg.construct, V0, SPL_IR_AGG_CONSTRUCT) \ X(agg.extract, V0, SPL_IR_AGG_EXTRACT) \ X(agg.insert, V0, SPL_IR_AGG_INSERT) \ X(control.select, V0, SPL_IR_CONTROL_SELECT) \ X(control.br, V0, SPL_IR_CONTROL_BR) \ X(control.jmp, V0, SPL_IR_CONTROL_JMP) \ X(control.call, V0, SPL_IR_CONTROL_CALL) \ X(control.param, V0, SPL_IR_CONTROL_PARAM) \ X(control.ret, V0, SPL_IR_CONTROL_RET) \ X(control.unreachable, V0, SPL_IR_CONTROL_UNREACHABLE) \ X(control.trap, V0, SPL_IR_CONTROL_TRAP) \ X(dbg.breakpoint, V0, SPL_IR_DBG_BREAKPOINT) \ typedef enum { #ifdef X #undef X #endif #define X(a, b, c) c, SPL_IR_FN_TABLE #undef X } spl_ir_kind_t; /* clang-format on */ typedef usize spl_ir_node_ref_t; /* 0 is error */ typedef VEC(spl_ir_node_ref_t) spl_ir_node_ref_vec_t; typedef usize spl_ir_func_ref_t; /* 0 is error */ typedef struct { spl_ir_kind_t kind; spl_dbg_node_t dbg; union { spl_type_id_t tid; struct { spl_type_id_t tid; spl_ir_node_ref_t left; spl_ir_node_ref_t right; } arith; struct { spl_type_id_t tid; spl_ir_node_ref_t a; spl_ir_node_ref_t b; } cmp; struct { spl_type_id_t from_tid; spl_type_id_t to_tid; spl_ir_node_ref_t val; } cast; struct { spl_type_id_t tid; spl_ir_node_ref_t count; } mem_alloc; struct { spl_type_id_t tid; spl_ir_node_ref_t const_node; } mem_global_alloc; struct { spl_type_id_t tid; spl_ir_node_ref_t ptr; } mem_load; struct { spl_type_id_t tid; spl_ir_node_ref_t ptr; spl_ir_node_ref_t val; } mem_store; struct { spl_type_id_t tid; spl_ir_node_ref_t ptr; spl_ir_node_ref_t offset; } mem_offset; struct { spl_type_id_t tid; spl_ir_node_ref_t agg; usize field_idx; } mem_field_ptr; struct { spl_type_id_t tid; spl_ir_node_ref_t dst; spl_ir_node_ref_t src; spl_ir_node_ref_t size; } mem_copy; struct { spl_type_id_t tid; spl_ir_node_ref_t dst; spl_ir_node_ref_t val; spl_ir_node_ref_t size; } mem_set; struct { spl_type_id_t tid; union { usize int_lit; double float_lit; const char *cstr_lit; char ch_lit; spl_ir_func_ref_t fn; }; } type_const; struct { spl_type_id_t tid; } bitsizeof; struct { spl_type_id_t tid; } ir_sizeof; struct { spl_type_id_t tid; } ir_alignof; struct { spl_type_id_t tid; spl_ir_node_ref_t field_idx; } ir_offsetof; struct { spl_type_id_t tid; } field_count; struct { spl_type_id_t tid; spl_ir_node_ref_vec_t fields; } agg_construct; struct { spl_type_id_t tid; spl_type_id_t field_tid; usize field_idx; spl_ir_node_ref_t val; } agg_extract; struct { spl_type_id_t tid; usize field_idx; spl_ir_node_ref_t agg; spl_ir_node_ref_t field; } agg_insert; struct { spl_type_id_t tid; spl_ir_node_ref_t cond; spl_ir_node_ref_t true_val; spl_ir_node_ref_t false_val; } control_select; struct { spl_ir_node_ref_t cond; spl_ir_node_ref_t true_label; spl_ir_node_ref_t false_label; } control_br; struct { spl_ir_node_ref_t label; } control_jmp; struct { spl_type_id_t tid; spl_ir_node_ref_t func; spl_ir_node_ref_vec_t params; } control_call; struct { spl_type_id_t tid; spl_ir_node_ref_t idx; } control_param; struct { spl_type_id_t tid; spl_ir_node_ref_t val; } control_ret; }; } spl_ir_node_t; typedef VEC(spl_ir_node_t) spl_ir_node_vec_t; typedef struct { enum { SPL_IR_ATTR_NONE, SPL_IR_ATTR_LINK, /* 不实现 */ SPL_IR_ATTR_ABI, /* 只有 C ABI 支持 */ SPL_IR_ATTR_SYMBOL, /* 不实现 */ SPL_IR_ATTR_NAKED, /* 不实现 */ SPL_IR_ATTR_NOINLINE, /* 不实现 */ SPL_IR_ATTR_ALWAYSINLINE, /* 不实现 */ }; } spl_ir_attr_t; typedef VEC(spl_ir_attr_t) spl_ir_attr_vec_t; typedef struct { const char *name; spl_ir_attr_t attr; spl_type_id_t fn_tid; spl_ir_node_vec_t nodes; spl_ir_node_ref_vec_t labels; } spl_ir_func_t; typedef VEC(spl_ir_func_t) spl_ir_func_vec_t; typedef struct { spl_ir_func_vec_t funcs; spl_ir_node_vec_t gdata; } spl_ir_t; void spl_ir_init(spl_ir_t *ir); void spl_ir_drop(spl_ir_t *ir); spl_ir_node_ref_t spl_ir_alloc_node(spl_ir_t *ir, spl_ir_func_ref_t fn_id); spl_ir_func_ref_t spl_ir_alloc_fn(spl_ir_t *ir); spl_ir_node_t *spl_ir_node(spl_ir_t *ir, spl_ir_func_ref_t fn_id, spl_ir_node_ref_t node_id); spl_ir_func_t *spl_ir_func(spl_ir_t *ir, spl_ir_func_ref_t fn_id); void spl_ir_dump(spl_ir_t *ir, const spl_type_t *ty); const char *spl_ir_kind_name(spl_ir_kind_t kind); typedef struct { spl_ir_t ir; spl_ir_func_ref_t current_fn; spl_ir_node_ref_t current_node; spl_ir_node_ref_vec_t reloc_label; spl_dbg_node_t dbg; } spl_ir_builder_t; /* clang-format off */ #define SPL_IR_BIN_ARITH_TABLE \ X(arith_add, SPL_IR_ARITH_ADD) \ X(arith_sub, SPL_IR_ARITH_SUB) \ X(arith_mul, SPL_IR_ARITH_MUL) \ X(arith_div, SPL_IR_ARITH_DIV) \ X(arith_rem, SPL_IR_ARITH_REM) \ X(arith_and, SPL_IR_ARITH_AND) \ X(arith_or, SPL_IR_ARITH_OR) \ X(arith_xor, SPL_IR_ARITH_XOR) \ X(arith_shl, SPL_IR_ARITH_SHL) \ X(arith_shr, SPL_IR_ARITH_SHR) #define SPL_IR_UN_ARITH_TABLE \ X(arith_neg, SPL_IR_ARITH_NEG) \ X(arith_abs, SPL_IR_ARITH_ABS) \ X(arith_not, SPL_IR_ARITH_NOT) #define SPL_IR_CMP_TABLE \ X(cmp_eq, SPL_IR_CMP_EQ) \ X(cmp_ne, SPL_IR_CMP_NE) \ X(cmp_lt, SPL_IR_CMP_LT) \ X(cmp_le, SPL_IR_CMP_LE) \ X(cmp_gt, SPL_IR_CMP_GT) \ X(cmp_ge, SPL_IR_CMP_GE) #define SPL_IR_CAST_TABLE \ X(cast_trunc, SPL_IR_CAST_TRUNC) \ X(cast_zext, SPL_IR_CAST_ZEXT) \ X(cast_sext, SPL_IR_CAST_SEXT) \ X(cast_fext, SPL_IR_CAST_FEXT) \ X(cast_ftrunc, SPL_IR_CAST_FTRUNC) \ X(cast_bitcast, SPL_IR_CAST_BITCAST) \ X(cast_ptr2int, SPL_IR_CAST_PTR2INT) \ X(cast_int2ptr, SPL_IR_CAST_INT2PTR) \ X(cast_bool2int, SPL_IR_CAST_BOOL2INT) \ X(case_int2float, SPL_IR_CASE_INT2FLOAT) \ X(case_float2int, SPL_IR_CASE_FLOAT2INT) /* clang-format on */ void spl_ir_builder_init(spl_ir_builder_t *b); void spl_ir_builder_drop(spl_ir_builder_t *b); spl_ir_func_ref_t spl_ir_builder_fn_new(spl_ir_builder_t *b, const char *name, spl_type_id_t fn_tid); spl_ir_func_ref_t spl_ir_builder_cur_fn(const spl_ir_builder_t *b); void spl_ir_builder_set_dbg(spl_ir_builder_t *b, spl_dbg_node_t dbg); spl_ir_node_ref_t spl_ir_builder_block_new(spl_ir_builder_t *b); #define X(name, kind) \ spl_ir_node_ref_t spl_ir_builder_##name(spl_ir_builder_t *b, spl_type_id_t tid, \ spl_ir_node_ref_t left, spl_ir_node_ref_t right); SPL_IR_BIN_ARITH_TABLE #undef X #define X(name, kind) \ spl_ir_node_ref_t spl_ir_builder_##name(spl_ir_builder_t *b, spl_type_id_t tid, \ spl_ir_node_ref_t val); SPL_IR_UN_ARITH_TABLE #undef X #define X(name, kind) \ spl_ir_node_ref_t spl_ir_builder_##name(spl_ir_builder_t *builder, spl_type_id_t tid, \ spl_ir_node_ref_t a, spl_ir_node_ref_t b); SPL_IR_CMP_TABLE #undef X #define X(name, kind) \ spl_ir_node_ref_t spl_ir_builder_##name(spl_ir_builder_t *b, spl_type_id_t from_tid, \ spl_type_id_t to_tid, spl_ir_node_ref_t val); SPL_IR_CAST_TABLE #undef X spl_ir_node_ref_t spl_ir_builder_mem_alloca(spl_ir_builder_t *b, spl_type_id_t tid, spl_ir_node_ref_t count); spl_ir_node_ref_t spl_ir_builder_mem_global_alloc(spl_ir_builder_t *b, spl_type_id_t tid, spl_ir_node_ref_t const_node); spl_ir_node_ref_t spl_ir_builder_mem_load(spl_ir_builder_t *b, spl_type_id_t tid, spl_ir_node_ref_t ptr); spl_ir_node_ref_t spl_ir_builder_mem_store(spl_ir_builder_t *b, spl_type_id_t tid, spl_ir_node_ref_t ptr, spl_ir_node_ref_t val); spl_ir_node_ref_t spl_ir_builder_mem_offset(spl_ir_builder_t *b, spl_type_id_t tid, spl_ir_node_ref_t ptr, spl_ir_node_ref_t offset); spl_ir_node_ref_t spl_ir_builder_mem_field(spl_ir_builder_t *b, spl_type_id_t tid, spl_ir_node_ref_t agg, usize field_idx); spl_ir_node_ref_t spl_ir_builder_mem_copy(spl_ir_builder_t *b, spl_type_id_t tid, spl_ir_node_ref_t dst, spl_ir_node_ref_t src, spl_ir_node_ref_t size); spl_ir_node_ref_t spl_ir_builder_mem_set(spl_ir_builder_t *b, spl_type_id_t tid, spl_ir_node_ref_t dst, spl_ir_node_ref_t val, spl_ir_node_ref_t size); spl_ir_node_ref_t spl_ir_builder_type_const_int(spl_ir_builder_t *b, spl_type_id_t tid, usize val); spl_ir_node_ref_t spl_ir_builder_type_const_float(spl_ir_builder_t *b, spl_type_id_t tid, double val); spl_ir_node_ref_t spl_ir_builder_type_const_cstr(spl_ir_builder_t *b, spl_type_id_t tid, const char *val); spl_ir_node_ref_t spl_ir_builder_type_const_char(spl_ir_builder_t *b, spl_type_id_t tid, char val); spl_ir_node_ref_t spl_ir_builder_type_const_fn(spl_ir_builder_t *b, spl_type_id_t tid, spl_ir_func_ref_t val); spl_ir_node_ref_t spl_ir_builder_type_bitsizeof(spl_ir_builder_t *b, spl_type_id_t tid); spl_ir_node_ref_t spl_ir_builder_type_sizeof(spl_ir_builder_t *b, spl_type_id_t tid); spl_ir_node_ref_t spl_ir_builder_type_alignof(spl_ir_builder_t *b, spl_type_id_t tid); spl_ir_node_ref_t spl_ir_builder_type_offsetof(spl_ir_builder_t *b, spl_type_id_t tid, spl_ir_node_ref_t field_idx); spl_ir_node_ref_t spl_ir_builder_type_field_count(spl_ir_builder_t *b, spl_type_id_t tid); spl_ir_node_ref_t spl_ir_builder_agg_construct(spl_ir_builder_t *b, spl_type_id_t tid); void spl_ir_builder_agg_construct_field(spl_ir_builder_t *b, spl_ir_node_ref_t node, spl_ir_node_ref_t field); spl_ir_node_ref_t spl_ir_builder_agg_extract(spl_ir_builder_t *b, spl_type_id_t tid, spl_type_id_t field_tid, usize field_idx, spl_ir_node_ref_t val); spl_ir_node_ref_t spl_ir_builder_agg_insert(spl_ir_builder_t *b, spl_type_id_t tid, usize field_idx, spl_ir_node_ref_t agg, spl_ir_node_ref_t field); spl_ir_node_ref_t spl_ir_builder_control_select(spl_ir_builder_t *b, spl_type_id_t tid, spl_ir_node_ref_t cond, spl_ir_node_ref_t true_val, spl_ir_node_ref_t false_val); spl_ir_node_ref_t spl_ir_builder_control_br(spl_ir_builder_t *b, spl_ir_node_ref_t cond, spl_ir_node_ref_t true_label, spl_ir_node_ref_t false_label); spl_ir_node_ref_t spl_ir_builder_control_jmp(spl_ir_builder_t *b, spl_ir_node_ref_t label); spl_ir_node_ref_t spl_ir_builder_control_call(spl_ir_builder_t *b, spl_type_id_t tid, spl_ir_node_ref_t func); void spl_ir_builder_control_call_param(spl_ir_builder_t *b, spl_ir_node_ref_t node, spl_ir_node_ref_t arg); spl_ir_node_ref_t spl_ir_builder_control_param(spl_ir_builder_t *b, spl_type_id_t tid, spl_ir_node_ref_t idx); spl_ir_node_ref_t spl_ir_builder_control_ret(spl_ir_builder_t *b, spl_type_id_t tid, spl_ir_node_ref_t val); spl_ir_node_ref_t spl_ir_builder_control_unreachable(spl_ir_builder_t *b); spl_ir_node_ref_t spl_ir_builder_control_trap(spl_ir_builder_t *b); spl_ir_node_ref_t spl_ir_builder_dbg_breakpoint(spl_ir_builder_t *b); #endif /* __SPL_IR_H__ */