- 在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): 改进错误处理机制 - 修正语义分析上下文变量命名 - 添加解析错误码检查,及时返回错误状态
403 lines
14 KiB
C
403 lines
14 KiB
C
#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);
|
||
}
|
||
}
|