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 {
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_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) {
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__
#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__ */

View File

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

View File

@@ -59,14 +59,24 @@ typedef struct scc_mir_func_meta {
// 栈帧信息 (由 FrameLayout Pass 填充)
int frame_size;
int stack_alignment;
int vregs_count;
// 寄存器分配信息
scc_mir_stack_slot_vec_t stack_slots;
scc_hashtable_t vreg2preg; // vreg -> phys reg-1 表示溢出
scc_hashtable_t vreg2slot; // vreg -> stack slot index
// vreg -> phys reg and stack slot index
// positive means stack slot index
// negative means physic register
scc_hashtable_t vreg2physic;
} scc_mir_func_meta_t;
#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);
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__ */

View File

@@ -19,10 +19,10 @@ typedef enum {
/** Pass 运行阶段 (用于自动排序) */
typedef enum {
SCC_MIR_STAGE_ANY, // 无特殊阶段要求
SCC_MIR_STAGE_PRE_REGALLOC, // 寄存器分配
SCC_MIR_STAGE_REGALLOC, // 寄存器分配本身
SCC_MIR_STAGE_POST_REGALLOC // 寄存器分配后
SCC_MIR_STAGE_ANY, // 无特殊阶段要求
SCC_MIR_STAGE_REGALLOC, // 寄存器分配本身
SCC_MIR_STAGE_FRAME_LAYOUT, // 帧布局
SCC_MIR_STAGE_PROLOGUE_EPILOGUE, // 函数头尾处理
} scc_mir_pass_stage_t;
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];
switch (op->kind) {
case SCC_MIR_OP_VREG:
scc_tree_dump_append_fmt(td, "$%d", op->vreg);
scc_tree_dump_append_fmt(td, "%%%d", op->vreg);
break;
case SCC_MIR_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) {
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,
@@ -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);
}
static void emit_alloca(scc_x86_64_isel_t *isel, scc_mir_operand_t dst,
i64 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};
add_instr_2(isel, SCC_X86_IFORM_SUB_GPRV_IMMZ, rsp, imm);
scc_x86_emit_move(isel, dst, rsp, 8);
}
// static void emit_alloca(scc_x86_64_isel_t *isel, scc_mir_operand_t dst,
// i64 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}; add_instr_2(isel, SCC_X86_IFORM_SUB_GPRV_IMMZ, rsp,
// 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) {
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:
// emit_alloca(isel, dst, instr->metadata.alloca.size_bytes);
add_instr_2(isel, (scc_x86_iform_t)SCC_MIR_PSUEDO_ALLOCA,
scc_x86_lir_val_to_mir_op(isel, &instr->to),
scc_mir_operand_t op = 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){
.kind = SCC_MIR_OP_IMM,
.imm = instr->size,
});
Assert(op.kind == SCC_MIR_OP_VREG);
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,
const scc_lir_func_t *func) {
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);
const scc_lir_func_t *func, scc_x86_64_isel_t *isel) {
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_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_vec_foreach(*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;
scc_vec_init(isel.instrs);
bb->values = *(scc_cfg_value_vec_t *)&isel->instrs;
scc_vec_init(isel->instrs);
}
}
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) {
if (i == 0)
continue;
@@ -479,8 +474,12 @@ void scc_isel_x86_64(scc_mir_module_t *mir_module,
scc_malloc(sizeof(scc_mir_func_meta_t));
Assert(func_meta != nullptr);
scc_mir_func_meta_init(func_meta);
scc_vec_push(mir_module->func_metas, func_meta);
sel_func(lir_module, func);
// FIXME
func_meta->vregs_count = SCC_LIR_FUNC_META(func)->vregs_count;
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 <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) {
scc_mir_instr_t ins = {
@@ -74,13 +74,10 @@ static void x86_get_implicit_regs(void *vctx, int opcode, const int **uses,
}
}
/* 组装 hooks 表 */
scc_reg_alloc_op_t x86_reg_alloc_hooks = {
.emit_spill = x86_emit_spill,
.emit_reload = x86_emit_reload,
.emit_copy = x86_emit_copy,
.acquire_reg = x86_acquire_temp_reg,
.release_reg = x86_release_temp_reg,
.get_operand_access = x86_get_operand_access,
.get_implicit_regs = x86_get_implicit_regs,
};
void scc_reg_alloc_fill_arch_x86(scc_reg_alloc_op_t *ops) {
ops->emit_spill = x86_emit_spill;
ops->emit_reload = x86_emit_reload;
ops->emit_copy = x86_emit_copy;
ops->get_operand_access = x86_get_operand_access;
ops->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_mir_module.h>
static int ensure_slot(scc_reg_alloc_ctx_t *ctx, int vreg) {
void *key = (void *)(usize)vreg;
void *val = scc_hashtable_get(&ctx->func_meta->vreg2slot, key);
if (val != NULL)
return (int)(usize)val;
int new_slot = scc_vec_size(ctx->func_meta->stack_slots) + 1; // 1-based
scc_mir_stack_slot_t s = {
.slot_id = new_slot, .size = 8, .alignment = 8, .offset = 0};
scc_vec_push(ctx->func_meta->stack_slots, s);
scc_hashtable_set(&ctx->func_meta->vreg2slot, key, (void *)(usize)new_slot);
return new_slot;
}
// static void alloc_instr(scc_reg_alloc_ctx_t *ctx,
// scc_mir_instr_vec_t *instr_vec,
// scc_mir_instr_t *instr) {
// const scc_reg_alloc_op_t *ops = &ctx->ops;
// scc_mir_instr_vec_t before, after;
// scc_vec_init(before);
// scc_vec_init(after);
// // 1. 标记隐式寄存器为占用
// 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);
// 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,
scc_mir_instr_vec_t *instr_vec,
scc_mir_instr_t *instr) {
const scc_reg_alloc_op_t *ops = ctx->ops;
scc_mir_instr_vec_t before_instrs;
scc_vec_init(before_instrs);
scc_mir_instr_vec_t after_instrs;
scc_vec_init(after_instrs);
const scc_reg_alloc_op_t *ops = &ctx->ops;
scc_mir_instr_vec_t before, after;
scc_vec_init(before);
scc_vec_init(after);
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;
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;
scc_op_access_t op_access =
ops->get_operand_access(ctx, instr->opcode, i);
int slot = ensure_slot(ctx, vreg);
// 在本指令内查找是否已为这个 vreg 分配了 preg
int preg = -1;
// if (implicit_uses && implicit_uses[0] != -1)
// preg = implicit_uses[0];
// else
preg = ops->acquire_reg(ctx);
if (op_access == SCC_REG_ALLOC_OP_ACCESS_READ ||
op_access == SCC_REG_ALLOC_OP_ACCESS_READWRITE) {
ops->emit_reload(&before_instrs, preg, slot);
for (int k = 0; k < local_cnt; k++) {
if (local_vreg[k] == vreg) {
preg = local_preg[k];
break;
}
}
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);
if (preg == -1) {
// 新分配
preg = ops->acquire_reg(ctx);
scc_vec_push(allocated_pregs, preg);
local_vreg[local_cnt] = vreg;
local_preg[local_cnt] = preg;
local_cnt++;
}
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);
}
// spill: preg → slot
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(before_instrs, i) {
scc_vec_push(*instr_vec, scc_vec_at(before_instrs, i));
}
// 释放本指令分配的临时寄存器
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);
// TODO reverse it
scc_vec_foreach(after_instrs, i) {
scc_vec_push(*instr_vec, scc_vec_at(after_instrs, i));
}
scc_vec_foreach(after, i) scc_vec_push(*instr_vec, scc_vec_at(after, 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_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);
}
@@ -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,
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_cfg_bblock_id_t bb_id = scc_vec_at(func->bblocks, i);
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) {
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) {
if (i == 0)
continue;

View File

@@ -1,12 +1,13 @@
#include <arch/x86_64_isel.h>
#include <scc_lir2mir.h>
extern void scc_isel_x86_64(scc_mir_module_t *mir_module,
const scc_lir_module_t *lir_module);
#include <target/scc_win64.h>
void scc_lir2mir(scc_mir_module_t *mir_module,
const scc_lir_module_t *lir_module) {
// FIXME hack 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) {
func_meta->frame_size = 0;
func_meta->stack_alignment = 0;
func_meta->vregs_count = 0;
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);
if (ins->operands[0].kind == SCC_MIR_OP_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 {
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 <scc_mir_module.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) {
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);
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 <core_pass/scc_abi_lowering.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;
@@ -199,6 +200,44 @@ 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_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) {
prolog_epilog->prolog = prologue;
prolog_epilog->epilog = epilogue;