feat(ast2ir): 实现C11类型提升系统并重构HIR基本块管理
- 新增 scc_ast2ir_promote.c 实现整数提升(6.3.1.1)和寻常算术转换(6.3.1.8) - 重构 HIR Builder: bblock → create_bblock + append_bblock,引入BBList链表管理 - AST2IR 全面集成类型提升:二元运算、赋值、函数调用参数、自增/自减操作符 - 变参函数支持:跳过 ... 假参数,实现默认参数提升(float→double等) - 简化 HIR Dump 实现 - MIR: Win64 ABI改进、x86指令选择优化 - 新增 printf 测试用例
This commit is contained in:
@@ -101,40 +101,6 @@ scc_mir_x86_instr_3(scc_mir_x86_instr_t *out, scc_x86_iform_t opcode,
|
||||
out->x86_instr.src_loc = pos;
|
||||
}
|
||||
|
||||
static inline scc_x86_iform_t
|
||||
scc_mir_x86_mov_reg_mem(scc_x86_operand_value_t op0,
|
||||
scc_x86_operand_value_t op1) {
|
||||
Assert(op0.size == op1.size);
|
||||
Assert(op0.kind == SCC_X86_OPR_REG && op1.kind == SCC_X86_OPR_MEM);
|
||||
return op0.size == 1 ? SCC_X86_IFORM_MOV_GPR8_MEMB
|
||||
: SCC_X86_IFORM_MOV_GPRV_MEMV;
|
||||
}
|
||||
static inline scc_x86_iform_t
|
||||
scc_mir_x86_mov_mem_reg(scc_x86_operand_value_t op0,
|
||||
scc_x86_operand_value_t op1) {
|
||||
Assert(op0.size == op1.size);
|
||||
Assert(op0.kind == SCC_X86_OPR_MEM && op1.kind == SCC_X86_OPR_REG);
|
||||
return op0.size == 1 ? SCC_X86_IFORM_MOV_MEMB_GPR8
|
||||
: SCC_X86_IFORM_MOV_MEMV_GPRV;
|
||||
}
|
||||
static inline scc_x86_iform_t
|
||||
scc_mir_x86_mov_reg_reg(scc_x86_operand_value_t op0,
|
||||
scc_x86_operand_value_t op1) {
|
||||
Assert(op0.size == op1.size);
|
||||
Assert(op0.kind == SCC_X86_OPR_REG && op1.kind == SCC_X86_OPR_REG);
|
||||
return op0.size == 1 ? SCC_X86_IFORM_MOV_GPR8_GPR8_8A
|
||||
: SCC_X86_IFORM_MOV_GPRV_GPRV_8B;
|
||||
}
|
||||
|
||||
static inline scc_x86_iform_t
|
||||
scc_mir_x86_mov_reg_imm(scc_x86_operand_value_t op0,
|
||||
scc_x86_operand_value_t op1) {
|
||||
Assert(op0.size == op1.size);
|
||||
Assert(op0.kind == SCC_X86_OPR_REG && op1.kind == SCC_X86_OPR_IMM);
|
||||
return op0.size == 1 ? SCC_X86_IFORM_MOV_GPR8_IMMB_B0
|
||||
: SCC_X86_IFORM_MOV_GPRV_IMMV;
|
||||
}
|
||||
|
||||
void scc_x86_emit_move_to_vec(scc_mir_x86_instr_vec_t *vec,
|
||||
scc_x86_operand_value_t dst,
|
||||
scc_x86_operand_value_t src);
|
||||
|
||||
@@ -29,6 +29,7 @@ typedef struct scc_mir_stack_slot {
|
||||
int size; // 通常是 8 字节 (指针大小)
|
||||
int alignment; // 对齐要求
|
||||
int offset; // 相对于 RSP 的偏移 (最终确定)
|
||||
int arg_idx; // == 0 means local slot, > 0 means argument slot
|
||||
} scc_mir_stack_slot_t;
|
||||
typedef SCC_VEC(scc_mir_stack_slot_t) scc_mir_stack_slot_vec_t;
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
void scc_win_pc_x64_abi_lowering(scc_abi_lowering_t *abi_lowering);
|
||||
void scc_win_pc_x64_reg_alloc_fill(scc_reg_alloc_op_t *ops);
|
||||
void scc_win_pc_x64_frame_alloc_init(scc_frame_layout_t *ctx);
|
||||
void scc_win_pc_x64_frame_layout_init(scc_frame_layout_t *ctx);
|
||||
void scc_win_pc_x64_prolog_epilog_init(scc_prolog_epilog_t *ctx);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -47,9 +47,14 @@ void scc_x86_instr_dump(scc_tree_dump_t *td, const scc_mir_func_t *func,
|
||||
if (slot == nullptr) {
|
||||
scc_tree_dump_append_fmt(td, "[slot:%d<null>]", slot_id);
|
||||
} else {
|
||||
scc_tree_dump_append_fmt(td, "[slot:%d(of=%d,sz=%d,al=%d)]",
|
||||
slot_id, slot->offset, slot->size,
|
||||
slot->alignment);
|
||||
if (slot->arg_idx > 0) {
|
||||
scc_tree_dump_append_fmt(td, "[slot:arg%d]",
|
||||
slot->arg_idx);
|
||||
} else {
|
||||
scc_tree_dump_append_fmt(
|
||||
td, "[slot:%d(of=%d,sz=%d,al=%d)]", slot_id,
|
||||
slot->offset, slot->size, slot->alignment);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
scc_tree_dump_append(td, "(");
|
||||
@@ -137,29 +142,6 @@ scc_x86_operand_value_t scc_x86_lir_val_to_mir_op(scc_x86_64_isel_t *isel,
|
||||
return op;
|
||||
}
|
||||
|
||||
static scc_x86_operand_value_t build_mem_op(scc_x86_64_isel_t *isel,
|
||||
scc_x86_operand_value_t base,
|
||||
scc_x86_operand_value_t index,
|
||||
int scale, i64 offset) {
|
||||
(void)isel;
|
||||
scc_x86_operand_value_t mem_op;
|
||||
mem_op.kind = SCC_X86_OPR_MEM;
|
||||
// base 必须为寄存器
|
||||
Assert(base.kind == SCC_X86_OPR_REG);
|
||||
mem_op.mem.base = base.reg;
|
||||
// index 可选
|
||||
if (index.kind == SCC_X86_OPR_REG) {
|
||||
mem_op.mem.index = index.reg;
|
||||
mem_op.mem.scale = scale;
|
||||
} else {
|
||||
mem_op.mem.index = SCC_X86_REG_INVALID;
|
||||
mem_op.mem.scale = 1;
|
||||
}
|
||||
mem_op.mem.disp.displacement = offset;
|
||||
mem_op.mem.disp.displacement_bits = 0;
|
||||
return mem_op;
|
||||
}
|
||||
|
||||
// 虚拟临时寄存器分配(简单递增)
|
||||
static scc_x86_operand_value_t new_vreg_temp(scc_x86_64_isel_t *isel,
|
||||
int size) {
|
||||
@@ -247,20 +229,21 @@ void scc_x86_emit_move(scc_x86_64_isel_t *isel, scc_x86_operand_value_t dst_reg,
|
||||
|
||||
void scc_x86_emit_load(scc_x86_64_isel_t *isel, scc_x86_operand_value_t dst,
|
||||
scc_x86_operand_value_t src) {
|
||||
scc_x86_operand_value_t tmp_reg = dst;
|
||||
if (dst.kind != SCC_X86_OPR_REG) {
|
||||
scc_x86_operand_value_t tmp_reg = new_vreg_temp(isel, dst.size);
|
||||
scc_x86_emit_move(isel, tmp_reg, dst);
|
||||
dst = tmp_reg;
|
||||
tmp_reg = new_vreg_temp(isel, src.size);
|
||||
}
|
||||
scc_x86_emit_load_to_vec(&isel->instrs, tmp_reg, src);
|
||||
if (dst.kind != SCC_X86_OPR_REG) {
|
||||
scc_x86_emit_move(isel, dst, tmp_reg);
|
||||
}
|
||||
|
||||
scc_x86_emit_load_to_vec(&isel->instrs, dst, src);
|
||||
}
|
||||
|
||||
void scc_x86_emit_store(scc_x86_64_isel_t *isel, scc_x86_operand_value_t dst,
|
||||
scc_x86_operand_value_t src) {
|
||||
if (src.kind != SCC_X86_OPR_REG) {
|
||||
if (src.kind == SCC_X86_OPR_MEM) {
|
||||
scc_x86_operand_value_t tmp_reg = new_vreg_temp(isel, src.size);
|
||||
scc_x86_emit_move(isel, tmp_reg, src);
|
||||
scc_x86_emit_load(isel, tmp_reg, src);
|
||||
src = tmp_reg;
|
||||
}
|
||||
scc_x86_emit_store_to_vec(&isel->instrs, dst, src);
|
||||
@@ -279,52 +262,55 @@ static void emit_load_addr(scc_x86_64_isel_t *isel, scc_x86_operand_value_t dst,
|
||||
|
||||
// ---- 处理 base ----
|
||||
scc_x86_operand_value_t base_reg = base;
|
||||
if (base.kind != SCC_X86_OPR_REG) {
|
||||
base_reg = new_vreg_temp(isel, size);
|
||||
switch (base.kind) {
|
||||
case SCC_X86_OPR_REG: {
|
||||
base_reg = base;
|
||||
} break;
|
||||
case SCC_X86_OPR_RELOC: {
|
||||
Assert(base.reloc.target == SCC_X86_RELOC_TARGET_SYMBOL);
|
||||
base_reg = new_vreg_temp(isel, 8);
|
||||
scc_x86_emit_move(isel, base_reg, base);
|
||||
} break;
|
||||
case SCC_X86_OPR_MEM: {
|
||||
base_reg = new_vreg_temp(isel, 8);
|
||||
scc_x86_emit_move(isel, base_reg, base);
|
||||
} break;
|
||||
default: {
|
||||
Panic("Unsupported base kind %d in load_addr", base.kind);
|
||||
}
|
||||
}
|
||||
|
||||
// ---- 处理 index * scale ----
|
||||
scc_x86_operand_value_t scaled_index = index;
|
||||
Assert(index.kind != SCC_X86_OPR_NONE);
|
||||
// 确保 index 在寄存器中
|
||||
if (index.kind != SCC_X86_OPR_REG) {
|
||||
scc_x86_operand_value_t index_tmp = new_vreg_temp(isel, index.size);
|
||||
scc_x86_emit_move(isel, index_tmp, index);
|
||||
index = index_tmp;
|
||||
scc_x86_operand_value_t index_reg = index;
|
||||
switch (index.kind) {
|
||||
case SCC_X86_OPR_REG: {
|
||||
index_reg = index;
|
||||
} break;
|
||||
case SCC_X86_OPR_RELOC: {
|
||||
Assert(index.reloc.target == SCC_X86_RELOC_TARGET_SYMBOL);
|
||||
index_reg = new_vreg_temp(isel, 8);
|
||||
scc_x86_emit_move(isel, index_reg, index);
|
||||
} break;
|
||||
case SCC_X86_OPR_MEM: {
|
||||
index_reg = new_vreg_temp(isel, 8);
|
||||
scc_x86_emit_move(isel, index_reg, index);
|
||||
} break;
|
||||
case SCC_X86_OPR_IMM: {
|
||||
index_reg = new_vreg_temp(isel, index.size);
|
||||
scc_x86_emit_move(isel, index_reg, index);
|
||||
} break;
|
||||
default: {
|
||||
Panic("Unsupported index kind %d in load_addr", base.kind);
|
||||
}
|
||||
}
|
||||
|
||||
// ---- 计算 base + scaled_index ----
|
||||
scc_x86_operand_value_t sum = base_reg;
|
||||
if (base_reg.kind == SCC_X86_OPR_REG &&
|
||||
scaled_index.kind == SCC_X86_OPR_REG) {
|
||||
if (dst.reg != base_reg.reg) {
|
||||
scc_x86_emit_move(isel, dst, base_reg);
|
||||
sum = dst;
|
||||
}
|
||||
add_instr_2(isel, SCC_X86_IFORM_ADD_GPRV_GPRV_03, sum, scaled_index);
|
||||
} else if (base_reg.kind == SCC_X86_OPR_REG) {
|
||||
if (dst.reg != base_reg.reg)
|
||||
scc_x86_emit_move(isel, dst, base_reg);
|
||||
sum = dst;
|
||||
} else if (scaled_index.kind == SCC_X86_OPR_REG) {
|
||||
scc_x86_emit_move(isel, dst, scaled_index);
|
||||
sum = dst;
|
||||
} else {
|
||||
// base 和 index 都无效 => 结果为 0
|
||||
scc_x86_emit_move(isel, dst, scc_x86_op_imm(0, size));
|
||||
return;
|
||||
}
|
||||
|
||||
// ---- 加上 offset ----
|
||||
if (offset != 0) {
|
||||
scc_x86_operand_value_t mem_op = build_mem_op(
|
||||
isel, sum, (scc_x86_operand_value_t){.kind = SCC_X86_OPR_NONE}, 1,
|
||||
offset);
|
||||
scc_x86_emit_move(isel, dst, mem_op);
|
||||
} else if (sum.reg != dst.reg) {
|
||||
scc_x86_emit_move(isel, dst, sum);
|
||||
}
|
||||
scc_x86_operand_value_t mem_op =
|
||||
scc_x86_op_mem((scc_x86_mem_t){.base = base_reg.reg,
|
||||
.index = index_reg.reg,
|
||||
.scale = scale,
|
||||
.disp.displacement = offset,
|
||||
.disp.displacement_bits = 8},
|
||||
size);
|
||||
scc_x86_emit_move(isel, dst, mem_op);
|
||||
}
|
||||
|
||||
static void sel_mir(scc_x86_64_isel_t *isel, const scc_lir_instr_t *instr) {
|
||||
@@ -455,8 +441,9 @@ static void sel_mir(scc_x86_64_isel_t *isel, const scc_lir_instr_t *instr) {
|
||||
case SCC_LIR_CMP: {
|
||||
Assert(src0.size == src1.size);
|
||||
if (scc_x86_op_is_vreg(&src0) && src1.kind == SCC_X86_OPR_IMM)
|
||||
// SCC_X86_IFORM_CMP_GPR8_IMMB_82R7 历史遗留指令在amd64中已不再使用
|
||||
add_instr_2(isel,
|
||||
src0.size == 1 ? SCC_X86_IFORM_CMP_GPR8_IMMB_82R7
|
||||
src0.size == 1 ? SCC_X86_IFORM_CMP_GPR8_IMMB_80R7
|
||||
: SCC_X86_IFORM_CMP_GPRV_IMMZ,
|
||||
src0, src1);
|
||||
else if (scc_x86_op_is_vreg(&src0) && scc_x86_op_is_vreg(&src1))
|
||||
@@ -519,6 +506,44 @@ static void sel_mir(scc_x86_64_isel_t *isel, const scc_lir_instr_t *instr) {
|
||||
break;
|
||||
}
|
||||
|
||||
/* ---- 类型扩展 ---- */
|
||||
case SCC_LIR_EXTEND: {
|
||||
int from_size = instr->metadata.extend.from_size;
|
||||
scc_x86_operand_value_t ext_src =
|
||||
scc_x86_lir_val_to_mir_op(isel, &instr->arg0, from_size);
|
||||
|
||||
if (instr->ext == SCC_LIR_EXT_ZEXT) {
|
||||
if (from_size == 4) {
|
||||
// 32→64: x86-64 写32位寄存器自动零扩展到64位
|
||||
scc_x86_emit_move(isel, dst, ext_src);
|
||||
} else {
|
||||
scc_x86_iform_t iform = (from_size == 1)
|
||||
? SCC_X86_IFORM_MOVZX_GPRV_GPR8
|
||||
: SCC_X86_IFORM_MOVZX_GPRV_GPR16;
|
||||
add_instr_2(isel, iform, dst, ext_src);
|
||||
}
|
||||
} else if (instr->ext == SCC_LIR_EXT_SEXT) {
|
||||
scc_x86_iform_t iform;
|
||||
switch (from_size) {
|
||||
case 1:
|
||||
iform = SCC_X86_IFORM_MOVSX_GPRV_GPR8;
|
||||
break;
|
||||
case 2:
|
||||
iform = SCC_X86_IFORM_MOVSX_GPRV_GPR16;
|
||||
break;
|
||||
case 4:
|
||||
iform = SCC_X86_IFORM_MOVSXD_GPRV_GPRZ;
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
add_instr_2(isel, iform, dst, ext_src);
|
||||
} else {
|
||||
UNREACHABLE();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* ---- 其他(占位) ---- */
|
||||
case SCC_LIR_NOP:
|
||||
add_instr_0(isel, SCC_X86_IFORM_NOP_90);
|
||||
@@ -575,11 +600,10 @@ static void sel_func(const scc_lir_module_t *lir_module,
|
||||
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);
|
||||
scc_lir_instr_t *ins = &scc_vec_at(*instrs, i);
|
||||
// HACK BR size
|
||||
if (ins->op == SCC_LIR_CMP && i + 1 < scc_vec_size(*instrs) &&
|
||||
scc_vec_at(*instrs, i + 1).op == SCC_LIR_BR) {
|
||||
scc_vec_at(*instrs, i + 1).size = ins->size;
|
||||
if (ins->op == SCC_LIR_BR) {
|
||||
ins->size = scc_vec_at(*instrs, i - 1).size;
|
||||
}
|
||||
sel_mir(isel, ins);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,47 @@
|
||||
#include <arch/scc_x86_mir.h>
|
||||
|
||||
static inline scc_x86_iform_t
|
||||
scc_mir_x86_mov_reg_mem(scc_x86_operand_value_t op0,
|
||||
scc_x86_operand_value_t op1) {
|
||||
Assert(op0.size == op1.size);
|
||||
Assert(op0.kind == SCC_X86_OPR_REG && op1.kind == SCC_X86_OPR_MEM);
|
||||
return op0.size == 1 ? SCC_X86_IFORM_MOV_GPR8_MEMB
|
||||
: SCC_X86_IFORM_MOV_GPRV_MEMV;
|
||||
}
|
||||
static inline scc_x86_iform_t
|
||||
scc_mir_x86_mov_reg_reg(scc_x86_operand_value_t op0,
|
||||
scc_x86_operand_value_t op1) {
|
||||
Assert(op0.size == op1.size);
|
||||
Assert(op0.kind == SCC_X86_OPR_REG && op1.kind == SCC_X86_OPR_REG);
|
||||
return op0.size == 1 ? SCC_X86_IFORM_MOV_GPR8_GPR8_8A
|
||||
: SCC_X86_IFORM_MOV_GPRV_GPRV_8B;
|
||||
}
|
||||
|
||||
static inline scc_x86_iform_t
|
||||
scc_mir_x86_mov_reg_imm(scc_x86_operand_value_t op0,
|
||||
scc_x86_operand_value_t op1) {
|
||||
Assert(op0.size == op1.size);
|
||||
Assert(op0.kind == SCC_X86_OPR_REG && op1.kind == SCC_X86_OPR_IMM);
|
||||
return op0.size == 1 ? SCC_X86_IFORM_MOV_GPR8_IMMB_B0
|
||||
: SCC_X86_IFORM_MOV_GPRV_IMMV;
|
||||
}
|
||||
static inline scc_x86_iform_t
|
||||
scc_mir_x86_mov_mem_reg(scc_x86_operand_value_t op0,
|
||||
scc_x86_operand_value_t op1) {
|
||||
Assert(op0.size == op1.size);
|
||||
Assert(op0.kind == SCC_X86_OPR_MEM && op1.kind == SCC_X86_OPR_REG);
|
||||
return op0.size == 1 ? SCC_X86_IFORM_MOV_MEMB_GPR8
|
||||
: SCC_X86_IFORM_MOV_MEMV_GPRV;
|
||||
}
|
||||
static inline scc_x86_iform_t
|
||||
scc_mir_x86_mov_mem_imm(scc_x86_operand_value_t op0,
|
||||
scc_x86_operand_value_t op1) {
|
||||
Assert(op0.size == op1.size);
|
||||
Assert(op0.kind == SCC_X86_OPR_MEM && op1.kind == SCC_X86_OPR_IMM);
|
||||
return op0.size == 1 ? SCC_X86_IFORM_MOV_MEMB_IMMB
|
||||
: SCC_X86_IFORM_MOV_MEMV_IMMZ;
|
||||
}
|
||||
|
||||
void scc_x86_emit_move_to_vec(scc_mir_x86_instr_vec_t *vec,
|
||||
scc_x86_operand_value_t dst,
|
||||
scc_x86_operand_value_t src) {
|
||||
@@ -7,21 +49,35 @@ void scc_x86_emit_move_to_vec(scc_mir_x86_instr_vec_t *vec,
|
||||
LOG_WARN("Mismatched register sizes for move %d != %d", dst.size,
|
||||
src.size);
|
||||
}
|
||||
Assert(dst.kind == SCC_X86_OPR_REG);
|
||||
scc_mir_x86_instr_t ins;
|
||||
if (src.kind == SCC_X86_OPR_REG) {
|
||||
scc_mir_x86_instr_2(&ins, scc_mir_x86_mov_reg_reg(dst, src), dst, src,
|
||||
scc_pos_create());
|
||||
} else if (src.kind == SCC_X86_OPR_IMM) {
|
||||
scc_mir_x86_instr_2(&ins, scc_mir_x86_mov_reg_imm(dst, src), dst, src,
|
||||
scc_pos_create());
|
||||
} else if (src.kind == SCC_X86_OPR_MEM ||
|
||||
(src.kind == SCC_X86_OPR_RELOC &&
|
||||
src.reloc.target == SCC_X86_RELOC_TARGET_SYMBOL)) {
|
||||
scc_mir_x86_instr_2(&ins, SCC_X86_IFORM_LEA_GPRV_AGEN, dst, src,
|
||||
scc_pos_create());
|
||||
if (dst.kind == SCC_X86_OPR_REG) {
|
||||
if (src.kind == SCC_X86_OPR_REG) {
|
||||
scc_mir_x86_instr_2(&ins, scc_mir_x86_mov_reg_reg(dst, src), dst,
|
||||
src, scc_pos_create());
|
||||
} else if (src.kind == SCC_X86_OPR_IMM) {
|
||||
scc_mir_x86_instr_2(&ins, scc_mir_x86_mov_reg_imm(dst, src), dst,
|
||||
src, scc_pos_create());
|
||||
} else if (src.kind == SCC_X86_OPR_MEM ||
|
||||
(src.kind == SCC_X86_OPR_RELOC &&
|
||||
src.reloc.target == SCC_X86_RELOC_TARGET_SYMBOL)) {
|
||||
Assert(dst.size == 8);
|
||||
scc_mir_x86_instr_2(&ins, SCC_X86_IFORM_LEA_GPRV_AGEN, dst, src,
|
||||
scc_pos_create());
|
||||
} else {
|
||||
Panic("emit_move: unsupported src kind %d", src.kind);
|
||||
}
|
||||
} else if (dst.kind == SCC_X86_OPR_MEM) {
|
||||
if (src.kind == SCC_X86_OPR_IMM) {
|
||||
scc_mir_x86_instr_2(&ins, scc_mir_x86_mov_mem_imm(dst, src), dst,
|
||||
src, scc_pos_create());
|
||||
} else if (src.kind == SCC_X86_OPR_REG) {
|
||||
scc_mir_x86_instr_2(&ins, scc_mir_x86_mov_mem_reg(dst, src), dst,
|
||||
src, scc_pos_create());
|
||||
} else {
|
||||
Panic("emit_move: unsupported src kind %d", src.kind);
|
||||
}
|
||||
} else {
|
||||
Panic("emit_move: unsupported src kind %d", src.kind);
|
||||
Panic("emit_move: unsupported dst kind %d", dst.kind);
|
||||
}
|
||||
scc_vec_push(*vec, ins);
|
||||
}
|
||||
@@ -65,7 +121,6 @@ void scc_x86_emit_store_to_vec(scc_mir_x86_instr_vec_t *vec,
|
||||
LOG_WARN("Mismatched sizes for store %d != %d", dst_addr.size,
|
||||
src.size);
|
||||
}
|
||||
Assert(src.kind == SCC_X86_OPR_REG);
|
||||
scc_x86_operand_value_t mem_op;
|
||||
if (dst_addr.kind == SCC_X86_OPR_REG) {
|
||||
mem_op = (scc_x86_operand_value_t){
|
||||
@@ -83,10 +138,17 @@ void scc_x86_emit_store_to_vec(scc_mir_x86_instr_vec_t *vec,
|
||||
} else if (dst_addr.kind == SCC_X86_OPR_MEM) {
|
||||
mem_op = dst_addr;
|
||||
} else {
|
||||
Panic("emit_store: dst_addr must be REG or MEM");
|
||||
Panic("emit_store: dst_addr kind not supported %d", dst_addr.kind);
|
||||
}
|
||||
scc_mir_x86_instr_t ins;
|
||||
scc_mir_x86_instr_2(&ins, scc_mir_x86_mov_mem_reg(mem_op, src), mem_op, src,
|
||||
scc_pos_create());
|
||||
if (src.kind == SCC_X86_OPR_REG) {
|
||||
scc_mir_x86_instr_2(&ins, scc_mir_x86_mov_mem_reg(mem_op, src), mem_op,
|
||||
src, scc_pos_create());
|
||||
} else if (src.kind == SCC_X86_OPR_IMM) {
|
||||
scc_mir_x86_instr_2(&ins, scc_mir_x86_mov_mem_imm(mem_op, src), mem_op,
|
||||
src, scc_pos_create());
|
||||
} else {
|
||||
Panic("unsupported src kind not supported %d", src.kind);
|
||||
}
|
||||
scc_vec_push(*vec, ins);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,8 +39,11 @@ int scc_mir_vreg_map2slot(scc_mir_func_t *func, int vreg, int size, int align) {
|
||||
return 0;
|
||||
}
|
||||
int new_slot = scc_vec_size(meta->stack_slots);
|
||||
scc_mir_stack_slot_t s = {
|
||||
.slot_id = new_slot, .size = size, .alignment = align, .offset = 0};
|
||||
scc_mir_stack_slot_t s = {.slot_id = new_slot,
|
||||
.size = size,
|
||||
.alignment = align,
|
||||
.offset = 0,
|
||||
.arg_idx = 0};
|
||||
scc_vec_push(meta->stack_slots, s);
|
||||
scc_hashtable_set(&meta->vreg2physic, (void *)(usize)vreg,
|
||||
(void *)(usize)new_slot);
|
||||
|
||||
@@ -14,7 +14,9 @@ void scc_frame_layout(scc_frame_layout_t *ctx, scc_mir_module_t *module) {
|
||||
scc_vec_foreach(module->cfg_module.funcs, i) {
|
||||
if (i == 0)
|
||||
continue;
|
||||
ctx->impl_fn(ctx, module, &scc_vec_at(module->cfg_module.funcs, i));
|
||||
scc_mir_func_t *func = &scc_vec_at(module->cfg_module.funcs, i);
|
||||
ctx->offset = SCC_MIR_FUNC_META(func)->frame_size;
|
||||
ctx->impl_fn(ctx, module, func);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,7 +71,7 @@ void scc_mir_pass(scc_mir_module_t *mir_module, scc_mir_pass_stage_t stage) {
|
||||
// scc_x86_peephole_optimize(mir_module);
|
||||
|
||||
scc_frame_layout_t frame_layout_ctx = {0};
|
||||
scc_win_pc_x64_frame_alloc_init(&frame_layout_ctx);
|
||||
scc_win_pc_x64_frame_layout_init(&frame_layout_ctx);
|
||||
scc_frame_layout(&frame_layout_ctx, mir_module);
|
||||
if (stage == SCC_MIR_STAGE_FRAME_LAYOUT) {
|
||||
return;
|
||||
|
||||
@@ -7,11 +7,13 @@
|
||||
|
||||
static const int WIN64_STACK_ALIGN = 16;
|
||||
|
||||
static void frame_alloc_impl(scc_frame_layout_t *ctx,
|
||||
scc_mir_module_t *mir_module,
|
||||
scc_mir_func_t *mir_func) {
|
||||
ctx->offset = 8;
|
||||
static void frame_layout_impl(scc_frame_layout_t *ctx,
|
||||
scc_mir_module_t *mir_module,
|
||||
scc_mir_func_t *mir_func) {
|
||||
ctx->offset += 8; // call return address frame
|
||||
scc_mir_func_meta_t *func_meta = SCC_MIR_FUNC_META(mir_func);
|
||||
|
||||
// Pass 1: 处理局部变量槽 (arg_idx == 0),从 RSP 向上分配偏移
|
||||
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 =
|
||||
@@ -25,16 +27,17 @@ static void frame_alloc_impl(scc_frame_layout_t *ctx,
|
||||
int slot_id = scc_x86_op_slot_id(op);
|
||||
scc_mir_stack_slot_t *slot =
|
||||
scc_mir_unsafe_slot(mir_func, slot_id);
|
||||
if (slot->arg_idx > 0)
|
||||
continue; // 传入参数槽,Pass 2 处理
|
||||
if (slot->offset == 0) {
|
||||
ctx->offset += slot->size;
|
||||
slot->offset = ctx->offset;
|
||||
ctx->offset += slot->size;
|
||||
}
|
||||
|
||||
*op = scc_x86_op_mem(
|
||||
(scc_x86_mem_t){
|
||||
.seg = SCC_X86_REG_INVALID,
|
||||
.base = SCC_X86_REG_RSP,
|
||||
.disp = {.displacement = -slot->offset},
|
||||
.disp = {.displacement = slot->offset},
|
||||
.index = SCC_X86_REG_INVALID,
|
||||
.scale = 1,
|
||||
},
|
||||
@@ -44,14 +47,50 @@ static void frame_alloc_impl(scc_frame_layout_t *ctx,
|
||||
}
|
||||
}
|
||||
|
||||
int total_size = ctx->offset + 32; // shadow space
|
||||
int total_size = ctx->offset;
|
||||
ctx->offset =
|
||||
(total_size + WIN64_STACK_ALIGN - 1) & ~(WIN64_STACK_ALIGN - 1);
|
||||
func_meta->frame_size = ctx->offset;
|
||||
|
||||
// Pass 2: 处理传入参数槽 (arg_idx > 0)
|
||||
// 在 Win64 布局中,栈上参数位于 return address + 8 + arg_idx * 8
|
||||
// 即 RSP + frame_size + 8 + arg_idx * 8
|
||||
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_x86_instr_vec_t *instrs = SCC_MIR_X86_BBLOCK_INSTRS(bb);
|
||||
scc_vec_foreach(*instrs, j) {
|
||||
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, slot_id);
|
||||
if (slot->arg_idx == 0)
|
||||
continue; // 局部变量槽,Pass 1 已处理
|
||||
if (slot->offset == 0) {
|
||||
slot->offset =
|
||||
func_meta->frame_size + 8 + slot->arg_idx * 8;
|
||||
}
|
||||
*op = scc_x86_op_mem(
|
||||
(scc_x86_mem_t){
|
||||
.seg = SCC_X86_REG_INVALID,
|
||||
.base = SCC_X86_REG_RSP,
|
||||
.disp = {.displacement = slot->offset},
|
||||
.index = SCC_X86_REG_INVALID,
|
||||
.scale = 1,
|
||||
},
|
||||
op->size);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void scc_win_pc_x64_frame_alloc_init(scc_frame_layout_t *ctx) {
|
||||
ctx->impl_fn = frame_alloc_impl;
|
||||
void scc_win_pc_x64_frame_layout_init(scc_frame_layout_t *ctx) {
|
||||
ctx->impl_fn = frame_layout_impl;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -136,6 +175,15 @@ static void lower_call(void *userdata, const scc_lir_instr_t *instr) {
|
||||
scc_x86_64_isel_t *isel = userdata;
|
||||
|
||||
u8 size = 8;
|
||||
scc_mir_func_meta_t *meta = SCC_MIR_FUNC_META(isel->func);
|
||||
int call_stack_size = instr->metadata.call.arg_count * 8;
|
||||
if (meta->frame_size < call_stack_size) {
|
||||
meta->frame_size = call_stack_size;
|
||||
}
|
||||
if (meta->frame_size < 32) {
|
||||
meta->frame_size = 32; // Windows X64 shadow space
|
||||
}
|
||||
|
||||
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) {
|
||||
@@ -156,10 +204,15 @@ static void lower_call(void *userdata, const scc_lir_instr_t *instr) {
|
||||
scc_x86_lir_val_to_mir_op(isel, args, size));
|
||||
break;
|
||||
default:
|
||||
scc_x86_operand_value_t op =
|
||||
scc_x86_lir_val_to_mir_op(isel, args, size);
|
||||
TODO();
|
||||
add_instr_1(isel, SCC_X86_ICLASS_PUSH, op);
|
||||
scc_x86_emit_move(
|
||||
isel,
|
||||
scc_x86_op_mem((scc_x86_mem_t){.base = SCC_X86_REG_RSP,
|
||||
.index = SCC_X86_REG_INVALID,
|
||||
.scale = 1,
|
||||
.disp.displacement = i * 8,
|
||||
.disp.displacement_bits = 8},
|
||||
size),
|
||||
scc_x86_lir_val_to_mir_op(isel, args, size));
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -176,14 +229,34 @@ static void lower_call(void *userdata, const scc_lir_instr_t *instr) {
|
||||
Panic("unhandled opcode");
|
||||
}
|
||||
|
||||
int ret_size = instr->size;
|
||||
scc_x86_operand_value_t ret_reg =
|
||||
scc_x86_lir_val_to_mir_op(isel, &instr->to, size);
|
||||
if (ret_reg.kind != SCC_X86_OPR_NONE) {
|
||||
scc_x86_lir_val_to_mir_op(isel, &instr->to, ret_size);
|
||||
if (ret_reg.kind != SCC_X86_OPR_NONE && ret_size != 0) {
|
||||
scc_x86_emit_move(isel, ret_reg,
|
||||
scc_x86_op_preg(SCC_X86_REG_RAX, size));
|
||||
scc_x86_op_preg(SCC_X86_REG_RAX, ret_size));
|
||||
}
|
||||
}
|
||||
|
||||
// 查找或创建传入参数的栈槽 (arg_idx > 0 表示栈上传入参数)
|
||||
static int get_or_create_arg_slot(scc_mir_func_t *func, int arg_idx, int size) {
|
||||
scc_mir_func_meta_t *meta = SCC_MIR_FUNC_META(func);
|
||||
scc_vec_foreach(meta->stack_slots, i) {
|
||||
scc_mir_stack_slot_t *s = &scc_vec_at(meta->stack_slots, i);
|
||||
if (s->arg_idx == arg_idx)
|
||||
return s->slot_id;
|
||||
}
|
||||
int slot_id = (int)scc_vec_size(meta->stack_slots);
|
||||
scc_vec_push(meta->stack_slots, ((scc_mir_stack_slot_t){
|
||||
.slot_id = slot_id,
|
||||
.size = size,
|
||||
.alignment = 8,
|
||||
.offset = 0,
|
||||
.arg_idx = arg_idx,
|
||||
}));
|
||||
return slot_id;
|
||||
}
|
||||
|
||||
static void lower_param(void *userdata, const scc_lir_val_t *val,
|
||||
void *out_op) {
|
||||
scc_x86_operand_value_t *out = out_op;
|
||||
@@ -202,10 +275,13 @@ static void lower_param(void *userdata, const scc_lir_val_t *val,
|
||||
case 3:
|
||||
*out = scc_x86_op_preg(SCC_X86_REG_R9, size);
|
||||
break;
|
||||
default:
|
||||
*out = scc_x86_op_slot(-val->data.arg, size);
|
||||
default: {
|
||||
scc_x86_64_isel_t *isel = userdata;
|
||||
int slot_id = get_or_create_arg_slot(isel->func, val->data.arg, size);
|
||||
*out = scc_x86_op_slot(slot_id, size);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void lower_ret(void *userdata, const scc_lir_instr_t *instr) {
|
||||
|
||||
Reference in New Issue
Block a user