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:
@@ -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) \
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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__ */
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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__ */
|
||||
|
||||
@@ -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);
|
||||
|
||||
// 读写属性与隐式寄存器
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
92
libs/ir/mir/src/arch/scc_x86_mir.c
Normal file
92
libs/ir/mir/src/arch/scc_x86_mir.c
Normal 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);
|
||||
}
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user