#include #include #include #include #include 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 : ""); // 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); } }