feat(compiler): 实现HIR到LIR的函数定义标记和直接/间接调用区分

- 在HIR函数元数据中添加defined字段来标记函数是否已定义
- 在AST到IR转换过程中设置函数定义状态
- 修改LIR模块函数声明接口以支持定义状态参数
- 实现直接调用和间接调用的区别处理,通过符号查找确定调用类型
- 更新LIR调用指令结构以支持直接和间接调用的不同表示方式
- 调整x86后端指令选择以正确处理不同类型的调用

fix(x86-isel): 优化x86指令发射和操作数大小处理

- 移除move/load/store函数中的size参数,改由操作数本身携带大小信息
- 简化x86指令操作数结构,减少操作数数量限制
- 添加专门的mov系列表单选择函数,根据操作数类型和大小自动选择正确的指令形式
- 修正间接调用的指令形式为CALL_NEAR_MEMV而非GPRV
- 添加向量版本的load/store/move发射函数

refactor(reg-alloc): 更新寄存器分配迭代器接口

- 为分配迭代器的替换方法添加size参数,以便正确处理不同大小的寄存器
This commit is contained in:
zzy
2026-05-23 15:33:54 +08:00
parent d78b91894e
commit ea553718f0
21 changed files with 495 additions and 444 deletions

View File

@@ -249,6 +249,7 @@ typedef struct scc_hir_bblock_meta {
typedef struct scc_hir_func_meta {
scc_hir_type_ref_t type;
scc_hir_value_ref_vec_t params;
int defined;
} scc_hir_func_meta_t;
#define SCC_HIR_BBLOCK_VALUES(bblock) \

View File

@@ -188,6 +188,7 @@ scc_hir_func_ref_t scc_hir_builder_func(scc_hir_builder_t *builder,
// 创建新函数
scc_hir_func_t func;
scc_hir_func_meta_t *meta = scc_malloc(sizeof(scc_hir_func_meta_t));
meta->defined = 0;
Assert(meta != nullptr);
func.meta = meta;
scc_hir_func_init(&func, name);

View File

@@ -185,21 +185,16 @@ typedef struct scc_lir_ins {
scc_lir_bblock_id_t jmp_target;
struct scc_lir_call {
const char *callee;
scc_lir_val_t *args;
int arg_count;
scc_lir_val_t ret_vreg;
u64 clobber_mask;
union {
const char *callee_name;
scc_lir_val_t callee_target;
};
} call;
struct scc_lir_call_indirect {
scc_lir_val_t target;
scc_lir_val_t *args;
int arg_count;
scc_lir_val_t ret_vreg;
u64 clobber_mask;
} call_indirect;
scc_lir_val_t ret_val;
struct scc_lir_parallel_copy {

View File

@@ -33,11 +33,11 @@ void scc_lir_module_drop(scc_lir_module_t *lir_module);
* @brief 添加一个函数声明(外部或未定义)
* @param mod 模块
* @param name 函数名
* @param attr 属性
* @param defined 是否定义
* @return 符号指针
*/
scc_lir_symbol_id_t scc_lir_module_add_func_decl(scc_lir_module_t *lir_module,
const char *name);
const char *name, int defined);
/**
* @brief 添加一个全局数据符号(定义或外部)
@@ -56,4 +56,8 @@ scc_lir_symbol_id_t scc_lir_module_add_data(scc_lir_module_t *lir_module,
const u8 *init_data, usize size,
u32 align);
scc_lir_symbol_t *
scc_lir_module_unsafe_lookup_symbol(const scc_lir_module_t *lir_module,
const char *name);
#endif /* __SCC_LIR_MODULE_H__ */

View File

@@ -27,6 +27,7 @@ static void ir2lir_ctx_init(ir2lir_ctx_t *ctx, scc_lir_module_t *lir_module,
}
static void ir2lir_ctx_drop(ir2lir_ctx_t *ctx) {
// FIXME memory leak
scc_hashtable_drop(&ctx->value_to_vreg);
scc_hashtable_drop(&ctx->func_decl_map);
}
@@ -373,15 +374,26 @@ static void translate_hir_value(ir2lir_ctx_t *ctx, scc_hir_value_t *value,
lir_args[i] = ir_value_to_lir_operand(ctx, arg_ref);
}
scc_lir_instr_t instr = {
.op = SCC_LIR_CALL,
// TODO this is on windows all extern is indirect call
// On Linux ELF all call is direct call expect using `-no-plt`
scc_lir_symbol_t *sym =
scc_lir_module_unsafe_lookup_symbol(ctx->lir_module, callee->name);
Assert(sym != nullptr);
int is_direct_call = sym->kind == SCC_CFG_SYMBOL_KIND_FUNC;
scc_lir_instr_t instr = (scc_lir_instr_t){
.op = is_direct_call ? SCC_LIR_CALL : SCC_LIR_CALL_INDIRECT,
.size = size,
.to = SCC_LIR_VREG(dst_vreg),
.metadata.call = {.callee = callee->name,
.args = lir_args,
.metadata.call = {.args = lir_args,
.arg_count = arg_count,
.ret_vreg = SCC_LIR_VREG(dst_vreg),
.clobber_mask = 0}};
.clobber_mask = 0},
};
if (is_direct_call) {
instr.metadata.call.callee_name = callee->name;
} else {
instr.metadata.call.callee_target = SCC_LIR_SYMBOL(callee->name);
}
scc_lir_builder_add_instr(ctx, &instr);
// 注意lir_args 内存将随指令结构体复制到基本块向量中,但
// metadata.call.args 指针仍指向 malloc 内存,
@@ -598,11 +610,11 @@ void scc_hir2lir(scc_lir_module_t *module, scc_hir_cprog_t *cprog) {
scc_hir_module_get_func(&cprog->module, func_ref);
if (!func)
continue;
scc_lir_symbol_id_t id =
scc_lir_module_add_func_decl(module, func->name);
scc_lir_symbol_id_t id = scc_lir_module_add_func_decl(
module, func->name, SCC_HIR_FUNC_META(func)->defined);
Assert(id != SCC_CFG_ID_nullptr);
// 记录映射,供调用时使用
scc_hashtable_set(&ctx.func_decl_map, (void *)(uintptr_t)func_ref,
scc_hashtable_set(&ctx.func_decl_map, (void *)(usize)func_ref,
(void *)func->name);
}
@@ -613,8 +625,8 @@ void scc_hir2lir(scc_lir_module_t *module, scc_hir_cprog_t *cprog) {
scc_hir_module_get_func(&cprog->module, func_ref);
if (!func)
continue;
translate_func(&ctx, func);
}
ir2lir_ctx_drop(&ctx);
}

View File

@@ -290,30 +290,21 @@ void scc_lir_dump_ins(scc_lir_dump_ctx_t *ctx, const scc_lir_instr_t *ins) {
case SCC_LIR_JMP_INDIRECT:
dump_operand(ctx, &ins->arg0);
break;
case SCC_LIR_CALL: {
case SCC_LIR_CALL:
case SCC_LIR_CALL_INDIRECT: {
const struct scc_lir_call *c = &ins->metadata.call;
if (c->ret_vreg.kind != SCC_LIR_INSTR_KIND_NONE) {
dump_operand(ctx, &c->ret_vreg);
scc_tree_dump_append(td, " = ");
}
scc_tree_dump_append_fmt(td, "call @%s(",
c->callee ? c->callee : "<null>");
for (u8 i = 0; i < c->arg_count; i++) {
if (i > 0)
scc_tree_dump_append(td, ", ");
dump_operand(ctx, &c->args[i]);
}
scc_tree_dump_append_fmt(td, ") clobber=0x%llx",
(unsigned long long)c->clobber_mask);
} break;
case SCC_LIR_CALL_INDIRECT: {
const struct scc_lir_call_indirect *c = &ins->metadata.call_indirect;
if (c->ret_vreg.kind != SCC_LIR_INSTR_KIND_NONE) {
dump_operand(ctx, &c->ret_vreg);
scc_tree_dump_append(td, " = ");
}
scc_tree_dump_append(td, "call ");
dump_operand(ctx, &c->target);
if (ins->op == SCC_LIR_CALL) {
scc_tree_dump_append_fmt(
td, "@%s", c->callee_name ? c->callee_name : "<null>");
} else {
dump_operand(ctx, &c->callee_target);
}
scc_tree_dump_append(td, "(");
for (u8 i = 0; i < c->arg_count; i++) {
if (i > 0)

View File

@@ -3,7 +3,6 @@
void scc_lir_module_init(scc_lir_module_t *lir_module) {
// FIXME
// lir_module->lir_module
scc_vec_init(lir_module->func_metas);
scc_vec_init(lir_module->symbol_metas);
}
@@ -14,15 +13,25 @@ void scc_lir_module_drop(scc_lir_module_t *lir_module) {
scc_vec_free(lir_module->symbol_metas);
}
scc_lir_symbol_t *
scc_lir_module_unsafe_lookup_symbol(const scc_lir_module_t *lir_module,
const char *name) {
// FIXME const ?
return (void *)scc_cfg_module_unsafe_lookup_symbol(&lir_module->cfg_module,
name);
}
scc_lir_symbol_id_t scc_lir_module_add_func_decl(scc_lir_module_t *lir_module,
const char *name) {
const char *name,
int defined) {
if (!lir_module || !name)
return SCC_CFG_ID_nullptr;
scc_lir_symbol_meta_t *meta = scc_malloc(sizeof(scc_lir_symbol_meta_t));
Assert(meta != nullptr);
scc_lir_symbol_t sym = {.name = name,
.kind = SCC_CFG_SYMBOL_KIND_FUNC,
.kind = defined ? SCC_CFG_SYMBOL_KIND_FUNC
: SCC_CFG_SYMBOL_KIND_EXTERN,
.linkage = SCC_CFG_SYMBOL_LINK_GLOABL,
.meta = meta};
meta->func.func = nullptr;

View File

@@ -20,13 +20,15 @@ void scc_isel_x86_64(scc_mir_module_t *mir_module,
// Utils
void scc_x86_emit_move(scc_x86_64_isel_t *isel, scc_x86_operand_value_t dst_reg,
scc_x86_operand_value_t src, u8 size);
scc_x86_operand_value_t src);
void scc_x86_emit_load(scc_x86_64_isel_t *isel, scc_x86_operand_value_t dst,
scc_x86_operand_value_t src, u8 size);
scc_x86_operand_value_t src);
void scc_x86_emit_store(scc_x86_64_isel_t *isel, scc_x86_operand_value_t dst,
scc_x86_operand_value_t src, u8 size);
scc_x86_operand_value_t src);
scc_x86_operand_value_t scc_x86_lir_val_to_mir_op(scc_x86_64_isel_t *isel,
const scc_lir_val_t *val);
const scc_lir_val_t *val,
u8 size);
static inline void emit_direct_call(scc_x86_64_isel_t *isel,
const char *callee) {
scc_mir_x86_instr_t instr = {0};
@@ -37,10 +39,11 @@ static inline void emit_direct_call(scc_x86_64_isel_t *isel,
}
static inline void emit_indirect_call(scc_x86_64_isel_t *isel,
scc_x86_operand_value_t reg) {
scc_x86_operand_value_t mem) {
scc_mir_x86_instr_t instr = {0};
scc_mir_x86_instr_1(&instr, SCC_X86_IFORM_CALL_NEAR_GPRV, reg,
scc_mir_x86_instr_1(&instr, SCC_X86_IFORM_CALL_NEAR_MEMV, mem,
scc_pos_create());
scc_vec_push(isel->instrs, instr);
}
static inline void emit_ret(scc_x86_64_isel_t *isel) {
@@ -56,18 +59,16 @@ static inline void emit_ret(scc_x86_64_isel_t *isel) {
scc_vec_push((isel)->instrs, instr); \
} while (0)
#define add_instr_1(isel, iform, arg1, _size) \
#define add_instr_1(isel, iform, arg1) \
do { \
scc_mir_x86_instr_t instr; \
(arg1).size = (_size); \
scc_mir_x86_instr_1(&instr, (iform), (arg1), (isel)->pos); \
scc_vec_push((isel)->instrs, instr); \
} while (0)
#define add_instr_2(isel, iform, arg1, arg2, _size) \
#define add_instr_2(isel, iform, arg1, arg2) \
do { \
scc_mir_x86_instr_t instr; \
(arg1).size = (_size); \
scc_mir_x86_instr_2(&instr, (iform), (arg1), (arg2), (isel)->pos); \
scc_vec_push((isel)->instrs, instr); \
} while (0)

View File

@@ -9,16 +9,12 @@
#include <x86/scc_x86_reg.h>
typedef struct {
union {
int opcode;
scc_x86_iform_t iform;
};
u8 num_operands;
scc_x86_operand_value_t operands[6];
scc_x86_iform_t opcode; // must be int or enum
int num_operands;
scc_x86_operand_value_t operands[3];
scc_pos_t src_loc;
} scc_x86_instr_t;
// x86 后端指令:首字段 int opcode正 = scc_x86_iform_t负 = 伪指令)
typedef union scc_mir_x86_instr {
scc_mir_instr_t instr;
scc_x86_instr_t x86_instr;
@@ -26,8 +22,6 @@ typedef union scc_mir_x86_instr {
typedef SCC_VEC(scc_mir_x86_instr_t) scc_mir_x86_instr_vec_t;
// ── 基本块 values 强制转换 ──────────────────────────────────────────────
#define SCC_MIR_X86_BBLOCK_INSTRS(bb) ((scc_mir_x86_instr_vec_t *)&bb->values)
#define SCC_MIR_X86_BBLOCK_INSTRS_C(bb) \
((const scc_mir_x86_instr_vec_t *)&bb->values)
@@ -51,13 +45,14 @@ static inline void scc_x86_op_set_preg(scc_x86_operand_value_t *op,
}
// slot_id 编码为 base=INVALID, disp=slot_id
static inline scc_x86_operand_value_t scc_x86_op_slot(int slot_id) {
static inline scc_x86_operand_value_t scc_x86_op_slot(int slot_id, u8 size) {
scc_x86_operand_value_t o = {.kind = SCC_X86_OPR_MEM};
o.mem.base = SCC_X86_REG_INVALID;
o.mem.index = SCC_X86_REG_INVALID;
o.mem.scale = 1;
o.mem.disp.displacement = slot_id;
o.mem.disp.displacement_bits = 0;
o.size = size;
return o;
}
@@ -68,13 +63,14 @@ static inline int scc_x86_op_slot_id(const scc_x86_operand_value_t *op) {
return op->mem.disp.displacement;
}
static inline void scc_mir_x86_instr_0(scc_mir_x86_instr_t *out, int opcode,
scc_pos_t pos) {
static inline void scc_mir_x86_instr_0(scc_mir_x86_instr_t *out,
scc_x86_iform_t opcode, scc_pos_t pos) {
out->x86_instr.opcode = opcode;
out->x86_instr.num_operands = 0;
out->x86_instr.src_loc = pos;
}
static inline void scc_mir_x86_instr_1(scc_mir_x86_instr_t *out, int opcode,
static inline void scc_mir_x86_instr_1(scc_mir_x86_instr_t *out,
scc_x86_iform_t opcode,
scc_x86_operand_value_t op0,
scc_pos_t pos) {
out->x86_instr.opcode = opcode;
@@ -82,7 +78,8 @@ static inline void scc_mir_x86_instr_1(scc_mir_x86_instr_t *out, int opcode,
out->x86_instr.operands[0] = op0;
out->x86_instr.src_loc = pos;
}
static inline void scc_mir_x86_instr_2(scc_mir_x86_instr_t *out, int opcode,
static inline void scc_mir_x86_instr_2(scc_mir_x86_instr_t *out,
scc_x86_iform_t opcode,
scc_x86_operand_value_t op0,
scc_x86_operand_value_t op1,
scc_pos_t pos) {
@@ -92,11 +89,10 @@ static inline void scc_mir_x86_instr_2(scc_mir_x86_instr_t *out, int opcode,
out->x86_instr.operands[1] = op1;
out->x86_instr.src_loc = pos;
}
static inline void scc_mir_x86_instr_3(scc_mir_x86_instr_t *out, int opcode,
scc_x86_operand_value_t op0,
scc_x86_operand_value_t op1,
scc_x86_operand_value_t op2,
scc_pos_t pos) {
static inline void
scc_mir_x86_instr_3(scc_mir_x86_instr_t *out, scc_x86_iform_t opcode,
scc_x86_operand_value_t op0, scc_x86_operand_value_t op1,
scc_x86_operand_value_t op2, scc_pos_t pos) {
out->x86_instr.opcode = opcode;
out->x86_instr.num_operands = 3;
out->x86_instr.operands[0] = op0;
@@ -105,4 +101,48 @@ static inline void scc_mir_x86_instr_3(scc_mir_x86_instr_t *out, int opcode,
out->x86_instr.src_loc = pos;
}
static inline scc_x86_iform_t
scc_mir_x86_mov_reg_mem(scc_x86_operand_value_t op0,
scc_x86_operand_value_t op1) {
Assert(op0.size == op1.size);
Assert(op0.kind == SCC_X86_OPR_REG && op1.kind == SCC_X86_OPR_MEM);
return op0.size == 1 ? SCC_X86_IFORM_MOV_GPR8_MEMB
: SCC_X86_IFORM_MOV_GPRV_MEMV;
}
static inline scc_x86_iform_t
scc_mir_x86_mov_mem_reg(scc_x86_operand_value_t op0,
scc_x86_operand_value_t op1) {
Assert(op0.size == op1.size);
Assert(op0.kind == SCC_X86_OPR_MEM && op1.kind == SCC_X86_OPR_REG);
return op0.size == 1 ? SCC_X86_IFORM_MOV_MEMB_GPR8
: SCC_X86_IFORM_MOV_MEMV_GPRV;
}
static inline scc_x86_iform_t
scc_mir_x86_mov_reg_reg(scc_x86_operand_value_t op0,
scc_x86_operand_value_t op1) {
Assert(op0.size == op1.size);
Assert(op0.kind == SCC_X86_OPR_REG && op1.kind == SCC_X86_OPR_REG);
return op0.size == 1 ? SCC_X86_IFORM_MOV_GPR8_GPR8_8A
: SCC_X86_IFORM_MOV_GPRV_GPRV_8B;
}
static inline scc_x86_iform_t
scc_mir_x86_mov_reg_imm(scc_x86_operand_value_t op0,
scc_x86_operand_value_t op1) {
Assert(op0.size == op1.size);
Assert(op0.kind == SCC_X86_OPR_REG && op1.kind == SCC_X86_OPR_IMM);
return op0.size == 1 ? SCC_X86_IFORM_MOV_GPR8_IMMB_B0
: SCC_X86_IFORM_MOV_GPRV_IMMV;
}
void scc_x86_emit_move_to_vec(scc_mir_x86_instr_vec_t *vec,
scc_x86_operand_value_t dst,
scc_x86_operand_value_t src);
void scc_x86_emit_load_to_vec(scc_mir_x86_instr_vec_t *vec,
scc_x86_operand_value_t dst,
scc_x86_operand_value_t src_addr);
void scc_x86_emit_store_to_vec(scc_mir_x86_instr_vec_t *vec,
scc_x86_operand_value_t dst_addr,
scc_x86_operand_value_t src);
#endif /* __SCC_X86_MIR_H__ */

View File

@@ -28,8 +28,10 @@ typedef struct scc_reg_alloc_op {
void (*alloc_iter_begin)(scc_reg_alloc_iter_t *iter);
cbool (*alloc_iter_next)(scc_reg_alloc_iter_t *iter, int *out_vreg,
int *out_size, scc_reg_op_access_t *out_access);
void (*alloc_iter_replace_preg)(scc_reg_alloc_iter_t *iter, int preg);
void (*alloc_iter_replace_slot)(scc_reg_alloc_iter_t *iter, int slot);
void (*alloc_iter_replace_preg)(scc_reg_alloc_iter_t *iter, int preg,
int size);
void (*alloc_iter_replace_slot)(scc_reg_alloc_iter_t *iter, int slot,
int size);
void (*alloc_iter_end)(scc_reg_alloc_iter_t *iter);
// 读写属性与隐式寄存器

View File

@@ -24,8 +24,8 @@ void scc_x86_instr_dump(scc_tree_dump_t *td, const scc_mir_func_t *func,
scc_tree_dump_append_fmt(td, " ???");
return;
}
scc_x86_iform_t iform = instr->x86_instr.opcode;
const scc_x86_iform_info_t *info = &scc_x86_iform_table[iform];
scc_x86_iform_t opcode = instr->x86_instr.opcode;
const scc_x86_iform_info_t *info = &scc_x86_iform_table[opcode];
scc_tree_dump_append_fmt(td, " %s", info->iform_name);
for (int i = 0; i < instr->x86_instr.num_operands; i += 1) {
if (i == 0)
@@ -63,12 +63,12 @@ void scc_x86_instr_dump(scc_tree_dump_t *td, const scc_mir_func_t *func,
scc_tree_dump_append_fmt(td, "(x%d)", op->mem.scale);
}
if (op->mem.disp.displacement != 0) {
i64 data = op->mem.disp.displacement < 0
? -op->mem.disp.displacement
: op->mem.disp.displacement;
scc_tree_dump_append_fmt(
td, " %c %llu",
op->mem.disp.displacement >= 0 ? '+' : '-',
op->mem.disp.displacement < 0
? -op->mem.disp.displacement
: op->mem.disp.displacement);
td, " %c %lld/%#llx",
op->mem.disp.displacement >= 0 ? '+' : '-', data, data);
}
scc_tree_dump_append(td, ")");
}
@@ -93,33 +93,34 @@ void scc_x86_instr_dump(scc_tree_dump_t *td, const scc_mir_func_t *func,
scc_tree_dump_append(td, "<?>");
break;
}
scc_tree_dump_append_fmt(td, "(%zu)", op->size);
scc_tree_dump_append_fmt(td, ".(%zu)", op->size);
}
}
// 将 LIR 值转换为 x86 操作数
scc_x86_operand_value_t scc_x86_lir_val_to_mir_op(scc_x86_64_isel_t *isel,
const scc_lir_val_t *val) {
const scc_lir_val_t *val,
u8 size) {
scc_x86_operand_value_t op = {0};
switch (val->kind) {
case SCC_LIR_INSTR_KIND_NONE:
op.kind = SCC_X86_OPR_NONE;
break;
case SCC_LIR_INSTR_KIND_VREG:
op = scc_x86_op_vreg(val->data.reg);
op = scc_x86_op_vreg(val->data.reg, size);
int id = 0;
int ret = scc_mir_vreg_lookup(isel->func, val->data.reg, &id);
if (ret > 0) {
op = scc_x86_op_preg(id);
op = scc_x86_op_preg(id, size);
} else if (ret < 0) {
op = scc_x86_op_slot(id);
op = scc_x86_op_slot(id, size);
}
break;
case SCC_LIR_INSTR_KIND_IMM:
op = scc_x86_op_imm(val->data.imm.data.digit);
op = scc_x86_op_imm(val->data.imm.data.digit, size);
break;
case SCC_LIR_INSTR_KIND_FIMM:
op = scc_x86_op_imm(*(i64 *)&val->data.fimm);
op = scc_x86_op_imm(*(i64 *)&val->data.fimm, size);
break;
case SCC_LIR_INSTR_KIND_SYMBOL:
op = scc_x86_op_reloc_global_relrip(val->data.symbol, 0);
@@ -127,6 +128,7 @@ scc_x86_operand_value_t scc_x86_lir_val_to_mir_op(scc_x86_64_isel_t *isel,
case SCC_LIR_INSTR_KIND_ARG:
Assert(isel->abi_lowering.lower_param);
isel->abi_lowering.lower_param(isel, val, &op);
op.size = size;
break;
default:
Panic("unsupported lir instr kind %d", val->kind);
@@ -159,20 +161,9 @@ static scc_x86_operand_value_t build_mem_op(scc_x86_64_isel_t *isel,
}
// 虚拟临时寄存器分配(简单递增)
static scc_x86_operand_value_t new_vreg_temp(scc_x86_64_isel_t *isel) {
return scc_x86_op_vreg(scc_mir_alloc_vreg(isel->func));
}
static void emit_compare(scc_x86_64_isel_t *isel, scc_x86_operand_value_t op0,
scc_x86_operand_value_t op1, u8 size) {
(void)size;
if (scc_x86_op_is_vreg(&op0) && op1.kind == SCC_X86_OPR_IMM) {
add_instr_2(isel, SCC_X86_IFORM_CMP_GPRV_IMMZ, op0, op1, size);
} else if (scc_x86_op_is_vreg(&op0) && scc_x86_op_is_vreg(&op1)) {
add_instr_2(isel, SCC_X86_IFORM_CMP_GPRV_GPRV_3B, op0, op1, size);
} else {
UNREACHABLE();
}
static scc_x86_operand_value_t new_vreg_temp(scc_x86_64_isel_t *isel,
int size) {
return scc_x86_op_vreg(scc_mir_alloc_vreg(isel->func), size);
}
static scc_x86_iform_t cond_to_setcc(scc_lir_cond_t cond) {
@@ -204,138 +195,75 @@ static scc_x86_iform_t cond_to_setcc(scc_lir_cond_t cond) {
static void emit_copy_if_needed(scc_x86_64_isel_t *isel,
scc_x86_operand_value_t dst,
scc_x86_operand_value_t src0, u8 size) {
scc_x86_operand_value_t src0) {
if (scc_x86_op_is_vreg(&dst) && scc_x86_op_is_vreg(&src0) &&
scc_x86_op_get_vreg(&dst) == scc_x86_op_get_vreg(&src0)) {
return;
}
scc_x86_emit_move(isel, dst, src0, size);
scc_x86_emit_move(isel, dst, src0);
}
static void emit_binary_op(scc_x86_64_isel_t *isel, scc_lir_op_t op,
scc_x86_operand_value_t dst,
scc_x86_operand_value_t src0,
scc_x86_operand_value_t src1, u8 size) {
(void)size;
emit_copy_if_needed(isel, dst, src0, size);
dst.size = size;
src0.size = size;
src1.size = size;
scc_x86_operand_value_t src1) {
emit_copy_if_needed(isel, dst, src0);
bool is_imm = (src1.kind == SCC_X86_OPR_IMM);
scc_x86_iform_t iform;
Assert(src0.size == src1.size);
int is_8b = src0.size == 1;
int is_imm = src1.kind == SCC_X86_OPR_IMM;
scc_x86_iform_t opcode;
switch (op) {
case SCC_LIR_ADD:
iform = is_imm ? SCC_X86_IFORM_ADD_GPRV_IMMZ
: SCC_X86_IFORM_ADD_GPRV_GPRV_03;
opcode = is_imm ? SCC_X86_IFORM_ADD_GPRV_IMMZ
: SCC_X86_IFORM_ADD_GPRV_GPRV_03;
break;
case SCC_LIR_SUB:
iform = is_imm ? SCC_X86_IFORM_SUB_GPRV_IMMZ
: SCC_X86_IFORM_SUB_GPRV_GPRV_2B;
opcode = is_imm ? SCC_X86_IFORM_SUB_GPRV_IMMZ
: SCC_X86_IFORM_SUB_GPRV_GPRV_2B;
break;
case SCC_LIR_AND:
iform = is_imm ? SCC_X86_IFORM_AND_GPRV_IMMZ
: SCC_X86_IFORM_AND_GPRV_GPRV_23;
opcode = is_imm ? SCC_X86_IFORM_AND_GPRV_IMMZ
: SCC_X86_IFORM_AND_GPRV_GPRV_23;
break;
case SCC_LIR_OR:
iform =
opcode =
is_imm ? SCC_X86_IFORM_OR_GPRV_IMMZ : SCC_X86_IFORM_OR_GPRV_GPRV_0B;
break;
case SCC_LIR_XOR:
iform = is_imm ? SCC_X86_IFORM_XOR_GPRV_IMMZ
: SCC_X86_IFORM_XOR_GPRV_GPRV_33;
opcode = is_imm ? SCC_X86_IFORM_XOR_GPRV_IMMZ
: SCC_X86_IFORM_XOR_GPRV_GPRV_33;
break;
default:
UNREACHABLE();
}
add_instr_2(isel, iform, dst, src1, size);
add_instr_2(isel, opcode, dst, src1);
}
void scc_x86_emit_move(scc_x86_64_isel_t *isel, scc_x86_operand_value_t dst_reg,
scc_x86_operand_value_t src, u8 size) {
if (size == 0) {
size = dst_reg.size;
}
if (dst_reg.size != src.size) {
LOG_WARN("Mismatched register sizes for move %d != %d", dst_reg.size,
src.size);
}
Assert(dst_reg.kind == SCC_X86_OPR_REG);
if (src.kind == SCC_X86_OPR_REG) {
add_instr_2(isel, SCC_X86_IFORM_MOV_GPRV_GPRV_8B, dst_reg, src, size);
} else if (src.kind == SCC_X86_OPR_IMM) {
add_instr_2(isel, SCC_X86_IFORM_MOV_GPRV_IMMV, dst_reg, src, size);
} else if (src.kind == SCC_X86_OPR_MEM ||
(src.kind == SCC_X86_OPR_RELOC &&
src.reloc.target == SCC_X86_RELOC_TARGET_SYMBOL)) {
add_instr_2(isel, SCC_X86_IFORM_LEA_GPRV_AGEN, dst_reg, src, size);
} else {
Panic("emit_move: unsupported src kind %d", src.kind);
}
scc_x86_operand_value_t src) {
scc_x86_emit_move_to_vec(&isel->instrs, dst_reg, src);
}
void scc_x86_emit_load(scc_x86_64_isel_t *isel, scc_x86_operand_value_t dst,
scc_x86_operand_value_t src, u8 size) {
if (size == 0) {
size = dst.size;
}
if (dst.size != src.size) {
LOG_WARN("Mismatched register sizes for store %d != %d", dst.size,
src.size);
}
scc_x86_operand_value_t src) {
if (dst.kind != SCC_X86_OPR_REG) {
scc_x86_operand_value_t tmp_reg = new_vreg_temp(isel);
scc_x86_emit_move(isel, tmp_reg, dst, size);
scc_x86_operand_value_t tmp_reg = new_vreg_temp(isel, dst.size);
scc_x86_emit_move(isel, tmp_reg, dst);
dst = tmp_reg;
}
scc_x86_operand_value_t mem_op;
if (src.kind == SCC_X86_OPR_REG) {
// 地址在寄存器中 -> 构造 [reg]
mem_op = (scc_x86_operand_value_t){
.kind = SCC_X86_OPR_MEM,
.mem = {.base = src.reg,
.index = SCC_X86_REG_INVALID,
.scale = 1,
.disp = {.displacement = 0, .displacement_bits = size * 8}},
};
} else if (src.kind == SCC_X86_OPR_MEM) {
mem_op = src;
} else {
Panic("emit_load: src must be REG or MEM");
}
add_instr_2(isel, SCC_X86_IFORM_MOV_GPRV_MEMV, dst, mem_op, size);
scc_x86_emit_load_to_vec(&isel->instrs, dst, src);
}
void scc_x86_emit_store(scc_x86_64_isel_t *isel, scc_x86_operand_value_t dst,
scc_x86_operand_value_t src, u8 size) {
if (size == 0) {
size = dst.size;
}
if (dst.size != src.size) {
LOG_WARN("Mismatched register sizes for store %d != %d", dst.size,
src.size);
}
scc_x86_operand_value_t src) {
if (src.kind != SCC_X86_OPR_REG) {
scc_x86_operand_value_t tmp_reg = new_vreg_temp(isel);
scc_x86_emit_move(isel, tmp_reg, src, size);
scc_x86_operand_value_t tmp_reg = new_vreg_temp(isel, src.size);
scc_x86_emit_move(isel, tmp_reg, src);
src = tmp_reg;
}
scc_x86_operand_value_t mem_op;
if (dst.kind == SCC_X86_OPR_REG) {
mem_op = (scc_x86_operand_value_t){
.kind = SCC_X86_OPR_MEM,
.mem = {.base = dst.reg,
.index = SCC_X86_REG_INVALID,
.scale = 1,
.disp = {.displacement = 0, .displacement_bits = 0}}};
} else if (dst.kind == SCC_X86_OPR_MEM) {
mem_op = dst;
} else {
Panic("emit_store: dst_addr must be REG or MEM");
}
mem_op.size = size;
src.size = size;
add_instr_2(isel, SCC_X86_IFORM_MOV_MEMV_GPRV, mem_op, src, size);
scc_x86_emit_store_to_vec(&isel->instrs, dst, src);
}
static void emit_load_addr(scc_x86_64_isel_t *isel, scc_x86_operand_value_t dst,
@@ -343,6 +271,7 @@ static void emit_load_addr(scc_x86_64_isel_t *isel, scc_x86_operand_value_t dst,
scc_x86_operand_value_t index, int scale,
i64 offset) {
usize size = dst.size;
Assert(size == 8);
// 前置断言dst 必须是寄存器
Assert(dst.kind == SCC_X86_OPR_REG);
// scale 必须是 1,2,4,8 之一
@@ -351,8 +280,8 @@ static void emit_load_addr(scc_x86_64_isel_t *isel, scc_x86_operand_value_t dst,
// ---- 处理 base ----
scc_x86_operand_value_t base_reg = base;
if (base.kind != SCC_X86_OPR_REG) {
base_reg = new_vreg_temp(isel);
scc_x86_emit_move(isel, base_reg, base, 8);
base_reg = new_vreg_temp(isel, size);
scc_x86_emit_move(isel, base_reg, base);
}
// ---- 处理 index * scale ----
@@ -360,8 +289,8 @@ static void emit_load_addr(scc_x86_64_isel_t *isel, scc_x86_operand_value_t dst,
Assert(index.kind != SCC_X86_OPR_NONE);
// 确保 index 在寄存器中
if (index.kind != SCC_X86_OPR_REG) {
scc_x86_operand_value_t index_tmp = new_vreg_temp(isel);
scc_x86_emit_move(isel, index_tmp, index, 8);
scc_x86_operand_value_t index_tmp = new_vreg_temp(isel, index.size);
scc_x86_emit_move(isel, index_tmp, index);
index = index_tmp;
}
@@ -370,21 +299,20 @@ static void emit_load_addr(scc_x86_64_isel_t *isel, scc_x86_operand_value_t dst,
if (base_reg.kind == SCC_X86_OPR_REG &&
scaled_index.kind == SCC_X86_OPR_REG) {
if (dst.reg != base_reg.reg) {
scc_x86_emit_move(isel, dst, base_reg, 8);
scc_x86_emit_move(isel, dst, base_reg);
sum = dst;
}
add_instr_2(isel, SCC_X86_IFORM_ADD_GPRV_GPRV_03, sum, scaled_index,
size);
add_instr_2(isel, SCC_X86_IFORM_ADD_GPRV_GPRV_03, sum, scaled_index);
} else if (base_reg.kind == SCC_X86_OPR_REG) {
if (dst.reg != base_reg.reg)
scc_x86_emit_move(isel, dst, base_reg, 8);
scc_x86_emit_move(isel, dst, base_reg);
sum = dst;
} else if (scaled_index.kind == SCC_X86_OPR_REG) {
scc_x86_emit_move(isel, dst, scaled_index, 8);
scc_x86_emit_move(isel, dst, scaled_index);
sum = dst;
} else {
// base 和 index 都无效 => 结果为 0
scc_x86_emit_move(isel, dst, scc_x86_op_imm(0), 8);
scc_x86_emit_move(isel, dst, scc_x86_op_imm(0, size));
return;
}
@@ -393,33 +321,34 @@ static void emit_load_addr(scc_x86_64_isel_t *isel, scc_x86_operand_value_t dst,
scc_x86_operand_value_t mem_op = build_mem_op(
isel, sum, (scc_x86_operand_value_t){.kind = SCC_X86_OPR_NONE}, 1,
offset);
scc_x86_emit_move(isel, dst, mem_op, 8);
scc_x86_emit_move(isel, dst, mem_op);
} else if (sum.reg != dst.reg) {
scc_x86_emit_move(isel, dst, sum, 8);
scc_x86_emit_move(isel, dst, sum);
}
}
static void sel_mir(scc_x86_64_isel_t *isel, const scc_lir_instr_t *instr) {
scc_x86_operand_value_t dst = scc_x86_lir_val_to_mir_op(isel, &instr->to);
scc_x86_operand_value_t src0 =
scc_x86_lir_val_to_mir_op(isel, &instr->arg0);
scc_x86_operand_value_t src1 =
scc_x86_lir_val_to_mir_op(isel, &instr->arg1);
u8 size = instr->size;
scc_x86_operand_value_t dst =
scc_x86_lir_val_to_mir_op(isel, &instr->to, size);
scc_x86_operand_value_t src0 =
scc_x86_lir_val_to_mir_op(isel, &instr->arg0, size);
scc_x86_operand_value_t src1 =
scc_x86_lir_val_to_mir_op(isel, &instr->arg1, size);
switch (instr->op) {
/* ---- 数据移动 ---- */
case SCC_LIR_LOAD:
// src0 是地址可能是寄存器或内存操作数dst 是寄存器
scc_x86_emit_load(isel, dst, src0, size);
scc_x86_emit_load(isel, dst, src0);
break;
case SCC_LIR_STORE:
// src0 是要存储的值寄存器src1 是目标地址
scc_x86_emit_store(isel, src1, src0, size);
scc_x86_emit_store(isel, src1, src0);
break;
case SCC_LIR_MOV:
// 纯粹的寄存器/立即数复制
scc_x86_emit_move(isel, dst, src0, size);
scc_x86_emit_move(isel, dst, src0);
break;
case SCC_LIR_LOAD_ADDR:
// 计算地址,结果放入 dst寄存器
@@ -428,10 +357,10 @@ static void sel_mir(scc_x86_64_isel_t *isel, const scc_lir_instr_t *instr) {
break;
/* ---- 一元运算 ---- */
case SCC_LIR_NEG:
add_instr_1(isel, SCC_X86_IFORM_NEG_GPRV, dst, size);
add_instr_1(isel, SCC_X86_IFORM_NEG_GPRV, dst);
break;
case SCC_LIR_NOT:
add_instr_1(isel, SCC_X86_IFORM_NOT_GPRV, dst, size);
add_instr_1(isel, SCC_X86_IFORM_NOT_GPRV, dst);
break;
/* ---- 算术/逻辑二元运算 ---- */
case SCC_LIR_ADD:
@@ -439,24 +368,23 @@ static void sel_mir(scc_x86_64_isel_t *isel, const scc_lir_instr_t *instr) {
case SCC_LIR_AND:
case SCC_LIR_OR:
case SCC_LIR_XOR:
emit_binary_op(isel, instr->op, dst, src0, src1, size);
emit_binary_op(isel, instr->op, dst, src0, src1);
break;
case SCC_LIR_MUL:
emit_copy_if_needed(isel, dst, src0, size);
emit_copy_if_needed(isel, dst, src0);
if (src1.kind == SCC_X86_OPR_IMM) {
scc_x86_operand_value_t op = new_vreg_temp(isel);
scc_x86_emit_move(isel, op, src1, size);
scc_x86_operand_value_t op = new_vreg_temp(isel, size);
scc_x86_emit_move(isel, op, src1);
src1 = op;
}
add_instr_2(isel, SCC_X86_IFORM_IMUL_GPRV_GPRV, dst, src1, size);
add_instr_2(isel, SCC_X86_IFORM_IMUL_GPRV_GPRV, dst, src1);
break;
case SCC_LIR_SHL:
case SCC_LIR_SHR:
case SCC_LIR_SAR: {
emit_copy_if_needed(isel, dst, src0, size);
emit_copy_if_needed(isel, dst, src0);
if (src1.kind == SCC_X86_OPR_IMM) {
scc_x86_iform_t iform;
switch (instr->op) {
@@ -472,10 +400,10 @@ static void sel_mir(scc_x86_64_isel_t *isel, const scc_lir_instr_t *instr) {
default:
UNREACHABLE();
}
add_instr_2(isel, iform, dst, src1, size);
add_instr_2(isel, iform, dst, src1);
} else {
scc_x86_operand_value_t cl = scc_x86_op_preg(SCC_X86_REG_CL);
scc_x86_emit_move(isel, cl, src1, 1);
scc_x86_operand_value_t cl = scc_x86_op_preg(SCC_X86_REG_CL, 1);
scc_x86_emit_move(isel, cl, src1);
scc_x86_iform_t iform;
switch (instr->op) {
case SCC_LIR_SHL:
@@ -490,7 +418,7 @@ static void sel_mir(scc_x86_64_isel_t *isel, const scc_lir_instr_t *instr) {
default:
UNREACHABLE();
}
add_instr_2(isel, iform, dst, cl, size);
add_instr_2(isel, iform, dst, cl);
}
} break;
@@ -499,44 +427,54 @@ static void sel_mir(scc_x86_64_isel_t *isel, const scc_lir_instr_t *instr) {
case SCC_LIR_DIV_U:
case SCC_LIR_REM_S:
case SCC_LIR_REM_U: {
scc_x86_operand_value_t rax = scc_x86_op_preg(SCC_X86_REG_RAX);
scc_x86_operand_value_t rdx = scc_x86_op_preg(SCC_X86_REG_RDX);
scc_x86_operand_value_t rax = scc_x86_op_preg(SCC_X86_REG_RAX, size);
scc_x86_operand_value_t rdx = scc_x86_op_preg(SCC_X86_REG_RDX, size);
scc_x86_emit_move(isel, rax, src0, size);
scc_x86_emit_move(isel, rax, src0);
if (instr->op == SCC_LIR_DIV_S || instr->op == SCC_LIR_REM_S) {
add_instr_0(isel, SCC_X86_IFORM_CQO);
} else {
scc_x86_operand_value_t zero = scc_x86_op_imm(0);
scc_x86_emit_move(isel, rdx, zero, size);
scc_x86_operand_value_t zero = scc_x86_op_imm(0, size);
scc_x86_emit_move(isel, rdx, zero);
}
scc_x86_iform_t div_if =
(instr->op == SCC_LIR_DIV_S || instr->op == SCC_LIR_REM_S)
? SCC_X86_IFORM_IDIV_GPRV
: SCC_X86_IFORM_DIV_GPRV;
add_instr_1(isel, div_if, src1, size);
add_instr_1(isel, div_if, src1);
if (instr->op == SCC_LIR_REM_S || instr->op == SCC_LIR_REM_U)
scc_x86_emit_move(isel, dst, rdx, size);
scc_x86_emit_move(isel, dst, rdx);
else
scc_x86_emit_move(isel, dst, rax, size);
scc_x86_emit_move(isel, dst, rax);
} break;
/* ---- 比较指令 ---- */
case SCC_LIR_CMP: {
Assert(src0.size == src1.size);
if (scc_x86_op_is_vreg(&src0) && src1.kind == SCC_X86_OPR_IMM)
add_instr_2(isel, SCC_X86_IFORM_CMP_GPRV_IMMZ, src0, src1, size);
add_instr_2(isel,
src0.size == 1 ? SCC_X86_IFORM_CMP_GPR8_IMMB_82R7
: SCC_X86_IFORM_CMP_GPRV_IMMZ,
src0, src1);
else if (scc_x86_op_is_vreg(&src0) && scc_x86_op_is_vreg(&src1))
add_instr_2(isel, SCC_X86_IFORM_CMP_GPRV_GPRV_3B, src0, src1, size);
add_instr_2(isel,
src0.size == 1 ? SCC_X86_IFORM_CMP_GPR8_GPR8_3A
: SCC_X86_IFORM_CMP_GPRV_GPRV_3B,
src0, src1);
else
UNREACHABLE();
scc_x86_iform_t setcc = cond_to_setcc(instr->metadata.cond);
add_instr_1(isel, setcc, dst, size);
add_instr_1(isel, setcc, dst);
if (size > 1) {
scc_x86_operand_value_t one = scc_x86_op_imm(1);
add_instr_2(isel, SCC_X86_IFORM_AND_GPRV_IMMZ, dst, one, size);
scc_x86_operand_value_t one = scc_x86_op_imm(1, size);
add_instr_2(isel,
src1.size == 1 ? SCC_X86_IFORM_AND_GPR8_IMMB_82R4
: SCC_X86_IFORM_AND_GPRV_IMMZ,
dst, one);
}
} break;
@@ -546,22 +484,26 @@ static void sel_mir(scc_x86_64_isel_t *isel, const scc_lir_instr_t *instr) {
scc_x86_op_reloc_block(instr->metadata.br.true_target, 0);
scc_x86_operand_value_t false_bb =
scc_x86_op_reloc_block(instr->metadata.br.false_target, 0);
add_instr_2(isel, SCC_X86_IFORM_TEST_GPRV_GPRV, src0, src0, size);
add_instr_1(isel, SCC_X86_IFORM_JNZ_RELBRZ, true_bb, size);
add_instr_1(isel, SCC_X86_IFORM_JMP_RELBRZ, false_bb, size);
true_bb.size = instr->size;
false_bb.size = instr->size;
add_instr_2(isel,
src0.size == 1 ? SCC_X86_IFORM_TEST_GPR8_GPR8
: SCC_X86_IFORM_TEST_GPRV_GPRV,
src0, src0);
add_instr_1(isel, SCC_X86_IFORM_JNZ_RELBRZ, true_bb);
add_instr_1(isel, SCC_X86_IFORM_JMP_RELBRZ, false_bb);
} break;
case SCC_LIR_JMP: {
scc_x86_operand_value_t jmp_bb =
scc_x86_op_reloc_block(instr->metadata.jmp_target, 0);
add_instr_1(isel, SCC_X86_IFORM_JMP_RELBRZ, jmp_bb, size);
add_instr_1(isel, SCC_X86_IFORM_JMP_RELBRZ, jmp_bb);
} break;
/* ---- 栈分配 ---- */
case SCC_LIR_ALLOCA: {
scc_x86_operand_value_t op =
scc_x86_lir_val_to_mir_op(isel, &instr->to);
scc_x86_lir_val_to_mir_op(isel, &instr->to, instr->size);
scc_mir_x86_instr_t x86instr;
x86instr.instr.opcode = SCC_MIR_PSEUDO_ALLOCA;
Assert(op.kind == SCC_X86_OPR_REG);
@@ -588,13 +530,8 @@ static void sel_mir(scc_x86_64_isel_t *isel, const scc_lir_instr_t *instr) {
isel->abi_lowering.lower_call(isel, instr);
} break;
case SCC_LIR_CALL_INDIRECT: {
TODO();
// 假设函数指针的 LIR 值在某个 vreg 中
// scc_x86_operand_value_t func_ptr_op =
// scc_x86_lir_val_to_mir_op(isel, &func_ptr_val);
// scc_x86_operand_value_t temp_reg = new_vreg_temp(isel);
// scc_x86_emit_lea(isel, temp_reg, func_ptr_op); // 确保得到地址
// emit_indirect_call(isel, temp_reg);
Assert(isel->abi_lowering.lower_call);
isel->abi_lowering.lower_call(isel, instr);
} break;
case SCC_LIR_RET: {
Assert(isel->abi_lowering.lower_ret);
@@ -607,18 +544,18 @@ static void sel_mir(scc_x86_64_isel_t *isel, const scc_lir_instr_t *instr) {
// 将 dest 的地址放入 RDI
scc_x86_operand_value_t dest_op =
scc_x86_lir_val_to_mir_op(isel, &dest_val);
scc_x86_emit_move(isel, scc_x86_op_preg(SCC_X86_REG_RDI), dest_op, 8);
scc_x86_lir_val_to_mir_op(isel, &dest_val, 8);
scc_x86_emit_move(isel, scc_x86_op_preg(SCC_X86_REG_RDI, 8), dest_op);
// 将 src 的地址放入 RSI
scc_x86_operand_value_t src_op =
scc_x86_lir_val_to_mir_op(isel, &src_val);
scc_x86_emit_move(isel, scc_x86_op_preg(SCC_X86_REG_RSI), src_op, 8);
scc_x86_lir_val_to_mir_op(isel, &src_val, 8);
scc_x86_emit_move(isel, scc_x86_op_preg(SCC_X86_REG_RSI, 8), src_op);
// 长度处理保持不变...
scc_x86_operand_value_t len_op =
scc_x86_lir_val_to_mir_op(isel, &instr->metadata.memcpy.size);
scc_x86_emit_move(isel, scc_x86_op_preg(SCC_X86_REG_RCX), len_op, 8);
scc_x86_lir_val_to_mir_op(isel, &instr->metadata.memcpy.size, 8);
scc_x86_emit_move(isel, scc_x86_op_preg(SCC_X86_REG_RCX, 8), len_op);
add_instr_0(isel, SCC_X86_IFORM_REP_MOVSB);
} break;
@@ -639,6 +576,11 @@ static void sel_func(const scc_lir_module_t *lir_module,
scc_lir_instr_vec_t *instrs = SCC_LIR_BBLOCK_VALUES(bb);
scc_vec_foreach(*instrs, i) {
const scc_lir_instr_t *ins = &scc_vec_at(*instrs, i);
// HACK BR size
if (ins->op == SCC_LIR_CMP && i + 1 < scc_vec_size(*instrs) &&
scc_vec_at(*instrs, i + 1).op == SCC_LIR_BR) {
scc_vec_at(*instrs, i + 1).size = ins->size;
}
sel_mir(isel, ins);
}

View File

@@ -0,0 +1,92 @@
#include <arch/scc_x86_mir.h>
void scc_x86_emit_move_to_vec(scc_mir_x86_instr_vec_t *vec,
scc_x86_operand_value_t dst,
scc_x86_operand_value_t src) {
if (dst.size != src.size) {
LOG_WARN("Mismatched register sizes for move %d != %d", dst.size,
src.size);
}
Assert(dst.kind == SCC_X86_OPR_REG);
scc_mir_x86_instr_t ins;
if (src.kind == SCC_X86_OPR_REG) {
scc_mir_x86_instr_2(&ins, scc_mir_x86_mov_reg_reg(dst, src), dst, src,
scc_pos_create());
} else if (src.kind == SCC_X86_OPR_IMM) {
scc_mir_x86_instr_2(&ins, scc_mir_x86_mov_reg_imm(dst, src), dst, src,
scc_pos_create());
} else if (src.kind == SCC_X86_OPR_MEM ||
(src.kind == SCC_X86_OPR_RELOC &&
src.reloc.target == SCC_X86_RELOC_TARGET_SYMBOL)) {
scc_mir_x86_instr_2(&ins, SCC_X86_IFORM_LEA_GPRV_AGEN, dst, src,
scc_pos_create());
} else {
Panic("emit_move: unsupported src kind %d", src.kind);
}
scc_vec_push(*vec, ins);
}
void scc_x86_emit_load_to_vec(scc_mir_x86_instr_vec_t *vec,
scc_x86_operand_value_t dst,
scc_x86_operand_value_t src_addr) {
if (dst.size != src_addr.size) {
LOG_WARN("Mismatched sizes for load %d != %d", dst.size, src_addr.size);
}
Assert(dst.kind == SCC_X86_OPR_REG);
scc_x86_operand_value_t mem_op;
if (src_addr.kind == SCC_X86_OPR_REG) {
mem_op = (scc_x86_operand_value_t){
.kind = SCC_X86_OPR_MEM,
.mem =
{
.base = src_addr.reg,
.index = SCC_X86_REG_INVALID,
.scale = 1,
.disp.displacement = 0,
.disp.displacement_bits = src_addr.size * 8,
},
.size = src_addr.size,
};
} else if (src_addr.kind == SCC_X86_OPR_MEM) {
mem_op = src_addr;
} else {
Panic("emit_load: src must be REG or MEM");
}
scc_mir_x86_instr_t ins;
scc_mir_x86_instr_2(&ins, scc_mir_x86_mov_reg_mem(dst, mem_op), dst, mem_op,
scc_pos_create());
scc_vec_push(*vec, ins);
}
void scc_x86_emit_store_to_vec(scc_mir_x86_instr_vec_t *vec,
scc_x86_operand_value_t dst_addr,
scc_x86_operand_value_t src) {
if (dst_addr.size != src.size) {
LOG_WARN("Mismatched sizes for store %d != %d", dst_addr.size,
src.size);
}
Assert(src.kind == SCC_X86_OPR_REG);
scc_x86_operand_value_t mem_op;
if (dst_addr.kind == SCC_X86_OPR_REG) {
mem_op = (scc_x86_operand_value_t){
.kind = SCC_X86_OPR_MEM,
.mem =
{
.base = dst_addr.reg,
.index = SCC_X86_REG_INVALID,
.scale = 1,
.disp.displacement = 0,
.disp.displacement_bits = dst_addr.size * 8,
},
.size = dst_addr.size,
};
} else if (dst_addr.kind == SCC_X86_OPR_MEM) {
mem_op = dst_addr;
} else {
Panic("emit_store: dst_addr must be REG or MEM");
}
scc_mir_x86_instr_t ins;
scc_mir_x86_instr_2(&ins, scc_mir_x86_mov_mem_reg(mem_op, src), mem_op, src,
scc_pos_create());
scc_vec_push(*vec, ins);
}

View File

@@ -6,42 +6,27 @@
static void emit_spill(void *out, int preg, int slot, int size) {
scc_mir_x86_instr_vec_t *vec = out;
scc_x86_operand_value_t val_slot = scc_x86_op_slot(slot);
scc_x86_operand_value_t val_preg = scc_x86_op_preg(preg);
val_slot.size = size;
val_preg.size = size;
scc_mir_x86_instr_t ins = {
.x86_instr.opcode = SCC_X86_IFORM_MOV_MEMV_GPRV,
.x86_instr.num_operands = 2,
.x86_instr.operands = {val_slot, val_preg},
};
scc_vec_push(*vec, ins);
scc_x86_operand_value_t val_slot = scc_x86_op_slot(slot, size);
scc_x86_operand_value_t val_preg = scc_x86_op_preg(preg, size);
scc_x86_emit_store_to_vec(vec, val_slot, val_preg);
}
static void emit_reload(void *out, int preg, int slot, int size) {
scc_x86_operand_value_t val_slot = scc_x86_op_slot(slot);
scc_x86_operand_value_t val_preg = scc_x86_op_preg(preg);
val_slot.size = size;
val_preg.size = size;
scc_mir_x86_instr_vec_t *vec = out;
scc_mir_x86_instr_t ins = {.x86_instr.opcode = SCC_X86_IFORM_MOV_GPRV_MEMV,
.x86_instr.num_operands = 2,
.x86_instr.operands = {val_preg, val_slot}};
scc_vec_push(*vec, ins);
scc_x86_operand_value_t val_slot = scc_x86_op_slot(slot, size);
scc_x86_operand_value_t val_preg = scc_x86_op_preg(preg, size);
scc_x86_emit_load_to_vec(vec, val_preg, val_slot);
}
static void emit_copy(void *out, int dst_preg, int src_preg, int size) {
(void)size;
scc_mir_x86_instr_vec_t *vec = out;
scc_mir_x86_instr_t ins = {
.x86_instr.opcode = SCC_X86_IFORM_MOV_GPRV_GPRV_8B,
.x86_instr.num_operands = 2,
.x86_instr.operands = {scc_x86_op_preg(dst_preg),
scc_x86_op_preg(src_preg)}};
scc_vec_push(*vec, ins);
scc_x86_operand_value_t val_dst = scc_x86_op_preg(dst_preg, size);
scc_x86_operand_value_t val_src = scc_x86_op_preg(src_preg, size);
scc_x86_emit_move_to_vec(vec, val_dst, val_src);
}
static scc_reg_op_access_t get_operand_access(int opcode, int op_idx) {
static scc_reg_op_access_t get_operand_access(scc_x86_iform_t opcode,
int op_idx) {
if (opcode >= 0 && opcode < SCC_X86_IFORM_COUNT) {
const scc_x86_iform_info_t *info = &scc_x86_iform_table[opcode];
if (op_idx >= info->num_ops || op_idx < 0)
@@ -137,14 +122,14 @@ static cbool x86_alloc_iter_next(scc_reg_alloc_iter_t *iter, int *out_vreg,
int *out_size,
scc_reg_op_access_t *out_access) {
const scc_mir_x86_instr_t *ins = (const scc_mir_x86_instr_t *)iter->instr;
int opcode = ins->x86_instr.opcode;
scc_x86_iform_t opcode = ins->x86_instr.opcode;
int num_ops = ins->x86_instr.num_operands;
while (iter->op_idx < num_ops) {
const scc_x86_operand_value_t *op =
&ins->x86_instr.operands[iter->op_idx];
scc_reg_op_access_t base_access =
get_operand_access(opcode, iter->op_idx);
scc_reg_op_access_t base_access = SCC_REG_ALLOC_OP_ACCESS_READWRITE;
// base_access = get_operand_access(opcode, iter->op_idx);
*out_size = op->size;
if (op->kind == SCC_X86_OPR_REG) {
@@ -159,6 +144,7 @@ static cbool x86_alloc_iter_next(scc_reg_alloc_iter_t *iter, int *out_vreg,
continue;
} else if (op->kind == SCC_X86_OPR_MEM) {
const scc_x86_mem_t *mem = &op->mem;
*out_size = 8;
// 子索引 0: 基址寄存器
if (iter->op_sub_idx == 0) {
if (mem->base != SCC_X86_REG_INVALID &&
@@ -195,7 +181,9 @@ static cbool x86_alloc_iter_next(scc_reg_alloc_iter_t *iter, int *out_vreg,
return false;
}
static void x86_alloc_iter_replace_preg(scc_reg_alloc_iter_t *iter, int preg) {
static void x86_alloc_iter_replace_preg(scc_reg_alloc_iter_t *iter, int preg,
int size) {
(void)size;
scc_mir_x86_instr_t *ins = (scc_mir_x86_instr_t *)iter->instr;
int op_idx = iter->op_idx;
int sub_idx = iter->op_sub_idx;
@@ -220,11 +208,12 @@ static void x86_alloc_iter_replace_preg(scc_reg_alloc_iter_t *iter, int preg) {
}
}
static void x86_alloc_iter_replace_slot(scc_reg_alloc_iter_t *iter, int slot) {
static void x86_alloc_iter_replace_slot(scc_reg_alloc_iter_t *iter, int slot,
int size) {
scc_mir_x86_instr_t *ins = (scc_mir_x86_instr_t *)iter->instr;
int op_idx = iter->op_idx;
if (op_idx < ins->x86_instr.num_operands && iter->op_sub_idx == 0) {
ins->x86_instr.operands[op_idx] = scc_x86_op_slot(slot);
ins->x86_instr.operands[op_idx] = scc_x86_op_slot(slot, size);
} else {
Panic("x86_alloc_iter_replace_slot: invalid op_idx");
}

View File

@@ -43,7 +43,7 @@ static void alloc_instr(scc_reg_alloc_ctx_t *ctx,
if (mapping == 1) {
ops->mark_reg_used(ctx, preg);
ops->alloc_iter_replace_preg(&iter, preg);
ops->alloc_iter_replace_preg(&iter, preg, size);
continue;
}
if (mapping == 0)
@@ -58,7 +58,7 @@ static void alloc_instr(scc_reg_alloc_ctx_t *ctx,
access == SCC_REG_ALLOC_OP_ACCESS_READWRITE)
ops->emit_spill(&after, preg, slot, size);
ops->alloc_iter_replace_preg(&iter, preg);
ops->alloc_iter_replace_preg(&iter, preg, size);
}
ops->alloc_iter_end(&iter);

View File

@@ -29,13 +29,16 @@ static void frame_alloc_impl(scc_frame_layout_t *ctx,
ctx->offset += slot->size;
slot->offset = ctx->offset;
}
*op = scc_x86_op_mem((scc_x86_mem_t){
.seg = SCC_X86_REG_INVALID,
.base = SCC_X86_REG_RSP,
.disp = {.displacement = -slot->offset},
.index = SCC_X86_REG_INVALID,
.scale = 1,
});
*op = scc_x86_op_mem(
(scc_x86_mem_t){
.seg = SCC_X86_REG_INVALID,
.base = SCC_X86_REG_RSP,
.disp = {.displacement = -slot->offset},
.index = SCC_X86_REG_INVALID,
.scale = 1,
},
op->size);
}
}
}
@@ -76,11 +79,12 @@ static void prologue(scc_mir_instr_vec_t *userdata,
/// FILL to shadow space
}
u8 size = 8;
// sub rsp, frame_size
if (frame_size > 0) {
scc_mir_x86_instr_2(&instr, SCC_X86_IFORM_SUB_GPRV_IMMZ,
scc_x86_op_preg(SCC_X86_REG_RSP),
scc_x86_op_imm(frame_size), scc_pos_create());
scc_x86_op_preg(SCC_X86_REG_RSP, size),
scc_x86_op_imm(frame_size, size), scc_pos_create());
scc_vec_push(*instrs, instr);
}
}
@@ -98,12 +102,12 @@ static void epilogue(scc_mir_instr_vec_t *userdata,
*/
scc_mir_func_meta_t *meta = SCC_MIR_FUNC_META(func);
int frame_size = meta->frame_size;
u8 size = 8;
// add rsp, frame_size
if (frame_size > 0) {
scc_mir_x86_instr_2(&instr, SCC_X86_IFORM_ADD_GPRV_IMMZ,
scc_x86_op_preg(SCC_X86_REG_RSP),
scc_x86_op_imm(frame_size), scc_pos_create());
scc_x86_op_preg(SCC_X86_REG_RSP, size),
scc_x86_op_imm(frame_size, size), scc_pos_create());
scc_vec_push(*instrs, instr);
}
}
@@ -131,41 +135,52 @@ void scc_win_pc_x64_prolog_epilog_init(scc_prolog_epilog_t *ctx) {
static void lower_call(void *userdata, const scc_lir_instr_t *instr) {
scc_x86_64_isel_t *isel = userdata;
u8 size = 8;
for (int i = instr->metadata.call.arg_count - 1; i >= 0; i -= 1) {
scc_lir_val_t *args = &instr->metadata.call.args[i];
switch (i) {
case 0:
scc_x86_emit_move(isel, scc_x86_op_preg(SCC_X86_REG_RCX),
scc_x86_lir_val_to_mir_op(isel, args), 8);
scc_x86_emit_move(isel, scc_x86_op_preg(SCC_X86_REG_RCX, size),
scc_x86_lir_val_to_mir_op(isel, args, size));
break;
case 1:
scc_x86_emit_move(isel, scc_x86_op_preg(SCC_X86_REG_RDX),
scc_x86_lir_val_to_mir_op(isel, args), 8);
scc_x86_emit_move(isel, scc_x86_op_preg(SCC_X86_REG_RDX, size),
scc_x86_lir_val_to_mir_op(isel, args, size));
break;
case 2:
scc_x86_emit_move(isel, scc_x86_op_preg(SCC_X86_REG_R8),
scc_x86_lir_val_to_mir_op(isel, args), 8);
scc_x86_emit_move(isel, scc_x86_op_preg(SCC_X86_REG_R8, size),
scc_x86_lir_val_to_mir_op(isel, args, size));
break;
case 3:
scc_x86_emit_move(isel, scc_x86_op_preg(SCC_X86_REG_R9),
scc_x86_lir_val_to_mir_op(isel, args), 8);
scc_x86_emit_move(isel, scc_x86_op_preg(SCC_X86_REG_R9, size),
scc_x86_lir_val_to_mir_op(isel, args, size));
break;
default:
scc_x86_operand_value_t op = scc_x86_lir_val_to_mir_op(isel, args);
add_instr_1(isel,
op.kind == SCC_X86_OPR_REG ? SCC_X86_IFORM_PUSH_GPRV_50
: SCC_X86_IFORM_PUSH_IMMZ,
op, 8);
scc_x86_operand_value_t op =
scc_x86_lir_val_to_mir_op(isel, args, size);
TODO();
add_instr_1(isel, SCC_X86_ICLASS_PUSH, op);
break;
}
}
emit_direct_call(isel, instr->metadata.call.callee);
if (instr->op == SCC_LIR_CALL) {
emit_direct_call(isel, instr->metadata.call.callee_name);
} else if (instr->op == SCC_LIR_CALL_INDIRECT) {
Assert(instr->metadata.call.callee_target.kind ==
SCC_LIR_INSTR_KIND_SYMBOL);
emit_indirect_call(
isel, scc_x86_op_reloc_global_mem(
instr->metadata.call.callee_target.data.symbol, 0));
} else {
Panic("unhandled opcode");
}
scc_x86_operand_value_t ret_reg =
scc_x86_lir_val_to_mir_op(isel, &instr->to);
scc_x86_lir_val_to_mir_op(isel, &instr->to, size);
if (ret_reg.kind != SCC_X86_OPR_NONE) {
scc_x86_emit_move(isel, ret_reg, scc_x86_op_preg(SCC_X86_REG_RAX), 8);
scc_x86_emit_move(isel, ret_reg,
scc_x86_op_preg(SCC_X86_REG_RAX, size));
}
}
@@ -173,21 +188,22 @@ static void lower_param(void *userdata, const scc_lir_val_t *val,
void *out_op) {
scc_x86_operand_value_t *out = out_op;
Assert(val->kind == SCC_LIR_INSTR_KIND_ARG);
u8 size = 8;
switch (val->data.arg) {
case 0:
*out = scc_x86_op_preg(SCC_X86_REG_RCX);
*out = scc_x86_op_preg(SCC_X86_REG_RCX, size);
break;
case 1:
*out = scc_x86_op_preg(SCC_X86_REG_RDX);
*out = scc_x86_op_preg(SCC_X86_REG_RDX, size);
break;
case 2:
*out = scc_x86_op_preg(SCC_X86_REG_R8);
*out = scc_x86_op_preg(SCC_X86_REG_R8, size);
break;
case 3:
*out = scc_x86_op_preg(SCC_X86_REG_R9);
*out = scc_x86_op_preg(SCC_X86_REG_R9, size);
break;
default:
*out = scc_x86_op_slot(-val->data.arg);
*out = scc_x86_op_slot(-val->data.arg, size);
break;
}
}
@@ -195,9 +211,15 @@ static void lower_param(void *userdata, const scc_lir_val_t *val,
static void lower_ret(void *userdata, const scc_lir_instr_t *instr) {
scc_x86_64_isel_t *isel = userdata;
scc_lir_val_t ret_val = instr->metadata.ret_val;
u8 size = 0;
if (instr->size) {
size = instr->size;
} else {
size = 8;
}
if (ret_val.kind != SCC_LIR_INSTR_KIND_NONE) {
scc_x86_emit_move(isel, scc_x86_op_preg(SCC_X86_REG_RAX),
scc_x86_lir_val_to_mir_op(isel, &ret_val), 8);
scc_x86_emit_move(isel, scc_x86_op_preg(SCC_X86_REG_RAX, size),
scc_x86_lir_val_to_mir_op(isel, &ret_val, size));
}
emit_ret(isel);
}