feat(mir): 添加栈偏移操作数类型并重构内存访问表示

- 将 MIR 中的 SCC_MIR_OP_MEM 替换为更精确的 SCC_MIR_OP_STACK_SLOT 和
  SCC_MIR_OP_STACK_OFFSET 类型
- 在 x86_64 指令选择中更新相应的内存操作数处理逻辑
- 修改寄存器分配器中的栈槽操作数类型检查
- 更新 IR 转机器码过程中的内存操作数转换

refactor(hir): 使用 tree_dump_node 输出函数节点

- 将 hir_dump 中的函数名输出从 append 改为 node 类型

refactor(frame-layout): 重构栈帧布局传递实现结构

- 引入函数指针实现方式替代直接函数实现
- 将栈帧分配功能集成到 MIR 传递流程中
- 移除独立的 frame_layout 实现文件

refactor(prolog-epilog): 添加函数序言/尾声传递框架

- 为 Windows x64 平台初始化序言/尾声生成器
- 在 MIR 传递阶段添加序言/尾声处理步骤

refactor(win64): 更新 Windows x64 目标平台接口

- 重命名寄存器分配填充函数为 scc_win_pc_x64_reg_alloc_fill
- 添加栈帧分配和序言/尾声初始化函数
- 修正参数传递中的栈槽操作数类型

refactor(dump): 改进 MIR 输出格式

- 将基本块显示改为分支节点类型
- 更新操作数类型的显示处理

chore: 添加 x86 编码相关数据结构定义

- 新增 scc_x86_encode.h 头文件包含内存操作数和指令编码接口定义
This commit is contained in:
zzy
2026-05-13 18:47:44 +08:00
parent 68eac24152
commit 3df858fb85
20 changed files with 662 additions and 85 deletions

View File

@@ -0,0 +1,28 @@
#ifndef __SCC_X86_ENCODE_H__
#define __SCC_X86_ENCODE_H__
#include "../scc_mcode.h"
#include "scc_x86_iform.h"
#include "scc_x86_reg.h"
typedef struct {
scc_x86_reg_t base;
scc_x86_reg_t index;
u8 scale; /* 1,2,4,8 */
i32 disp;
} scc_x86_mem_t;
typedef struct {
scc_x86_operand_kind_t kind;
union {
scc_x86_reg_t reg;
i64 imm;
scc_x86_mem_t mem;
};
} scc_x86_operand_value_t;
/* 按 iform 发射一条指令ops 数组长度需与 iform 定义的操作数数目一致 */
int scc_x86_encode_inst(scc_mcode_t *mcode, scc_x86_iform_t iform,
const scc_x86_operand_value_t *ops);
#endif /* __SCC_X86_ENCODE_H__ */

View File

@@ -0,0 +1,449 @@
#include <assert.h>
#include <string.h>
#include <x86/scc_x86_encode.h>
#include <x86/scc_x86_iform.h>
#include <x86/scc_x86_reg.h>
/* ---------- 内部辅助 ---------- */
static inline void emit_u8(scc_mcode_t *m, uint8_t v) {
scc_mcode_add_u8(m, v);
}
static inline void emit_u16(scc_mcode_t *m, uint16_t v) {
scc_mcode_add_u16(m, v);
}
static inline void emit_u32(scc_mcode_t *m, uint32_t v) {
scc_mcode_add_u32(m, v);
}
static inline void emit_u64(scc_mcode_t *m, uint64_t v) {
scc_mcode_add_u64(m, v);
}
/* ---------- 寄存器查询 ---------- */
static inline uint16_t scc_reg_width(scc_x86_reg_t reg) {
if (reg >= SCC_X86_REG_COUNT || reg == SCC_X86_REG_INVALID)
return 0;
return scc_x86_reg_table[reg].width;
}
static inline int scc_reg_ordinal(scc_x86_reg_t reg) {
if (reg >= SCC_X86_REG_COUNT || reg == SCC_X86_REG_INVALID)
return 0;
return scc_x86_reg_table[reg].ordinal;
}
static int reg_low3(scc_x86_reg_t reg) {
if (reg == SCC_X86_REG_INVALID)
return 0;
return scc_reg_ordinal(reg) & 7;
}
static int reg_rex_bit(scc_x86_reg_t reg) {
if (reg == SCC_X86_REG_INVALID)
return 0;
if (reg >= SCC_X86_REG_AH && reg <= SCC_X86_REG_DH)
return 0;
return (scc_reg_ordinal(reg) >= 8) ? 1 : 0;
}
/* ---------- 操作数宽度推导 ---------- */
static int infer_operand_width(const scc_x86_iform_info_t *info,
const scc_x86_operand_value_t ops[]) {
for (int i = 0; i < info->num_explicit_ops; i++) {
if (ops[i].kind == SCC_X86_OPR_REG && !info->ops[i].is_implicit) {
uint16_t w = scc_reg_width(ops[i].reg);
if (w > 0)
return w;
}
}
const char *eosz = info->encode.eosz;
int default_64 = info->encode.default_64b;
if (!strcmp(eosz, "o16"))
return 16;
if (!strcmp(eosz, "o32"))
return 32;
if (!strcmp(eosz, "o64"))
return 64;
if (!strcmp(eosz, "oszall") || !strcmp(eosz, "osznot16"))
return default_64 ? 64 : 32;
return 32;
}
/* ---------- 前缀决策 ---------- */
static int need_rexw(const scc_x86_encoding_t *enc, scc_x86_reg_t reg_op,
scc_x86_reg_t rm_op, scc_x86_reg_t base,
scc_x86_reg_t idx) {
/* 强制要求 / 明确禁止 优先级最高 */
if (enc->rex_w == 1)
return 1;
if (enc->rex_w == 0)
return 0;
/* 指令已隐含 64 位语义(如 PUSH/POP但仍可能被 64 位操作数需要 W例如
* PUSH r64 不需要 W但 PUSH r/m64 也不需要。总之 default_64b
* 时一般无需额外 W但若操作数明确是 64 位且模板没有禁止,我们仍加上以兼容
* movabs 等 */
int has_64bit_op = 0;
if (reg_op != SCC_X86_REG_INVALID && scc_reg_width(reg_op) == 64)
has_64bit_op = 1;
if (rm_op != SCC_X86_REG_INVALID && scc_reg_width(rm_op) == 64)
has_64bit_op = 1;
if (base != SCC_X86_REG_INVALID && scc_reg_width(base) == 64)
has_64bit_op = 1;
if (idx != SCC_X86_REG_INVALID && scc_reg_width(idx) == 64)
has_64bit_op = 1;
if (enc->default_64b) {
/* 对于默认 64 位的指令(如 CALL, JMP有些仍需要 REX.W
* 访问扩展寄存器,但若 reg/rm 本身是 64 位且需要 REX.B/R 则一并设置 W
* 来保证编码正确?这里简单处理:只要访问扩展寄存器就加 W */
return (reg_op != SCC_X86_REG_INVALID && reg_rex_bit(reg_op)) ||
(rm_op != SCC_X86_REG_INVALID && reg_rex_bit(rm_op)) ||
(base != SCC_X86_REG_INVALID && reg_rex_bit(base)) ||
(idx != SCC_X86_REG_INVALID && reg_rex_bit(idx))
? 1
: 0;
}
/* 普通指令:有 64 位操作数即加 W */
return has_64bit_op;
}
static int need_66_prefix(const scc_x86_encoding_t *enc, scc_x86_reg_t reg_op,
scc_x86_reg_t rm_op) {
if (enc->osz_required)
return 1;
// 如果强制指定了操作大小不自动加66
if (!strcmp(enc->eosz, "o32") || !strcmp(enc->eosz, "o64"))
return 0;
if (reg_op != SCC_X86_REG_INVALID && scc_reg_width(reg_op) == 16)
return 1;
if (rm_op != SCC_X86_REG_INVALID && scc_reg_width(rm_op) == 16)
return 1;
return 0;
}
static int need_67_prefix(const scc_x86_encoding_t *enc, scc_x86_reg_t base,
scc_x86_reg_t idx) {
(void)enc;
(void)base;
(void)idx;
return 0;
}
static void emit_legacy_prefixes(scc_mcode_t *m, const scc_x86_encoding_t *enc,
scc_x86_reg_t reg_op, scc_x86_reg_t rm_op,
scc_x86_reg_t base, scc_x86_reg_t idx) {
if (enc->has_lock)
emit_u8(m, 0xF0);
if (enc->f2_required)
emit_u8(m, 0xF2);
if (enc->f3_required)
emit_u8(m, 0xF3);
if (need_66_prefix(enc, reg_op, rm_op))
emit_u8(m, 0x66);
if (need_67_prefix(enc, base, idx))
emit_u8(m, 0x67);
}
static void emit_rex(scc_mcode_t *m, const scc_x86_encoding_t *enc,
scc_x86_reg_t reg_op, scc_x86_reg_t rm_op,
scc_x86_reg_t base, scc_x86_reg_t idx) {
int rex = 0x40;
if (need_rexw(enc, reg_op, rm_op, base, idx))
rex |= 8;
if (reg_op != SCC_X86_REG_INVALID && reg_rex_bit(reg_op))
rex |= 4;
if (idx != SCC_X86_REG_INVALID && reg_rex_bit(idx))
rex |= 2;
scc_x86_reg_t b = (rm_op != SCC_X86_REG_INVALID) ? rm_op : base;
if (b != SCC_X86_REG_INVALID && reg_rex_bit(b))
rex |= 1;
if (rex != 0x40) {
LOG_INFO("[REX] emit 0x%02x", (uint8_t)rex);
emit_u8(m, (uint8_t)rex);
}
}
static void emit_escape_map(scc_mcode_t *m, const scc_x86_encoding_t *enc) {
if (enc->map == 1) {
emit_u8(m, 0x0F);
} else if (enc->map == 2) {
emit_u8(m, 0x0F);
emit_u8(m, 0x38);
} else if (enc->map == 3) {
emit_u8(m, 0x0F);
emit_u8(m, 0x3A);
}
}
static void emit_opcode(scc_mcode_t *m, const scc_x86_encoding_t *enc,
scc_x86_reg_t rm_reg, scc_x86_reg_t base_reg) {
for (int i = 0; i < enc->opcode_len; i++) {
uint8_t byte = enc->opcode[i];
if (enc->partial_opcode && i == enc->opcode_len - 1) {
scc_x86_reg_t target =
(rm_reg != SCC_X86_REG_INVALID) ? rm_reg : base_reg;
if (target != SCC_X86_REG_INVALID)
byte |= (reg_low3(target) & 7);
}
emit_u8(m, byte);
}
}
static int scale_to_enc(uint8_t scale) {
switch (scale) {
case 1:
return 0;
case 2:
return 1;
case 4:
return 2;
case 8:
return 3;
default:
return -1;
}
}
static int disp_size(int32_t disp, scc_x86_reg_t base) {
if (disp == 0 && base != SCC_X86_REG_RBP && base != SCC_X86_REG_R13)
return 0;
if (disp >= -128 && disp <= 127)
return 8;
return 32;
}
/* ---------- 立即数发射(独立函数) ---------- */
static void emit_immediate(scc_mcode_t *m, const scc_x86_encoding_t *enc,
const scc_x86_operand_t *tmpl, int imm_idx,
int64_t imm_val, int op_width) {
const char *oc2 = tmpl[imm_idx].oc2;
int imm_size = enc->imm_size;
if (!strcmp(oc2, "b"))
imm_size = 1;
else if (!strcmp(oc2, "w"))
imm_size = 2;
else if (!strcmp(oc2, "z"))
imm_size = (op_width <= 16) ? op_width / 8 : (op_width <= 32 ? 4 : 4);
else if (!strcmp(oc2, "v"))
imm_size = op_width / 8;
else if (!strcmp(oc2, "d") || !strcmp(oc2, "ss"))
imm_size = 4;
else if (!strcmp(oc2, "q"))
imm_size = 8;
LOG_INFO("[IMM] val=%lld size=%d", imm_val, imm_size);
switch (imm_size) {
case 1:
emit_u8(m, (uint8_t)imm_val);
break;
case 2:
emit_u16(m, (uint16_t)imm_val);
break;
case 4:
emit_u32(m, (uint32_t)imm_val);
break;
case 8:
emit_u64(m, (uint64_t)imm_val);
break;
default:
break;
}
}
/* ---------- ModR/M + SIB + 位移 + 立即数 ---------- */
static void emit_modrm_sib_disp(scc_mcode_t *m,
const scc_x86_iform_info_t *info,
const scc_x86_operand_value_t ops[],
int op_width) {
const scc_x86_encoding_t *enc = &info->encode;
const scc_x86_operand_t *tmpl = info->ops;
int num_ops = info->num_explicit_ops;
scc_x86_reg_t reg_r = SCC_X86_REG_INVALID;
scc_x86_reg_t reg_b = SCC_X86_REG_INVALID;
int has_mem = 0;
scc_x86_mem_t memdesc = {0};
int64_t imm_val = 0;
int imm_idx = -1;
for (int i = 0; i < num_ops; i++) {
const char *tname = tmpl[i].name;
if (ops[i].kind == SCC_X86_OPR_REG) {
LOG_INFO("[OPD] %d: REG kind, name=\"%s\" reg=%d", i, tname,
ops[i].reg);
if (strncmp(tname, "REG0", 4) == 0)
reg_r = ops[i].reg;
else if (strncmp(tname, "REG1", 4) == 0)
reg_b = ops[i].reg;
else {
if (reg_r == SCC_X86_REG_INVALID)
reg_r = ops[i].reg;
else if (reg_b == SCC_X86_REG_INVALID)
reg_b = ops[i].reg;
}
} else if (ops[i].kind == SCC_X86_OPR_MEM) {
has_mem = 1;
memdesc = ops[i].mem;
} else if (ops[i].kind == SCC_X86_OPR_IMM) {
imm_val = ops[i].imm;
imm_idx = i;
}
}
LOG_INFO("[MODRM] reg_r=%d (ord=%d) reg_b=%d (ord=%d)", reg_r,
scc_reg_ordinal(reg_r), reg_b, scc_reg_ordinal(reg_b));
uint8_t modrm = 0;
if (has_mem) {
if (reg_r != SCC_X86_REG_INVALID)
modrm |= (reg_low3(reg_r) & 7) << 3;
else if (enc->modrm_reg_fix >= 0)
modrm |= (enc->modrm_reg_fix & 7) << 3;
int32_t disp = memdesc.disp;
int dsize = disp_size(disp, memdesc.base);
modrm |= (dsize == 0) ? 0 : (dsize == 8) ? 0x40 : 0x80;
if (memdesc.index != SCC_X86_REG_INVALID) {
modrm |= 4;
int idx_ord = scc_reg_ordinal(memdesc.index);
int base_ord = scc_reg_ordinal(memdesc.base);
int scale_enc = scale_to_enc(memdesc.scale);
if (scale_enc < 0)
return;
uint8_t sib = (uint8_t)((scale_enc << 6) | ((idx_ord & 7) << 3) |
(base_ord & 7));
emit_u8(m, modrm);
emit_u8(m, sib);
if (dsize == 8)
emit_u8(m, (uint8_t)disp);
else if (dsize == 32)
emit_u32(m, (uint32_t)disp);
} else if (memdesc.base == SCC_X86_REG_INVALID) {
modrm |= 5;
emit_u8(m, modrm);
emit_u32(m, (uint32_t)disp);
} else {
int base_ord = scc_reg_ordinal(memdesc.base);
if (memdesc.base == SCC_X86_REG_RSP ||
memdesc.base == SCC_X86_REG_R12) {
modrm |= 4;
uint8_t sib = (uint8_t)((base_ord & 7) | (4 << 3));
emit_u8(m, modrm);
emit_u8(m, sib);
if (dsize == 8)
emit_u8(m, (uint8_t)disp);
else if (dsize == 32)
emit_u32(m, (uint32_t)disp);
} else {
modrm |= (base_ord & 7);
emit_u8(m, modrm);
if (dsize == 8)
emit_u8(m, (uint8_t)disp);
else if (dsize == 32)
emit_u32(m, (uint32_t)disp);
}
}
} else {
modrm = 0xC0;
if (enc->modrm_reg_fix >= 0)
modrm |= (enc->modrm_reg_fix & 7) << 3;
else if (reg_r != SCC_X86_REG_INVALID)
modrm |= (reg_low3(reg_r) & 7) << 3;
if (enc->modrm_rm_fix >= 0) {
modrm |= enc->modrm_rm_fix & 7;
} else if (reg_b != SCC_X86_REG_INVALID) {
modrm |= reg_low3(reg_b) & 7;
} else if (enc->modrm_reg_fix >= 0 && reg_r != SCC_X86_REG_INVALID) {
modrm |= reg_low3(reg_r) & 7;
} else if (reg_r != SCC_X86_REG_INVALID) {
modrm |= reg_low3(reg_r) & 7;
}
emit_u8(m, modrm);
}
LOG_INFO("[MODRM] emit byte 0x%02x", modrm);
/* 立即数在 ModRM 后发射 */
if (imm_idx >= 0) {
emit_immediate(m, enc, tmpl, imm_idx, imm_val, op_width);
}
}
/* ---------- 主编码入口 ---------- */
int scc_x86_encode_inst(scc_mcode_t *mcode, scc_x86_iform_t iform,
const scc_x86_operand_value_t *ops) {
if (!mcode || !ops)
return -1;
if (iform >= SCC_X86_IFORM_COUNT || iform < 0)
Panic("invalid iform %d", iform);
const scc_x86_iform_info_t *info = &scc_x86_iform_table[iform];
const scc_x86_encoding_t *enc = &info->encode;
const scc_x86_operand_t *tmpl = info->ops;
int num_ops = info->num_explicit_ops;
LOG_INFO("[IFORM] %s, explicit_ops=%d (total=%d)", info->iform_name,
num_ops, info->num_ops);
scc_x86_reg_t reg_field = SCC_X86_REG_INVALID;
scc_x86_reg_t rm_field = SCC_X86_REG_INVALID;
scc_x86_reg_t base_reg = SCC_X86_REG_INVALID;
scc_x86_reg_t idx_reg = SCC_X86_REG_INVALID;
/* ---------- 收集立即数信息(用于无 ModRM 指令) ---------- */
int64_t imm_val = 0;
int imm_idx = -1;
for (int i = 0; i < num_ops; i++) {
const char *tname = tmpl[i].name;
if (ops[i].kind == SCC_X86_OPR_REG) {
if (strncmp(tname, "REG0", 4) == 0) {
if (enc->modrm_reg_fix >= 0)
rm_field = ops[i].reg; // reg固定 → REG0为rm
else
reg_field = ops[i].reg; // 否则为reg
} else if (strncmp(tname, "REG1", 4) == 0) {
if (enc->modrm_rm_fix >= 0)
reg_field = ops[i].reg; // rm固定 → REG1为reg
else
rm_field = ops[i].reg; // 否则为rm
} else {
// 未命名的寄存器,按先 reg 后 rm 填充
if (reg_field == SCC_X86_REG_INVALID)
reg_field = ops[i].reg;
else if (rm_field == SCC_X86_REG_INVALID)
rm_field = ops[i].reg;
}
} else if (ops[i].kind == SCC_X86_OPR_MEM) {
base_reg = ops[i].mem.base;
idx_reg = ops[i].mem.index;
} else if (ops[i].kind == SCC_X86_OPR_IMM ||
ops[i].kind == SCC_X86_OPR_RELBR) {
imm_val = ops[i].imm;
imm_idx = i;
}
}
int op_width = infer_operand_width(info, ops);
LOG_INFO("[OPWIDTH] %d bits", op_width);
// +++ 新增:无 ModRM 时,寄存器用 REX.B 扩展 +++
if (!enc->has_modrm) {
rm_field = reg_field;
reg_field = SCC_X86_REG_INVALID;
}
emit_legacy_prefixes(mcode, enc, reg_field, rm_field, base_reg, idx_reg);
emit_rex(mcode, enc, reg_field, rm_field, base_reg, idx_reg);
emit_escape_map(mcode, enc);
if (enc->has_modrm) {
emit_opcode(mcode, enc, rm_field, base_reg);
emit_modrm_sib_disp(mcode, info, ops, op_width);
} else {
// 无 ModRMopcode 中的寄存器来自 rm_field
emit_opcode(mcode, enc, rm_field, base_reg);
if (imm_idx >= 0) {
emit_immediate(mcode, enc, tmpl, imm_idx, imm_val, op_width);
}
}
return 0;
}