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:
@@ -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);
|
||||
}
|
||||
|
||||
8
libs/ir/mir/include/arch/x86_64_reg_alloc.h
Normal file
8
libs/ir/mir/include/arch/x86_64_reg_alloc.h
Normal 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__ */
|
||||
@@ -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__ */
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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__ */
|
||||
|
||||
@@ -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);
|
||||
|
||||
9
libs/ir/mir/include/target/scc_win64.h
Normal file
9
libs/ir/mir/include/target/scc_win64.h
Normal 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
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
3
libs/ir/mir/src/reg_alloc/frame_layout.c
Normal file
3
libs/ir/mir/src/reg_alloc/frame_layout.c
Normal 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) {}
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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>");
|
||||
}
|
||||
|
||||
@@ -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(®_alloc_ctx.ops);
|
||||
scc_reg_alloc_fill_win_x64(®_alloc_ctx.ops);
|
||||
|
||||
scc_reg_alloc(®_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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -281,10 +281,10 @@ sstream_drop:
|
||||
scc_mir_pass(&mir_module, SCC_MIR_STAGE_REGALLOC);
|
||||
goto mir_dump;
|
||||
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;
|
||||
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;
|
||||
break;
|
||||
default:
|
||||
|
||||
Reference in New Issue
Block a user