#include #include #include #include #include #include #include #include scc_x86_reg_t mir_x86_trans_gpr(scc_x86_reg_t reg, u8 size) { size *= 8; if (size == 0) { return reg; } for (scc_x86_reg_t i = 0; i < SCC_X86_REG_COUNT; i += 1) { if (scc_x86_reg_table[i].max_enclosing == reg && scc_x86_reg_table[i].width == size) { return i; } } return reg; } void mir_x86_to_mcode(scc_mcode_t *mcode, scc_reloc_vec_t *relocs, const scc_mir_x86_instr_t *_ins) { Assert(mcode != nullptr && _ins != nullptr); int skip_reloc = relocs == nullptr; scc_x86_instr_t *ins = (void *)_ins; if (ins->opcode < 0 || ins->opcode >= SCC_X86_IFORM_COUNT) { return; } scc_x86_operand_value_t ops[8] = {0}; scc_reloc_t reloc = {0}; for (int i = 0; i < ins->num_operands; i++) { scc_x86_operand_value_t *op_ptr = &ins->operands[i]; if (scc_x86_op_is_vreg(op_ptr)) Panic("can't convert vreg to mcode"); if (scc_x86_op_is_slot(op_ptr)) Panic("can't convert unresolved slot to mcode"); if (op_ptr->kind == SCC_X86_OPR_RELOC) { ops[i].kind = op_ptr->reloc.kind; switch (op_ptr->reloc.kind) { case SCC_X86_OPR_RELBR: ops[i].brdisp = 0; break; case SCC_X86_OPR_MEM: ops[i].mem.base = SCC_X86_REG_RIP; ops[i].mem.index = SCC_X86_REG_INVALID; ops[i].mem.scale = 1; ops[i].mem.disp.displacement = 0; ops[i].mem.disp.displacement_bits = 32; break; default: Panic("unsupported reloc type %d", op_ptr->reloc.kind); break; } if (skip_reloc) { continue; } if (skip_reloc != SCC_RELOC_TARGET_NONE) { LOG_FATAL("can't using twice reloc in one instr"); continue; } reloc.addend = op_ptr->reloc.addend; reloc.arch_type = (int)op_ptr->reloc.kind; reloc.size = 0; reloc.offset = scc_mcode_size(mcode); if (op_ptr->reloc.target == SCC_X86_RELOC_TARGET_SYMBOL) { reloc.target_kind = SCC_RELOC_TARGET_SYMBOL; reloc.symbol = op_ptr->reloc.global_name; } else if (op_ptr->reloc.target == SCC_X86_RELOC_TARGET_BBLOCK) { reloc.target_kind = SCC_RELOC_TARGET_BBLOCK; reloc.bblock_id = op_ptr->reloc.bblock_id; } else { TODO(); } } else if (op_ptr->kind == SCC_X86_OPR_REG) { ops[i].kind = SCC_X86_OPR_REG; ops[i].reg = mir_x86_trans_gpr(op_ptr->reg, op_ptr->size); } else { ops[i] = *op_ptr; } } scc_x86_encode_inst(mcode, ins->opcode, ops); if (!skip_reloc && reloc.target_kind != SCC_RELOC_TARGET_NONE) { reloc.offset = scc_mcode_size(mcode); scc_vec_push(*relocs, reloc); } } void mir_x86_patch(scc_mcode_t *mcode, scc_reloc_t *reloc, i64 value) { // return; scc_x86_patch_type_t patch_type = SCC_X86_PATCH_NONE; switch (reloc->arch_type) { case SCC_X86_OPR_RELBR: patch_type = SCC_X86_PATCH_PC32; break; default: Panic("unsupported reloc type"); break; } scc_x86_patch(mcode, patch_type, reloc->offset + reloc->addend, value); } void scc_ir2mcode_emit_instr(scc_mcode_t *mcode, scc_reloc_vec_t *relocs, const scc_mir_instr_t *mir_instr) { mir_x86_to_mcode(mcode, relocs, (const scc_mir_x86_instr_t *)mir_instr); } void scc_ir2mcode_patch(scc_mcode_t *mcode, scc_reloc_t *reloc, i64 value) { mir_x86_patch(mcode, reloc, value); } void scc_ir2mcode(scc_mcode_t *mcode, scc_reloc_vec_t *relocs, const scc_mir_module_t *mir_module) { Assert(mir_module != nullptr && mcode != nullptr); scc_vec_foreach(mir_module->cfg_module.funcs, i) { if (i == 0) continue; scc_mir_func_t *func = &scc_vec_at(mir_module->cfg_module.funcs, i); scc_vec_foreach(func->bblocks, i) { scc_cfg_bblock_id_t id = scc_vec_at(func->bblocks, i); const scc_cfg_bblock_t *bb = scc_cfg_module_unsafe_get_bblock(&mir_module->cfg_module, id); const scc_mir_x86_instr_vec_t *instrs = SCC_MIR_BBLOCK_VALUES_PTR(bb); scc_vec_foreach(*instrs, i) { const scc_mir_instr_t *ins = scc_vec_sized_at_ptr(*instrs, mir_module->instr_size, i); scc_ir2mcode_emit_instr(mcode, relocs, ins); } } } }