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:
61
libs/ir/mir/include/arch/scc_x86_isel.h
Normal file
61
libs/ir/mir/include/arch/scc_x86_isel.h
Normal file
@@ -0,0 +1,61 @@
|
||||
#ifndef __SCC_X86_ISEL_H__
|
||||
#define __SCC_X86_ISEL_H__
|
||||
|
||||
#include <scc_lir_module.h>
|
||||
#include <scc_tree_dump.h>
|
||||
|
||||
#include "../core_pass/scc_abi_lowering.h"
|
||||
#include "scc_x86_mir.h"
|
||||
|
||||
typedef struct scc_x86_64_isel {
|
||||
scc_mir_x86_instr_vec_t instrs;
|
||||
scc_mir_func_t *func;
|
||||
scc_pos_t pos;
|
||||
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);
|
||||
|
||||
// Utils
|
||||
void scc_x86_emit_move(scc_x86_64_isel_t *isel, scc_x86_operand_value_t dst,
|
||||
scc_x86_operand_value_t src, u8 size);
|
||||
scc_x86_operand_value_t scc_x86_lir_val_to_mir_op(scc_x86_64_isel_t *isel,
|
||||
const scc_lir_val_t *val);
|
||||
static inline void emit_direct_call(scc_x86_64_isel_t *isel,
|
||||
const char *callee) {
|
||||
(void)callee;
|
||||
scc_mir_x86_instr_t instr = {0};
|
||||
scc_mir_x86_instr_1(&instr, SCC_X86_IFORM_CALL_NEAR_GPRV,
|
||||
scc_x86_op_relbr(0), scc_pos_create());
|
||||
scc_vec_push(isel->instrs, instr);
|
||||
}
|
||||
static inline void emit_ret(scc_x86_64_isel_t *isel) {
|
||||
scc_mir_x86_instr_t instr = {0};
|
||||
scc_mir_x86_instr_0(&instr, SCC_X86_IFORM_RET_NEAR, scc_pos_create());
|
||||
scc_vec_push(isel->instrs, instr);
|
||||
}
|
||||
|
||||
#define add_instr_0(isel, iform) \
|
||||
do { \
|
||||
scc_mir_x86_instr_t instr; \
|
||||
scc_mir_x86_instr_0(&instr, (iform), (isel)->pos); \
|
||||
scc_vec_push((isel)->instrs, instr); \
|
||||
} while (0)
|
||||
|
||||
#define add_instr_1(isel, iform, arg1) \
|
||||
do { \
|
||||
scc_mir_x86_instr_t instr; \
|
||||
scc_mir_x86_instr_1(&instr, (iform), (arg1), (isel)->pos); \
|
||||
scc_vec_push((isel)->instrs, instr); \
|
||||
} while (0)
|
||||
|
||||
#define add_instr_2(isel, iform, arg1, arg2) \
|
||||
do { \
|
||||
scc_mir_x86_instr_t instr; \
|
||||
scc_mir_x86_instr_2(&instr, (iform), (arg1), (arg2), (isel)->pos); \
|
||||
scc_vec_push((isel)->instrs, instr); \
|
||||
} while (0)
|
||||
|
||||
#endif /* __SCC_X86_ISEL_H__ */
|
||||
134
libs/ir/mir/include/arch/scc_x86_mir.h
Normal file
134
libs/ir/mir/include/arch/scc_x86_mir.h
Normal file
@@ -0,0 +1,134 @@
|
||||
#ifndef __SCC_X86_MIR_H__
|
||||
#define __SCC_X86_MIR_H__
|
||||
|
||||
#include "../scc_mir.h"
|
||||
#include <scc_cfg.h>
|
||||
#include <scc_pos.h>
|
||||
#include <x86/scc_x86_encode.h>
|
||||
#include <x86/scc_x86_iform.h>
|
||||
#include <x86/scc_x86_reg.h>
|
||||
|
||||
typedef struct {
|
||||
int opcode;
|
||||
uint8_t num_operands;
|
||||
scc_x86_operand_value_t operands[6];
|
||||
scc_pos_t src_loc;
|
||||
} scc_x86_instr_t;
|
||||
|
||||
// x86 后端指令:首字段 int opcode(正 = scc_x86_iform_t,负 = 伪指令)
|
||||
typedef union scc_mir_x86_instr {
|
||||
scc_mir_instr_t instr;
|
||||
scc_x86_instr_t x86_instr;
|
||||
} scc_mir_x86_instr_t;
|
||||
|
||||
typedef SCC_VEC(scc_mir_x86_instr_t) scc_mir_x86_instr_vec_t;
|
||||
|
||||
// ── 基本块 values 强制转换 ──────────────────────────────────────────────
|
||||
|
||||
#define SCC_MIR_X86_BBLOCK_INSTRS(bb) ((scc_mir_x86_instr_vec_t *)&bb->values)
|
||||
#define SCC_MIR_X86_BBLOCK_INSTRS_C(bb) \
|
||||
((const scc_mir_x86_instr_vec_t *)&bb->values)
|
||||
|
||||
// ── vreg 编码 ──────────────────────────────────────────────────────────
|
||||
static inline bool scc_x86_op_is_vreg(const scc_x86_operand_value_t *op) {
|
||||
return op->kind == SCC_X86_OPR_REG &&
|
||||
(int)op->reg >= (int)SCC_X86_REG_COUNT;
|
||||
}
|
||||
static inline int scc_x86_op_get_vreg(const scc_x86_operand_value_t *op) {
|
||||
return (int)op->reg - (int)SCC_X86_REG_COUNT;
|
||||
}
|
||||
static inline void scc_x86_op_set_preg(scc_x86_operand_value_t *op,
|
||||
scc_x86_reg_t preg) {
|
||||
op->kind = SCC_X86_OPR_REG;
|
||||
op->reg = preg;
|
||||
}
|
||||
|
||||
// ── 未解析栈槽编码 (base=INVALID, disp=slot_id) ──────────────────────
|
||||
static inline bool scc_x86_op_is_slot(const scc_x86_operand_value_t *op) {
|
||||
return op->kind == SCC_X86_OPR_MEM && op->mem.base == SCC_X86_REG_INVALID;
|
||||
}
|
||||
static inline int scc_x86_op_slot_id(const scc_x86_operand_value_t *op) {
|
||||
return op->mem.disp;
|
||||
}
|
||||
|
||||
// ── 指令构建辅助 ──────────────────────────────────────────────────────
|
||||
static inline void scc_mir_x86_instr_0(scc_mir_x86_instr_t *out, int opcode,
|
||||
scc_pos_t pos) {
|
||||
out->x86_instr.opcode = opcode;
|
||||
out->x86_instr.num_operands = 0;
|
||||
out->x86_instr.src_loc = pos;
|
||||
}
|
||||
static inline void scc_mir_x86_instr_1(scc_mir_x86_instr_t *out, int opcode,
|
||||
scc_x86_operand_value_t op0,
|
||||
scc_pos_t pos) {
|
||||
out->x86_instr.opcode = opcode;
|
||||
out->x86_instr.num_operands = 1;
|
||||
out->x86_instr.operands[0] = op0;
|
||||
out->x86_instr.src_loc = pos;
|
||||
}
|
||||
static inline void scc_mir_x86_instr_2(scc_mir_x86_instr_t *out, int opcode,
|
||||
scc_x86_operand_value_t op0,
|
||||
scc_x86_operand_value_t op1,
|
||||
scc_pos_t pos) {
|
||||
out->x86_instr.opcode = opcode;
|
||||
out->x86_instr.num_operands = 2;
|
||||
out->x86_instr.operands[0] = op0;
|
||||
out->x86_instr.operands[1] = op1;
|
||||
out->x86_instr.src_loc = pos;
|
||||
}
|
||||
static inline void scc_mir_x86_instr_3(scc_mir_x86_instr_t *out, int opcode,
|
||||
scc_x86_operand_value_t op0,
|
||||
scc_x86_operand_value_t op1,
|
||||
scc_x86_operand_value_t op2,
|
||||
scc_pos_t pos) {
|
||||
out->x86_instr.opcode = opcode;
|
||||
out->x86_instr.num_operands = 3;
|
||||
out->x86_instr.operands[0] = op0;
|
||||
out->x86_instr.operands[1] = op1;
|
||||
out->x86_instr.operands[2] = op2;
|
||||
out->x86_instr.src_loc = pos;
|
||||
}
|
||||
|
||||
// ── 常用操作数构造器 ──────────────────────────────────────────────────
|
||||
static inline scc_x86_operand_value_t scc_x86_op_preg(scc_x86_reg_t reg) {
|
||||
scc_x86_operand_value_t o = {.kind = SCC_X86_OPR_REG, .reg = reg};
|
||||
return o;
|
||||
}
|
||||
static inline scc_x86_operand_value_t scc_x86_op_vreg(int vreg) {
|
||||
scc_x86_operand_value_t o = {
|
||||
.kind = SCC_X86_OPR_REG,
|
||||
.reg = (scc_x86_reg_t)((int)SCC_X86_REG_COUNT + vreg)};
|
||||
return o;
|
||||
}
|
||||
static inline scc_x86_operand_value_t scc_x86_op_relbr(i32 rel) {
|
||||
scc_x86_operand_value_t o = {.kind = SCC_X86_OPR_RELBR, .imm = rel};
|
||||
return o;
|
||||
}
|
||||
static inline scc_x86_operand_value_t scc_x86_op_imm(i64 imm) {
|
||||
scc_x86_operand_value_t o = {.kind = SCC_X86_OPR_IMM, .imm = imm};
|
||||
return o;
|
||||
}
|
||||
// slot_id 编码为 base=INVALID, disp=slot_id
|
||||
static inline scc_x86_operand_value_t scc_x86_op_slot(int slot_id) {
|
||||
scc_x86_operand_value_t o = {.kind = SCC_X86_OPR_MEM};
|
||||
o.mem.base = SCC_X86_REG_INVALID;
|
||||
o.mem.index = SCC_X86_REG_INVALID;
|
||||
o.mem.scale = 1;
|
||||
o.mem.disp = slot_id;
|
||||
return o;
|
||||
}
|
||||
static inline scc_x86_operand_value_t scc_x86_op_symbol(const char *sym) {
|
||||
scc_x86_operand_value_t o = {.kind = SCC_X86_OPR_IMM,
|
||||
.imm = (i64)(usize)sym};
|
||||
(void)o;
|
||||
// symbol 暂用一个近似值占位,编码阶段处理重定位
|
||||
return o;
|
||||
}
|
||||
static inline scc_x86_operand_value_t
|
||||
scc_x86_op_block(scc_cfg_bblock_id_t bid) {
|
||||
scc_x86_operand_value_t o = {.kind = SCC_X86_OPR_RELBR, .imm = 0};
|
||||
(void)bid;
|
||||
return o;
|
||||
}
|
||||
|
||||
#endif /* __SCC_X86_MIR_H__ */
|
||||
8
libs/ir/mir/include/arch/scc_x86_reg_alloc.h
Normal file
8
libs/ir/mir/include/arch/scc_x86_reg_alloc.h
Normal file
@@ -0,0 +1,8 @@
|
||||
#ifndef __SCC_X86_REG_ALLOC_H__
|
||||
#define __SCC_X86_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_REG_ALLOC_H__ */
|
||||
@@ -1,66 +0,0 @@
|
||||
#ifndef __SCC_X86_64_ISEL_H__
|
||||
#define __SCC_X86_64_ISEL_H__
|
||||
|
||||
#include <scc_lir_module.h>
|
||||
#include <scc_tree_dump.h>
|
||||
|
||||
#include <x86/scc_x86_iform.h>
|
||||
#include <x86/scc_x86_reg.h>
|
||||
|
||||
#include "../core_pass/scc_abi_lowering.h"
|
||||
#include "../scc_mir_module.h"
|
||||
|
||||
typedef struct scc_x86_64_isel {
|
||||
scc_mir_instr_vec_t instrs;
|
||||
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);
|
||||
}
|
||||
|
||||
static inline void add_instr_0(scc_x86_64_isel_t *isel,
|
||||
scc_x86_iform_t opcode) {
|
||||
scc_mir_instr_t out = {.opcode = opcode, .num_operands = 0};
|
||||
add_instr(isel, &out);
|
||||
}
|
||||
|
||||
static inline void add_instr_1(scc_x86_64_isel_t *isel, scc_x86_iform_t opcode,
|
||||
scc_mir_operand_t op1) {
|
||||
scc_mir_instr_t out = {.opcode = opcode, .num_operands = 1};
|
||||
out.operands[0] = op1;
|
||||
add_instr(isel, &out);
|
||||
}
|
||||
|
||||
static inline void add_instr_2(scc_x86_64_isel_t *isel, scc_x86_iform_t opcode,
|
||||
scc_mir_operand_t op1, scc_mir_operand_t op2) {
|
||||
scc_mir_instr_t out = {.opcode = opcode, .num_operands = 2};
|
||||
out.operands[0] = op1;
|
||||
out.operands[1] = op2;
|
||||
add_instr(isel, &out);
|
||||
}
|
||||
|
||||
static inline scc_mir_operand_t reg_operand(scc_x86_reg_t reg) {
|
||||
return (scc_mir_operand_t){.kind = SCC_MIR_OP_PREG, .preg = reg};
|
||||
}
|
||||
|
||||
// Utils
|
||||
|
||||
void scc_x86_emit_move(scc_x86_64_isel_t *isel, scc_mir_operand_t dst,
|
||||
scc_mir_operand_t src, u8 size);
|
||||
scc_mir_operand_t scc_x86_lir_val_to_mir_op(scc_x86_64_isel_t *isel,
|
||||
const scc_lir_val_t *val);
|
||||
static inline void emit_call(scc_x86_64_isel_t *isel, const char *callee) {
|
||||
scc_mir_operand_t sym = {.kind = SCC_MIR_OP_SYMBOL, .symbol = callee};
|
||||
add_instr_1(isel, SCC_X86_IFORM_CALL_NEAR_GPRV, sym);
|
||||
}
|
||||
static inline void emit_ret(scc_x86_64_isel_t *isel) {
|
||||
add_instr_0(isel, SCC_X86_IFORM_RET_NEAR);
|
||||
}
|
||||
|
||||
#endif /* __SCC_X86_64_ISEL_H__ */
|
||||
@@ -1,8 +0,0 @@
|
||||
#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__ */
|
||||
@@ -4,9 +4,12 @@
|
||||
#include "../scc_mir_module.h"
|
||||
#include <scc_lir_module.h>
|
||||
|
||||
// 所有回调通过 void* userdata / void* out_op 保持类型无关
|
||||
typedef void (*scc_abi_lower_fn)(void *user_data, const scc_lir_instr_t *instr);
|
||||
typedef scc_mir_operand_t (*scc_abi_lower_param_fn)(void *userdata,
|
||||
const scc_lir_val_t *val);
|
||||
// lower_param 将 LIR 值转化为后端操作数,写入 out_op(后端知道实际类型)
|
||||
typedef void (*scc_abi_lower_param_fn)(void *userdata,
|
||||
const scc_lir_val_t *val,
|
||||
void *out_op);
|
||||
|
||||
typedef struct scc_abi_lowering {
|
||||
scc_abi_lower_fn lower_call;
|
||||
|
||||
@@ -7,37 +7,46 @@ typedef enum {
|
||||
SCC_REG_ALLOC_OP_ACCESS_READ = 0,
|
||||
SCC_REG_ALLOC_OP_ACCESS_WRITE = 1,
|
||||
SCC_REG_ALLOC_OP_ACCESS_READWRITE = 2,
|
||||
} scc_op_access_t;
|
||||
} scc_reg_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
|
||||
void (*emit_reload)(scc_mir_instr_vec_t *ctx, int preg, int slot);
|
||||
// preg → preg
|
||||
void (*emit_copy)(scc_mir_instr_vec_t *ctx, int dst_preg, int src_preg,
|
||||
int size);
|
||||
|
||||
// 通用寄存器申请 / 释放
|
||||
int (*acquire_reg)(void *ctx); // 返回一个物理寄存器编号
|
||||
void (*release_reg)(void *ctx, int preg); // 归还该寄存器
|
||||
|
||||
// 显式标记某个寄存器已占用 / 未占用(用于隐式寄存器、固定分配等)
|
||||
// ── 寄存器池 ──
|
||||
int (*acquire_reg)(void *ctx);
|
||||
void (*release_reg)(void *ctx, int preg);
|
||||
void (*mark_reg_used)(void *ctx, int preg);
|
||||
void (*clean_mark_regs)(void *ctx);
|
||||
|
||||
// ---- 指令信息查询(只读) ----
|
||||
scc_op_access_t (*get_operand_access)(void *ctx, int opcode, int op_idx);
|
||||
// ── 指令信息 ──
|
||||
int (*instr_opcode)(const void *instr);
|
||||
int (*instr_num_operands)(const void *instr);
|
||||
bool (*op_is_vreg)(const void *instr, int idx);
|
||||
int (*op_get_vreg)(const void *instr, int idx);
|
||||
void (*op_set_preg)(void *instr, int idx, int preg);
|
||||
void (*op_set_slot)(void *instr, int idx, int slot);
|
||||
// 读写属性与隐式寄存器
|
||||
scc_reg_op_access_t (*get_operand_access)(void *ctx, int opcode,
|
||||
int op_idx);
|
||||
void (*get_implicit_regs)(void *ctx, int opcode, const int **out_uses,
|
||||
const int **out_defs);
|
||||
|
||||
// ── 伪指令处理 ──
|
||||
bool (*is_pseudo)(const void *instr);
|
||||
void (*handle_pseudo)(scc_mir_func_t *func, void *instr, void *out);
|
||||
|
||||
// ── 溢出/重载(写入 out 向量) ──
|
||||
void (*emit_spill)(void *out, int preg, int slot);
|
||||
void (*emit_reload)(void *out, int preg, int slot);
|
||||
void (*emit_copy)(void *out, int dst_preg, int src_preg, int size);
|
||||
} scc_reg_alloc_op_t;
|
||||
|
||||
typedef struct scc_reg_alloc_ctx {
|
||||
scc_reg_alloc_op_t ops;
|
||||
scc_mir_module_t *module;
|
||||
scc_mir_func_t *func;
|
||||
scc_mir_instr_vec_t *instrs;
|
||||
} scc_reg_alloc_ctx_t;
|
||||
|
||||
// 通用寄存器分配入口:遍历所有函数/基本块,对每条指令做 vreg → preg 分配
|
||||
void scc_reg_alloc(scc_reg_alloc_ctx_t *ctx, scc_mir_module_t *module);
|
||||
|
||||
#endif /* __SCC_REG_ALLOC__ */
|
||||
#endif /* __SCC_REG_ALLOC_H__ */
|
||||
|
||||
@@ -1,53 +1,29 @@
|
||||
// scc_mir.h (示意)
|
||||
|
||||
#ifndef __SCC_MIR_H__
|
||||
#define __SCC_MIR_H__
|
||||
|
||||
#include <scc_lir.h>
|
||||
#include <scc_cfg.h>
|
||||
|
||||
// 伪指令 opcode(负数),所有后端通用约定
|
||||
typedef enum {
|
||||
SCC_MIR_OP_NONE,
|
||||
SCC_MIR_OP_STACK_OFFSET, // 已分配的内存
|
||||
SCC_MIR_OP_STACK_SLOT, // 栈空间
|
||||
SCC_MIR_OP_VREG, // 虚拟寄存器
|
||||
SCC_MIR_OP_PREG, // 物理寄存器
|
||||
SCC_MIR_OP_IMM, // 立即数
|
||||
SCC_MIR_OP_SYMBOL, // 符号地址(用于重定位)
|
||||
SCC_MIR_OP_BLOCK // 基本块引用(label)
|
||||
} scc_mir_op_kind_t;
|
||||
|
||||
typedef struct scc_mir_operand {
|
||||
scc_mir_op_kind_t kind;
|
||||
union {
|
||||
int vreg; // 虚拟寄存器索引
|
||||
int preg; // 物理寄存器
|
||||
i64 imm; // 立即数
|
||||
const char *symbol; // 符号名
|
||||
int stack_slot; // 栈槽 ID (由 FrameLayout 分配)
|
||||
int stack_offset; // 栈偏移
|
||||
scc_lir_bblock_id_t block_id; // 目标基本块
|
||||
};
|
||||
} scc_mir_operand_t;
|
||||
|
||||
typedef enum {
|
||||
SCC_MIR_PSUEDO_ALLOCA = -1,
|
||||
} scc_mir_psuedo_op_t;
|
||||
SCC_MIR_PSEUDO_NONE = 0,
|
||||
SCC_MIR_PSEUDO_ALLOCA = -1,
|
||||
SCC_MIR_PSEUDO_VA_START = -2,
|
||||
} scc_mir_pseudo_t;
|
||||
|
||||
typedef struct scc_mir_instr {
|
||||
int opcode; // 目标特定的指令编码 (如 X86::ADD32rr)
|
||||
int num_operands; // 实际使用的操作数个数
|
||||
scc_mir_operand_t
|
||||
operands[8]; // 固定小数组,RISC 风格指令通常不超过 4 操作数
|
||||
scc_pos_t src_loc; // 调试信息 (继承自 LIR)
|
||||
int opcode;
|
||||
union {
|
||||
struct {
|
||||
int size;
|
||||
int align;
|
||||
int vreg;
|
||||
} alloc;
|
||||
} data;
|
||||
} scc_mir_instr_t;
|
||||
typedef SCC_VEC(scc_mir_instr_t) scc_mir_instr_vec_t;
|
||||
|
||||
typedef scc_cfg_bblock_t scc_mir_bblock_t;
|
||||
typedef struct scc_mir_bblock_meta {
|
||||
} scc_mir_bblock_meta_t;
|
||||
#define SCC_MIR_BBLOCK_VALUES(bblock) \
|
||||
((scc_mir_instr_vec_t *)&((bblock)->values))
|
||||
#define SCC_MIR_BBLOCK_VALUES_PTR(bb) ((void *)(&(bb)->values))
|
||||
|
||||
// 栈槽信息(由 FrameLayout Pass 填充)
|
||||
typedef struct scc_mir_stack_slot {
|
||||
int slot_id;
|
||||
int size; // 通常是 8 字节 (指针大小)
|
||||
@@ -56,18 +32,22 @@ typedef struct scc_mir_stack_slot {
|
||||
} scc_mir_stack_slot_t;
|
||||
typedef SCC_VEC(scc_mir_stack_slot_t) scc_mir_stack_slot_vec_t;
|
||||
|
||||
typedef scc_cfg_bblock_t scc_mir_bblock_t;
|
||||
|
||||
// 函数元数据 —— 不包含任何指令结构,由各后端自行定义指令布局
|
||||
typedef scc_cfg_func_t scc_mir_func_t;
|
||||
typedef struct scc_mir_func_meta {
|
||||
// 栈帧信息 (由 FrameLayout Pass 填充)
|
||||
int frame_size;
|
||||
int stack_alignment;
|
||||
int vregs_count;
|
||||
|
||||
// 寄存器分配信息
|
||||
void *target_data; // 目标后端私有数据,例如 x86_64_func_info_t*
|
||||
|
||||
scc_mir_stack_slot_vec_t stack_slots;
|
||||
// vreg -> phys reg and stack slot index
|
||||
// positive means stack slot index
|
||||
// negative means physic register
|
||||
// vreg -> phys reg / stack slot
|
||||
// 0 = not mapped (still a vreg)
|
||||
// >0 = stack slot index
|
||||
// <0 = physical register (negated)
|
||||
scc_hashtable_t vreg2physic;
|
||||
} scc_mir_func_meta_t;
|
||||
#define SCC_MIR_FUNC_META(func) ((scc_mir_func_meta_t *)(func)->meta)
|
||||
@@ -75,11 +55,28 @@ typedef struct scc_mir_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);
|
||||
|
||||
// 从 vreg2physic 表中查询映射结果:
|
||||
// 返回 0 → 该 vreg 仍为 vreg,未映射
|
||||
// 返回 1 → 已映射到物理寄存器,*out_preg 有效
|
||||
// 返回 -1 → 已溢出到栈槽,*out_slot 有效
|
||||
static inline int scc_mir_vreg_lookup(const scc_mir_func_t *func, int vreg,
|
||||
int *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)
|
||||
return 0;
|
||||
if (idx < 0) {
|
||||
*out = (int)-idx;
|
||||
return 1;
|
||||
}
|
||||
*out = (int)idx;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static inline scc_mir_stack_slot_t *
|
||||
scc_mir_unsafe_slot(const scc_mir_func_t *func, int slot) {
|
||||
Assert(slot > 0);
|
||||
|
||||
@@ -4,9 +4,13 @@
|
||||
#include "scc_mir.h"
|
||||
#include <scc_lir_module.h>
|
||||
|
||||
typedef SCC_VEC(char) scc_mir_instr_vec_t;
|
||||
|
||||
typedef scc_lir_symbol_meta_vec_t scc_mir_symbol_meta_vec_t;
|
||||
|
||||
typedef SCC_VEC(scc_mir_func_meta_t *) scc_mir_func_meta_vec_t;
|
||||
typedef struct scc_mir_module {
|
||||
usize instr_size;
|
||||
scc_cfg_module_t cfg_module;
|
||||
scc_mir_func_meta_vec_t func_metas;
|
||||
scc_mir_symbol_meta_vec_t symbol_metas;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#ifndef __SCC_WIN64_H__
|
||||
#define __SCC_WIN64_H__
|
||||
|
||||
#include "../arch/x86_64_isel.h"
|
||||
#include "../arch/scc_x86_isel.h"
|
||||
#include "../core_pass/scc_frame_layout.h"
|
||||
#include "../core_pass/scc_prolog_epilog.h"
|
||||
#include "../core_pass/scc_reg_alloc.h"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#include <arch/x86_64_isel.h>
|
||||
#include <arch/scc_x86_isel.h>
|
||||
|
||||
#include <x86/scc_x86_iform.c>
|
||||
#include <x86/scc_x86_reg.c>
|
||||
@@ -9,73 +9,77 @@ static const char *preg_name(int preg_id) {
|
||||
return scc_x86_reg_table[preg_id].display_str;
|
||||
}
|
||||
|
||||
void scc_x86_instr_dump(scc_tree_dump_t *td, const scc_mir_instr_t *instr) {
|
||||
scc_x86_iform_t iform = instr->opcode;
|
||||
void scc_x86_instr_dump(scc_tree_dump_t *td, const scc_mir_x86_instr_t *instr) {
|
||||
if (instr->x86_instr.opcode >= SCC_X86_IFORM_COUNT ||
|
||||
instr->x86_instr.opcode < 0) {
|
||||
scc_tree_dump_append_fmt(td, " ???");
|
||||
return;
|
||||
}
|
||||
scc_x86_iform_t iform = instr->x86_instr.opcode;
|
||||
const scc_x86_iform_info_t *info = &scc_x86_iform_table[iform];
|
||||
scc_tree_dump_append_fmt(td, " %s", info->iform_name);
|
||||
// Assert(instr->num_operands == info->num_ops);
|
||||
for (int i = 0; i < instr->num_operands; i += 1) {
|
||||
for (int i = 0; i < instr->x86_instr.num_operands; i += 1) {
|
||||
if (i == 0)
|
||||
scc_tree_dump_append(td, " ");
|
||||
else
|
||||
scc_tree_dump_append_fmt(td, ", ");
|
||||
scc_mir_operand_t *op = &instr->operands[i];
|
||||
const scc_x86_operand_value_t *op = &instr->x86_instr.operands[i];
|
||||
switch (op->kind) {
|
||||
case SCC_MIR_OP_VREG:
|
||||
scc_tree_dump_append_fmt(td, "%%%d", op->vreg);
|
||||
case SCC_X86_OPR_REG:
|
||||
if (scc_x86_op_is_vreg(op))
|
||||
scc_tree_dump_append_fmt(td, "%%%d", scc_x86_op_get_vreg(op));
|
||||
else
|
||||
scc_tree_dump_append_fmt(td, "$%s", preg_name(op->reg));
|
||||
break;
|
||||
case SCC_MIR_OP_PREG:
|
||||
scc_tree_dump_append_fmt(td, "$%s", preg_name(op->preg));
|
||||
break;
|
||||
case SCC_MIR_OP_IMM:
|
||||
case SCC_X86_OPR_IMM:
|
||||
scc_tree_dump_append_fmt(td, "%ld", op->imm);
|
||||
break;
|
||||
case SCC_MIR_OP_BLOCK:
|
||||
scc_tree_dump_append_fmt(td, "#BB%d", op->block_id);
|
||||
case SCC_X86_OPR_MEM:
|
||||
if (scc_x86_op_is_slot(op))
|
||||
scc_tree_dump_append_fmt(td, "[slot:%d]",
|
||||
scc_x86_op_slot_id(op));
|
||||
else
|
||||
scc_tree_dump_append_fmt(td, "[sp%+d]", op->mem.disp);
|
||||
break;
|
||||
case SCC_MIR_OP_SYMBOL:
|
||||
scc_tree_dump_append_fmt(td, "@%s", op->symbol);
|
||||
case SCC_X86_OPR_RELBR:
|
||||
scc_tree_dump_append(td, "label");
|
||||
break;
|
||||
case SCC_MIR_OP_STACK_SLOT:
|
||||
scc_tree_dump_append_fmt(td, "[%d]", op->stack_slot);
|
||||
break;
|
||||
case SCC_MIR_OP_STACK_OFFSET:
|
||||
scc_tree_dump_append_fmt(td, "[sp, %d]", op->stack_offset);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 将 LIR 值转换为 MIR 操作数
|
||||
scc_mir_operand_t scc_x86_lir_val_to_mir_op(scc_x86_64_isel_t *isel,
|
||||
const scc_lir_val_t *val) {
|
||||
scc_mir_operand_t op = {0};
|
||||
// 将 LIR 值转换为 x86 操作数
|
||||
scc_x86_operand_value_t scc_x86_lir_val_to_mir_op(scc_x86_64_isel_t *isel,
|
||||
const scc_lir_val_t *val) {
|
||||
scc_x86_operand_value_t op = {0};
|
||||
switch (val->kind) {
|
||||
case SCC_LIR_INSTR_KIND_NONE:
|
||||
op.kind = SCC_MIR_OP_NONE;
|
||||
op.kind = SCC_X86_OPR_NONE;
|
||||
break;
|
||||
case SCC_LIR_INSTR_KIND_VREG:
|
||||
op.kind = SCC_MIR_OP_VREG;
|
||||
op.vreg = val->data.reg;
|
||||
op = scc_x86_op_vreg(val->data.reg);
|
||||
int id = 0;
|
||||
int ret = scc_mir_vreg_lookup(isel->func, val->data.reg, &id);
|
||||
if (ret > 0) {
|
||||
op = scc_x86_op_preg(id);
|
||||
} else if (ret < 0) {
|
||||
op = scc_x86_op_slot(id);
|
||||
}
|
||||
break;
|
||||
case SCC_LIR_INSTR_KIND_IMM:
|
||||
op.kind = SCC_MIR_OP_IMM;
|
||||
// FIXME hack ap
|
||||
op.imm = val->data.imm.data.digit;
|
||||
op = scc_x86_op_imm(val->data.imm.data.digit);
|
||||
break;
|
||||
case SCC_LIR_INSTR_KIND_FIMM:
|
||||
// 浮点立即数暂时作为普通立即数处理(后端需特殊处理)
|
||||
op.kind = SCC_MIR_OP_IMM;
|
||||
op.imm = *(i64 *)&val->data.fimm;
|
||||
op = scc_x86_op_imm(*(i64 *)&val->data.fimm);
|
||||
break;
|
||||
case SCC_LIR_INSTR_KIND_SYMBOL:
|
||||
op.kind = SCC_MIR_OP_SYMBOL;
|
||||
op.symbol = val->data.symbol;
|
||||
op = scc_x86_op_symbol(val->data.symbol);
|
||||
break;
|
||||
case SCC_LIR_INSTR_KIND_ARG:
|
||||
Assert(isel->abi_lowering.lower_param);
|
||||
op = isel->abi_lowering.lower_param(isel, val);
|
||||
isel->abi_lowering.lower_param(isel, val, &op);
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
@@ -84,39 +88,40 @@ 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 = scc_mir_alloc_vreg(isel->func)};
|
||||
static scc_x86_operand_value_t new_vreg_temp(scc_x86_64_isel_t *isel) {
|
||||
return scc_x86_op_vreg(scc_mir_alloc_vreg(isel->func));
|
||||
}
|
||||
|
||||
void scc_x86_emit_move(scc_x86_64_isel_t *isel, scc_mir_operand_t dst,
|
||||
scc_mir_operand_t src, u8 size) {
|
||||
if (dst.kind == SCC_MIR_OP_VREG || dst.kind == SCC_MIR_OP_PREG) {
|
||||
if (src.kind == SCC_MIR_OP_VREG || src.kind == SCC_MIR_OP_PREG) {
|
||||
add_instr_2(isel, SCC_X86_IFORM_MOV_GPRV_GPRV_89, dst, src);
|
||||
} else if (src.kind == SCC_MIR_OP_IMM) {
|
||||
void scc_x86_emit_move(scc_x86_64_isel_t *isel, scc_x86_operand_value_t dst,
|
||||
scc_x86_operand_value_t src, u8 size) {
|
||||
|
||||
if (dst.kind == SCC_X86_OPR_REG) {
|
||||
if (src.kind == SCC_X86_OPR_REG) {
|
||||
add_instr_2(isel, SCC_X86_IFORM_MOV_GPRV_GPRV_8B, dst, src);
|
||||
} else if (src.kind == SCC_X86_OPR_IMM) {
|
||||
add_instr_2(isel,
|
||||
(size == 8) ? SCC_X86_IFORM_MOV_GPRV_IMMZ
|
||||
: SCC_X86_IFORM_MOV_GPRV_IMMV,
|
||||
dst, src);
|
||||
} else if (src.kind == SCC_MIR_OP_SYMBOL) {
|
||||
} else if (src.kind == SCC_X86_OPR_IMM && src.imm == 0) {
|
||||
// 特殊:符号作为立即数地址
|
||||
add_instr_2(isel, SCC_X86_IFORM_MOV_GPRV_IMMZ, dst, src);
|
||||
} else if (src.kind == SCC_MIR_OP_STACK_SLOT) {
|
||||
} else if (src.kind == SCC_X86_OPR_MEM) {
|
||||
add_instr_2(isel, SCC_X86_IFORM_MOV_GPRV_MEMV, dst, src);
|
||||
} else {
|
||||
UNREACHABLE();
|
||||
}
|
||||
} else if (dst.kind == SCC_MIR_OP_STACK_SLOT) {
|
||||
if (src.kind == SCC_MIR_OP_VREG || src.kind == SCC_MIR_OP_PREG) {
|
||||
} else if (dst.kind == SCC_X86_OPR_MEM) {
|
||||
if (src.kind == SCC_X86_OPR_REG) {
|
||||
add_instr_2(isel, SCC_X86_IFORM_MOV_MEMV_GPRV, dst, src);
|
||||
} else if (src.kind == SCC_MIR_OP_IMM) {
|
||||
} else if (src.kind == SCC_X86_OPR_IMM) {
|
||||
add_instr_2(isel, SCC_X86_IFORM_MOV_MEMV_IMMZ, dst, src);
|
||||
} else if (src.kind == SCC_MIR_OP_SYMBOL) {
|
||||
scc_mir_operand_t temp = new_vreg_temp(isel);
|
||||
} else if (src.kind == SCC_X86_OPR_IMM) {
|
||||
scc_x86_operand_value_t temp = new_vreg_temp(isel);
|
||||
add_instr_2(isel, SCC_X86_IFORM_MOV_GPRV_IMMZ, temp, src);
|
||||
add_instr_2(isel, SCC_X86_IFORM_MOV_MEMV_GPRV, dst, temp);
|
||||
} else if (src.kind == SCC_MIR_OP_STACK_SLOT) {
|
||||
scc_mir_operand_t temp = new_vreg_temp(isel);
|
||||
} else if (src.kind == SCC_X86_OPR_MEM) {
|
||||
scc_x86_operand_value_t temp = new_vreg_temp(isel);
|
||||
scc_x86_emit_move(isel, temp, src, size);
|
||||
scc_x86_emit_move(isel, dst, temp, size);
|
||||
} else {
|
||||
@@ -127,19 +132,18 @@ void scc_x86_emit_move(scc_x86_64_isel_t *isel, scc_mir_operand_t dst,
|
||||
}
|
||||
}
|
||||
|
||||
static void emit_compare(scc_x86_64_isel_t *isel, scc_mir_operand_t op0,
|
||||
scc_mir_operand_t op1, u8 size) {
|
||||
// cmp op0, op1 (注意 x86 是 cmp a, b 即 a - b)
|
||||
if (op0.kind == SCC_MIR_OP_VREG && op1.kind == SCC_MIR_OP_IMM) {
|
||||
static void emit_compare(scc_x86_64_isel_t *isel, scc_x86_operand_value_t op0,
|
||||
scc_x86_operand_value_t op1, u8 size) {
|
||||
(void)size;
|
||||
if (scc_x86_op_is_vreg(&op0) && op1.kind == SCC_X86_OPR_IMM) {
|
||||
add_instr_2(isel, SCC_X86_IFORM_CMP_GPRV_IMMZ, op0, op1);
|
||||
} else if (op0.kind == SCC_MIR_OP_VREG && op1.kind == SCC_MIR_OP_VREG) {
|
||||
add_instr_2(isel, SCC_X86_IFORM_CMP_GPRV_GPRV_39, op0, op1);
|
||||
} else if (scc_x86_op_is_vreg(&op0) && scc_x86_op_is_vreg(&op1)) {
|
||||
add_instr_2(isel, SCC_X86_IFORM_CMP_GPRV_GPRV_3B, op0, op1);
|
||||
} else {
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
/* 条件码到 setcc 指令的映射 */
|
||||
static scc_x86_iform_t cond_to_setcc(scc_lir_cond_t cond) {
|
||||
switch (cond) {
|
||||
case SCC_LIR_COND_EQ:
|
||||
@@ -151,58 +155,61 @@ static scc_x86_iform_t cond_to_setcc(scc_lir_cond_t cond) {
|
||||
case SCC_LIR_COND_SLE:
|
||||
return SCC_X86_IFORM_SETLE_GPR8;
|
||||
case SCC_LIR_COND_SGT:
|
||||
return SCC_X86_IFORM_SETNLE_GPR8; // SETG
|
||||
return SCC_X86_IFORM_SETNLE_GPR8;
|
||||
case SCC_LIR_COND_SGE:
|
||||
return SCC_X86_IFORM_SETNL_GPR8; // SETGE
|
||||
return SCC_X86_IFORM_SETNL_GPR8;
|
||||
case SCC_LIR_COND_ULT:
|
||||
return SCC_X86_IFORM_SETB_GPR8;
|
||||
case SCC_LIR_COND_ULE:
|
||||
return SCC_X86_IFORM_SETBE_GPR8;
|
||||
case SCC_LIR_COND_UGT:
|
||||
return SCC_X86_IFORM_SETNBE_GPR8; // SETA
|
||||
return SCC_X86_IFORM_SETNBE_GPR8;
|
||||
case SCC_LIR_COND_UGE:
|
||||
return SCC_X86_IFORM_SETNB_GPR8; // SETAE
|
||||
return SCC_X86_IFORM_SETNB_GPR8;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
static void emit_copy_if_needed(scc_x86_64_isel_t *isel, scc_mir_operand_t dst,
|
||||
scc_mir_operand_t src0, u8 size) {
|
||||
if (dst.kind == SCC_MIR_OP_VREG && src0.kind == SCC_MIR_OP_VREG &&
|
||||
dst.vreg == src0.vreg) {
|
||||
static void emit_copy_if_needed(scc_x86_64_isel_t *isel,
|
||||
scc_x86_operand_value_t dst,
|
||||
scc_x86_operand_value_t src0, u8 size) {
|
||||
if (scc_x86_op_is_vreg(&dst) && scc_x86_op_is_vreg(&src0) &&
|
||||
scc_x86_op_get_vreg(&dst) == scc_x86_op_get_vreg(&src0)) {
|
||||
return;
|
||||
}
|
||||
scc_x86_emit_move(isel, dst, src0, size);
|
||||
}
|
||||
|
||||
static void emit_binary_op(scc_x86_64_isel_t *isel, scc_lir_op_t op,
|
||||
scc_mir_operand_t dst, scc_mir_operand_t src0,
|
||||
scc_mir_operand_t src1, u8 size) {
|
||||
scc_x86_operand_value_t dst,
|
||||
scc_x86_operand_value_t src0,
|
||||
scc_x86_operand_value_t src1, u8 size) {
|
||||
(void)size;
|
||||
emit_copy_if_needed(isel, dst, src0, size);
|
||||
|
||||
bool is_imm = (src1.kind == SCC_MIR_OP_IMM);
|
||||
bool is_imm = (src1.kind == SCC_X86_OPR_IMM);
|
||||
scc_x86_iform_t iform;
|
||||
switch (op) {
|
||||
case SCC_LIR_ADD:
|
||||
iform = is_imm ? SCC_X86_IFORM_ADD_GPRV_IMMZ
|
||||
: SCC_X86_IFORM_ADD_GPRV_GPRV_01;
|
||||
: SCC_X86_IFORM_ADD_GPRV_GPRV_03;
|
||||
break;
|
||||
case SCC_LIR_SUB:
|
||||
iform = is_imm ? SCC_X86_IFORM_SUB_GPRV_IMMZ
|
||||
: SCC_X86_IFORM_SUB_GPRV_GPRV_29;
|
||||
: SCC_X86_IFORM_SUB_GPRV_GPRV_2B;
|
||||
break;
|
||||
case SCC_LIR_AND:
|
||||
iform = is_imm ? SCC_X86_IFORM_AND_GPRV_IMMZ
|
||||
: SCC_X86_IFORM_AND_GPRV_GPRV_21;
|
||||
: SCC_X86_IFORM_AND_GPRV_GPRV_23;
|
||||
break;
|
||||
case SCC_LIR_OR:
|
||||
iform =
|
||||
is_imm ? SCC_X86_IFORM_OR_GPRV_IMMZ : SCC_X86_IFORM_OR_GPRV_GPRV_09;
|
||||
is_imm ? SCC_X86_IFORM_OR_GPRV_IMMZ : SCC_X86_IFORM_OR_GPRV_GPRV_0B;
|
||||
break;
|
||||
case SCC_LIR_XOR:
|
||||
iform = is_imm ? SCC_X86_IFORM_XOR_GPRV_IMMZ
|
||||
: SCC_X86_IFORM_XOR_GPRV_GPRV_31;
|
||||
: SCC_X86_IFORM_XOR_GPRV_GPRV_33;
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
@@ -210,33 +217,22 @@ static void emit_binary_op(scc_x86_64_isel_t *isel, scc_lir_op_t op,
|
||||
add_instr_2(isel, iform, dst, src1);
|
||||
}
|
||||
|
||||
static scc_mir_operand_t stack_slot_op(int offset) {
|
||||
return (scc_mir_operand_t){.kind = SCC_MIR_OP_STACK_SLOT,
|
||||
.stack_slot = offset};
|
||||
static void emit_spill_load(scc_x86_64_isel_t *isel, int vreg, int slot) {
|
||||
scc_x86_operand_value_t dst = scc_x86_op_vreg(vreg);
|
||||
add_instr_2(isel, SCC_X86_IFORM_MOV_GPRV_MEMV, dst, scc_x86_op_slot(slot));
|
||||
}
|
||||
|
||||
static void emit_spill_load(scc_x86_64_isel_t *isel, int vreg, int offset) {
|
||||
scc_mir_operand_t dst = {.kind = SCC_MIR_OP_VREG, .vreg = vreg};
|
||||
add_instr_2(isel, SCC_X86_IFORM_MOV_GPRV_MEMV, dst, stack_slot_op(offset));
|
||||
static void emit_spill_store(scc_x86_64_isel_t *isel, int vreg, int slot) {
|
||||
scc_x86_operand_value_t src = scc_x86_op_vreg(vreg);
|
||||
add_instr_2(isel, SCC_X86_IFORM_MOV_MEMV_GPRV, scc_x86_op_slot(slot), src);
|
||||
}
|
||||
|
||||
static void emit_spill_store(scc_x86_64_isel_t *isel, int vreg, int offset) {
|
||||
scc_mir_operand_t src = {.kind = SCC_MIR_OP_VREG, .vreg = vreg};
|
||||
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 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 src0 = scc_x86_lir_val_to_mir_op(isel, &instr->arg0);
|
||||
scc_mir_operand_t src1 = scc_x86_lir_val_to_mir_op(isel, &instr->arg1);
|
||||
scc_x86_operand_value_t dst = scc_x86_lir_val_to_mir_op(isel, &instr->to);
|
||||
scc_x86_operand_value_t src0 =
|
||||
scc_x86_lir_val_to_mir_op(isel, &instr->arg0);
|
||||
scc_x86_operand_value_t src1 =
|
||||
scc_x86_lir_val_to_mir_op(isel, &instr->arg1);
|
||||
u8 size = instr->size;
|
||||
|
||||
switch (instr->op) {
|
||||
@@ -244,23 +240,19 @@ static void sel_mir(scc_x86_64_isel_t *isel, const scc_lir_instr_t *instr) {
|
||||
case SCC_LIR_MOV:
|
||||
scc_x86_emit_move(isel, dst, src0, size);
|
||||
break;
|
||||
|
||||
case SCC_LIR_LOAD:
|
||||
// 从 [addr] 加载到 vreg(addr 通常为 vreg)
|
||||
add_instr_2(isel, SCC_X86_IFORM_MOV_GPRV_MEMV, dst, src0);
|
||||
scc_x86_emit_move(isel, dst, src0, size);
|
||||
break;
|
||||
case SCC_LIR_STORE:
|
||||
scc_x86_emit_move(isel, src1, src0, size);
|
||||
break;
|
||||
|
||||
case SCC_LIR_STORE_ADDR:
|
||||
TODO();
|
||||
break;
|
||||
case SCC_LIR_STORE:
|
||||
// 将 src0 存入 [src1]
|
||||
add_instr_2(isel, SCC_X86_IFORM_MOV_MEMV_GPRV, src1, src0);
|
||||
break;
|
||||
|
||||
case SCC_LIR_LEA:
|
||||
case SCC_LIR_LOAD_ADDR:
|
||||
// 地址计算,src0 是复杂地址(LIR 的 MEM 类型)
|
||||
add_instr_2(isel, SCC_X86_IFORM_LEA_GPRV_AGEN, dst, src0);
|
||||
break;
|
||||
|
||||
@@ -282,10 +274,9 @@ static void sel_mir(scc_x86_64_isel_t *isel, const scc_lir_instr_t *instr) {
|
||||
break;
|
||||
|
||||
case SCC_LIR_MUL:
|
||||
// imul dst, src0, src1 → 需要 mov + imul
|
||||
emit_copy_if_needed(isel, dst, src0, size);
|
||||
if (src1.kind == SCC_MIR_OP_IMM) {
|
||||
scc_mir_operand_t op = new_vreg_temp(isel);
|
||||
if (src1.kind == SCC_X86_OPR_IMM) {
|
||||
scc_x86_operand_value_t op = new_vreg_temp(isel);
|
||||
scc_x86_emit_move(isel, op, src1, size);
|
||||
src1 = op;
|
||||
}
|
||||
@@ -295,10 +286,9 @@ static void sel_mir(scc_x86_64_isel_t *isel, const scc_lir_instr_t *instr) {
|
||||
case SCC_LIR_SHL:
|
||||
case SCC_LIR_SHR:
|
||||
case SCC_LIR_SAR: {
|
||||
// 双地址:dst = dst op count
|
||||
emit_copy_if_needed(isel, dst, src0, size);
|
||||
|
||||
if (src1.kind == SCC_MIR_OP_IMM) {
|
||||
if (src1.kind == SCC_X86_OPR_IMM) {
|
||||
scc_x86_iform_t iform;
|
||||
switch (instr->op) {
|
||||
case SCC_LIR_SHL:
|
||||
@@ -315,10 +305,8 @@ static void sel_mir(scc_x86_64_isel_t *isel, const scc_lir_instr_t *instr) {
|
||||
}
|
||||
add_instr_2(isel, iform, dst, src1);
|
||||
} else {
|
||||
// 移位量在 CL(需要先 mov cl, src1)
|
||||
scc_mir_operand_t cl = {.kind = SCC_MIR_OP_PREG,
|
||||
.preg = SCC_X86_REG_CL};
|
||||
scc_x86_emit_move(isel, cl, src1, 1); // CL 是 8 位
|
||||
scc_x86_operand_value_t cl = scc_x86_op_preg(SCC_X86_REG_CL);
|
||||
scc_x86_emit_move(isel, cl, src1, 1);
|
||||
scc_x86_iform_t iform;
|
||||
switch (instr->op) {
|
||||
case SCC_LIR_SHL:
|
||||
@@ -342,19 +330,15 @@ static void sel_mir(scc_x86_64_isel_t *isel, const scc_lir_instr_t *instr) {
|
||||
case SCC_LIR_DIV_U:
|
||||
case SCC_LIR_REM_S:
|
||||
case SCC_LIR_REM_U: {
|
||||
scc_mir_operand_t rax = {.kind = SCC_MIR_OP_PREG,
|
||||
.preg = SCC_X86_REG_RAX};
|
||||
scc_mir_operand_t rdx = {.kind = SCC_MIR_OP_PREG,
|
||||
.preg = SCC_X86_REG_RDX};
|
||||
scc_x86_operand_value_t rax = scc_x86_op_preg(SCC_X86_REG_RAX);
|
||||
scc_x86_operand_value_t rdx = scc_x86_op_preg(SCC_X86_REG_RDX);
|
||||
|
||||
scc_x86_emit_move(isel, rax, src0, size);
|
||||
|
||||
if (instr->op == SCC_LIR_DIV_S || instr->op == SCC_LIR_REM_S) {
|
||||
// 有符号扩展:cqo / cdq(根据 size 选择,这里简化为 64 位 cqo)
|
||||
add_instr_0(isel, SCC_X86_IFORM_CQO);
|
||||
} else {
|
||||
// 无符号:xor edx, edx
|
||||
scc_mir_operand_t zero = {.kind = SCC_MIR_OP_IMM, .imm = 0};
|
||||
scc_x86_operand_value_t zero = scc_x86_op_imm(0);
|
||||
scc_x86_emit_move(isel, rdx, zero, size);
|
||||
}
|
||||
|
||||
@@ -364,7 +348,6 @@ static void sel_mir(scc_x86_64_isel_t *isel, const scc_lir_instr_t *instr) {
|
||||
: SCC_X86_IFORM_DIV_GPRV;
|
||||
add_instr_1(isel, div_if, src1);
|
||||
|
||||
// 结果:商在 RAX,余数在 RDX
|
||||
if (instr->op == SCC_LIR_REM_S || instr->op == SCC_LIR_REM_U)
|
||||
scc_x86_emit_move(isel, dst, rdx, size);
|
||||
else
|
||||
@@ -373,68 +356,57 @@ static void sel_mir(scc_x86_64_isel_t *isel, const scc_lir_instr_t *instr) {
|
||||
|
||||
/* ---- 比较指令 ---- */
|
||||
case SCC_LIR_CMP: {
|
||||
// 1. 比较并设置标志位
|
||||
if (src0.kind == SCC_MIR_OP_VREG && src1.kind == SCC_MIR_OP_IMM)
|
||||
if (scc_x86_op_is_vreg(&src0) && src1.kind == SCC_X86_OPR_IMM)
|
||||
add_instr_2(isel, SCC_X86_IFORM_CMP_GPRV_IMMZ, src0, src1);
|
||||
else if (src0.kind == SCC_MIR_OP_VREG && src1.kind == SCC_MIR_OP_VREG)
|
||||
add_instr_2(isel, SCC_X86_IFORM_CMP_GPRV_GPRV_39, src0, src1);
|
||||
else if (scc_x86_op_is_vreg(&src0) && scc_x86_op_is_vreg(&src1))
|
||||
add_instr_2(isel, SCC_X86_IFORM_CMP_GPRV_GPRV_3B, src0, src1);
|
||||
else
|
||||
UNREACHABLE();
|
||||
|
||||
// 2. 标志位 -> 布尔值 (写入 dst)
|
||||
scc_x86_iform_t setcc = cond_to_setcc(instr->metadata.cond);
|
||||
add_instr_1(isel, setcc, dst); // 注意 setcc 只写低 8 位
|
||||
// 若需 32/64 位布尔值,可再 movzx dst, dst
|
||||
add_instr_1(isel, setcc, dst);
|
||||
if (size > 1) {
|
||||
// movzx dst, dst (假设 MOVZX_GPRV_GPR8 存在;这里临时用 and 模拟)
|
||||
// 简单处理:用 and dst, 1 清理高位
|
||||
scc_mir_operand_t one = {.kind = SCC_MIR_OP_IMM, .imm = 1};
|
||||
scc_x86_operand_value_t one = scc_x86_op_imm(1);
|
||||
add_instr_2(isel, SCC_X86_IFORM_AND_GPRV_IMMZ, dst, one);
|
||||
}
|
||||
} break;
|
||||
|
||||
/* ---- 条件分支 ---- */
|
||||
case SCC_LIR_BR: {
|
||||
// arg0 是 CMP 产生的布尔值 (0 或 1)
|
||||
// test src0, src0 ; jnz true_bb ; jmp false_bb
|
||||
scc_mir_operand_t true_bb = {.kind = SCC_MIR_OP_BLOCK,
|
||||
.block_id =
|
||||
instr->metadata.br.true_target};
|
||||
scc_mir_operand_t false_bb = {.kind = SCC_MIR_OP_BLOCK,
|
||||
.block_id =
|
||||
instr->metadata.br.false_target};
|
||||
scc_x86_operand_value_t true_bb =
|
||||
scc_x86_op_block(instr->metadata.br.true_target);
|
||||
scc_x86_operand_value_t false_bb =
|
||||
scc_x86_op_block(instr->metadata.br.false_target);
|
||||
|
||||
// test src0, src0
|
||||
add_instr_2(isel, SCC_X86_IFORM_TEST_GPRV_GPRV, src0, src0);
|
||||
// jnz true
|
||||
add_instr_1(isel, SCC_X86_IFORM_JNZ_RELBRZ, true_bb);
|
||||
// jmp false
|
||||
add_instr_1(isel, SCC_X86_IFORM_JMP_RELBRZ, false_bb);
|
||||
} break;
|
||||
|
||||
case SCC_LIR_JMP: {
|
||||
add_instr_1(
|
||||
isel, SCC_X86_IFORM_JMP_RELBRZ,
|
||||
(scc_mir_operand_t){.kind = SCC_MIR_OP_BLOCK,
|
||||
.block_id = instr->metadata.jmp_target});
|
||||
scc_x86_operand_value_t jmp_bb =
|
||||
scc_x86_op_block(instr->metadata.jmp_target);
|
||||
add_instr_1(isel, SCC_X86_IFORM_JMP_RELBRZ, jmp_bb);
|
||||
} break;
|
||||
|
||||
/* ---- 栈分配 ---- */
|
||||
case SCC_LIR_ALLOCA:
|
||||
// emit_alloca(isel, dst, instr->metadata.alloca.size_bytes);
|
||||
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);
|
||||
// FIXME
|
||||
scc_mir_vreg_map2slot(isel->func, op.vreg, instr->size, 8);
|
||||
case SCC_LIR_ALLOCA: {
|
||||
scc_x86_operand_value_t op =
|
||||
scc_x86_lir_val_to_mir_op(isel, &instr->to);
|
||||
scc_mir_x86_instr_t x86instr;
|
||||
x86instr.instr.opcode = SCC_MIR_PSEUDO_ALLOCA;
|
||||
Assert(op.kind == SCC_X86_OPR_REG);
|
||||
x86instr.instr.data.alloc.vreg = op.reg;
|
||||
x86instr.instr.data.alloc.size = instr->size;
|
||||
x86instr.instr.data.alloc.align = 0;
|
||||
scc_vec_push(isel->instrs, x86instr);
|
||||
scc_mir_vreg_map2slot(isel->func, instr->to.data.reg, instr->size, 0);
|
||||
break;
|
||||
}
|
||||
|
||||
/* ---- 其他(占位) ---- */
|
||||
case SCC_LIR_NOP:
|
||||
add_instr_0(isel, SCC_X86_IFORM_NOP_90);
|
||||
break;
|
||||
|
||||
/* ---- 调用与返回 ---- */
|
||||
@@ -475,6 +447,7 @@ void scc_isel_x86_64(scc_mir_module_t *mir_module,
|
||||
const scc_lir_module_t *lir_module,
|
||||
scc_x86_64_isel_t *isel) {
|
||||
|
||||
mir_module->instr_size = sizeof(scc_mir_x86_instr_t);
|
||||
scc_vec_foreach(lir_module->cfg_module.funcs, i) {
|
||||
if (i == 0)
|
||||
continue;
|
||||
@@ -484,7 +457,6 @@ 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);
|
||||
// FIXME
|
||||
func_meta->vregs_count = SCC_LIR_FUNC_META(func)->vregs_count;
|
||||
func->meta = func_meta;
|
||||
|
||||
201
libs/ir/mir/src/arch/scc_x86_reg_alloc.c
Normal file
201
libs/ir/mir/src/arch/scc_x86_reg_alloc.c
Normal file
@@ -0,0 +1,201 @@
|
||||
#include <arch/scc_x86_isel.h>
|
||||
#include <arch/scc_x86_mir.h>
|
||||
#include <arch/scc_x86_reg_alloc.h>
|
||||
#include <x86/scc_x86_iform.h>
|
||||
#include <x86/scc_x86_reg.h>
|
||||
|
||||
/* ========== 指令访问回调 ========== */
|
||||
|
||||
static int instr_opcode(const void *instr) {
|
||||
return ((const scc_mir_x86_instr_t *)instr)->x86_instr.opcode;
|
||||
}
|
||||
static int instr_num_operands(const void *instr) {
|
||||
return ((const scc_mir_x86_instr_t *)instr)->x86_instr.num_operands;
|
||||
}
|
||||
static bool op_is_vreg(const void *instr, int idx) {
|
||||
return scc_x86_op_is_vreg(
|
||||
&((const scc_mir_x86_instr_t *)instr)->x86_instr.operands[idx]);
|
||||
}
|
||||
static int op_get_vreg(const void *instr, int idx) {
|
||||
return scc_x86_op_get_vreg(
|
||||
&((const scc_mir_x86_instr_t *)instr)->x86_instr.operands[idx]);
|
||||
}
|
||||
static void op_set_preg(void *instr, int idx, int preg) {
|
||||
scc_x86_op_set_preg(
|
||||
&((scc_mir_x86_instr_t *)instr)->x86_instr.operands[idx],
|
||||
(scc_x86_reg_t)preg);
|
||||
}
|
||||
static void op_set_slot(void *instr, int idx, int slot) {
|
||||
((scc_mir_x86_instr_t *)instr)->x86_instr.operands[idx] =
|
||||
scc_x86_op_slot(slot);
|
||||
}
|
||||
|
||||
/* ========== 伪指令处理 ========== */
|
||||
|
||||
static bool is_pseudo(const void *instr) {
|
||||
return ((const scc_mir_x86_instr_t *)instr)->x86_instr.opcode < 0;
|
||||
}
|
||||
|
||||
static void handle_pseudo(scc_mir_func_t *func, void *instr, void *out) {
|
||||
scc_mir_x86_instr_t *ins = instr;
|
||||
scc_mir_x86_instr_vec_t *out_vec = out;
|
||||
if (ins->x86_instr.opcode == SCC_MIR_PSEUDO_ALLOCA) {
|
||||
// // 指令选择时已分配 slot,直接替换为 slot 操作数
|
||||
// if (scc_x86_op_is_vreg(&ins->x86_instr.operands[0])) {
|
||||
// int vreg = scc_x86_op_get_vreg(&ins->x86_instr.operands[0]);
|
||||
// int slot = scc_mir_vreg_map2slot(func, vreg, 8, 8);
|
||||
// ins->x86_instr.operands[0] = scc_x86_op_slot(slot);
|
||||
// }
|
||||
// scc_vec_push(*out_vec, *ins);
|
||||
} else {
|
||||
scc_vec_push(*out_vec, *ins);
|
||||
}
|
||||
}
|
||||
|
||||
/* ========== Spill / Reload / Copy ========== */
|
||||
|
||||
static void emit_spill(void *out, int preg, int slot) {
|
||||
scc_mir_x86_instr_vec_t *vec = out;
|
||||
scc_mir_x86_instr_t ins = {
|
||||
.x86_instr.opcode = SCC_X86_IFORM_MOV_MEMV_GPRV,
|
||||
.x86_instr.num_operands = 2,
|
||||
.x86_instr.operands = {scc_x86_op_slot(slot), scc_x86_op_preg(preg)}};
|
||||
scc_vec_push(*vec, ins);
|
||||
}
|
||||
|
||||
static void emit_reload(void *out, int preg, int slot) {
|
||||
scc_mir_x86_instr_vec_t *vec = out;
|
||||
scc_mir_x86_instr_t ins = {
|
||||
.x86_instr.opcode = SCC_X86_IFORM_MOV_GPRV_MEMV,
|
||||
.x86_instr.num_operands = 2,
|
||||
.x86_instr.operands = {scc_x86_op_preg(preg), scc_x86_op_slot(slot)}};
|
||||
scc_vec_push(*vec, ins);
|
||||
}
|
||||
|
||||
static void emit_copy(void *out, int dst_preg, int src_preg, int size) {
|
||||
(void)size;
|
||||
scc_mir_x86_instr_vec_t *vec = out;
|
||||
scc_mir_x86_instr_t ins = {
|
||||
.x86_instr.opcode = SCC_X86_IFORM_MOV_GPRV_GPRV_8B,
|
||||
.x86_instr.num_operands = 2,
|
||||
.x86_instr.operands = {scc_x86_op_preg(dst_preg),
|
||||
scc_x86_op_preg(src_preg)}};
|
||||
scc_vec_push(*vec, ins);
|
||||
}
|
||||
|
||||
/* ========== 操作数读写属性 ========== */
|
||||
|
||||
static scc_reg_op_access_t get_operand_access(void *ctx, int opcode,
|
||||
int op_idx) {
|
||||
(void)ctx;
|
||||
if (opcode >= 0 && opcode < SCC_X86_IFORM_COUNT) {
|
||||
const scc_x86_iform_info_t *info = &scc_x86_iform_table[opcode];
|
||||
if (op_idx >= info->num_ops || op_idx < 0)
|
||||
return SCC_REG_ALLOC_OP_ACCESS_READWRITE;
|
||||
if (info->ops[op_idx].rw[0] == 'r')
|
||||
return info->ops[op_idx].rw[1] == 'w'
|
||||
? SCC_REG_ALLOC_OP_ACCESS_READWRITE
|
||||
: SCC_REG_ALLOC_OP_ACCESS_READ;
|
||||
else if (info->ops[op_idx].rw[0] == 'w')
|
||||
return SCC_REG_ALLOC_OP_ACCESS_WRITE;
|
||||
}
|
||||
return SCC_REG_ALLOC_OP_ACCESS_READWRITE;
|
||||
}
|
||||
|
||||
/* ========== 隐式寄存器 ========== */
|
||||
|
||||
static void get_implicit_regs(void *ctx, int opcode, const int **uses,
|
||||
const int **defs) {
|
||||
(void)ctx;
|
||||
static const int empty[] = {-1};
|
||||
static const int rax[] = {SCC_X86_REG_RAX, -1};
|
||||
static const int rdx[] = {SCC_X86_REG_RDX, -1};
|
||||
static const int rax_rdx[] = {SCC_X86_REG_RAX, SCC_X86_REG_RDX, -1};
|
||||
static const int cl[] = {SCC_X86_REG_CL, -1};
|
||||
|
||||
switch (opcode) {
|
||||
case SCC_X86_IFORM_IDIV_GPRV:
|
||||
case SCC_X86_IFORM_DIV_GPRV:
|
||||
*uses = rax_rdx;
|
||||
*defs = rax_rdx;
|
||||
break;
|
||||
case SCC_X86_IFORM_CQO:
|
||||
*uses = rax;
|
||||
*defs = rax_rdx;
|
||||
break;
|
||||
case SCC_X86_IFORM_SAR_GPRV_CL:
|
||||
*uses = cl;
|
||||
*defs = empty;
|
||||
break;
|
||||
default:
|
||||
*uses = empty;
|
||||
*defs = empty;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* ========== 寄存器池 ========== */
|
||||
|
||||
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;
|
||||
|
||||
static int acquire_reg(void *ctx) {
|
||||
(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) {
|
||||
(void)ctx;
|
||||
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) {
|
||||
(void)ctx;
|
||||
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) {
|
||||
(void)ctx;
|
||||
reg_mask = 0;
|
||||
}
|
||||
|
||||
/* ========== 注册全部 x86 回调 ========== */
|
||||
|
||||
void scc_reg_alloc_fill_arch_x86(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;
|
||||
|
||||
ops->instr_opcode = instr_opcode;
|
||||
ops->instr_num_operands = instr_num_operands;
|
||||
ops->op_is_vreg = op_is_vreg;
|
||||
ops->op_get_vreg = op_get_vreg;
|
||||
ops->op_set_preg = op_set_preg;
|
||||
ops->op_set_slot = op_set_slot;
|
||||
|
||||
ops->get_operand_access = get_operand_access;
|
||||
ops->get_implicit_regs = get_implicit_regs;
|
||||
|
||||
ops->is_pseudo = is_pseudo;
|
||||
ops->handle_pseudo = handle_pseudo;
|
||||
|
||||
ops->emit_spill = emit_spill;
|
||||
ops->emit_reload = emit_reload;
|
||||
ops->emit_copy = emit_copy;
|
||||
}
|
||||
@@ -1,83 +0,0 @@
|
||||
#include <arch/x86_64_isel.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 = {
|
||||
.opcode = SCC_X86_IFORM_MOV_MEMV_GPRV,
|
||||
.num_operands = 2,
|
||||
.operands = {{.kind = SCC_MIR_OP_STACK_SLOT, .stack_slot = slot},
|
||||
{.kind = SCC_MIR_OP_PREG, .preg = preg}}};
|
||||
scc_vec_push(*ctx, ins);
|
||||
}
|
||||
|
||||
static void x86_emit_reload(scc_mir_instr_vec_t *ctx, int preg, int slot) {
|
||||
scc_mir_instr_t ins = {
|
||||
.opcode = SCC_X86_IFORM_MOV_GPRV_MEMV,
|
||||
.num_operands = 2,
|
||||
.operands = {{.kind = SCC_MIR_OP_PREG, .preg = preg},
|
||||
{.kind = SCC_MIR_OP_STACK_SLOT, .stack_slot = slot}}};
|
||||
scc_vec_push(*ctx, ins);
|
||||
}
|
||||
|
||||
static void x86_emit_copy(scc_mir_instr_vec_t *ctx, int dst_preg, int src_preg,
|
||||
int size) {
|
||||
scc_mir_instr_t ins = {
|
||||
.opcode = SCC_X86_IFORM_MOV_GPRV_GPRV_89,
|
||||
.num_operands = 2,
|
||||
.operands = {{.kind = SCC_MIR_OP_PREG, .preg = dst_preg},
|
||||
{.kind = SCC_MIR_OP_PREG, .preg = src_preg}}};
|
||||
scc_vec_push(*ctx, ins);
|
||||
}
|
||||
|
||||
/* ---- 临时寄存器 ---- */
|
||||
static int x86_acquire_temp_reg(void *vctx) { return SCC_X86_REG_R11; }
|
||||
|
||||
static void x86_release_temp_reg(void *vctx, int preg) { /* 简单模式无需操作 */
|
||||
}
|
||||
|
||||
/* ---- 操作数读写属性 ---- */
|
||||
static scc_op_access_t x86_get_operand_access(void *vctx, int opcode,
|
||||
int op_idx) {
|
||||
switch (opcode) {
|
||||
default:
|
||||
return SCC_REG_ALLOC_OP_ACCESS_READWRITE; // 保守
|
||||
}
|
||||
}
|
||||
|
||||
/* ---- 隐式寄存器 ---- */
|
||||
static void x86_get_implicit_regs(void *vctx, int opcode, const int **uses,
|
||||
const int **defs) {
|
||||
static const int empty[] = {-1};
|
||||
static const int rax[] = {SCC_X86_REG_RAX, -1};
|
||||
static const int rdx[] = {SCC_X86_REG_RDX, -1};
|
||||
static const int rax_rdx[] = {SCC_X86_REG_RAX, SCC_X86_REG_RDX, -1};
|
||||
static const int cl[] = {SCC_X86_REG_CL, -1};
|
||||
|
||||
switch (opcode) {
|
||||
case SCC_X86_IFORM_IDIV_GPRV:
|
||||
case SCC_X86_IFORM_DIV_GPRV:
|
||||
*uses = rax_rdx;
|
||||
*defs = rax_rdx;
|
||||
break;
|
||||
case SCC_X86_IFORM_CQO:
|
||||
*uses = rax;
|
||||
*defs = rax_rdx;
|
||||
break;
|
||||
case SCC_X86_IFORM_SAR_GPRV_CL:
|
||||
*uses = cl;
|
||||
*defs = empty;
|
||||
break;
|
||||
default:
|
||||
*uses = empty;
|
||||
*defs = empty;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
@@ -1,174 +1,76 @@
|
||||
#include <core_pass/scc_reg_alloc.h>
|
||||
#include <scc_hashtable.h>
|
||||
#include <scc_mir_module.h>
|
||||
|
||||
// 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;
|
||||
usize instr_size = ctx->module->instr_size;
|
||||
if (ops->is_pseudo(instr)) {
|
||||
ops->handle_pseudo(ctx->func, (void *)instr, instr_vec);
|
||||
return;
|
||||
}
|
||||
|
||||
scc_mir_instr_vec_t before, after;
|
||||
scc_vec_init(before);
|
||||
scc_vec_init(after);
|
||||
SCC_VEC(int) allocated;
|
||||
scc_vec_init(allocated);
|
||||
|
||||
// 隐式寄存器标记
|
||||
int opcode = ops->instr_opcode(instr);
|
||||
|
||||
// 标记隐式寄存器
|
||||
const int *implicit_uses, *implicit_defs;
|
||||
ops->get_implicit_regs(ctx, instr->opcode, &implicit_uses, &implicit_defs);
|
||||
ops->get_implicit_regs(ctx, 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)
|
||||
int num_ops = ops->instr_num_operands(instr);
|
||||
for (int op_i = 0; op_i < num_ops; op_i++) {
|
||||
if (!ops->op_is_vreg(instr, op_i))
|
||||
continue;
|
||||
|
||||
int vreg = op->vreg;
|
||||
int vreg = ops->op_get_vreg(instr, op_i);
|
||||
int id = 0;
|
||||
int mapping = scc_mir_vreg_lookup(ctx->func, vreg, &id);
|
||||
int preg = id, slot = id;
|
||||
|
||||
// 查询当前 vreg 的映射(可能已经被之前的分配改为 MEM 等,但我们只需要
|
||||
// slot)
|
||||
scc_mir_vreg_op(ctx->func, vreg, op);
|
||||
int slot;
|
||||
if (op->kind == SCC_MIR_OP_VREG) {
|
||||
// 还没有 slot → 分配一个
|
||||
if (mapping == 1) {
|
||||
// 已预着色
|
||||
ops->mark_reg_used(ctx, preg);
|
||||
ops->op_set_preg(instr, op_i, preg);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (mapping == 0)
|
||||
slot = scc_mir_vreg_map2slot(ctx->func, vreg, 8, 8);
|
||||
} else {
|
||||
// 已经是 MEM,直接用它的 slot
|
||||
Assert(op->kind == SCC_MIR_OP_STACK_SLOT);
|
||||
slot = op->stack_slot;
|
||||
}
|
||||
|
||||
// 在本指令内查找是否已为这个 vreg 分配了 preg
|
||||
int preg = -1;
|
||||
for (int k = 0; k < local_cnt; k++) {
|
||||
if (local_vreg[k] == vreg) {
|
||||
preg = local_preg[k];
|
||||
break;
|
||||
}
|
||||
}
|
||||
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++;
|
||||
}
|
||||
preg = ops->acquire_reg(ctx);
|
||||
scc_vec_push(allocated, preg);
|
||||
|
||||
// 读写属性
|
||||
scc_op_access_t acc = ops->get_operand_access(ctx, instr->opcode, i);
|
||||
|
||||
// reload: slot → preg
|
||||
scc_reg_op_access_t acc = ops->get_operand_access(ctx, opcode, op_i);
|
||||
if (acc == SCC_REG_ALLOC_OP_ACCESS_READ ||
|
||||
acc == SCC_REG_ALLOC_OP_ACCESS_READWRITE) {
|
||||
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) {
|
||||
acc == SCC_REG_ALLOC_OP_ACCESS_READWRITE)
|
||||
ops->emit_spill(&after, preg, slot);
|
||||
}
|
||||
|
||||
// 替换操作数
|
||||
op->kind = SCC_MIR_OP_PREG;
|
||||
op->preg = preg;
|
||||
ops->op_set_preg(instr, op_i, 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_foreach(after, i) scc_vec_push(*instr_vec, scc_vec_at(after, i));
|
||||
scc_vec_foreach(before, i) scc_vec_sized_push(
|
||||
*instr_vec, instr_size, scc_vec_sized_at_ptr(before, instr_size, i),
|
||||
instr_size);
|
||||
scc_vec_sized_push(*instr_vec, instr_size, instr, instr_size);
|
||||
scc_vec_foreach(after, i) scc_vec_sized_push(
|
||||
*instr_vec, instr_size, scc_vec_sized_at_ptr(after, instr_size, i),
|
||||
instr_size);
|
||||
|
||||
// 隐式寄存器清理
|
||||
// 清理隐式寄存器
|
||||
for (const int *p = implicit_defs; *p != -1; p++)
|
||||
ops->mark_reg_used(ctx, *p);
|
||||
for (const int *p = implicit_uses; *p != -1; p++)
|
||||
@@ -176,63 +78,40 @@ static void alloc_instr(scc_reg_alloc_ctx_t *ctx,
|
||||
|
||||
scc_vec_free(before);
|
||||
scc_vec_free(after);
|
||||
scc_vec_free(allocated_pregs);
|
||||
scc_vec_foreach(allocated, l)
|
||||
ops->release_reg(ctx, scc_vec_at(allocated, l));
|
||||
scc_vec_free(allocated);
|
||||
}
|
||||
|
||||
/* 对一个基本块执行分配 */
|
||||
static void alloc_bb(scc_reg_alloc_ctx_t *ctx, scc_mir_module_t *module,
|
||||
scc_cfg_bblock_id_t bb_id) {
|
||||
scc_cfg_bblock_t *bb =
|
||||
scc_cfg_module_unsafe_get_bblock(&module->cfg_module, bb_id);
|
||||
Assert(bb != nullptr);
|
||||
scc_mir_instr_vec_t *old_instrs = SCC_MIR_BBLOCK_VALUES(bb);
|
||||
|
||||
scc_mir_instr_vec_t new_instrs;
|
||||
scc_vec_init(new_instrs);
|
||||
|
||||
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_mir_vreg_op(ctx->func, ins.operands[0].vreg, &ins.operands[0]);
|
||||
scc_vec_push(new_instrs, ins);
|
||||
continue;
|
||||
}
|
||||
alloc_instr(ctx, &new_instrs, &ins);
|
||||
}
|
||||
|
||||
scc_vec_free(*old_instrs);
|
||||
*old_instrs = new_instrs;
|
||||
}
|
||||
|
||||
/* 对一个函数运行分配 */
|
||||
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 = 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);
|
||||
}
|
||||
}
|
||||
|
||||
/* 公开入口 */
|
||||
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);
|
||||
const scc_reg_alloc_op_t *ops = &ctx->ops;
|
||||
ctx->module = module;
|
||||
|
||||
scc_vec_foreach(module->cfg_module.funcs, i) {
|
||||
if (i == 0)
|
||||
continue;
|
||||
alloc_func(ctx, module, &scc_vec_at(module->cfg_module.funcs, i));
|
||||
scc_mir_func_t *func = &scc_vec_at(module->cfg_module.funcs, i);
|
||||
|
||||
ops->clean_mark_regs(ctx);
|
||||
ctx->func = func;
|
||||
|
||||
scc_vec_foreach(func->bblocks, j) {
|
||||
scc_cfg_bblock_id_t bb_id = scc_vec_at(func->bblocks, j);
|
||||
scc_cfg_bblock_t *bb =
|
||||
scc_cfg_module_unsafe_get_bblock(&module->cfg_module, bb_id);
|
||||
|
||||
scc_mir_instr_vec_t *old_instrs = SCC_MIR_BBLOCK_VALUES_PTR(bb);
|
||||
scc_mir_instr_vec_t new_instrs;
|
||||
scc_vec_init(new_instrs);
|
||||
|
||||
scc_vec_foreach(*old_instrs, k) {
|
||||
scc_mir_instr_t *instr = scc_vec_sized_at_ptr(
|
||||
*old_instrs, ctx->module->instr_size, k);
|
||||
alloc_instr(ctx, &new_instrs, instr);
|
||||
}
|
||||
|
||||
scc_vec_free(*old_instrs);
|
||||
*old_instrs = new_instrs;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
#include <arch/x86_64_isel.h>
|
||||
#include <arch/scc_x86_isel.h>
|
||||
#include <scc_lir2mir.h>
|
||||
#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
|
||||
// Move
|
||||
mir_module->cfg_module = lir_module->cfg_module;
|
||||
|
||||
scc_x86_64_isel_t isel;
|
||||
|
||||
@@ -4,6 +4,7 @@ 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;
|
||||
func_meta->target_data = nullptr;
|
||||
scc_vec_init(func_meta->stack_slots);
|
||||
|
||||
// For null stack slot
|
||||
@@ -16,24 +17,6 @@ int scc_mir_alloc_vreg(scc_mir_func_t *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_STACK_SLOT;
|
||||
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 =
|
||||
|
||||
@@ -1,37 +1,11 @@
|
||||
#include <arch/scc_x86_mir.h>
|
||||
#include <scc_mir_dump.h>
|
||||
|
||||
void scc_x86_instr_dump(scc_tree_dump_t *dump, const scc_mir_instr_t *instr);
|
||||
|
||||
void scc_mir_dump_instr(scc_mir_dump_ctx_t *ctx, const scc_mir_instr_t *ins) {
|
||||
scc_tree_dump_t *td = ctx->dump_ctx;
|
||||
scc_tree_dump_begin_line(td);
|
||||
if (ins->opcode >= 0) {
|
||||
scc_x86_instr_dump(td, ins);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (ins->opcode) {
|
||||
case SCC_MIR_PSUEDO_ALLOCA:
|
||||
scc_tree_dump_node(td, " @alloca");
|
||||
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_STACK_SLOT) {
|
||||
scc_tree_dump_append_fmt(td, " [%d]", ins->operands[0].stack_slot);
|
||||
} else {
|
||||
scc_tree_dump_append(td, "<alloced>");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void scc_x86_instr_dump(scc_tree_dump_t *td, const scc_mir_x86_instr_t *instr);
|
||||
void scc_mir_dump_bblock(scc_mir_dump_ctx_t *ctx, const scc_mir_bblock_t *bb) {
|
||||
Assert(ctx != nullptr && bb != nullptr);
|
||||
scc_tree_dump_t *td = ctx->dump_ctx;
|
||||
|
||||
// 基本块头部
|
||||
scc_tree_dump_begin_line(td);
|
||||
scc_tree_dump_branch(td, "#BB%zu", bb->id);
|
||||
if (bb->name) {
|
||||
@@ -39,11 +13,22 @@ void scc_mir_dump_bblock(scc_mir_dump_ctx_t *ctx, const scc_mir_bblock_t *bb) {
|
||||
}
|
||||
scc_tree_dump_append(td, ":");
|
||||
|
||||
// 输出每条指令
|
||||
scc_mir_instr_vec_t *instrs = SCC_MIR_BBLOCK_VALUES(bb);
|
||||
scc_vec_foreach(*instrs, i) {
|
||||
const scc_mir_instr_t *ins = &scc_vec_at(*instrs, i);
|
||||
scc_mir_dump_instr(ctx, ins);
|
||||
for (int i = 0; i < scc_vec_size(bb->values); i += 1) {
|
||||
scc_tree_dump_begin_line(td);
|
||||
scc_mir_instr_t *instr =
|
||||
scc_vec_sized_at_ptr(bb->values, ctx->mir_module->instr_size, i);
|
||||
if (instr->opcode < 0) {
|
||||
switch (instr->opcode) {
|
||||
case SCC_MIR_PSEUDO_ALLOCA:
|
||||
scc_tree_dump_append_fmt(td, " alloca(%d)",
|
||||
instr->data.alloc.size);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
scc_x86_instr_dump(td, (void *)instr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,11 +37,9 @@ void scc_mir_dump_func(scc_mir_dump_ctx_t *ctx, const scc_mir_func_t *func) {
|
||||
scc_tree_dump_t *td = ctx->dump_ctx;
|
||||
|
||||
scc_mir_func_meta_t *meta = SCC_MIR_FUNC_META(func);
|
||||
// 函数头部
|
||||
scc_tree_dump_begin_line(td);
|
||||
scc_tree_dump_node(td, "func @%s", func->name ? func->name : "<anon>");
|
||||
|
||||
// 输出所有基本块
|
||||
scc_vec_foreach(func->bblocks, i) {
|
||||
scc_cfg_bblock_id_t id = scc_vec_at(func->bblocks, i);
|
||||
const scc_cfg_bblock_t *bb =
|
||||
@@ -67,7 +50,6 @@ void scc_mir_dump_func(scc_mir_dump_ctx_t *ctx, const scc_mir_func_t *func) {
|
||||
|
||||
void scc_mir_dump_module(scc_mir_dump_ctx_t *ctx) {
|
||||
scc_vec_foreach(ctx->mir_module->cfg_module.symbols, i) {
|
||||
// FIXME 0 is null
|
||||
if (i == 0)
|
||||
continue;
|
||||
scc_cfg_symbol_t *sym =
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
#include "scc_mir_module.h"
|
||||
|
||||
void scc_mir_module_init(scc_mir_module_t *mir_module) {
|
||||
mir_module->instr_size = 0;
|
||||
mir_module->cfg_module = (scc_cfg_module_t){0};
|
||||
scc_vec_init(mir_module->func_metas);
|
||||
scc_vec_init(mir_module->symbol_metas);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#include <arch/x86_64_reg_alloc.h>
|
||||
#include <arch/scc_x86_mir.h>
|
||||
#include <arch/scc_x86_reg_alloc.h>
|
||||
#include <target/scc_win64.h>
|
||||
|
||||
// #include <core_pass/scc_frame_layout.h>
|
||||
@@ -28,7 +29,7 @@ void scc_prolog_epilog(scc_prolog_epilog_t *ctx, scc_mir_module_t *module) {
|
||||
scc_cfg_bblock_t *bb =
|
||||
scc_cfg_module_unsafe_get_bblock(&module->cfg_module, bb_id);
|
||||
Assert(bb != nullptr);
|
||||
scc_mir_instr_vec_t *old_instrs = SCC_MIR_BBLOCK_VALUES(bb);
|
||||
scc_mir_instr_vec_t *old_instrs = SCC_MIR_BBLOCK_VALUES_PTR(bb);
|
||||
scc_mir_instr_vec_t new_instrs;
|
||||
scc_vec_init(new_instrs);
|
||||
|
||||
@@ -39,13 +40,15 @@ void scc_prolog_epilog(scc_prolog_epilog_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_mir_instr_t *ins =
|
||||
scc_vec_sized_at_ptr(*old_instrs, module->instr_size, i);
|
||||
if (ins->opcode == SCC_MIR_PSEUDO_ALLOCA) {
|
||||
continue;
|
||||
}
|
||||
scc_vec_push(new_instrs, ins);
|
||||
// FIXME error
|
||||
scc_vec_sized_push(new_instrs, module->instr_size, ins,
|
||||
module->instr_size);
|
||||
}
|
||||
|
||||
scc_vec_free(*old_instrs);
|
||||
*old_instrs = new_instrs;
|
||||
}
|
||||
@@ -53,8 +56,7 @@ void scc_prolog_epilog(scc_prolog_epilog_t *ctx, scc_mir_module_t *module) {
|
||||
}
|
||||
|
||||
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 = nullptr, .instrs = nullptr, .ops = {0}};
|
||||
scc_reg_alloc_ctx_t reg_alloc_ctx = {.func = nullptr, .ops = {0}};
|
||||
scc_reg_alloc_fill_arch_x86(®_alloc_ctx.ops);
|
||||
scc_win_pc_x64_reg_alloc_fill(®_alloc_ctx.ops);
|
||||
|
||||
|
||||
@@ -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