feat(mir): 添加x86架构相关头文件并重构MIR指令表示

- 创建scc_x86_mir.h头文件,定义x86后端MIR指令结构和操作数构造器
- 创建scc_x86_isel.h头文件,定义x86_64指令选择器和相关工具函数
- 创建scc_x86_reg_alloc.h头文件,定义x86寄存器分配架构特定接口
- 移除旧的x86_64_isel.h和x86_64_reg_alloc.h文件
- 重构scc_mir.h中的指令表示,使用联合体存储伪指令数据
- 更新ABI lowering回调参数,使用void指针保持类型无关
- 扩展寄存器分配操作接口,添加指令信息查询和伪指令处理功能
- 更新目标文件包含路径以使用新的头文件命名
This commit is contained in:
zzy
2026-05-20 11:07:05 +08:00
parent 2c13ac54df
commit c6e3bb2e20
22 changed files with 792 additions and 788 deletions

View File

@@ -1,54 +1,42 @@
#include <scc_mir_module.h>
#include <x86/scc_x86_iform.h>
#include <arch/x86_64_isel.h>
#include <arch/scc_x86_isel.h>
#include <core_pass/scc_prolog_epilog.h>
#include <target/scc_win64.h>
static const int WIN64_DEFAULT_ALIGN = 8;
static const int WIN64_STACK_ALIGN = 16;
static void transit_vreg(scc_mir_func_meta_t *func, scc_mir_operand_t *op) {
Assert(op->kind == SCC_MIR_OP_VREG);
}
static void frame_alloc_impl(scc_frame_layout_t *ctx,
scc_mir_module_t *mir_module,
scc_mir_func_t *mir_func) {
/*
WIN ABI
*/
ctx->offset = 8;
scc_mir_func_meta_t *func_meta = SCC_MIR_FUNC_META(mir_func);
scc_vec_foreach(mir_func->bblocks, i) {
scc_cfg_bblock_id_t id = scc_vec_at(mir_func->bblocks, i);
scc_cfg_bblock_t *bb =
scc_cfg_module_unsafe_get_bblock(&mir_module->cfg_module, id);
scc_mir_instr_vec_t *instrs = SCC_MIR_BBLOCK_VALUES(bb);
scc_mir_x86_instr_vec_t *instrs = SCC_MIR_X86_BBLOCK_INSTRS(bb);
scc_vec_foreach(*instrs, j) {
scc_mir_instr_t *ins = &scc_vec_at(*instrs, j);
for (int k = 0; k < ins->num_operands; k += 1) {
scc_mir_operand_t *op = &ins->operands[k];
if (op->kind == SCC_MIR_OP_VREG) {
Panic("vreg not supported in frame layout");
} else if (op->kind == SCC_MIR_OP_STACK_SLOT) {
scc_mir_x86_instr_t *ins = &scc_vec_at(*instrs, j);
for (int k = 0; k < ins->x86_instr.num_operands; k++) {
scc_x86_operand_value_t *op = &ins->x86_instr.operands[k];
if (scc_x86_op_is_slot(op)) {
int slot_id = scc_x86_op_slot_id(op);
scc_mir_stack_slot_t *slot =
scc_mir_unsafe_slot(mir_func, op->stack_slot);
op->kind = SCC_MIR_OP_STACK_OFFSET;
scc_mir_unsafe_slot(mir_func, slot_id);
if (slot->offset == 0) {
// FIXME align
ctx->offset += slot->size;
slot->offset = ctx->offset;
}
op->stack_offset = slot->offset;
op->mem.base = SCC_X86_REG_RSP;
op->mem.disp = -slot->offset;
}
}
}
}
// Windows shadow space
int total_size = ctx->offset + 32; // 加上影子空间
// 16 字节栈对齐
int total_size = ctx->offset + 32; // shadow space
ctx->offset =
(total_size + WIN64_STACK_ALIGN - 1) & ~(WIN64_STACK_ALIGN - 1);
func_meta->frame_size = ctx->offset;
@@ -77,17 +65,19 @@ static void prologue(void *userdata, const scc_mir_func_t *func) {
int frame_size = meta->frame_size; // 之前计算好的
// 1. push rbp
add_instr_1(isel, SCC_X86_IFORM_PUSH_GPRV_50, reg_operand(SCC_X86_REG_RBP));
add_instr_1(isel, SCC_X86_IFORM_PUSH_GPRV_50,
scc_x86_op_preg(SCC_X86_REG_RBP));
// 2. mov rbp, rsp
add_instr_2(isel, SCC_X86_IFORM_MOV_GPRV_GPRV_89,
reg_operand(SCC_X86_REG_RBP), reg_operand(SCC_X86_REG_RSP));
add_instr_2(isel, SCC_X86_IFORM_MOV_GPRV_GPRV_8B,
scc_x86_op_preg(SCC_X86_REG_RBP),
scc_x86_op_preg(SCC_X86_REG_RSP));
// 3. sub rsp, frame_size
if (frame_size > 0) {
scc_mir_operand_t imm = {.kind = SCC_MIR_OP_IMM, .imm = frame_size};
scc_x86_operand_value_t imm = scc_x86_op_imm(frame_size);
add_instr_2(isel, SCC_X86_IFORM_SUB_GPRV_IMMZ,
reg_operand(SCC_X86_REG_RSP), imm);
scc_x86_op_preg(SCC_X86_REG_RSP), imm);
}
}
@@ -101,11 +91,13 @@ static void epilogue(void *userdata, const scc_mir_func_t *func) {
ret
*/
// 1. mov rsp, rbp
add_instr_2(isel, SCC_X86_IFORM_MOV_GPRV_GPRV_89,
reg_operand(SCC_X86_REG_RSP), reg_operand(SCC_X86_REG_RBP));
add_instr_2(isel, SCC_X86_IFORM_MOV_GPRV_GPRV_8B,
scc_x86_op_preg(SCC_X86_REG_RSP),
scc_x86_op_preg(SCC_X86_REG_RBP));
// 2. pop rbp
add_instr_1(isel, SCC_X86_IFORM_POP_GPRV_58, reg_operand(SCC_X86_REG_RBP));
add_instr_1(isel, SCC_X86_IFORM_POP_GPRV_8F,
scc_x86_op_preg(SCC_X86_REG_RBP));
}
void scc_win_pc_x64_prolog_epilog_init(scc_prolog_epilog_t *ctx) {
@@ -115,81 +107,65 @@ 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;
/*
Windows x64 parameter passing
https://learn.microsoft.com/zh-cn/cpp/build/x64-calling-convention?view=msvc-180#parameter-passing
eg.
func1(int a, int b, int c, int d, int e, int f);
// a in RCX, b in RDX, c in R8, d in R9, f then e passed on stack
func2(float a, double b, float c, double d, float e, float f);
// a in XMM0, b in XMM1, c in XMM2, d in XMM3, f then e passed on stack
func3(int a, double b, int c, float d, int e, float f);
// a in RCX, b in XMM1, c in R8, d in XMM3, f then e passed on stack
func4(__m64 a, __m128 b, struct c, float d, __m128 e, __m128 f);
// a in RCX, ptr to b in RDX, ptr to c in R8, d in XMM3,
// ptr to f passed on stack, then ptr to e passed on stack
*/
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, reg_operand(SCC_X86_REG_RCX),
scc_x86_emit_move(isel, scc_x86_op_preg(SCC_X86_REG_RCX),
scc_x86_lir_val_to_mir_op(isel, args), 8);
break;
case 1:
scc_x86_emit_move(isel, reg_operand(SCC_X86_REG_RDX),
scc_x86_emit_move(isel, scc_x86_op_preg(SCC_X86_REG_RDX),
scc_x86_lir_val_to_mir_op(isel, args), 8);
break;
case 2:
scc_x86_emit_move(isel, reg_operand(SCC_X86_REG_R8),
scc_x86_emit_move(isel, scc_x86_op_preg(SCC_X86_REG_R8),
scc_x86_lir_val_to_mir_op(isel, args), 8);
break;
case 3:
scc_x86_emit_move(isel, reg_operand(SCC_X86_REG_R9),
scc_x86_emit_move(isel, scc_x86_op_preg(SCC_X86_REG_R9),
scc_x86_lir_val_to_mir_op(isel, args), 8);
break;
default:
// Using stack
scc_mir_operand_t op = scc_x86_lir_val_to_mir_op(isel, args);
scc_x86_operand_value_t op = scc_x86_lir_val_to_mir_op(isel, args);
add_instr_1(isel,
op.kind == SCC_MIR_OP_PREG || op.kind == SCC_MIR_OP_VREG
? SCC_X86_IFORM_PUSH_GPRV_50
: SCC_X86_IFORM_PUSH_IMMZ,
op.kind == SCC_X86_OPR_REG ? SCC_X86_IFORM_PUSH_GPRV_50
: SCC_X86_IFORM_PUSH_IMMZ,
op);
break;
}
}
emit_call(isel, instr->metadata.call.callee);
emit_direct_call(isel, instr->metadata.call.callee);
scc_mir_operand_t ret_reg = scc_x86_lir_val_to_mir_op(isel, &instr->to);
if (ret_reg.kind == SCC_MIR_OP_VREG) {
scc_x86_emit_move(isel, ret_reg, reg_operand(SCC_X86_REG_RAX), 8);
} else {
TODO();
scc_x86_operand_value_t ret_reg =
scc_x86_lir_val_to_mir_op(isel, &instr->to);
if (ret_reg.kind != SCC_X86_OPR_NONE) {
scc_x86_emit_move(isel, ret_reg, scc_x86_op_preg(SCC_X86_REG_RAX), 8);
}
}
static scc_mir_operand_t lower_param(void *userdata, const scc_lir_val_t *val) {
scc_x86_64_isel_t *isel = userdata;
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);
switch (val->data.arg) {
case 0:
return reg_operand(SCC_X86_REG_RCX);
*out = scc_x86_op_preg(SCC_X86_REG_RCX);
break;
case 1:
return reg_operand(SCC_X86_REG_RDX);
*out = scc_x86_op_preg(SCC_X86_REG_RDX);
break;
case 2:
return reg_operand(SCC_X86_REG_R8);
*out = scc_x86_op_preg(SCC_X86_REG_R8);
break;
case 3:
return reg_operand(SCC_X86_REG_R9);
*out = scc_x86_op_preg(SCC_X86_REG_R9);
break;
default:
return (scc_mir_operand_t){.kind = SCC_MIR_OP_STACK_SLOT,
.stack_slot = -val->data.arg};
*out = scc_x86_op_slot(-val->data.arg);
break;
}
}
@@ -197,7 +173,7 @@ 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;
if (ret_val.kind != SCC_LIR_INSTR_KIND_NONE) {
scc_x86_emit_move(isel, reg_operand(SCC_X86_REG_RAX),
scc_x86_emit_move(isel, scc_x86_op_preg(SCC_X86_REG_RAX),
scc_x86_lir_val_to_mir_op(isel, &ret_val), 8);
}
emit_ret(isel);
@@ -214,40 +190,7 @@ void scc_win_pc_x64_abi_lowering(scc_abi_lowering_t *abi_lowering) {
abi_lowering->lower_va_end = nullptr;
}
static const int reg_pool[] = {
SCC_X86_REG_R8, SCC_X86_REG_R9, SCC_X86_REG_R10, SCC_X86_REG_R11,
SCC_X86_REG_R12, SCC_X86_REG_R13, SCC_X86_REG_R14, SCC_X86_REG_R15};
static uint32_t reg_mask = 0; // 1 表示已占用
static int acquire_reg(void *ctx) {
for (int i = 0; i < SCC_ARRLEN(reg_pool); i++)
if (!(reg_mask & (1u << i))) {
reg_mask |= (1u << i);
return reg_pool[i];
}
UNREACHABLE(); // 可改为溢出逻辑
}
static void release_reg(void *ctx, int preg) {
for (int i = 0; i < SCC_ARRLEN(reg_pool); i++)
if (reg_pool[i] == preg) {
reg_mask &= ~(1u << i);
return;
}
}
static void mark_reg_used(void *ctx, int preg) {
for (int i = 0; i < SCC_ARRLEN(reg_pool); i++)
if (reg_pool[i] == preg) {
reg_mask |= (1u << i);
return;
}
}
static void clean_mark_regs(void *ctx) { reg_mask = 0; }
void scc_win_pc_x64_reg_alloc_fill(scc_reg_alloc_op_t *ops) {
ops->acquire_reg = acquire_reg;
ops->release_reg = release_reg;
ops->mark_reg_used = mark_reg_used;
ops->clean_mark_regs = clean_mark_regs;
(void)ops;
// 寄存器池已在 scc_reg_alloc_fill_arch_x86 中注册
}