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:
@@ -1362,6 +1362,13 @@ void scc_ast2ir_decl(scc_ast2ir_ctx_t *ctx, const scc_ast_decl_t *decl,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
scc_hir_func_t *hir_func =
|
||||||
|
scc_hir_module_get_func(&ctx->builder.cprog->module, func_ref);
|
||||||
|
Assert(hir_func != nullptr);
|
||||||
|
// TODO this is double check defined
|
||||||
|
Assert(SCC_HIR_FUNC_META(hir_func)->defined == false);
|
||||||
|
SCC_HIR_FUNC_META(hir_func)->defined = true;
|
||||||
|
|
||||||
scc_hir_builder_begin_func(&ctx->builder, func_ref);
|
scc_hir_builder_begin_func(&ctx->builder, func_ref);
|
||||||
scc_hir_builder_begin_bblock(&ctx->builder, "entry");
|
scc_hir_builder_begin_bblock(&ctx->builder, "entry");
|
||||||
|
|
||||||
|
|||||||
@@ -249,6 +249,7 @@ typedef struct scc_hir_bblock_meta {
|
|||||||
typedef struct scc_hir_func_meta {
|
typedef struct scc_hir_func_meta {
|
||||||
scc_hir_type_ref_t type;
|
scc_hir_type_ref_t type;
|
||||||
scc_hir_value_ref_vec_t params;
|
scc_hir_value_ref_vec_t params;
|
||||||
|
int defined;
|
||||||
} scc_hir_func_meta_t;
|
} scc_hir_func_meta_t;
|
||||||
|
|
||||||
#define SCC_HIR_BBLOCK_VALUES(bblock) \
|
#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_t func;
|
||||||
scc_hir_func_meta_t *meta = scc_malloc(sizeof(scc_hir_func_meta_t));
|
scc_hir_func_meta_t *meta = scc_malloc(sizeof(scc_hir_func_meta_t));
|
||||||
|
meta->defined = 0;
|
||||||
Assert(meta != nullptr);
|
Assert(meta != nullptr);
|
||||||
func.meta = meta;
|
func.meta = meta;
|
||||||
scc_hir_func_init(&func, name);
|
scc_hir_func_init(&func, name);
|
||||||
|
|||||||
@@ -185,21 +185,16 @@ typedef struct scc_lir_ins {
|
|||||||
scc_lir_bblock_id_t jmp_target;
|
scc_lir_bblock_id_t jmp_target;
|
||||||
|
|
||||||
struct scc_lir_call {
|
struct scc_lir_call {
|
||||||
const char *callee;
|
|
||||||
scc_lir_val_t *args;
|
scc_lir_val_t *args;
|
||||||
int arg_count;
|
int arg_count;
|
||||||
scc_lir_val_t ret_vreg;
|
scc_lir_val_t ret_vreg;
|
||||||
u64 clobber_mask;
|
u64 clobber_mask;
|
||||||
|
union {
|
||||||
|
const char *callee_name;
|
||||||
|
scc_lir_val_t callee_target;
|
||||||
|
};
|
||||||
} call;
|
} 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;
|
scc_lir_val_t ret_val;
|
||||||
|
|
||||||
struct scc_lir_parallel_copy {
|
struct scc_lir_parallel_copy {
|
||||||
|
|||||||
@@ -33,11 +33,11 @@ void scc_lir_module_drop(scc_lir_module_t *lir_module);
|
|||||||
* @brief 添加一个函数声明(外部或未定义)
|
* @brief 添加一个函数声明(外部或未定义)
|
||||||
* @param mod 模块
|
* @param mod 模块
|
||||||
* @param name 函数名
|
* @param name 函数名
|
||||||
* @param attr 属性
|
* @param defined 是否定义
|
||||||
* @return 符号指针
|
* @return 符号指针
|
||||||
*/
|
*/
|
||||||
scc_lir_symbol_id_t scc_lir_module_add_func_decl(scc_lir_module_t *lir_module,
|
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 添加一个全局数据符号(定义或外部)
|
* @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,
|
const u8 *init_data, usize size,
|
||||||
u32 align);
|
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__ */
|
#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) {
|
static void ir2lir_ctx_drop(ir2lir_ctx_t *ctx) {
|
||||||
|
// FIXME memory leak
|
||||||
scc_hashtable_drop(&ctx->value_to_vreg);
|
scc_hashtable_drop(&ctx->value_to_vreg);
|
||||||
scc_hashtable_drop(&ctx->func_decl_map);
|
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);
|
lir_args[i] = ir_value_to_lir_operand(ctx, arg_ref);
|
||||||
}
|
}
|
||||||
|
|
||||||
scc_lir_instr_t instr = {
|
// TODO this is on windows all extern is indirect call
|
||||||
.op = SCC_LIR_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,
|
.size = size,
|
||||||
.to = SCC_LIR_VREG(dst_vreg),
|
.to = SCC_LIR_VREG(dst_vreg),
|
||||||
.metadata.call = {.callee = callee->name,
|
.metadata.call = {.args = lir_args,
|
||||||
.args = lir_args,
|
|
||||||
.arg_count = arg_count,
|
.arg_count = arg_count,
|
||||||
.ret_vreg = SCC_LIR_VREG(dst_vreg),
|
.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);
|
scc_lir_builder_add_instr(ctx, &instr);
|
||||||
// 注意:lir_args 内存将随指令结构体复制到基本块向量中,但
|
// 注意:lir_args 内存将随指令结构体复制到基本块向量中,但
|
||||||
// metadata.call.args 指针仍指向 malloc 内存,
|
// 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);
|
scc_hir_module_get_func(&cprog->module, func_ref);
|
||||||
if (!func)
|
if (!func)
|
||||||
continue;
|
continue;
|
||||||
scc_lir_symbol_id_t id =
|
scc_lir_symbol_id_t id = scc_lir_module_add_func_decl(
|
||||||
scc_lir_module_add_func_decl(module, func->name);
|
module, func->name, SCC_HIR_FUNC_META(func)->defined);
|
||||||
Assert(id != SCC_CFG_ID_nullptr);
|
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);
|
(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);
|
scc_hir_module_get_func(&cprog->module, func_ref);
|
||||||
if (!func)
|
if (!func)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
translate_func(&ctx, func);
|
translate_func(&ctx, func);
|
||||||
}
|
}
|
||||||
|
|
||||||
ir2lir_ctx_drop(&ctx);
|
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:
|
case SCC_LIR_JMP_INDIRECT:
|
||||||
dump_operand(ctx, &ins->arg0);
|
dump_operand(ctx, &ins->arg0);
|
||||||
break;
|
break;
|
||||||
case SCC_LIR_CALL: {
|
case SCC_LIR_CALL:
|
||||||
|
case SCC_LIR_CALL_INDIRECT: {
|
||||||
const struct scc_lir_call *c = &ins->metadata.call;
|
const struct scc_lir_call *c = &ins->metadata.call;
|
||||||
if (c->ret_vreg.kind != SCC_LIR_INSTR_KIND_NONE) {
|
if (c->ret_vreg.kind != SCC_LIR_INSTR_KIND_NONE) {
|
||||||
dump_operand(ctx, &c->ret_vreg);
|
dump_operand(ctx, &c->ret_vreg);
|
||||||
scc_tree_dump_append(td, " = ");
|
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 ");
|
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, "(");
|
scc_tree_dump_append(td, "(");
|
||||||
for (u8 i = 0; i < c->arg_count; i++) {
|
for (u8 i = 0; i < c->arg_count; i++) {
|
||||||
if (i > 0)
|
if (i > 0)
|
||||||
|
|||||||
@@ -3,7 +3,6 @@
|
|||||||
void scc_lir_module_init(scc_lir_module_t *lir_module) {
|
void scc_lir_module_init(scc_lir_module_t *lir_module) {
|
||||||
// FIXME
|
// FIXME
|
||||||
// lir_module->lir_module
|
// lir_module->lir_module
|
||||||
|
|
||||||
scc_vec_init(lir_module->func_metas);
|
scc_vec_init(lir_module->func_metas);
|
||||||
scc_vec_init(lir_module->symbol_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_vec_free(lir_module->symbol_metas);
|
||||||
}
|
}
|
||||||
|
|
||||||
scc_lir_symbol_id_t scc_lir_module_add_func_decl(scc_lir_module_t *lir_module,
|
scc_lir_symbol_t *
|
||||||
|
scc_lir_module_unsafe_lookup_symbol(const scc_lir_module_t *lir_module,
|
||||||
const char *name) {
|
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,
|
||||||
|
int defined) {
|
||||||
if (!lir_module || !name)
|
if (!lir_module || !name)
|
||||||
return SCC_CFG_ID_nullptr;
|
return SCC_CFG_ID_nullptr;
|
||||||
|
|
||||||
scc_lir_symbol_meta_t *meta = scc_malloc(sizeof(scc_lir_symbol_meta_t));
|
scc_lir_symbol_meta_t *meta = scc_malloc(sizeof(scc_lir_symbol_meta_t));
|
||||||
Assert(meta != nullptr);
|
Assert(meta != nullptr);
|
||||||
scc_lir_symbol_t sym = {.name = name,
|
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,
|
.linkage = SCC_CFG_SYMBOL_LINK_GLOABL,
|
||||||
.meta = meta};
|
.meta = meta};
|
||||||
meta->func.func = nullptr;
|
meta->func.func = nullptr;
|
||||||
|
|||||||
@@ -20,13 +20,15 @@ void scc_isel_x86_64(scc_mir_module_t *mir_module,
|
|||||||
|
|
||||||
// Utils
|
// Utils
|
||||||
void scc_x86_emit_move(scc_x86_64_isel_t *isel, scc_x86_operand_value_t dst_reg,
|
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,
|
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,
|
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,
|
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,
|
static inline void emit_direct_call(scc_x86_64_isel_t *isel,
|
||||||
const char *callee) {
|
const char *callee) {
|
||||||
scc_mir_x86_instr_t instr = {0};
|
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,
|
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_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_pos_create());
|
||||||
|
scc_vec_push(isel->instrs, instr);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void emit_ret(scc_x86_64_isel_t *isel) {
|
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); \
|
scc_vec_push((isel)->instrs, instr); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#define add_instr_1(isel, iform, arg1, _size) \
|
#define add_instr_1(isel, iform, arg1) \
|
||||||
do { \
|
do { \
|
||||||
scc_mir_x86_instr_t instr; \
|
scc_mir_x86_instr_t instr; \
|
||||||
(arg1).size = (_size); \
|
|
||||||
scc_mir_x86_instr_1(&instr, (iform), (arg1), (isel)->pos); \
|
scc_mir_x86_instr_1(&instr, (iform), (arg1), (isel)->pos); \
|
||||||
scc_vec_push((isel)->instrs, instr); \
|
scc_vec_push((isel)->instrs, instr); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#define add_instr_2(isel, iform, arg1, arg2, _size) \
|
#define add_instr_2(isel, iform, arg1, arg2) \
|
||||||
do { \
|
do { \
|
||||||
scc_mir_x86_instr_t instr; \
|
scc_mir_x86_instr_t instr; \
|
||||||
(arg1).size = (_size); \
|
|
||||||
scc_mir_x86_instr_2(&instr, (iform), (arg1), (arg2), (isel)->pos); \
|
scc_mir_x86_instr_2(&instr, (iform), (arg1), (arg2), (isel)->pos); \
|
||||||
scc_vec_push((isel)->instrs, instr); \
|
scc_vec_push((isel)->instrs, instr); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|||||||
@@ -9,16 +9,12 @@
|
|||||||
#include <x86/scc_x86_reg.h>
|
#include <x86/scc_x86_reg.h>
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
union {
|
scc_x86_iform_t opcode; // must be int or enum
|
||||||
int opcode;
|
int num_operands;
|
||||||
scc_x86_iform_t iform;
|
scc_x86_operand_value_t operands[3];
|
||||||
};
|
|
||||||
u8 num_operands;
|
|
||||||
scc_x86_operand_value_t operands[6];
|
|
||||||
scc_pos_t src_loc;
|
scc_pos_t src_loc;
|
||||||
} scc_x86_instr_t;
|
} scc_x86_instr_t;
|
||||||
|
|
||||||
// x86 后端指令:首字段 int opcode(正 = scc_x86_iform_t,负 = 伪指令)
|
|
||||||
typedef union scc_mir_x86_instr {
|
typedef union scc_mir_x86_instr {
|
||||||
scc_mir_instr_t instr;
|
scc_mir_instr_t instr;
|
||||||
scc_x86_instr_t x86_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;
|
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(bb) ((scc_mir_x86_instr_vec_t *)&bb->values)
|
||||||
#define SCC_MIR_X86_BBLOCK_INSTRS_C(bb) \
|
#define SCC_MIR_X86_BBLOCK_INSTRS_C(bb) \
|
||||||
((const scc_mir_x86_instr_vec_t *)&bb->values)
|
((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
|
// 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};
|
scc_x86_operand_value_t o = {.kind = SCC_X86_OPR_MEM};
|
||||||
o.mem.base = SCC_X86_REG_INVALID;
|
o.mem.base = SCC_X86_REG_INVALID;
|
||||||
o.mem.index = SCC_X86_REG_INVALID;
|
o.mem.index = SCC_X86_REG_INVALID;
|
||||||
o.mem.scale = 1;
|
o.mem.scale = 1;
|
||||||
o.mem.disp.displacement = slot_id;
|
o.mem.disp.displacement = slot_id;
|
||||||
o.mem.disp.displacement_bits = 0;
|
o.mem.disp.displacement_bits = 0;
|
||||||
|
o.size = size;
|
||||||
return o;
|
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;
|
return op->mem.disp.displacement;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void scc_mir_x86_instr_0(scc_mir_x86_instr_t *out, int opcode,
|
static inline void scc_mir_x86_instr_0(scc_mir_x86_instr_t *out,
|
||||||
scc_pos_t pos) {
|
scc_x86_iform_t opcode, scc_pos_t pos) {
|
||||||
out->x86_instr.opcode = opcode;
|
out->x86_instr.opcode = opcode;
|
||||||
out->x86_instr.num_operands = 0;
|
out->x86_instr.num_operands = 0;
|
||||||
out->x86_instr.src_loc = pos;
|
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_x86_operand_value_t op0,
|
||||||
scc_pos_t pos) {
|
scc_pos_t pos) {
|
||||||
out->x86_instr.opcode = opcode;
|
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.operands[0] = op0;
|
||||||
out->x86_instr.src_loc = pos;
|
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 op0,
|
||||||
scc_x86_operand_value_t op1,
|
scc_x86_operand_value_t op1,
|
||||||
scc_pos_t pos) {
|
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.operands[1] = op1;
|
||||||
out->x86_instr.src_loc = pos;
|
out->x86_instr.src_loc = pos;
|
||||||
}
|
}
|
||||||
static inline void scc_mir_x86_instr_3(scc_mir_x86_instr_t *out, int opcode,
|
static inline void
|
||||||
scc_x86_operand_value_t op0,
|
scc_mir_x86_instr_3(scc_mir_x86_instr_t *out, scc_x86_iform_t opcode,
|
||||||
scc_x86_operand_value_t op1,
|
scc_x86_operand_value_t op0, scc_x86_operand_value_t op1,
|
||||||
scc_x86_operand_value_t op2,
|
scc_x86_operand_value_t op2, scc_pos_t pos) {
|
||||||
scc_pos_t pos) {
|
|
||||||
out->x86_instr.opcode = opcode;
|
out->x86_instr.opcode = opcode;
|
||||||
out->x86_instr.num_operands = 3;
|
out->x86_instr.num_operands = 3;
|
||||||
out->x86_instr.operands[0] = op0;
|
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;
|
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__ */
|
#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);
|
void (*alloc_iter_begin)(scc_reg_alloc_iter_t *iter);
|
||||||
cbool (*alloc_iter_next)(scc_reg_alloc_iter_t *iter, int *out_vreg,
|
cbool (*alloc_iter_next)(scc_reg_alloc_iter_t *iter, int *out_vreg,
|
||||||
int *out_size, scc_reg_op_access_t *out_access);
|
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_preg)(scc_reg_alloc_iter_t *iter, int preg,
|
||||||
void (*alloc_iter_replace_slot)(scc_reg_alloc_iter_t *iter, int slot);
|
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);
|
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, " ???");
|
scc_tree_dump_append_fmt(td, " ???");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
scc_x86_iform_t iform = instr->x86_instr.opcode;
|
scc_x86_iform_t opcode = instr->x86_instr.opcode;
|
||||||
const scc_x86_iform_info_t *info = &scc_x86_iform_table[iform];
|
const scc_x86_iform_info_t *info = &scc_x86_iform_table[opcode];
|
||||||
scc_tree_dump_append_fmt(td, " %s", info->iform_name);
|
scc_tree_dump_append_fmt(td, " %s", info->iform_name);
|
||||||
for (int i = 0; i < instr->x86_instr.num_operands; i += 1) {
|
for (int i = 0; i < instr->x86_instr.num_operands; i += 1) {
|
||||||
if (i == 0)
|
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);
|
scc_tree_dump_append_fmt(td, "(x%d)", op->mem.scale);
|
||||||
}
|
}
|
||||||
if (op->mem.disp.displacement != 0) {
|
if (op->mem.disp.displacement != 0) {
|
||||||
scc_tree_dump_append_fmt(
|
i64 data = op->mem.disp.displacement < 0
|
||||||
td, " %c %llu",
|
|
||||||
op->mem.disp.displacement >= 0 ? '+' : '-',
|
|
||||||
op->mem.disp.displacement < 0
|
|
||||||
? -op->mem.disp.displacement
|
? -op->mem.disp.displacement
|
||||||
: op->mem.disp.displacement);
|
: op->mem.disp.displacement;
|
||||||
|
scc_tree_dump_append_fmt(
|
||||||
|
td, " %c %lld/%#llx",
|
||||||
|
op->mem.disp.displacement >= 0 ? '+' : '-', data, data);
|
||||||
}
|
}
|
||||||
scc_tree_dump_append(td, ")");
|
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, "<?>");
|
scc_tree_dump_append(td, "<?>");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
scc_tree_dump_append_fmt(td, "(%zu)", op->size);
|
scc_tree_dump_append_fmt(td, ".(%zu)", op->size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 将 LIR 值转换为 x86 操作数
|
// 将 LIR 值转换为 x86 操作数
|
||||||
scc_x86_operand_value_t scc_x86_lir_val_to_mir_op(scc_x86_64_isel_t *isel,
|
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};
|
scc_x86_operand_value_t op = {0};
|
||||||
switch (val->kind) {
|
switch (val->kind) {
|
||||||
case SCC_LIR_INSTR_KIND_NONE:
|
case SCC_LIR_INSTR_KIND_NONE:
|
||||||
op.kind = SCC_X86_OPR_NONE;
|
op.kind = SCC_X86_OPR_NONE;
|
||||||
break;
|
break;
|
||||||
case SCC_LIR_INSTR_KIND_VREG:
|
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 id = 0;
|
||||||
int ret = scc_mir_vreg_lookup(isel->func, val->data.reg, &id);
|
int ret = scc_mir_vreg_lookup(isel->func, val->data.reg, &id);
|
||||||
if (ret > 0) {
|
if (ret > 0) {
|
||||||
op = scc_x86_op_preg(id);
|
op = scc_x86_op_preg(id, size);
|
||||||
} else if (ret < 0) {
|
} else if (ret < 0) {
|
||||||
op = scc_x86_op_slot(id);
|
op = scc_x86_op_slot(id, size);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case SCC_LIR_INSTR_KIND_IMM:
|
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;
|
break;
|
||||||
case SCC_LIR_INSTR_KIND_FIMM:
|
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;
|
break;
|
||||||
case SCC_LIR_INSTR_KIND_SYMBOL:
|
case SCC_LIR_INSTR_KIND_SYMBOL:
|
||||||
op = scc_x86_op_reloc_global_relrip(val->data.symbol, 0);
|
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:
|
case SCC_LIR_INSTR_KIND_ARG:
|
||||||
Assert(isel->abi_lowering.lower_param);
|
Assert(isel->abi_lowering.lower_param);
|
||||||
isel->abi_lowering.lower_param(isel, val, &op);
|
isel->abi_lowering.lower_param(isel, val, &op);
|
||||||
|
op.size = size;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
Panic("unsupported lir instr kind %d", val->kind);
|
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) {
|
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));
|
int size) {
|
||||||
}
|
return scc_x86_op_vreg(scc_mir_alloc_vreg(isel->func), size);
|
||||||
|
|
||||||
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_iform_t cond_to_setcc(scc_lir_cond_t cond) {
|
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,
|
static void emit_copy_if_needed(scc_x86_64_isel_t *isel,
|
||||||
scc_x86_operand_value_t dst,
|
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) &&
|
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)) {
|
scc_x86_op_get_vreg(&dst) == scc_x86_op_get_vreg(&src0)) {
|
||||||
return;
|
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,
|
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 dst,
|
||||||
scc_x86_operand_value_t src0,
|
scc_x86_operand_value_t src0,
|
||||||
scc_x86_operand_value_t src1, u8 size) {
|
scc_x86_operand_value_t src1) {
|
||||||
(void)size;
|
emit_copy_if_needed(isel, dst, src0);
|
||||||
emit_copy_if_needed(isel, dst, src0, size);
|
|
||||||
dst.size = size;
|
|
||||||
src0.size = size;
|
|
||||||
src1.size = size;
|
|
||||||
|
|
||||||
bool is_imm = (src1.kind == SCC_X86_OPR_IMM);
|
Assert(src0.size == src1.size);
|
||||||
scc_x86_iform_t iform;
|
int is_8b = src0.size == 1;
|
||||||
|
int is_imm = src1.kind == SCC_X86_OPR_IMM;
|
||||||
|
scc_x86_iform_t opcode;
|
||||||
switch (op) {
|
switch (op) {
|
||||||
case SCC_LIR_ADD:
|
case SCC_LIR_ADD:
|
||||||
iform = is_imm ? SCC_X86_IFORM_ADD_GPRV_IMMZ
|
opcode = is_imm ? SCC_X86_IFORM_ADD_GPRV_IMMZ
|
||||||
: SCC_X86_IFORM_ADD_GPRV_GPRV_03;
|
: SCC_X86_IFORM_ADD_GPRV_GPRV_03;
|
||||||
break;
|
break;
|
||||||
case SCC_LIR_SUB:
|
case SCC_LIR_SUB:
|
||||||
iform = is_imm ? SCC_X86_IFORM_SUB_GPRV_IMMZ
|
opcode = is_imm ? SCC_X86_IFORM_SUB_GPRV_IMMZ
|
||||||
: SCC_X86_IFORM_SUB_GPRV_GPRV_2B;
|
: SCC_X86_IFORM_SUB_GPRV_GPRV_2B;
|
||||||
break;
|
break;
|
||||||
case SCC_LIR_AND:
|
case SCC_LIR_AND:
|
||||||
iform = is_imm ? SCC_X86_IFORM_AND_GPRV_IMMZ
|
opcode = is_imm ? SCC_X86_IFORM_AND_GPRV_IMMZ
|
||||||
: SCC_X86_IFORM_AND_GPRV_GPRV_23;
|
: SCC_X86_IFORM_AND_GPRV_GPRV_23;
|
||||||
break;
|
break;
|
||||||
case SCC_LIR_OR:
|
case SCC_LIR_OR:
|
||||||
iform =
|
opcode =
|
||||||
is_imm ? SCC_X86_IFORM_OR_GPRV_IMMZ : SCC_X86_IFORM_OR_GPRV_GPRV_0B;
|
is_imm ? SCC_X86_IFORM_OR_GPRV_IMMZ : SCC_X86_IFORM_OR_GPRV_GPRV_0B;
|
||||||
break;
|
break;
|
||||||
case SCC_LIR_XOR:
|
case SCC_LIR_XOR:
|
||||||
iform = is_imm ? SCC_X86_IFORM_XOR_GPRV_IMMZ
|
opcode = is_imm ? SCC_X86_IFORM_XOR_GPRV_IMMZ
|
||||||
: SCC_X86_IFORM_XOR_GPRV_GPRV_33;
|
: SCC_X86_IFORM_XOR_GPRV_GPRV_33;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
UNREACHABLE();
|
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,
|
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) {
|
||||||
if (size == 0) {
|
scc_x86_emit_move_to_vec(&isel->instrs, dst_reg, src);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void scc_x86_emit_load(scc_x86_64_isel_t *isel, scc_x86_operand_value_t dst,
|
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) {
|
||||||
if (size == 0) {
|
|
||||||
size = dst.size;
|
|
||||||
}
|
|
||||||
if (dst.size != src.size) {
|
|
||||||
LOG_WARN("Mismatched register sizes for store %d != %d", dst.size,
|
|
||||||
src.size);
|
|
||||||
}
|
|
||||||
if (dst.kind != SCC_X86_OPR_REG) {
|
if (dst.kind != SCC_X86_OPR_REG) {
|
||||||
scc_x86_operand_value_t tmp_reg = new_vreg_temp(isel);
|
scc_x86_operand_value_t tmp_reg = new_vreg_temp(isel, dst.size);
|
||||||
scc_x86_emit_move(isel, tmp_reg, dst, size);
|
scc_x86_emit_move(isel, tmp_reg, dst);
|
||||||
dst = tmp_reg;
|
dst = tmp_reg;
|
||||||
}
|
}
|
||||||
scc_x86_operand_value_t mem_op;
|
|
||||||
if (src.kind == SCC_X86_OPR_REG) {
|
scc_x86_emit_load_to_vec(&isel->instrs, dst, src);
|
||||||
// 地址在寄存器中 -> 构造 [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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void scc_x86_emit_store(scc_x86_64_isel_t *isel, scc_x86_operand_value_t dst,
|
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) {
|
||||||
if (size == 0) {
|
|
||||||
size = dst.size;
|
|
||||||
}
|
|
||||||
if (dst.size != src.size) {
|
|
||||||
LOG_WARN("Mismatched register sizes for store %d != %d", dst.size,
|
|
||||||
src.size);
|
|
||||||
}
|
|
||||||
if (src.kind != SCC_X86_OPR_REG) {
|
if (src.kind != SCC_X86_OPR_REG) {
|
||||||
scc_x86_operand_value_t tmp_reg = new_vreg_temp(isel);
|
scc_x86_operand_value_t tmp_reg = new_vreg_temp(isel, src.size);
|
||||||
scc_x86_emit_move(isel, tmp_reg, src, size);
|
scc_x86_emit_move(isel, tmp_reg, src);
|
||||||
src = tmp_reg;
|
src = tmp_reg;
|
||||||
}
|
}
|
||||||
scc_x86_operand_value_t mem_op;
|
scc_x86_emit_store_to_vec(&isel->instrs, dst, src);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void emit_load_addr(scc_x86_64_isel_t *isel, scc_x86_operand_value_t dst,
|
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,
|
scc_x86_operand_value_t index, int scale,
|
||||||
i64 offset) {
|
i64 offset) {
|
||||||
usize size = dst.size;
|
usize size = dst.size;
|
||||||
|
Assert(size == 8);
|
||||||
// 前置断言:dst 必须是寄存器
|
// 前置断言:dst 必须是寄存器
|
||||||
Assert(dst.kind == SCC_X86_OPR_REG);
|
Assert(dst.kind == SCC_X86_OPR_REG);
|
||||||
// scale 必须是 1,2,4,8 之一
|
// 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 ----
|
// ---- 处理 base ----
|
||||||
scc_x86_operand_value_t base_reg = base;
|
scc_x86_operand_value_t base_reg = base;
|
||||||
if (base.kind != SCC_X86_OPR_REG) {
|
if (base.kind != SCC_X86_OPR_REG) {
|
||||||
base_reg = new_vreg_temp(isel);
|
base_reg = new_vreg_temp(isel, size);
|
||||||
scc_x86_emit_move(isel, base_reg, base, 8);
|
scc_x86_emit_move(isel, base_reg, base);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---- 处理 index * scale ----
|
// ---- 处理 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);
|
Assert(index.kind != SCC_X86_OPR_NONE);
|
||||||
// 确保 index 在寄存器中
|
// 确保 index 在寄存器中
|
||||||
if (index.kind != SCC_X86_OPR_REG) {
|
if (index.kind != SCC_X86_OPR_REG) {
|
||||||
scc_x86_operand_value_t index_tmp = new_vreg_temp(isel);
|
scc_x86_operand_value_t index_tmp = new_vreg_temp(isel, index.size);
|
||||||
scc_x86_emit_move(isel, index_tmp, index, 8);
|
scc_x86_emit_move(isel, index_tmp, index);
|
||||||
index = index_tmp;
|
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 &&
|
if (base_reg.kind == SCC_X86_OPR_REG &&
|
||||||
scaled_index.kind == SCC_X86_OPR_REG) {
|
scaled_index.kind == SCC_X86_OPR_REG) {
|
||||||
if (dst.reg != base_reg.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;
|
sum = dst;
|
||||||
}
|
}
|
||||||
add_instr_2(isel, SCC_X86_IFORM_ADD_GPRV_GPRV_03, sum, scaled_index,
|
add_instr_2(isel, SCC_X86_IFORM_ADD_GPRV_GPRV_03, sum, scaled_index);
|
||||||
size);
|
|
||||||
} else if (base_reg.kind == SCC_X86_OPR_REG) {
|
} else if (base_reg.kind == SCC_X86_OPR_REG) {
|
||||||
if (dst.reg != base_reg.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;
|
sum = dst;
|
||||||
} else if (scaled_index.kind == SCC_X86_OPR_REG) {
|
} 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;
|
sum = dst;
|
||||||
} else {
|
} else {
|
||||||
// base 和 index 都无效 => 结果为 0
|
// 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;
|
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(
|
scc_x86_operand_value_t mem_op = build_mem_op(
|
||||||
isel, sum, (scc_x86_operand_value_t){.kind = SCC_X86_OPR_NONE}, 1,
|
isel, sum, (scc_x86_operand_value_t){.kind = SCC_X86_OPR_NONE}, 1,
|
||||||
offset);
|
offset);
|
||||||
scc_x86_emit_move(isel, dst, mem_op, 8);
|
scc_x86_emit_move(isel, dst, mem_op);
|
||||||
} else if (sum.reg != dst.reg) {
|
} 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) {
|
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;
|
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) {
|
switch (instr->op) {
|
||||||
/* ---- 数据移动 ---- */
|
/* ---- 数据移动 ---- */
|
||||||
case SCC_LIR_LOAD:
|
case SCC_LIR_LOAD:
|
||||||
// src0 是地址(可能是寄存器或内存操作数),dst 是寄存器
|
// src0 是地址(可能是寄存器或内存操作数),dst 是寄存器
|
||||||
scc_x86_emit_load(isel, dst, src0, size);
|
scc_x86_emit_load(isel, dst, src0);
|
||||||
break;
|
break;
|
||||||
case SCC_LIR_STORE:
|
case SCC_LIR_STORE:
|
||||||
// src0 是要存储的值(寄存器),src1 是目标地址
|
// src0 是要存储的值(寄存器),src1 是目标地址
|
||||||
scc_x86_emit_store(isel, src1, src0, size);
|
scc_x86_emit_store(isel, src1, src0);
|
||||||
break;
|
break;
|
||||||
case SCC_LIR_MOV:
|
case SCC_LIR_MOV:
|
||||||
// 纯粹的寄存器/立即数复制
|
// 纯粹的寄存器/立即数复制
|
||||||
scc_x86_emit_move(isel, dst, src0, size);
|
scc_x86_emit_move(isel, dst, src0);
|
||||||
break;
|
break;
|
||||||
case SCC_LIR_LOAD_ADDR:
|
case SCC_LIR_LOAD_ADDR:
|
||||||
// 计算地址,结果放入 dst(寄存器)
|
// 计算地址,结果放入 dst(寄存器)
|
||||||
@@ -428,10 +357,10 @@ static void sel_mir(scc_x86_64_isel_t *isel, const scc_lir_instr_t *instr) {
|
|||||||
break;
|
break;
|
||||||
/* ---- 一元运算 ---- */
|
/* ---- 一元运算 ---- */
|
||||||
case SCC_LIR_NEG:
|
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;
|
break;
|
||||||
case SCC_LIR_NOT:
|
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;
|
break;
|
||||||
/* ---- 算术/逻辑二元运算 ---- */
|
/* ---- 算术/逻辑二元运算 ---- */
|
||||||
case SCC_LIR_ADD:
|
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_AND:
|
||||||
case SCC_LIR_OR:
|
case SCC_LIR_OR:
|
||||||
case SCC_LIR_XOR:
|
case SCC_LIR_XOR:
|
||||||
emit_binary_op(isel, instr->op, dst, src0, src1, size);
|
emit_binary_op(isel, instr->op, dst, src0, src1);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SCC_LIR_MUL:
|
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) {
|
if (src1.kind == SCC_X86_OPR_IMM) {
|
||||||
scc_x86_operand_value_t op = new_vreg_temp(isel);
|
scc_x86_operand_value_t op = new_vreg_temp(isel, size);
|
||||||
scc_x86_emit_move(isel, op, src1, size);
|
scc_x86_emit_move(isel, op, src1);
|
||||||
src1 = op;
|
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;
|
break;
|
||||||
|
|
||||||
case SCC_LIR_SHL:
|
case SCC_LIR_SHL:
|
||||||
case SCC_LIR_SHR:
|
case SCC_LIR_SHR:
|
||||||
case SCC_LIR_SAR: {
|
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) {
|
if (src1.kind == SCC_X86_OPR_IMM) {
|
||||||
scc_x86_iform_t iform;
|
scc_x86_iform_t iform;
|
||||||
switch (instr->op) {
|
switch (instr->op) {
|
||||||
@@ -472,10 +400,10 @@ static void sel_mir(scc_x86_64_isel_t *isel, const scc_lir_instr_t *instr) {
|
|||||||
default:
|
default:
|
||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
}
|
}
|
||||||
add_instr_2(isel, iform, dst, src1, size);
|
add_instr_2(isel, iform, dst, src1);
|
||||||
} else {
|
} else {
|
||||||
scc_x86_operand_value_t cl = scc_x86_op_preg(SCC_X86_REG_CL);
|
scc_x86_operand_value_t cl = scc_x86_op_preg(SCC_X86_REG_CL, 1);
|
||||||
scc_x86_emit_move(isel, cl, src1, 1);
|
scc_x86_emit_move(isel, cl, src1);
|
||||||
scc_x86_iform_t iform;
|
scc_x86_iform_t iform;
|
||||||
switch (instr->op) {
|
switch (instr->op) {
|
||||||
case SCC_LIR_SHL:
|
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:
|
default:
|
||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
}
|
}
|
||||||
add_instr_2(isel, iform, dst, cl, size);
|
add_instr_2(isel, iform, dst, cl);
|
||||||
}
|
}
|
||||||
} break;
|
} 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_DIV_U:
|
||||||
case SCC_LIR_REM_S:
|
case SCC_LIR_REM_S:
|
||||||
case SCC_LIR_REM_U: {
|
case SCC_LIR_REM_U: {
|
||||||
scc_x86_operand_value_t rax = scc_x86_op_preg(SCC_X86_REG_RAX);
|
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);
|
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) {
|
if (instr->op == SCC_LIR_DIV_S || instr->op == SCC_LIR_REM_S) {
|
||||||
add_instr_0(isel, SCC_X86_IFORM_CQO);
|
add_instr_0(isel, SCC_X86_IFORM_CQO);
|
||||||
} else {
|
} else {
|
||||||
scc_x86_operand_value_t zero = scc_x86_op_imm(0);
|
scc_x86_operand_value_t zero = scc_x86_op_imm(0, size);
|
||||||
scc_x86_emit_move(isel, rdx, zero, size);
|
scc_x86_emit_move(isel, rdx, zero);
|
||||||
}
|
}
|
||||||
|
|
||||||
scc_x86_iform_t div_if =
|
scc_x86_iform_t div_if =
|
||||||
(instr->op == SCC_LIR_DIV_S || instr->op == SCC_LIR_REM_S)
|
(instr->op == SCC_LIR_DIV_S || instr->op == SCC_LIR_REM_S)
|
||||||
? SCC_X86_IFORM_IDIV_GPRV
|
? SCC_X86_IFORM_IDIV_GPRV
|
||||||
: SCC_X86_IFORM_DIV_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)
|
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
|
else
|
||||||
scc_x86_emit_move(isel, dst, rax, size);
|
scc_x86_emit_move(isel, dst, rax);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
/* ---- 比较指令 ---- */
|
/* ---- 比较指令 ---- */
|
||||||
case SCC_LIR_CMP: {
|
case SCC_LIR_CMP: {
|
||||||
|
Assert(src0.size == src1.size);
|
||||||
if (scc_x86_op_is_vreg(&src0) && src1.kind == SCC_X86_OPR_IMM)
|
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))
|
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
|
else
|
||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
|
|
||||||
scc_x86_iform_t setcc = cond_to_setcc(instr->metadata.cond);
|
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) {
|
if (size > 1) {
|
||||||
scc_x86_operand_value_t one = scc_x86_op_imm(1);
|
scc_x86_operand_value_t one = scc_x86_op_imm(1, size);
|
||||||
add_instr_2(isel, SCC_X86_IFORM_AND_GPRV_IMMZ, dst, one, size);
|
add_instr_2(isel,
|
||||||
|
src1.size == 1 ? SCC_X86_IFORM_AND_GPR8_IMMB_82R4
|
||||||
|
: SCC_X86_IFORM_AND_GPRV_IMMZ,
|
||||||
|
dst, one);
|
||||||
}
|
}
|
||||||
} break;
|
} 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_op_reloc_block(instr->metadata.br.true_target, 0);
|
||||||
scc_x86_operand_value_t false_bb =
|
scc_x86_operand_value_t false_bb =
|
||||||
scc_x86_op_reloc_block(instr->metadata.br.false_target, 0);
|
scc_x86_op_reloc_block(instr->metadata.br.false_target, 0);
|
||||||
|
true_bb.size = instr->size;
|
||||||
add_instr_2(isel, SCC_X86_IFORM_TEST_GPRV_GPRV, src0, src0, size);
|
false_bb.size = instr->size;
|
||||||
add_instr_1(isel, SCC_X86_IFORM_JNZ_RELBRZ, true_bb, size);
|
add_instr_2(isel,
|
||||||
add_instr_1(isel, SCC_X86_IFORM_JMP_RELBRZ, false_bb, size);
|
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;
|
} break;
|
||||||
|
|
||||||
case SCC_LIR_JMP: {
|
case SCC_LIR_JMP: {
|
||||||
scc_x86_operand_value_t jmp_bb =
|
scc_x86_operand_value_t jmp_bb =
|
||||||
scc_x86_op_reloc_block(instr->metadata.jmp_target, 0);
|
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;
|
} break;
|
||||||
|
|
||||||
/* ---- 栈分配 ---- */
|
/* ---- 栈分配 ---- */
|
||||||
case SCC_LIR_ALLOCA: {
|
case SCC_LIR_ALLOCA: {
|
||||||
scc_x86_operand_value_t op =
|
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;
|
scc_mir_x86_instr_t x86instr;
|
||||||
x86instr.instr.opcode = SCC_MIR_PSEUDO_ALLOCA;
|
x86instr.instr.opcode = SCC_MIR_PSEUDO_ALLOCA;
|
||||||
Assert(op.kind == SCC_X86_OPR_REG);
|
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);
|
isel->abi_lowering.lower_call(isel, instr);
|
||||||
} break;
|
} break;
|
||||||
case SCC_LIR_CALL_INDIRECT: {
|
case SCC_LIR_CALL_INDIRECT: {
|
||||||
TODO();
|
Assert(isel->abi_lowering.lower_call);
|
||||||
// 假设函数指针的 LIR 值在某个 vreg 中
|
isel->abi_lowering.lower_call(isel, instr);
|
||||||
// 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);
|
|
||||||
} break;
|
} break;
|
||||||
case SCC_LIR_RET: {
|
case SCC_LIR_RET: {
|
||||||
Assert(isel->abi_lowering.lower_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
|
// 将 dest 的地址放入 RDI
|
||||||
scc_x86_operand_value_t dest_op =
|
scc_x86_operand_value_t dest_op =
|
||||||
scc_x86_lir_val_to_mir_op(isel, &dest_val);
|
scc_x86_lir_val_to_mir_op(isel, &dest_val, 8);
|
||||||
scc_x86_emit_move(isel, scc_x86_op_preg(SCC_X86_REG_RDI), dest_op, 8);
|
scc_x86_emit_move(isel, scc_x86_op_preg(SCC_X86_REG_RDI, 8), dest_op);
|
||||||
|
|
||||||
// 将 src 的地址放入 RSI
|
// 将 src 的地址放入 RSI
|
||||||
scc_x86_operand_value_t src_op =
|
scc_x86_operand_value_t src_op =
|
||||||
scc_x86_lir_val_to_mir_op(isel, &src_val);
|
scc_x86_lir_val_to_mir_op(isel, &src_val, 8);
|
||||||
scc_x86_emit_move(isel, scc_x86_op_preg(SCC_X86_REG_RSI), src_op, 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_operand_value_t len_op =
|
||||||
scc_x86_lir_val_to_mir_op(isel, &instr->metadata.memcpy.size);
|
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), len_op, 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);
|
add_instr_0(isel, SCC_X86_IFORM_REP_MOVSB);
|
||||||
} break;
|
} 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_lir_instr_vec_t *instrs = SCC_LIR_BBLOCK_VALUES(bb);
|
||||||
scc_vec_foreach(*instrs, i) {
|
scc_vec_foreach(*instrs, i) {
|
||||||
const scc_lir_instr_t *ins = &scc_vec_at(*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);
|
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) {
|
static void emit_spill(void *out, int preg, int slot, int size) {
|
||||||
scc_mir_x86_instr_vec_t *vec = out;
|
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_slot = scc_x86_op_slot(slot, size);
|
||||||
scc_x86_operand_value_t val_preg = scc_x86_op_preg(preg);
|
scc_x86_operand_value_t val_preg = scc_x86_op_preg(preg, size);
|
||||||
val_slot.size = size;
|
scc_x86_emit_store_to_vec(vec, val_slot, val_preg);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void emit_reload(void *out, int preg, int slot, int size) {
|
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_vec_t *vec = out;
|
||||||
scc_mir_x86_instr_t ins = {.x86_instr.opcode = SCC_X86_IFORM_MOV_GPRV_MEMV,
|
scc_x86_operand_value_t val_slot = scc_x86_op_slot(slot, size);
|
||||||
.x86_instr.num_operands = 2,
|
scc_x86_operand_value_t val_preg = scc_x86_op_preg(preg, size);
|
||||||
.x86_instr.operands = {val_preg, val_slot}};
|
scc_x86_emit_load_to_vec(vec, val_preg, val_slot);
|
||||||
scc_vec_push(*vec, ins);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void emit_copy(void *out, int dst_preg, int src_preg, int size) {
|
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_vec_t *vec = out;
|
||||||
scc_mir_x86_instr_t ins = {
|
scc_x86_operand_value_t val_dst = scc_x86_op_preg(dst_preg, size);
|
||||||
.x86_instr.opcode = SCC_X86_IFORM_MOV_GPRV_GPRV_8B,
|
scc_x86_operand_value_t val_src = scc_x86_op_preg(src_preg, size);
|
||||||
.x86_instr.num_operands = 2,
|
scc_x86_emit_move_to_vec(vec, val_dst, val_src);
|
||||||
.x86_instr.operands = {scc_x86_op_preg(dst_preg),
|
|
||||||
scc_x86_op_preg(src_preg)}};
|
|
||||||
scc_vec_push(*vec, ins);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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) {
|
if (opcode >= 0 && opcode < SCC_X86_IFORM_COUNT) {
|
||||||
const scc_x86_iform_info_t *info = &scc_x86_iform_table[opcode];
|
const scc_x86_iform_info_t *info = &scc_x86_iform_table[opcode];
|
||||||
if (op_idx >= info->num_ops || op_idx < 0)
|
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,
|
int *out_size,
|
||||||
scc_reg_op_access_t *out_access) {
|
scc_reg_op_access_t *out_access) {
|
||||||
const scc_mir_x86_instr_t *ins = (const scc_mir_x86_instr_t *)iter->instr;
|
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;
|
int num_ops = ins->x86_instr.num_operands;
|
||||||
|
|
||||||
while (iter->op_idx < num_ops) {
|
while (iter->op_idx < num_ops) {
|
||||||
const scc_x86_operand_value_t *op =
|
const scc_x86_operand_value_t *op =
|
||||||
&ins->x86_instr.operands[iter->op_idx];
|
&ins->x86_instr.operands[iter->op_idx];
|
||||||
scc_reg_op_access_t base_access =
|
scc_reg_op_access_t base_access = SCC_REG_ALLOC_OP_ACCESS_READWRITE;
|
||||||
get_operand_access(opcode, iter->op_idx);
|
// base_access = get_operand_access(opcode, iter->op_idx);
|
||||||
|
|
||||||
*out_size = op->size;
|
*out_size = op->size;
|
||||||
if (op->kind == SCC_X86_OPR_REG) {
|
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;
|
continue;
|
||||||
} else if (op->kind == SCC_X86_OPR_MEM) {
|
} else if (op->kind == SCC_X86_OPR_MEM) {
|
||||||
const scc_x86_mem_t *mem = &op->mem;
|
const scc_x86_mem_t *mem = &op->mem;
|
||||||
|
*out_size = 8;
|
||||||
// 子索引 0: 基址寄存器
|
// 子索引 0: 基址寄存器
|
||||||
if (iter->op_sub_idx == 0) {
|
if (iter->op_sub_idx == 0) {
|
||||||
if (mem->base != SCC_X86_REG_INVALID &&
|
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;
|
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;
|
scc_mir_x86_instr_t *ins = (scc_mir_x86_instr_t *)iter->instr;
|
||||||
int op_idx = iter->op_idx;
|
int op_idx = iter->op_idx;
|
||||||
int sub_idx = iter->op_sub_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;
|
scc_mir_x86_instr_t *ins = (scc_mir_x86_instr_t *)iter->instr;
|
||||||
int op_idx = iter->op_idx;
|
int op_idx = iter->op_idx;
|
||||||
if (op_idx < ins->x86_instr.num_operands && iter->op_sub_idx == 0) {
|
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 {
|
} else {
|
||||||
Panic("x86_alloc_iter_replace_slot: invalid op_idx");
|
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) {
|
if (mapping == 1) {
|
||||||
ops->mark_reg_used(ctx, preg);
|
ops->mark_reg_used(ctx, preg);
|
||||||
ops->alloc_iter_replace_preg(&iter, preg);
|
ops->alloc_iter_replace_preg(&iter, preg, size);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (mapping == 0)
|
if (mapping == 0)
|
||||||
@@ -58,7 +58,7 @@ static void alloc_instr(scc_reg_alloc_ctx_t *ctx,
|
|||||||
access == SCC_REG_ALLOC_OP_ACCESS_READWRITE)
|
access == SCC_REG_ALLOC_OP_ACCESS_READWRITE)
|
||||||
ops->emit_spill(&after, preg, slot, size);
|
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);
|
ops->alloc_iter_end(&iter);
|
||||||
|
|
||||||
|
|||||||
@@ -29,13 +29,16 @@ static void frame_alloc_impl(scc_frame_layout_t *ctx,
|
|||||||
ctx->offset += slot->size;
|
ctx->offset += slot->size;
|
||||||
slot->offset = ctx->offset;
|
slot->offset = ctx->offset;
|
||||||
}
|
}
|
||||||
*op = scc_x86_op_mem((scc_x86_mem_t){
|
|
||||||
|
*op = scc_x86_op_mem(
|
||||||
|
(scc_x86_mem_t){
|
||||||
.seg = SCC_X86_REG_INVALID,
|
.seg = SCC_X86_REG_INVALID,
|
||||||
.base = SCC_X86_REG_RSP,
|
.base = SCC_X86_REG_RSP,
|
||||||
.disp = {.displacement = -slot->offset},
|
.disp = {.displacement = -slot->offset},
|
||||||
.index = SCC_X86_REG_INVALID,
|
.index = SCC_X86_REG_INVALID,
|
||||||
.scale = 1,
|
.scale = 1,
|
||||||
});
|
},
|
||||||
|
op->size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -76,11 +79,12 @@ static void prologue(scc_mir_instr_vec_t *userdata,
|
|||||||
/// FILL to shadow space
|
/// FILL to shadow space
|
||||||
}
|
}
|
||||||
|
|
||||||
|
u8 size = 8;
|
||||||
// sub rsp, frame_size
|
// sub rsp, frame_size
|
||||||
if (frame_size > 0) {
|
if (frame_size > 0) {
|
||||||
scc_mir_x86_instr_2(&instr, SCC_X86_IFORM_SUB_GPRV_IMMZ,
|
scc_mir_x86_instr_2(&instr, SCC_X86_IFORM_SUB_GPRV_IMMZ,
|
||||||
scc_x86_op_preg(SCC_X86_REG_RSP),
|
scc_x86_op_preg(SCC_X86_REG_RSP, size),
|
||||||
scc_x86_op_imm(frame_size), scc_pos_create());
|
scc_x86_op_imm(frame_size, size), scc_pos_create());
|
||||||
scc_vec_push(*instrs, instr);
|
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);
|
scc_mir_func_meta_t *meta = SCC_MIR_FUNC_META(func);
|
||||||
int frame_size = meta->frame_size;
|
int frame_size = meta->frame_size;
|
||||||
|
u8 size = 8;
|
||||||
// add rsp, frame_size
|
// add rsp, frame_size
|
||||||
if (frame_size > 0) {
|
if (frame_size > 0) {
|
||||||
scc_mir_x86_instr_2(&instr, SCC_X86_IFORM_ADD_GPRV_IMMZ,
|
scc_mir_x86_instr_2(&instr, SCC_X86_IFORM_ADD_GPRV_IMMZ,
|
||||||
scc_x86_op_preg(SCC_X86_REG_RSP),
|
scc_x86_op_preg(SCC_X86_REG_RSP, size),
|
||||||
scc_x86_op_imm(frame_size), scc_pos_create());
|
scc_x86_op_imm(frame_size, size), scc_pos_create());
|
||||||
scc_vec_push(*instrs, instr);
|
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) {
|
static void lower_call(void *userdata, const scc_lir_instr_t *instr) {
|
||||||
scc_x86_64_isel_t *isel = userdata;
|
scc_x86_64_isel_t *isel = userdata;
|
||||||
|
|
||||||
|
u8 size = 8;
|
||||||
for (int i = instr->metadata.call.arg_count - 1; i >= 0; i -= 1) {
|
for (int i = instr->metadata.call.arg_count - 1; i >= 0; i -= 1) {
|
||||||
scc_lir_val_t *args = &instr->metadata.call.args[i];
|
scc_lir_val_t *args = &instr->metadata.call.args[i];
|
||||||
switch (i) {
|
switch (i) {
|
||||||
case 0:
|
case 0:
|
||||||
scc_x86_emit_move(isel, scc_x86_op_preg(SCC_X86_REG_RCX),
|
scc_x86_emit_move(isel, scc_x86_op_preg(SCC_X86_REG_RCX, size),
|
||||||
scc_x86_lir_val_to_mir_op(isel, args), 8);
|
scc_x86_lir_val_to_mir_op(isel, args, size));
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
scc_x86_emit_move(isel, scc_x86_op_preg(SCC_X86_REG_RDX),
|
scc_x86_emit_move(isel, scc_x86_op_preg(SCC_X86_REG_RDX, size),
|
||||||
scc_x86_lir_val_to_mir_op(isel, args), 8);
|
scc_x86_lir_val_to_mir_op(isel, args, size));
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
scc_x86_emit_move(isel, scc_x86_op_preg(SCC_X86_REG_R8),
|
scc_x86_emit_move(isel, scc_x86_op_preg(SCC_X86_REG_R8, size),
|
||||||
scc_x86_lir_val_to_mir_op(isel, args), 8);
|
scc_x86_lir_val_to_mir_op(isel, args, size));
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
scc_x86_emit_move(isel, scc_x86_op_preg(SCC_X86_REG_R9),
|
scc_x86_emit_move(isel, scc_x86_op_preg(SCC_X86_REG_R9, size),
|
||||||
scc_x86_lir_val_to_mir_op(isel, args), 8);
|
scc_x86_lir_val_to_mir_op(isel, args, size));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
scc_x86_operand_value_t op = scc_x86_lir_val_to_mir_op(isel, args);
|
scc_x86_operand_value_t op =
|
||||||
add_instr_1(isel,
|
scc_x86_lir_val_to_mir_op(isel, args, size);
|
||||||
op.kind == SCC_X86_OPR_REG ? SCC_X86_IFORM_PUSH_GPRV_50
|
TODO();
|
||||||
: SCC_X86_IFORM_PUSH_IMMZ,
|
add_instr_1(isel, SCC_X86_ICLASS_PUSH, op);
|
||||||
op, 8);
|
|
||||||
break;
|
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_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) {
|
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) {
|
void *out_op) {
|
||||||
scc_x86_operand_value_t *out = out_op;
|
scc_x86_operand_value_t *out = out_op;
|
||||||
Assert(val->kind == SCC_LIR_INSTR_KIND_ARG);
|
Assert(val->kind == SCC_LIR_INSTR_KIND_ARG);
|
||||||
|
u8 size = 8;
|
||||||
switch (val->data.arg) {
|
switch (val->data.arg) {
|
||||||
case 0:
|
case 0:
|
||||||
*out = scc_x86_op_preg(SCC_X86_REG_RCX);
|
*out = scc_x86_op_preg(SCC_X86_REG_RCX, size);
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
*out = scc_x86_op_preg(SCC_X86_REG_RDX);
|
*out = scc_x86_op_preg(SCC_X86_REG_RDX, size);
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
*out = scc_x86_op_preg(SCC_X86_REG_R8);
|
*out = scc_x86_op_preg(SCC_X86_REG_R8, size);
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
*out = scc_x86_op_preg(SCC_X86_REG_R9);
|
*out = scc_x86_op_preg(SCC_X86_REG_R9, size);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
*out = scc_x86_op_slot(-val->data.arg);
|
*out = scc_x86_op_slot(-val->data.arg, size);
|
||||||
break;
|
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) {
|
static void lower_ret(void *userdata, const scc_lir_instr_t *instr) {
|
||||||
scc_x86_64_isel_t *isel = userdata;
|
scc_x86_64_isel_t *isel = userdata;
|
||||||
scc_lir_val_t ret_val = instr->metadata.ret_val;
|
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) {
|
if (ret_val.kind != SCC_LIR_INSTR_KIND_NONE) {
|
||||||
scc_x86_emit_move(isel, scc_x86_op_preg(SCC_X86_REG_RAX),
|
scc_x86_emit_move(isel, scc_x86_op_preg(SCC_X86_REG_RAX, size),
|
||||||
scc_x86_lir_val_to_mir_op(isel, &ret_val), 8);
|
scc_x86_lir_val_to_mir_op(isel, &ret_val, size));
|
||||||
}
|
}
|
||||||
emit_ret(isel);
|
emit_ret(isel);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -83,6 +83,8 @@ void mir_x86_to_mcode(scc_mcode_t *mcode, scc_reloc_vec_t *relocs,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// scc_x86_iform_t iform =
|
||||||
|
// scc_x86_iclass_to_iform(ins->opcode, ops, ins->num_operands);
|
||||||
scc_x86_encode_inst(mcode, ins->opcode, ops);
|
scc_x86_encode_inst(mcode, ins->opcode, ops);
|
||||||
if (!skip_reloc && reloc.target_kind != SCC_RELOC_TARGET_NONE) {
|
if (!skip_reloc && reloc.target_kind != SCC_RELOC_TARGET_NONE) {
|
||||||
reloc.offset = scc_mcode_size(mcode);
|
reloc.offset = scc_mcode_size(mcode);
|
||||||
|
|||||||
@@ -45,33 +45,52 @@ typedef struct {
|
|||||||
scc_x86_mem_t mem;
|
scc_x86_mem_t mem;
|
||||||
scc_x86_reloc_op_t reloc;
|
scc_x86_reloc_op_t reloc;
|
||||||
};
|
};
|
||||||
usize size;
|
u8 size;
|
||||||
} scc_x86_operand_value_t;
|
} scc_x86_operand_value_t;
|
||||||
|
|
||||||
static inline scc_x86_operand_value_t scc_x86_op_preg(scc_x86_reg_t reg) {
|
static inline scc_x86_operand_value_t scc_x86_op_preg(scc_x86_reg_t reg,
|
||||||
scc_x86_operand_value_t o = {.kind = SCC_X86_OPR_REG, .reg = reg};
|
u8 size) {
|
||||||
|
scc_x86_operand_value_t o = {
|
||||||
|
.kind = SCC_X86_OPR_REG,
|
||||||
|
.reg = reg,
|
||||||
|
.size = size,
|
||||||
|
};
|
||||||
return o;
|
return o;
|
||||||
}
|
}
|
||||||
static inline scc_x86_reg_t scc_x86_op_vreg_reg(int vreg) {
|
static inline scc_x86_reg_t scc_x86_op_vreg_reg(int vreg) {
|
||||||
return (int)SCC_X86_REG_COUNT + vreg;
|
return (int)SCC_X86_REG_COUNT + vreg;
|
||||||
}
|
}
|
||||||
static inline scc_x86_operand_value_t scc_x86_op_vreg(int vreg) {
|
static inline scc_x86_operand_value_t scc_x86_op_vreg(int vreg, u8 size) {
|
||||||
scc_x86_operand_value_t o = {
|
scc_x86_operand_value_t o = {
|
||||||
.kind = SCC_X86_OPR_REG,
|
.kind = SCC_X86_OPR_REG,
|
||||||
.reg = scc_x86_op_vreg_reg(vreg),
|
.reg = scc_x86_op_vreg_reg(vreg),
|
||||||
|
.size = size,
|
||||||
};
|
};
|
||||||
return o;
|
return o;
|
||||||
}
|
}
|
||||||
static inline scc_x86_operand_value_t scc_x86_op_relbr(i32 rel) {
|
static inline scc_x86_operand_value_t scc_x86_op_relbr(i32 rel) {
|
||||||
scc_x86_operand_value_t o = {.kind = SCC_X86_OPR_RELBR, .brdisp = rel};
|
scc_x86_operand_value_t o = {
|
||||||
|
.kind = SCC_X86_OPR_RELBR,
|
||||||
|
.brdisp = rel,
|
||||||
|
.size = 4,
|
||||||
|
};
|
||||||
return o;
|
return o;
|
||||||
}
|
}
|
||||||
static inline scc_x86_operand_value_t scc_x86_op_imm(i64 imm) {
|
static inline scc_x86_operand_value_t scc_x86_op_imm(i64 imm, u8 size) {
|
||||||
scc_x86_operand_value_t o = {.kind = SCC_X86_OPR_IMM, .simm0 = imm};
|
scc_x86_operand_value_t o = {
|
||||||
|
.kind = SCC_X86_OPR_IMM,
|
||||||
|
.simm0 = imm,
|
||||||
|
.size = size,
|
||||||
|
};
|
||||||
return o;
|
return o;
|
||||||
}
|
}
|
||||||
static inline scc_x86_operand_value_t scc_x86_op_mem(scc_x86_mem_t mem) {
|
static inline scc_x86_operand_value_t scc_x86_op_mem(scc_x86_mem_t mem,
|
||||||
scc_x86_operand_value_t o = {.kind = SCC_X86_OPR_MEM, .mem = mem};
|
u8 size) {
|
||||||
|
scc_x86_operand_value_t o = {
|
||||||
|
.kind = SCC_X86_OPR_MEM,
|
||||||
|
.mem = mem,
|
||||||
|
.size = size,
|
||||||
|
};
|
||||||
return o;
|
return o;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -83,6 +102,7 @@ scc_x86_op_reloc_global_imm(const char *sym, i64 addend) {
|
|||||||
op.reloc.target = SCC_X86_RELOC_TARGET_SYMBOL;
|
op.reloc.target = SCC_X86_RELOC_TARGET_SYMBOL;
|
||||||
op.reloc.global_name = sym;
|
op.reloc.global_name = sym;
|
||||||
op.reloc.addend = addend;
|
op.reloc.addend = addend;
|
||||||
|
op.size = 0;
|
||||||
return op;
|
return op;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -93,6 +113,7 @@ scc_x86_op_reloc_global_relrip(const char *sym, i64 addend) {
|
|||||||
op.reloc.target = SCC_X86_RELOC_TARGET_SYMBOL;
|
op.reloc.target = SCC_X86_RELOC_TARGET_SYMBOL;
|
||||||
op.reloc.global_name = sym;
|
op.reloc.global_name = sym;
|
||||||
op.reloc.addend = addend;
|
op.reloc.addend = addend;
|
||||||
|
op.size = 4;
|
||||||
return op;
|
return op;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -104,6 +125,7 @@ scc_x86_op_reloc_global_relbr(const char *sym, i64 addend) {
|
|||||||
op.reloc.target = SCC_X86_RELOC_TARGET_SYMBOL;
|
op.reloc.target = SCC_X86_RELOC_TARGET_SYMBOL;
|
||||||
op.reloc.global_name = sym;
|
op.reloc.global_name = sym;
|
||||||
op.reloc.addend = addend;
|
op.reloc.addend = addend;
|
||||||
|
op.size = 4;
|
||||||
return op;
|
return op;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -115,6 +137,7 @@ static inline scc_x86_operand_value_t scc_x86_op_reloc_block(int bid,
|
|||||||
op.reloc.target = SCC_X86_RELOC_TARGET_BBLOCK;
|
op.reloc.target = SCC_X86_RELOC_TARGET_BBLOCK;
|
||||||
op.reloc.bblock_id = bid;
|
op.reloc.bblock_id = bid;
|
||||||
op.reloc.addend = addend;
|
op.reloc.addend = addend;
|
||||||
|
op.size = 4;
|
||||||
return op;
|
return op;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -128,11 +151,15 @@ scc_x86_op_reloc_global_mem(const char *sym, i64 addend) {
|
|||||||
op.reloc.global_name = sym;
|
op.reloc.global_name = sym;
|
||||||
op.reloc.addend = addend;
|
op.reloc.addend = addend;
|
||||||
// 编码时需生成 RIP 相对寻址的 ModRM/SIB
|
// 编码时需生成 RIP 相对寻址的 ModRM/SIB
|
||||||
|
op.size = 0;
|
||||||
return op;
|
return op;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 按 iform 发射一条指令,ops 数组长度需与 iform 定义的操作数数目一致 */
|
/* 按 iform 发射一条指令,ops 数组长度需与 iform 定义的操作数数目一致 */
|
||||||
int scc_x86_encode_inst(scc_mcode_t *mcode, scc_x86_iform_t iform,
|
int scc_x86_encode_inst(scc_mcode_t *mcode, scc_x86_iform_t iform,
|
||||||
const scc_x86_operand_value_t *ops);
|
const scc_x86_operand_value_t *ops);
|
||||||
|
scc_x86_iform_t scc_x86_iclass_to_iform(scc_x86_iclass_t iclass,
|
||||||
|
const scc_x86_operand_value_t *ops,
|
||||||
|
int num_ops);
|
||||||
|
|
||||||
#endif /* __SCC_X86_ENCODE_H__ */
|
#endif /* __SCC_X86_ENCODE_H__ */
|
||||||
|
|||||||
@@ -60,7 +60,14 @@ static int infer_operand_width(const scc_x86_iform_info_t *info,
|
|||||||
const scc_x86_operand_value_t ops[]) {
|
const scc_x86_operand_value_t ops[]) {
|
||||||
for (int i = 0; i < info->num_explicit_ops; i++) {
|
for (int i = 0; i < info->num_explicit_ops; i++) {
|
||||||
if (ops[i].kind == SCC_X86_OPR_REG && !info->ops[i].is_implicit) {
|
if (ops[i].kind == SCC_X86_OPR_REG && !info->ops[i].is_implicit) {
|
||||||
uint16_t w = scc_reg_width(ops[i].reg);
|
uint16_t w;
|
||||||
|
if (ops[i].size > 0 && ops[i].reg >= SCC_X86_REG_R8 &&
|
||||||
|
ops[i].reg <= SCC_X86_REG_R15) {
|
||||||
|
/* R8-R15:宽度由 size 字段推导 */
|
||||||
|
w = ops[i].size * 8;
|
||||||
|
} else {
|
||||||
|
w = scc_reg_width(ops[i].reg);
|
||||||
|
}
|
||||||
if (w > 0)
|
if (w > 0)
|
||||||
return w;
|
return w;
|
||||||
}
|
}
|
||||||
@@ -177,7 +184,8 @@ static void emit_escape_map(scc_mcode_t *m, const scc_x86_encoding_t *enc) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void emit_opcode(scc_mcode_t *m, const scc_x86_encoding_t *enc,
|
static void emit_opcode(scc_mcode_t *m, const scc_x86_encoding_t *enc,
|
||||||
scc_x86_reg_t rm_reg, scc_x86_reg_t base_reg) {
|
scc_x86_reg_t rm_reg, scc_x86_reg_t base_reg,
|
||||||
|
int op_width) {
|
||||||
for (int i = 0; i < enc->opcode_len; i++) {
|
for (int i = 0; i < enc->opcode_len; i++) {
|
||||||
uint8_t byte = enc->opcode[i];
|
uint8_t byte = enc->opcode[i];
|
||||||
if (enc->partial_opcode && i == enc->opcode_len - 1) {
|
if (enc->partial_opcode && i == enc->opcode_len - 1) {
|
||||||
@@ -186,6 +194,9 @@ static void emit_opcode(scc_mcode_t *m, const scc_x86_encoding_t *enc,
|
|||||||
if (target != SCC_X86_REG_INVALID)
|
if (target != SCC_X86_REG_INVALID)
|
||||||
byte |= (reg_low3(target) & 7);
|
byte |= (reg_low3(target) & 7);
|
||||||
}
|
}
|
||||||
|
/* MOV r8, imm8: B8-BF → B0-B7 */
|
||||||
|
if (op_width == 8 && (byte & 0xF8) == 0xB8)
|
||||||
|
byte -= 8;
|
||||||
emit_u8(m, byte);
|
emit_u8(m, byte);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -442,100 +453,6 @@ static void emit_modrm_sib_disp(scc_mcode_t *m,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static scc_x86_iform_t adapt_iform_to_8bit(scc_x86_iform_t iform,
|
|
||||||
const scc_x86_operand_value_t *ops,
|
|
||||||
int num_ops) {
|
|
||||||
// 只处理第一个操作数是 8
|
|
||||||
// 位寄存器的情况(大多数指令的目标或源是第一个寄存器)
|
|
||||||
if (num_ops > 0 && ops[0].kind == SCC_X86_OPR_REG &&
|
|
||||||
scc_reg_width(ops[0].reg) == 8) {
|
|
||||||
switch (iform) {
|
|
||||||
// ---- MOV 类 ----
|
|
||||||
case SCC_X86_IFORM_MOV_GPRV_IMMV:
|
|
||||||
case SCC_X86_IFORM_MOV_GPRV_IMMZ:
|
|
||||||
return SCC_X86_IFORM_MOV_GPR8_IMMB_B0;
|
|
||||||
case SCC_X86_IFORM_MOV_GPRV_GPRV_89: // mov r/m, r
|
|
||||||
return SCC_X86_IFORM_MOV_GPR8_GPR8_88;
|
|
||||||
case SCC_X86_IFORM_MOV_GPRV_GPRV_8B: // mov r, r/m
|
|
||||||
return SCC_X86_IFORM_MOV_GPR8_GPR8_8A;
|
|
||||||
case SCC_X86_IFORM_MOV_GPRV_MEMV: // mov r, mem
|
|
||||||
return SCC_X86_IFORM_MOV_GPR8_MEMB;
|
|
||||||
case SCC_X86_IFORM_MOV_MEMV_GPRV: // mov mem, r
|
|
||||||
return SCC_X86_IFORM_MOV_MEMB_GPR8;
|
|
||||||
// ---- ADD ----
|
|
||||||
case SCC_X86_IFORM_ADD_GPRV_IMMB:
|
|
||||||
case SCC_X86_IFORM_ADD_GPRV_IMMZ:
|
|
||||||
return SCC_X86_IFORM_ADD_GPR8_IMMB_80R0;
|
|
||||||
case SCC_X86_IFORM_ADD_GPRV_GPRV_01: // add r/m, r
|
|
||||||
return SCC_X86_IFORM_ADD_GPR8_GPR8_00;
|
|
||||||
case SCC_X86_IFORM_ADD_GPRV_GPRV_03: // add r, r/m
|
|
||||||
return SCC_X86_IFORM_ADD_GPR8_GPR8_02;
|
|
||||||
// ---- SUB ----
|
|
||||||
case SCC_X86_IFORM_SUB_GPRV_IMMB:
|
|
||||||
case SCC_X86_IFORM_SUB_GPRV_IMMZ:
|
|
||||||
return SCC_X86_IFORM_SUB_GPR8_IMMB_80R5;
|
|
||||||
case SCC_X86_IFORM_SUB_GPRV_GPRV_29:
|
|
||||||
return SCC_X86_IFORM_SUB_GPR8_GPR8_28;
|
|
||||||
case SCC_X86_IFORM_SUB_GPRV_GPRV_2B:
|
|
||||||
return SCC_X86_IFORM_SUB_GPR8_GPR8_2A;
|
|
||||||
// ---- CMP ----
|
|
||||||
case SCC_X86_IFORM_CMP_GPRV_IMMB:
|
|
||||||
case SCC_X86_IFORM_CMP_GPRV_IMMZ:
|
|
||||||
return SCC_X86_IFORM_CMP_GPR8_IMMB_80R7;
|
|
||||||
case SCC_X86_IFORM_CMP_GPRV_GPRV_39:
|
|
||||||
return SCC_X86_IFORM_CMP_GPR8_GPR8_38;
|
|
||||||
case SCC_X86_IFORM_CMP_GPRV_GPRV_3B:
|
|
||||||
return SCC_X86_IFORM_CMP_GPR8_GPR8_3A;
|
|
||||||
// ---- AND ----
|
|
||||||
case SCC_X86_IFORM_AND_GPRV_IMMB:
|
|
||||||
case SCC_X86_IFORM_AND_GPRV_IMMZ:
|
|
||||||
return SCC_X86_IFORM_AND_GPR8_IMMB_80R4;
|
|
||||||
case SCC_X86_IFORM_AND_GPRV_GPRV_21:
|
|
||||||
return SCC_X86_IFORM_AND_GPR8_GPR8_20;
|
|
||||||
// ---- OR ----
|
|
||||||
case SCC_X86_IFORM_OR_GPRV_IMMB:
|
|
||||||
case SCC_X86_IFORM_OR_GPRV_IMMZ:
|
|
||||||
return SCC_X86_IFORM_OR_GPR8_IMMB_80R1;
|
|
||||||
case SCC_X86_IFORM_OR_GPRV_GPRV_09:
|
|
||||||
return SCC_X86_IFORM_OR_GPR8_GPR8_08;
|
|
||||||
// ---- XOR ----
|
|
||||||
case SCC_X86_IFORM_XOR_GPRV_IMMB:
|
|
||||||
case SCC_X86_IFORM_XOR_GPRV_IMMZ:
|
|
||||||
return SCC_X86_IFORM_XOR_GPR8_IMMB_80R6;
|
|
||||||
case SCC_X86_IFORM_XOR_GPRV_GPRV_31:
|
|
||||||
return SCC_X86_IFORM_XOR_GPR8_GPR8_30;
|
|
||||||
// ---- TEST ----
|
|
||||||
case SCC_X86_IFORM_TEST_GPRV_GPRV:
|
|
||||||
return SCC_X86_IFORM_TEST_GPR8_GPR8;
|
|
||||||
case SCC_X86_IFORM_TEST_GPRV_IMMZ_F7R0:
|
|
||||||
return SCC_X86_IFORM_TEST_GPR8_IMMB_F6R0;
|
|
||||||
// ---- INC/DEC ----
|
|
||||||
case SCC_X86_IFORM_INC_GPRV_40:
|
|
||||||
case SCC_X86_IFORM_INC_GPRV_FFR0:
|
|
||||||
return SCC_X86_IFORM_INC_GPR8;
|
|
||||||
case SCC_X86_IFORM_DEC_GPRV_48:
|
|
||||||
case SCC_X86_IFORM_DEC_GPRV_FFR1:
|
|
||||||
return SCC_X86_IFORM_DEC_GPR8;
|
|
||||||
// ---- NEG/NOT ----
|
|
||||||
case SCC_X86_IFORM_NEG_GPRV:
|
|
||||||
return SCC_X86_IFORM_NEG_GPR8;
|
|
||||||
case SCC_X86_IFORM_NOT_GPRV:
|
|
||||||
return SCC_X86_IFORM_NOT_GPR8;
|
|
||||||
// ---- 移位操作 ----
|
|
||||||
case SCC_X86_IFORM_SHL_GPRV_ONE_D1R4:
|
|
||||||
return SCC_X86_IFORM_SHL_GPR8_ONE_D0R4;
|
|
||||||
case SCC_X86_IFORM_SHR_GPRV_ONE:
|
|
||||||
return SCC_X86_IFORM_SHR_GPR8_ONE;
|
|
||||||
case SCC_X86_IFORM_SAR_GPRV_ONE:
|
|
||||||
return SCC_X86_IFORM_SAR_GPR8_ONE;
|
|
||||||
// ---- 其他(根据需求继续添加)----
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return iform;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ---------- 主编码入口 ---------- */
|
/* ---------- 主编码入口 ---------- */
|
||||||
int scc_x86_encode_inst(scc_mcode_t *mcode, scc_x86_iform_t iform,
|
int scc_x86_encode_inst(scc_mcode_t *mcode, scc_x86_iform_t iform,
|
||||||
const scc_x86_operand_value_t *ops) {
|
const scc_x86_operand_value_t *ops) {
|
||||||
@@ -546,15 +463,9 @@ int scc_x86_encode_inst(scc_mcode_t *mcode, scc_x86_iform_t iform,
|
|||||||
|
|
||||||
const scc_x86_iform_info_t *info = &scc_x86_iform_table[iform];
|
const scc_x86_iform_info_t *info = &scc_x86_iform_table[iform];
|
||||||
int num_ops = info->num_explicit_ops;
|
int num_ops = info->num_explicit_ops;
|
||||||
// FIXME 自动适配 8 位操作数
|
|
||||||
iform = adapt_iform_to_8bit(iform, ops, num_ops);
|
|
||||||
// FIXME 重新获取 info 因为 iform 可能变了
|
|
||||||
info = &scc_x86_iform_table[iform];
|
|
||||||
|
|
||||||
const scc_x86_encoding_t *enc = &info->encode;
|
const scc_x86_encoding_t *enc = &info->encode;
|
||||||
const scc_x86_operand_t *tmpl = info->ops;
|
const scc_x86_operand_t *tmpl = info->ops;
|
||||||
LOG_INFO("[IFORM] %s, explicit_ops=%d (total=%d)", info->iform_name,
|
LOG_INFO("[ENCODE] %s", info->iform_name);
|
||||||
num_ops, info->num_ops);
|
|
||||||
|
|
||||||
scc_x86_reg_t reg_field = SCC_X86_REG_INVALID;
|
scc_x86_reg_t reg_field = SCC_X86_REG_INVALID;
|
||||||
scc_x86_reg_t rm_field = SCC_X86_REG_INVALID;
|
scc_x86_reg_t rm_field = SCC_X86_REG_INVALID;
|
||||||
@@ -616,10 +527,10 @@ int scc_x86_encode_inst(scc_mcode_t *mcode, scc_x86_iform_t iform,
|
|||||||
emit_escape_map(mcode, enc);
|
emit_escape_map(mcode, enc);
|
||||||
|
|
||||||
if (enc->has_modrm) {
|
if (enc->has_modrm) {
|
||||||
emit_opcode(mcode, enc, rm_field, base_reg);
|
emit_opcode(mcode, enc, rm_field, base_reg, op_width);
|
||||||
emit_modrm_sib_disp(mcode, info, ops, op_width);
|
emit_modrm_sib_disp(mcode, info, ops, op_width);
|
||||||
} else {
|
} else {
|
||||||
emit_opcode(mcode, enc, rm_field, base_reg);
|
emit_opcode(mcode, enc, rm_field, base_reg, op_width);
|
||||||
if (imm_idx >= 0) {
|
if (imm_idx >= 0) {
|
||||||
emit_immediate(mcode, enc, tmpl, imm_idx, imm_val, op_width);
|
emit_immediate(mcode, enc, tmpl, imm_idx, imm_val, op_width);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,9 @@ description = ""
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "sccf", path = "../../sccf" },
|
{ name = "sccf", path = "../../sccf" },
|
||||||
{ name = "pe", path = "../pe" },
|
{ name = "pe", path = "../pe" },
|
||||||
|
{ name = "elf", path = "../elf" },
|
||||||
|
# for mcode with x86_64
|
||||||
|
{ name = "mcode", path = "../../mcode" },
|
||||||
]
|
]
|
||||||
# features = {}
|
# features = {}
|
||||||
# default_features = []
|
# default_features = []
|
||||||
|
|||||||
Reference in New Issue
Block a user