Files
scc/libs/ir/mir/src/mir_x86.c
zzy b06c4fe3cc feat(ast2ir): 添加AST上下文支持并修复类型转换逻辑
- 在scc_ast2ir_ctx_t中添加ast_ctx字段用于访问AST上下文
- 修改scc_ast2ir_ctx_init函数签名以接收ast_ctx参数
- 修复enum类型的处理逻辑,使用正确的内置类型获取方式
- 修正for循环控制流中错误的跳转目标
- 移除未使用的parse_struct_union_layout函数

refactor(cfg): 优化模块接口的const正确性

- 将scc_cfg_module_unsafe_get_*系列函数的module参数标记为const
- 提高接口的安全性和一致性

refactor(lir): 简化寄存器定义宏

- 移除未使用的SCC_LIR_PREG宏定义
- 简化头文件中的冗余声明

fix(hir2lir): 修复空指针常量的表示方式

- 修正NULL值的AP整数表示,正确初始化ap结构体字段
- 确保空指针在低级IR中被正确表示

refactor(mir): 重构函数元数据结构

- 为MIR函数元数据添加栈槽位和寄存器分配相关字段
- 定义新的栈槽位数据结构scc_mir_stack_slot_t
- 添加函数元数据初始化函数scc_mir_func_meta_init

refactor(x86): 改进后端代码生成

- 修正ret指令生成,使用近返回指令RET_NEAR
- 修复伪alloca指令的形式转换问题
- 改进选择函数的const正确性
- 正确初始化函数元数据结构

style(config): 添加MIR阶段配置选项

- 为MIR各个处理阶段添加配置标志
- 包括寄存器分配、栈布局和前言后记生成的输出选项

fix(parser): 改进错误处理机制

- 修正语义分析上下文变量命名
- 添加解析错误码检查,及时返回错误状态
2026-05-01 22:51:31 +08:00

403 lines
14 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#include <scc_lir_module.h>
#include <scc_mir_module.h>
#include <scc_tree_dump.h>
#include <x86/scc_x86_iform.c>
#include <x86/scc_x86_reg.c>
static const char *preg_name(int preg_id) {
if (preg_id < 1 || preg_id >= SCC_X86_REG_COUNT)
return "???";
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;
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) {
if (i == 0)
scc_tree_dump_append(td, " ");
else
scc_tree_dump_append_fmt(td, ", ");
scc_mir_operand_t *op = &instr->operands[i];
switch (op->kind) {
case SCC_MIR_OP_VREG:
scc_tree_dump_append_fmt(td, "$%d", op->vreg);
break;
case SCC_MIR_OP_PREG:
scc_tree_dump_append_fmt(td, "$%s", preg_name(op->preg));
break;
case SCC_MIR_OP_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);
break;
case SCC_MIR_OP_SYMBOL:
scc_tree_dump_append_fmt(td, "@%s", op->symbol);
break;
default:
break;
}
}
}
typedef struct x86_isel {
scc_mir_instr_vec_t instrs;
} x86_isel_t;
static void add_instr(x86_isel_t *isel, const scc_mir_instr_t *instr) {
scc_vec_push(isel->instrs, *instr);
}
static inline void add_instr_0(x86_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(x86_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(x86_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);
}
// 将 LIR 值转换为 MIR 操作数
static scc_mir_operand_t lir_val_to_mir_op(const scc_lir_val_t *val) {
scc_mir_operand_t op = {0};
switch (val->kind) {
case SCC_LIR_INSTR_KIND_NONE:
op.kind = SCC_MIR_OP_NONE;
break;
case SCC_LIR_INSTR_KIND_VREG:
op.kind = SCC_MIR_OP_VREG;
op.vreg = val->data.reg;
break;
case SCC_LIR_INSTR_KIND_IMM:
op.kind = SCC_MIR_OP_IMM;
// FIXME hack ap
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;
break;
case SCC_LIR_INSTR_KIND_SYMBOL:
op.kind = SCC_MIR_OP_SYMBOL;
op.symbol = val->data.symbol;
break;
default:
UNREACHABLE();
}
return op;
}
static void sel_mir(x86_isel_t *isel, const scc_lir_instr_t *instr) {
switch (instr->op) {
case SCC_LIR_MOV: {
add_instr_2(isel, SCC_X86_IFORM_MOV_GPRV_GPRV_89,
lir_val_to_mir_op(&instr->to),
lir_val_to_mir_op(&instr->arg0));
} break;
case SCC_LIR_LOAD: {
add_instr_2(isel, SCC_X86_IFORM_MOV_GPRV_MEMV,
lir_val_to_mir_op(&instr->to),
lir_val_to_mir_op(&instr->arg0));
} break;
case SCC_LIR_LOAD_ADDR: {
add_instr_2(isel, SCC_X86_IFORM_LEA_GPRV_AGEN,
lir_val_to_mir_op(&instr->to),
lir_val_to_mir_op(&instr->arg0));
} break;
case SCC_LIR_STORE:
case SCC_LIR_STORE_ADDR: {
add_instr_2(isel, SCC_X86_IFORM_MOV_MEMV_GPRV,
lir_val_to_mir_op(&instr->arg1),
lir_val_to_mir_op(&instr->arg0));
} break;
// case SCC_LIR_LEA:
// case SCC_LIR_NEG:
// case SCC_LIR_NOT:
// case SCC_LIR_FNEG:
// case SCC_LIR_FCVT:
case SCC_LIR_ALLOCA: {
add_instr_2(isel, (scc_x86_iform_t)SCC_MIR_PSUEDO_ALLOCA,
lir_val_to_mir_op(&instr->to),
(scc_mir_operand_t){
.kind = SCC_MIR_OP_IMM,
.imm = instr->size,
});
} break;
case SCC_LIR_ADD:
case SCC_LIR_SUB:
case SCC_LIR_MUL:
case SCC_LIR_AND:
case SCC_LIR_OR:
case SCC_LIR_XOR:
case SCC_LIR_SHL:
case SCC_LIR_SHR:
case SCC_LIR_SAR: {
int base;
bool is_commutative =
(instr->op != SCC_LIR_SUB && instr->op != SCC_LIR_SHL &&
instr->op != SCC_LIR_SHR && instr->op != SCC_LIR_SAR);
switch (instr->op) {
case SCC_LIR_ADD:
base = SCC_X86_IFORM_ADD_GPRV_GPRV_01;
break;
case SCC_LIR_SUB:
base = SCC_X86_IFORM_SUB_GPRV_GPRV_29;
break;
case SCC_LIR_AND:
base = SCC_X86_IFORM_AND_GPRV_GPRV_21;
break;
case SCC_LIR_OR:
base = SCC_X86_IFORM_OR_GPRV_GPRV_09;
break;
case SCC_LIR_XOR:
base = SCC_X86_IFORM_XOR_GPRV_GPRV_31;
break;
case SCC_LIR_MUL:
base = SCC_X86_IFORM_IMUL_GPRV_GPRV;
break;
case SCC_LIR_SHL:
base = SCC_X86_IFORM_SHR_GPRV_IMMB;
break; // 简化,实际应处理 CL 移位
case SCC_LIR_SHR:
base = SCC_X86_IFORM_SHR_GPRV_IMMB;
break;
case SCC_LIR_SAR:
base = SCC_X86_IFORM_SAR_GPRV_IMMB;
break;
default:
return;
}
if (instr->arg0.kind == SCC_LIR_INSTR_KIND_IMM) {
add_instr_2(isel, SCC_X86_IFORM_MOV_GPRV_IMMV,
lir_val_to_mir_op(&instr->to),
lir_val_to_mir_op(&instr->arg0));
}
// 三地址转两地址:若 to != arg0需先 mov to, arg0
if (instr->to.kind == SCC_LIR_INSTR_KIND_VREG &&
instr->arg0.kind == SCC_LIR_INSTR_KIND_VREG &&
instr->to.data.reg != instr->arg0.data.reg) {
add_instr_2(isel, SCC_X86_IFORM_MOV_GPRV_GPRV_89,
lir_val_to_mir_op(&instr->to),
lir_val_to_mir_op(&instr->arg0));
}
// 如果是立即数,使用 RI 变体
if (instr->arg1.kind == SCC_LIR_INSTR_KIND_IMM) {
// 需要根据立即数大小选择 RI8/RI32
add_instr_2(isel, base, lir_val_to_mir_op(&instr->to),
lir_val_to_mir_op(&instr->arg1));
break;
}
// 生成两地址运算指令
add_instr_2(isel, base, lir_val_to_mir_op(&instr->to),
lir_val_to_mir_op(&instr->arg1));
} break;
// case SCC_LIR_DIV_S:
// case SCC_LIR_DIV_U:
// case SCC_LIR_REM_S:
// case SCC_LIR_REM_U:
// case SCC_LIR_FADD:
// case SCC_LIR_FSUB:
// case SCC_LIR_FMUL:
// case SCC_LIR_FDIV:
// dump_operand(ctx, &instr->to);
// scc_tree_dump_append(td, ", ");
// dump_operand(ctx, &instr->arg0);
// scc_tree_dump_append(td, ", ");
// dump_operand(ctx, &instr->arg1);
// break;
// case SCC_LIR_CMP:
// dump_operand(ctx, &instr->to);
// scc_tree_dump_append_fmt(td, ", %s, ",
// cond_to_string(instr->metadata.cond));
// dump_operand(ctx, &instr->arg0);
// scc_tree_dump_append(td, ", ");
// dump_operand(ctx, &instr->arg1);
// break;
// case SCC_LIR_BR:
// dump_operand(ctx, &instr->arg0);
// scc_tree_dump_append_fmt(td, ", BB#%zu, BB#%zu",
// instr->metadata.br.true_target,
// instr->metadata.br.false_target);
// break;
case SCC_LIR_JMP: {
add_instr_1(isel, SCC_X86_IFORM_JMP_GPRV,
(scc_mir_operand_t){
.kind = SCC_MIR_OP_BLOCK,
.block_id = instr->metadata.jmp_target,
});
} break;
// case SCC_LIR_JMP_INDIRECT:
// dump_operand(ctx, &instr->arg0);
// break;
case SCC_LIR_CALL: {
const struct scc_lir_call *c = &instr->metadata.call;
Assert(c->callee != nullptr);
add_instr_1(isel, SCC_X86_IFORM_CALL_NEAR_GPRV,
(scc_mir_operand_t){
.kind = SCC_MIR_OP_SYMBOL,
.symbol = c->callee,
});
} break;
// case SCC_LIR_CALL: {
// const struct scc_lir_call *c = &instr->metadata.call;
// if (c->ret_vreg.kind != SCC_LIR_INSTR_KIND_NONE) {
// dump_operand(ctx, &c->ret_vreg);
// scc_tree_dump_append(td, " = ");
// }
// scc_tree_dump_append_fmt(td, "call @%s(",
// c->callee ? c->callee : "<null>");
// for (u8 i = 0; i < c->arg_count; i++) {
// if (i > 0)
// scc_tree_dump_append(td, ", ");
// dump_operand(ctx, &c->args[i]);
// }
// scc_tree_dump_append_fmt(td, ") clobber=0x%llx",
// (unsigned long long)c->clobber_mask);
// break;
// }
// case SCC_LIR_CALL_INDIRECT: {
// const struct scc_lir_call_indirect *c =
// &instr->metadata.call_indirect; if (c->ret_vreg.kind !=
// SCC_LIR_INSTR_KIND_NONE) {
// dump_operand(ctx, &c->ret_vreg);
// scc_tree_dump_append(td, " = ");
// }
// scc_tree_dump_append(td, "call ");
// dump_operand(ctx, &c->target);
// scc_tree_dump_append(td, "(");
// for (u8 i = 0; i < c->arg_count; i++) {
// if (i > 0)
// scc_tree_dump_append(td, ", ");
// dump_operand(ctx, &c->args[i]);
// }
// scc_tree_dump_append_fmt(td, ") clobber=0x%llx",
// (unsigned long long)c->clobber_mask);
// break;
// }
case SCC_LIR_RET: {
if (instr->metadata.ret_val.kind != SCC_LIR_INSTR_KIND_NONE) {
// FIXME target ABI
add_instr_2(isel, SCC_X86_IFORM_MOV_GPRV_GPRV_89,
(scc_mir_operand_t){
.kind = SCC_MIR_OP_PREG,
.preg = SCC_X86_REG_RAX,
},
lir_val_to_mir_op(&instr->metadata.ret_val));
}
add_instr_0(isel, SCC_X86_IFORM_RET_NEAR);
} break;
// case SCC_LIR_PARALLEL_COPY: {
// const struct scc_lir_parallel_copy *pc =
// &instr->metadata.parallel_copy; scc_tree_dump_append(td, "[");
// for (u8 i = 0; i < pc->num_copies; i++) {
// if (i > 0)
// scc_tree_dump_append(td, ", ");
// dump_operand(ctx, &pc->dests[i]);
// scc_tree_dump_append(td, " <- ");
// dump_operand(ctx, &pc->srcs[i]);
// }
// scc_tree_dump_append(td, "]");
// break;
// }
// case SCC_LIR_VA_START:
// dump_operand(ctx, &instr->metadata.va_start.ap);
// scc_tree_dump_append(td, ", ");
// dump_operand(ctx, &instr->metadata.va_start.last);
// break;
// case SCC_LIR_VA_ARG:
// dump_operand(ctx, &instr->metadata.va_arg.to);
// scc_tree_dump_append(td, " = va_arg ");
// dump_operand(ctx, &instr->metadata.va_arg.ap);
// scc_tree_dump_append_fmt(td, ", size=%u, align=%u, float=%d",
// instr->metadata.va_arg.type_size,
// instr->metadata.va_arg.type_align,
// instr->metadata.va_arg.is_float);
// break;
// case SCC_LIR_VA_END:
// dump_operand(ctx, &instr->metadata.va_end.ap);
// break;
// case SCC_LIR_VA_COPY:
// dump_operand(ctx, &instr->metadata.va_copy.dest);
// scc_tree_dump_append(td, ", ");
// dump_operand(ctx, &instr->metadata.va_copy.src);
// break;
// case SCC_LIR_NOP:
// break;
//
default:
break;
UNREACHABLE();
break;
}
}
static void sel_func(const scc_lir_module_t *lir_module,
const scc_lir_func_t *func) {
x86_isel_t isel;
scc_vec_foreach(func->bblocks, i) {
scc_vec_init(isel.instrs);
scc_cfg_bblock_id_t id = scc_vec_at(func->bblocks, i);
scc_cfg_bblock_t *bb =
scc_cfg_module_unsafe_get_bblock(&lir_module->cfg_module, id);
scc_lir_instr_vec_t *instrs = SCC_LIR_BBLOCK_VALUES(bb);
scc_vec_foreach(*instrs, i) {
const scc_lir_instr_t *ins = &scc_vec_at(*instrs, i);
sel_mir(&isel, ins);
}
bb->values = *(scc_cfg_value_vec_t *)&isel.instrs;
scc_vec_init(isel.instrs);
}
}
void scc_isel_x86_64(scc_mir_module_t *mir_module,
const scc_lir_module_t *lir_module) {
scc_vec_foreach(lir_module->cfg_module.funcs, i) {
if (i == 0)
continue;
scc_lir_func_t *func = &scc_vec_at(lir_module->cfg_module.funcs, i);
scc_mir_func_meta_t *func_meta =
scc_malloc(sizeof(scc_mir_func_meta_t));
Assert(func_meta != nullptr);
scc_mir_func_meta_init(func_meta);
scc_vec_push(mir_module->func_metas, func_meta);
func->meta = func_meta;
sel_func(lir_module, func);
}
}