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:
@@ -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 中注册
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user