feat(mir): 实现x86-64架构寄存器分配和指令选择优化

- 修改x86_64_isel.h接口,将func_meta替换为func指针,并添加新的isel函数原型
- 添加x86_64_reg_alloc.h头文件,提供架构特定的寄存器分配操作填充函数
- 更新frame_layout.h定义frame_layout上下文结构
- 重构reg_alloc.h中的寄存器分配操作结构体,将ops从指针改为值类型,
  并将mark_reg_unused重命名为clean_mark_regs
- 扩展scc_mir.h中的函数元数据,添加vregs_count字段和虚拟寄存器管理函数
- 重新定义MIR pass阶段枚举,添加FRAME_LAYOUT和PROLOGUE_EPILOGUE阶段
- 添加win64目标相关头文件和实现,提供Windows x64 ABI降低和寄存器分配填充
- 更新虚拟寄存器表示格式从$到%,修复alloca指令处理
- 重构寄存器分配算法,改进虚拟寄存器到物理寄存器/栈槽的映射机制
- 完善MIR pass调度,支持多阶段处理流程
This commit is contained in:
zzy
2026-05-12 10:55:58 +08:00
parent 4f40f0d5e4
commit 68eac24152
17 changed files with 386 additions and 115 deletions

View File

@@ -12,11 +12,14 @@
typedef struct scc_x86_64_isel { typedef struct scc_x86_64_isel {
scc_mir_instr_vec_t instrs; scc_mir_instr_vec_t instrs;
scc_lir_func_meta_t *func_meta; scc_mir_func_t *func;
scc_abi_lowering_t abi_lowering; scc_abi_lowering_t abi_lowering;
} scc_x86_64_isel_t; } scc_x86_64_isel_t;
void scc_isel_x86_64(scc_mir_module_t *mir_module,
const scc_lir_module_t *lir_module,
scc_x86_64_isel_t *isel);
static void add_instr(scc_x86_64_isel_t *isel, const scc_mir_instr_t *instr) { static void add_instr(scc_x86_64_isel_t *isel, const scc_mir_instr_t *instr) {
scc_vec_push(isel->instrs, *instr); scc_vec_push(isel->instrs, *instr);
} }

View File

@@ -0,0 +1,8 @@
#ifndef __SCC_X86_64_REG_ALLOC_H__
#define __SCC_X86_64_REG_ALLOC_H__
#include "../core_pass/scc_reg_alloc.h"
void scc_reg_alloc_fill_arch_x86(scc_reg_alloc_op_t *ops);
#endif /* __SCC_X86_64_REG_ALLOC_H__ */

View File

@@ -1,4 +1,12 @@
#ifndef __SCC_FRAME_LAYOUT_H__ #ifndef __SCC_FRAME_LAYOUT_H__
#define __SCC_FRAME_LAYOUT_H__ #define __SCC_FRAME_LAYOUT_H__
#include "../scc_mir_module.h"
typedef struct scc_frame_layout {
scc_mir_func_t *func;
} scc_frame_layout_t;
void scc_frame_layout(scc_frame_layout_t *ctx, scc_mir_module_t *module);
#endif /* __SCC_FRAME_LAYOUT_H__ */ #endif /* __SCC_FRAME_LAYOUT_H__ */

View File

@@ -10,8 +10,6 @@ typedef enum {
} scc_op_access_t; } scc_op_access_t;
typedef struct scc_reg_alloc_op { typedef struct scc_reg_alloc_op {
// ---- 指令生成(纯动作,无状态) ----
// preg → [slot] // preg → [slot]
void (*emit_spill)(scc_mir_instr_vec_t *ctx, int preg, int slot); void (*emit_spill)(scc_mir_instr_vec_t *ctx, int preg, int slot);
// [slot] → preg // [slot] → preg
@@ -26,7 +24,7 @@ typedef struct scc_reg_alloc_op {
// 显式标记某个寄存器已占用 / 未占用(用于隐式寄存器、固定分配等) // 显式标记某个寄存器已占用 / 未占用(用于隐式寄存器、固定分配等)
void (*mark_reg_used)(void *ctx, int preg); void (*mark_reg_used)(void *ctx, int preg);
void (*mark_reg_unused)(void *ctx, int preg); void (*clean_mark_regs)(void *ctx);
// ---- 指令信息查询(只读) ---- // ---- 指令信息查询(只读) ----
scc_op_access_t (*get_operand_access)(void *ctx, int opcode, int op_idx); scc_op_access_t (*get_operand_access)(void *ctx, int opcode, int op_idx);
@@ -35,8 +33,8 @@ typedef struct scc_reg_alloc_op {
} scc_reg_alloc_op_t; } scc_reg_alloc_op_t;
typedef struct scc_reg_alloc_ctx { typedef struct scc_reg_alloc_ctx {
const scc_reg_alloc_op_t *ops; scc_reg_alloc_op_t ops;
scc_mir_func_meta_t *func_meta; scc_mir_func_t *func;
scc_mir_instr_vec_t *instrs; scc_mir_instr_vec_t *instrs;
} scc_reg_alloc_ctx_t; } scc_reg_alloc_ctx_t;

View File

@@ -59,14 +59,24 @@ typedef struct scc_mir_func_meta {
// 栈帧信息 (由 FrameLayout Pass 填充) // 栈帧信息 (由 FrameLayout Pass 填充)
int frame_size; int frame_size;
int stack_alignment; int stack_alignment;
int vregs_count;
// 寄存器分配信息 // 寄存器分配信息
scc_mir_stack_slot_vec_t stack_slots; scc_mir_stack_slot_vec_t stack_slots;
scc_hashtable_t vreg2preg; // vreg -> phys reg-1 表示溢出 // vreg -> phys reg and stack slot index
scc_hashtable_t vreg2slot; // vreg -> stack slot index // positive means stack slot index
// negative means physic register
scc_hashtable_t vreg2physic;
} scc_mir_func_meta_t; } scc_mir_func_meta_t;
#define SCC_MIR_FUNC_META(func) ((scc_mir_func_meta_t *)(func)->meta) #define SCC_MIR_FUNC_META(func) ((scc_mir_func_meta_t *)(func)->meta)
void scc_mir_func_meta_init(scc_mir_func_meta_t *func_meta); void scc_mir_func_meta_init(scc_mir_func_meta_t *func_meta);
int scc_mir_alloc_vreg(scc_mir_func_t *func);
void scc_mir_vreg_op(const scc_mir_func_t *func, int vreg,
scc_mir_operand_t *out);
void scc_mir_vreg_map2preg(scc_mir_func_t *func, int vreg, int preg);
int scc_mir_vreg_map2slot(scc_mir_func_t *func, int vreg, int size, int align);
#endif /* __SCC_MIR_H__ */ #endif /* __SCC_MIR_H__ */

View File

@@ -20,9 +20,9 @@ typedef enum {
/** Pass 运行阶段 (用于自动排序) */ /** Pass 运行阶段 (用于自动排序) */
typedef enum { typedef enum {
SCC_MIR_STAGE_ANY, // 无特殊阶段要求 SCC_MIR_STAGE_ANY, // 无特殊阶段要求
SCC_MIR_STAGE_PRE_REGALLOC, // 寄存器分配前
SCC_MIR_STAGE_REGALLOC, // 寄存器分配本身 SCC_MIR_STAGE_REGALLOC, // 寄存器分配本身
SCC_MIR_STAGE_POST_REGALLOC // 寄存器分配后 SCC_MIR_STAGE_FRAME_LAYOUT, // 帧布局
SCC_MIR_STAGE_PROLOGUE_EPILOGUE, // 函数头尾处理
} scc_mir_pass_stage_t; } scc_mir_pass_stage_t;
void scc_mir_pass(scc_mir_module_t *mir_module, scc_mir_pass_stage_t stage); void scc_mir_pass(scc_mir_module_t *mir_module, scc_mir_pass_stage_t stage);

View File

@@ -0,0 +1,9 @@
#ifndef __SCC_WIN64_H__
#define __SCC_WIN64_H__
#include "../arch/x86_64_isel.h"
#include "../core_pass/scc_reg_alloc.h"
void scc_win_pc_x64_abi_lowering(scc_abi_lowering_t *abi_lowering);
void scc_reg_alloc_fill_win_x64(scc_reg_alloc_op_t *ops);
#endif

View File

@@ -22,7 +22,7 @@ void scc_x86_instr_dump(scc_tree_dump_t *td, const scc_mir_instr_t *instr) {
scc_mir_operand_t *op = &instr->operands[i]; scc_mir_operand_t *op = &instr->operands[i];
switch (op->kind) { switch (op->kind) {
case SCC_MIR_OP_VREG: case SCC_MIR_OP_VREG:
scc_tree_dump_append_fmt(td, "$%d", op->vreg); scc_tree_dump_append_fmt(td, "%%%d", op->vreg);
break; break;
case SCC_MIR_OP_PREG: case SCC_MIR_OP_PREG:
scc_tree_dump_append_fmt(td, "$%s", preg_name(op->preg)); scc_tree_dump_append_fmt(td, "$%s", preg_name(op->preg));
@@ -84,7 +84,7 @@ scc_mir_operand_t scc_x86_lir_val_to_mir_op(scc_x86_64_isel_t *isel,
// 虚拟临时寄存器分配(简单递增) // 虚拟临时寄存器分配(简单递增)
static scc_mir_operand_t new_vreg_temp(scc_x86_64_isel_t *isel) { static scc_mir_operand_t new_vreg_temp(scc_x86_64_isel_t *isel) {
return (scc_mir_operand_t){.kind = SCC_MIR_OP_VREG, return (scc_mir_operand_t){.kind = SCC_MIR_OP_VREG,
.vreg = isel->func_meta->vregs_count++}; .vreg = scc_mir_alloc_vreg(isel->func)};
} }
void scc_x86_emit_move(scc_x86_64_isel_t *isel, scc_mir_operand_t dst, void scc_x86_emit_move(scc_x86_64_isel_t *isel, scc_mir_operand_t dst,
@@ -222,13 +222,13 @@ static void emit_spill_store(scc_x86_64_isel_t *isel, int vreg, int offset) {
add_instr_2(isel, SCC_X86_IFORM_MOV_MEMV_GPRV, stack_slot_op(offset), src); add_instr_2(isel, SCC_X86_IFORM_MOV_MEMV_GPRV, stack_slot_op(offset), src);
} }
static void emit_alloca(scc_x86_64_isel_t *isel, scc_mir_operand_t dst, // static void emit_alloca(scc_x86_64_isel_t *isel, scc_mir_operand_t dst,
i64 size) { // i64 size) {
scc_mir_operand_t imm = {.kind = SCC_MIR_OP_IMM, .imm = size}; // scc_mir_operand_t imm = {.kind = SCC_MIR_OP_IMM, .imm = size};
scc_mir_operand_t rsp = {.kind = SCC_MIR_OP_PREG, .preg = SCC_X86_REG_RSP}; // scc_mir_operand_t rsp = {.kind = SCC_MIR_OP_PREG, .preg =
add_instr_2(isel, SCC_X86_IFORM_SUB_GPRV_IMMZ, rsp, imm); // SCC_X86_REG_RSP}; add_instr_2(isel, SCC_X86_IFORM_SUB_GPRV_IMMZ, rsp,
scc_x86_emit_move(isel, dst, rsp, 8); // imm); scc_x86_emit_move(isel, dst, rsp, 8);
} // }
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_mir_operand_t dst = scc_x86_lir_val_to_mir_op(isel, &instr->to); scc_mir_operand_t dst = scc_x86_lir_val_to_mir_op(isel, &instr->to);
@@ -414,12 +414,13 @@ static void sel_mir(scc_x86_64_isel_t *isel, const scc_lir_instr_t *instr) {
/* ---- 栈分配 ---- */ /* ---- 栈分配 ---- */
case SCC_LIR_ALLOCA: case SCC_LIR_ALLOCA:
// emit_alloca(isel, dst, instr->metadata.alloca.size_bytes); // emit_alloca(isel, dst, instr->metadata.alloca.size_bytes);
add_instr_2(isel, (scc_x86_iform_t)SCC_MIR_PSUEDO_ALLOCA, scc_mir_operand_t op = scc_x86_lir_val_to_mir_op(isel, &instr->to);
scc_x86_lir_val_to_mir_op(isel, &instr->to), add_instr_2(isel, (scc_x86_iform_t)SCC_MIR_PSUEDO_ALLOCA, op,
(scc_mir_operand_t){ (scc_mir_operand_t){
.kind = SCC_MIR_OP_IMM, .kind = SCC_MIR_OP_IMM,
.imm = instr->size, .imm = instr->size,
}); });
Assert(op.kind == SCC_MIR_OP_VREG);
break; break;
/* ---- 其他(占位) ---- */ /* ---- 其他(占位) ---- */
@@ -442,17 +443,9 @@ static void sel_mir(scc_x86_64_isel_t *isel, const scc_lir_instr_t *instr) {
} }
static void sel_func(const scc_lir_module_t *lir_module, static void sel_func(const scc_lir_module_t *lir_module,
const scc_lir_func_t *func) { const scc_lir_func_t *func, scc_x86_64_isel_t *isel) {
scc_x86_64_isel_t isel;
void scc_win_pc_x64_abi_lowering(scc_abi_lowering_t * abi_lowering);
// TODO target got real abi_lowering
isel.abi_lowering = (scc_abi_lowering_t){0};
scc_win_pc_x64_abi_lowering(&isel.abi_lowering);
isel.func_meta = SCC_LIR_FUNC_META(func);
scc_vec_foreach(func->bblocks, i) { scc_vec_foreach(func->bblocks, i) {
scc_vec_init(isel.instrs); scc_vec_init(isel->instrs);
scc_cfg_bblock_id_t id = scc_vec_at(func->bblocks, i); scc_cfg_bblock_id_t id = scc_vec_at(func->bblocks, i);
scc_cfg_bblock_t *bb = scc_cfg_bblock_t *bb =
@@ -460,16 +453,18 @@ 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);
sel_mir(&isel, ins); sel_mir(isel, ins);
} }
bb->values = *(scc_cfg_value_vec_t *)&isel.instrs; bb->values = *(scc_cfg_value_vec_t *)&isel->instrs;
scc_vec_init(isel.instrs); scc_vec_init(isel->instrs);
} }
} }
void scc_isel_x86_64(scc_mir_module_t *mir_module, void scc_isel_x86_64(scc_mir_module_t *mir_module,
const scc_lir_module_t *lir_module) { const scc_lir_module_t *lir_module,
scc_x86_64_isel_t *isel) {
scc_vec_foreach(lir_module->cfg_module.funcs, i) { scc_vec_foreach(lir_module->cfg_module.funcs, i) {
if (i == 0) if (i == 0)
continue; continue;
@@ -479,8 +474,12 @@ void scc_isel_x86_64(scc_mir_module_t *mir_module,
scc_malloc(sizeof(scc_mir_func_meta_t)); scc_malloc(sizeof(scc_mir_func_meta_t));
Assert(func_meta != nullptr); Assert(func_meta != nullptr);
scc_mir_func_meta_init(func_meta); scc_mir_func_meta_init(func_meta);
scc_vec_push(mir_module->func_metas, func_meta); // FIXME
sel_func(lir_module, func); func_meta->vregs_count = SCC_LIR_FUNC_META(func)->vregs_count;
func->meta = func_meta; func->meta = func_meta;
isel->func = func;
scc_vec_push(mir_module->func_metas, func_meta);
sel_func(lir_module, func, isel);
} }
} }

View File

@@ -1,5 +1,5 @@
#include <arch/x86_64_isel.h> #include <arch/x86_64_isel.h>
#include <core_pass/scc_reg_alloc.h> #include <arch/x86_64_reg_alloc.h>
static void x86_emit_spill(scc_mir_instr_vec_t *ctx, int preg, int slot) { static void x86_emit_spill(scc_mir_instr_vec_t *ctx, int preg, int slot) {
scc_mir_instr_t ins = { scc_mir_instr_t ins = {
@@ -74,13 +74,10 @@ static void x86_get_implicit_regs(void *vctx, int opcode, const int **uses,
} }
} }
/* 组装 hooks 表 */ void scc_reg_alloc_fill_arch_x86(scc_reg_alloc_op_t *ops) {
scc_reg_alloc_op_t x86_reg_alloc_hooks = { ops->emit_spill = x86_emit_spill;
.emit_spill = x86_emit_spill, ops->emit_reload = x86_emit_reload;
.emit_reload = x86_emit_reload, ops->emit_copy = x86_emit_copy;
.emit_copy = x86_emit_copy, ops->get_operand_access = x86_get_operand_access;
.acquire_reg = x86_acquire_temp_reg, ops->get_implicit_regs = x86_get_implicit_regs;
.release_reg = x86_release_temp_reg, }
.get_operand_access = x86_get_operand_access,
.get_implicit_regs = x86_get_implicit_regs,
};

View File

@@ -0,0 +1,3 @@
#include <core_pass/scc_frame_layout.h>
void scc_frame_layout(scc_frame_layout_t *ctx, scc_mir_module_t *module) {}

View File

@@ -2,66 +2,181 @@
#include <scc_hashtable.h> #include <scc_hashtable.h>
#include <scc_mir_module.h> #include <scc_mir_module.h>
static int ensure_slot(scc_reg_alloc_ctx_t *ctx, int vreg) { // static void alloc_instr(scc_reg_alloc_ctx_t *ctx,
void *key = (void *)(usize)vreg; // scc_mir_instr_vec_t *instr_vec,
void *val = scc_hashtable_get(&ctx->func_meta->vreg2slot, key); // scc_mir_instr_t *instr) {
if (val != NULL) // const scc_reg_alloc_op_t *ops = &ctx->ops;
return (int)(usize)val; // scc_mir_instr_vec_t before, after;
int new_slot = scc_vec_size(ctx->func_meta->stack_slots) + 1; // 1-based // scc_vec_init(before);
scc_mir_stack_slot_t s = { // scc_vec_init(after);
.slot_id = new_slot, .size = 8, .alignment = 8, .offset = 0};
scc_vec_push(ctx->func_meta->stack_slots, s); // // 1. 标记隐式寄存器为占用
scc_hashtable_set(&ctx->func_meta->vreg2slot, key, (void *)(usize)new_slot); // const int *implicit_uses, *implicit_defs;
return new_slot; // ops->get_implicit_regs(ctx, instr->opcode, &implicit_uses,
} // &implicit_defs); for (const int *p = implicit_uses; *p != -1; p++)
// ops->mark_reg_used(ctx, *p);
// for (const int *p = implicit_defs; *p != -1; p++)
// ops->mark_reg_used(ctx, *p);
// SCC_VEC(int) preg_vec;
// scc_vec_init(preg_vec);
// for (int i = 0; i < instr->num_operands; i++) {
// if (instr->operands[i].kind != SCC_MIR_OP_VREG)
// continue;
// int vreg = instr->operands[i].vreg;
// scc_mir_vreg_op(ctx->func, vreg, &instr->operands[i]);
// if (instr->operands[i].kind != SCC_MIR_OP_VREG)
// continue;
// // FIXME size alian
// int slot = scc_mir_vreg_map2slot(ctx->func, vreg, 8, 8);
// int preg = -1;
// // if (implicit_uses && implicit_uses[0] != -1)
// // preg = implicit_uses[0];
// // else
// preg = ops->acquire_reg(ctx);
// scc_vec_push(preg_vec, preg);
// // 根据操作数读写属性决定是否需要 reload
// scc_op_access_t acc = ops->get_operand_access(ctx, instr->opcode, i);
// if (acc == SCC_REG_ALLOC_OP_ACCESS_READ ||
// acc == SCC_REG_ALLOC_OP_ACCESS_READWRITE) {
// ops->emit_reload(&before, preg, slot);
// }
// if (acc == SCC_REG_ALLOC_OP_ACCESS_WRITE ||
// acc == SCC_REG_ALLOC_OP_ACCESS_READWRITE) {
// ops->emit_spill(&after, preg, slot);
// }
// // 替换操作数为物理寄存器
// instr->operands[i].kind = SCC_MIR_OP_PREG;
// instr->operands[i].preg = preg;
// }
// scc_vec_foreach(preg_vec, i) {
// int preg = scc_vec_at(preg_vec, i);
// ops->release_reg(ctx, preg);
// }
// scc_vec_foreach(before, i) scc_vec_push(*instr_vec, scc_vec_at(before,
// i)); scc_vec_push(*instr_vec, *instr); scc_vec_foreach(after, i)
// scc_vec_push(*instr_vec, scc_vec_at(after, i));
// // 7. 取消隐式寄存器的占用标记
// Assert(ops->mark_reg_used != nullptr);
// for (const int *p = implicit_defs; *p != -1; p++)
// ops->mark_reg_used(ctx, *p);
// for (const int *p = implicit_uses; *p != -1; p++)
// ops->release_reg(ctx, *p);
// scc_vec_free(before);
// scc_vec_free(after);
// }
static void alloc_instr(scc_reg_alloc_ctx_t *ctx, static void alloc_instr(scc_reg_alloc_ctx_t *ctx,
scc_mir_instr_vec_t *instr_vec, scc_mir_instr_vec_t *instr_vec,
scc_mir_instr_t *instr) { scc_mir_instr_t *instr) {
const scc_reg_alloc_op_t *ops = ctx->ops; const scc_reg_alloc_op_t *ops = &ctx->ops;
scc_mir_instr_vec_t before_instrs; scc_mir_instr_vec_t before, after;
scc_vec_init(before_instrs); scc_vec_init(before);
scc_mir_instr_vec_t after_instrs; scc_vec_init(after);
scc_vec_init(after_instrs);
for (int i = 0; i < instr->num_operands; i += 1) { // 隐式寄存器标记
if (instr->operands[i].kind != SCC_MIR_OP_VREG) { const int *implicit_uses, *implicit_defs;
ops->get_implicit_regs(ctx, instr->opcode, &implicit_uses, &implicit_defs);
for (const int *p = implicit_uses; *p != -1; p++)
ops->mark_reg_used(ctx, *p);
for (const int *p = implicit_defs; *p != -1; p++)
ops->mark_reg_used(ctx, *p);
// 指令内 vreg→preg 的简单映射(操作数不超过 8 个)
int local_vreg[8], local_preg[8];
int local_cnt = 0;
SCC_VEC(int) allocated_pregs;
scc_vec_init(allocated_pregs);
for (int i = 0; i < instr->num_operands; i++) {
scc_mir_operand_t *op = &instr->operands[i];
// 只处理 vreg
if (op->kind != SCC_MIR_OP_VREG)
continue; continue;
int vreg = op->vreg;
// 查询当前 vreg 的映射(可能已经被之前的分配改为 MEM 等,但我们只需要
// slot
scc_mir_vreg_op(ctx->func, vreg, op);
int slot;
if (op->kind == SCC_MIR_OP_VREG) {
// 还没有 slot → 分配一个
slot = scc_mir_vreg_map2slot(ctx->func, vreg, 8, 8);
} else {
// 已经是 MEM直接用它的 slot
Assert(op->kind == SCC_MIR_OP_MEM);
slot = op->stack_slot;
} }
int vreg = instr->operands[i].vreg; // 在本指令内查找是否已为这个 vreg 分配了 preg
scc_op_access_t op_access =
ops->get_operand_access(ctx, instr->opcode, i);
int slot = ensure_slot(ctx, vreg);
int preg = -1; int preg = -1;
// if (implicit_uses && implicit_uses[0] != -1) for (int k = 0; k < local_cnt; k++) {
// preg = implicit_uses[0]; if (local_vreg[k] == vreg) {
// else preg = local_preg[k];
break;
}
}
if (preg == -1) {
// 新分配
preg = ops->acquire_reg(ctx); preg = ops->acquire_reg(ctx);
scc_vec_push(allocated_pregs, preg);
if (op_access == SCC_REG_ALLOC_OP_ACCESS_READ || local_vreg[local_cnt] = vreg;
op_access == SCC_REG_ALLOC_OP_ACCESS_READWRITE) { local_preg[local_cnt] = preg;
ops->emit_reload(&before_instrs, preg, slot); local_cnt++;
}
instr->operands[i].kind = SCC_MIR_OP_PREG;
instr->operands[i].preg = preg;
if (op_access == SCC_REG_ALLOC_OP_ACCESS_WRITE ||
op_access == SCC_REG_ALLOC_OP_ACCESS_READWRITE) {
ops->emit_spill(&after_instrs, preg, slot);
} }
ops->release_reg(ctx, preg); // 读写属性
scc_op_access_t acc = ops->get_operand_access(ctx, instr->opcode, i);
// reload: slot → preg
if (acc == SCC_REG_ALLOC_OP_ACCESS_READ ||
acc == SCC_REG_ALLOC_OP_ACCESS_READWRITE) {
ops->emit_reload(&before, preg, slot);
} }
scc_vec_foreach(before_instrs, i) { // spill: preg → slot
scc_vec_push(*instr_vec, scc_vec_at(before_instrs, i)); if (acc == SCC_REG_ALLOC_OP_ACCESS_WRITE ||
acc == SCC_REG_ALLOC_OP_ACCESS_READWRITE) {
ops->emit_spill(&after, preg, slot);
} }
// 替换操作数
op->kind = SCC_MIR_OP_PREG;
op->preg = preg;
}
// 释放本指令分配的临时寄存器
scc_vec_foreach(allocated_pregs, i)
ops->release_reg(ctx, scc_vec_at(allocated_pregs, i));
// 合并指令流
scc_vec_foreach(before, i) scc_vec_push(*instr_vec, scc_vec_at(before, i));
scc_vec_push(*instr_vec, *instr); scc_vec_push(*instr_vec, *instr);
// TODO reverse it scc_vec_foreach(after, i) scc_vec_push(*instr_vec, scc_vec_at(after, i));
scc_vec_foreach(after_instrs, i) {
scc_vec_push(*instr_vec, scc_vec_at(after_instrs, i)); // 隐式寄存器清理
} for (const int *p = implicit_defs; *p != -1; p++)
ops->mark_reg_used(ctx, *p);
for (const int *p = implicit_uses; *p != -1; p++)
ops->release_reg(ctx, *p);
scc_vec_free(before);
scc_vec_free(after);
scc_vec_free(allocated_pregs);
} }
/* 对一个基本块执行分配 */ /* 对一个基本块执行分配 */
@@ -77,10 +192,6 @@ static void alloc_bb(scc_reg_alloc_ctx_t *ctx, scc_mir_module_t *module,
scc_vec_foreach(*old_instrs, i) { scc_vec_foreach(*old_instrs, i) {
scc_mir_instr_t ins = scc_vec_at(*old_instrs, i); scc_mir_instr_t ins = scc_vec_at(*old_instrs, i);
if (ins.opcode == SCC_MIR_PSUEDO_ALLOCA) {
scc_vec_push(new_instrs, ins);
continue;
}
alloc_instr(ctx, &new_instrs, &ins); alloc_instr(ctx, &new_instrs, &ins);
} }
@@ -91,18 +202,29 @@ static void alloc_bb(scc_reg_alloc_ctx_t *ctx, scc_mir_module_t *module,
/* 对一个函数运行分配 */ /* 对一个函数运行分配 */
static void alloc_func(scc_reg_alloc_ctx_t *ctx, scc_mir_module_t *module, static void alloc_func(scc_reg_alloc_ctx_t *ctx, scc_mir_module_t *module,
scc_mir_func_t *func) { scc_mir_func_t *func) {
ctx->ops.clean_mark_regs(ctx);
ctx->func_meta = SCC_MIR_FUNC_META(func); ctx->func = func;
scc_vec_foreach(func->bblocks, i) { scc_vec_foreach(func->bblocks, i) {
scc_cfg_bblock_id_t bb_id = scc_vec_at(func->bblocks, i); scc_cfg_bblock_id_t bb_id = scc_vec_at(func->bblocks, i);
alloc_bb(ctx, module, bb_id); alloc_bb(ctx, module, bb_id);
} }
ctx->func_meta = nullptr;
} }
/* 公开入口 */ /* 公开入口 */
void scc_reg_alloc(scc_reg_alloc_ctx_t *ctx, scc_mir_module_t *module) { void scc_reg_alloc(scc_reg_alloc_ctx_t *ctx, scc_mir_module_t *module) {
Assert(ctx != nullptr && module != nullptr); Assert(ctx != nullptr && module != nullptr);
Assert(ctx->ops.acquire_reg != nullptr);
Assert(ctx->ops.clean_mark_regs != nullptr);
Assert(ctx->ops.emit_copy != nullptr);
Assert(ctx->ops.emit_reload != nullptr);
Assert(ctx->ops.emit_spill != nullptr);
Assert(ctx->ops.get_implicit_regs != nullptr);
Assert(ctx->ops.get_operand_access != nullptr);
Assert(ctx->ops.mark_reg_used != nullptr);
Assert(ctx->ops.release_reg != nullptr);
scc_vec_foreach(module->cfg_module.funcs, i) { scc_vec_foreach(module->cfg_module.funcs, i) {
if (i == 0) if (i == 0)
continue; continue;

View File

@@ -1,12 +1,13 @@
#include <arch/x86_64_isel.h>
#include <scc_lir2mir.h> #include <scc_lir2mir.h>
#include <target/scc_win64.h>
extern void scc_isel_x86_64(scc_mir_module_t *mir_module,
const scc_lir_module_t *lir_module);
void scc_lir2mir(scc_mir_module_t *mir_module, void scc_lir2mir(scc_mir_module_t *mir_module,
const scc_lir_module_t *lir_module) { const scc_lir_module_t *lir_module) {
// FIXME hack cfg module // FIXME hack cfg module
mir_module->cfg_module = lir_module->cfg_module; mir_module->cfg_module = lir_module->cfg_module;
// TODO using target ABI choice it
scc_isel_x86_64(mir_module, lir_module); scc_x86_64_isel_t isel;
scc_win_pc_x64_abi_lowering(&isel.abi_lowering);
scc_isel_x86_64(mir_module, lir_module, &isel);
} }

View File

@@ -1,9 +1,64 @@
#include "scc_mir.h" #include <scc_mir.h>
void scc_mir_func_meta_init(scc_mir_func_meta_t *func_meta) { void scc_mir_func_meta_init(scc_mir_func_meta_t *func_meta) {
func_meta->frame_size = 0; func_meta->frame_size = 0;
func_meta->stack_alignment = 0; func_meta->stack_alignment = 0;
func_meta->vregs_count = 0;
scc_vec_init(func_meta->stack_slots); scc_vec_init(func_meta->stack_slots);
scc_hashtable_usize_init(&func_meta->vreg2preg);
scc_hashtable_usize_init(&func_meta->vreg2slot); // For null stack slot
scc_vec_push(func_meta->stack_slots, (scc_mir_stack_slot_t){0});
scc_hashtable_usize_init(&func_meta->vreg2physic);
}
int scc_mir_alloc_vreg(scc_mir_func_t *func) {
scc_mir_func_meta_t *meta = SCC_MIR_FUNC_META(func);
return meta->vregs_count++;
}
void scc_mir_vreg_op(const scc_mir_func_t *func, int vreg,
scc_mir_operand_t *out) {
scc_mir_func_meta_t *meta = SCC_MIR_FUNC_META(func);
isize idx =
(isize)scc_hashtable_get(&meta->vreg2physic, (void *)(usize)vreg);
if (idx == 0) {
out->kind = SCC_MIR_OP_VREG;
out->vreg = vreg;
} else if (idx < 0) {
out->kind = SCC_MIR_OP_PREG;
out->preg = (int)-idx;
} else {
out->kind = SCC_MIR_OP_MEM;
Assert(idx < scc_vec_size(meta->stack_slots));
out->stack_slot = (int)(usize)idx;
}
}
void scc_mir_vreg_map2preg(scc_mir_func_t *func, int vreg, int preg) {
scc_mir_func_meta_t *meta = SCC_MIR_FUNC_META(func);
isize val =
(isize)scc_hashtable_get(&meta->vreg2physic, (void *)(usize)vreg);
if (val != 0) {
Panic("vreg %d already mapped", vreg);
return;
}
scc_hashtable_set(&meta->vreg2physic, (void *)(usize)vreg,
(void *)(usize)(isize)-preg);
}
int scc_mir_vreg_map2slot(scc_mir_func_t *func, int vreg, int size, int align) {
scc_mir_func_meta_t *meta = SCC_MIR_FUNC_META(func);
isize val =
(isize)scc_hashtable_get(&meta->vreg2physic, (void *)(usize)vreg);
if (val != 0) {
Panic("vreg %d already mapped", vreg);
return 0;
}
int new_slot = scc_vec_size(meta->stack_slots);
scc_mir_stack_slot_t s = {
.slot_id = new_slot, .size = size, .alignment = align, .offset = 0};
scc_vec_push(meta->stack_slots, s);
scc_hashtable_set(&meta->vreg2physic, (void *)(usize)vreg,
(void *)(usize)new_slot);
return new_slot;
} }

View File

@@ -16,6 +16,8 @@ void scc_mir_dump_instr(scc_mir_dump_ctx_t *ctx, const scc_mir_instr_t *ins) {
scc_tree_dump_append_fmt(td, "(%d)", ins->operands[1].imm); scc_tree_dump_append_fmt(td, "(%d)", ins->operands[1].imm);
if (ins->operands[0].kind == SCC_MIR_OP_VREG) { if (ins->operands[0].kind == SCC_MIR_OP_VREG) {
scc_tree_dump_append_fmt(td, " %%%d", ins->operands[0].vreg); scc_tree_dump_append_fmt(td, " %%%d", ins->operands[0].vreg);
} else if (ins->operands[0].kind == SCC_MIR_OP_MEM) {
scc_tree_dump_append_fmt(td, " [%d]", ins->operands[0].stack_slot);
} else { } else {
scc_tree_dump_append(td, "<alloced>"); scc_tree_dump_append(td, "<alloced>");
} }

View File

@@ -1,11 +1,28 @@
#include <arch/x86_64_reg_alloc.h>
#include <target/scc_win64.h>
#include <core_pass/scc_frame_layout.h>
#include <core_pass/scc_reg_alloc.h> #include <core_pass/scc_reg_alloc.h>
#include <scc_mir_module.h> #include <scc_mir_module.h>
#include <scc_mir_pass.h> #include <scc_mir_pass.h>
extern scc_reg_alloc_op_t x86_reg_alloc_hooks;
void scc_mir_pass(scc_mir_module_t *mir_module, scc_mir_pass_stage_t stage) { void scc_mir_pass(scc_mir_module_t *mir_module, scc_mir_pass_stage_t stage) {
scc_reg_alloc_ctx_t reg_alloc_ctx = { scc_reg_alloc_ctx_t reg_alloc_ctx = {
.func_meta = nullptr, .instrs = nullptr, .ops = &x86_reg_alloc_hooks}; .func = nullptr, .instrs = nullptr, .ops = {0}};
scc_reg_alloc_fill_arch_x86(&reg_alloc_ctx.ops);
scc_reg_alloc_fill_win_x64(&reg_alloc_ctx.ops);
scc_reg_alloc(&reg_alloc_ctx, mir_module); scc_reg_alloc(&reg_alloc_ctx, mir_module);
if (stage == SCC_MIR_STAGE_REGALLOC) {
return;
}
if (stage == SCC_MIR_STAGE_FRAME_LAYOUT) {
return;
}
if (stage == SCC_MIR_STAGE_PROLOGUE_EPILOGUE) {
return;
}
} }

View File

@@ -4,6 +4,7 @@
#include <arch/x86_64_isel.h> #include <arch/x86_64_isel.h>
#include <core_pass/scc_abi_lowering.h> #include <core_pass/scc_abi_lowering.h>
#include <core_pass/scc_prolog_epilog.h> #include <core_pass/scc_prolog_epilog.h>
#include <target/scc_win64.h>
static const int WIN64_DEFAULT_ALIGN = 8; static const int WIN64_DEFAULT_ALIGN = 8;
static const int WIN64_STACK_ALIGN = 16; static const int WIN64_STACK_ALIGN = 16;
@@ -199,6 +200,44 @@ void scc_win_pc_x64_abi_lowering(scc_abi_lowering_t *abi_lowering) {
abi_lowering->lower_va_end = nullptr; 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_reg_alloc_fill_win_x64(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 scc_win_pc_x64_prolog_epilog(scc_prolog_epilog_t *prolog_epilog) { void scc_win_pc_x64_prolog_epilog(scc_prolog_epilog_t *prolog_epilog) {
prolog_epilog->prolog = prologue; prolog_epilog->prolog = prologue;
prolog_epilog->epilog = epilogue; prolog_epilog->epilog = epilogue;

View File

@@ -281,10 +281,10 @@ sstream_drop:
scc_mir_pass(&mir_module, SCC_MIR_STAGE_REGALLOC); scc_mir_pass(&mir_module, SCC_MIR_STAGE_REGALLOC);
goto mir_dump; goto mir_dump;
case SCC_EMIT_STAGE_MIR_PASS_FLAME_LAYOUT: case SCC_EMIT_STAGE_MIR_PASS_FLAME_LAYOUT:
scc_mir_pass(&mir_module, SCC_MIR_STAGE_POST_REGALLOC); scc_mir_pass(&mir_module, SCC_MIR_STAGE_FRAME_LAYOUT);
goto mir_dump; goto mir_dump;
case SCC_EMIT_STAGE_MIR_PASS_PROLOG_EPILOG: case SCC_EMIT_STAGE_MIR_PASS_PROLOG_EPILOG:
scc_mir_pass(&mir_module, SCC_MIR_STAGE_POST_REGALLOC); scc_mir_pass(&mir_module, SCC_MIR_STAGE_PROLOGUE_EPILOGUE);
goto mir_dump; goto mir_dump;
break; break;
default: default: