#include 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; } static inline u8 get_op_size(scc_x86_operand_value_t op, cbool get_value) { if (get_value) { return op.size; } if (op.kind == SCC_X86_OPR_MEM) { return 8; } if (op.kind == SCC_X86_OPR_RELOC && op.reloc.kind == SCC_X86_OPR_MEM) { return 8; } return op.size; } 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) { u8 dst_size = get_op_size(dst, false); u8 src_size = get_op_size(src, false); if (dst_size != src_size) { LOG_FATAL("Mismatched register sizes for move %d != %d", dst_size, src_size); } scc_mir_x86_instr_t ins; 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 dst kind %d", dst.kind); } scc_vec_push(*vec, ins); } void scc_x86_emit_load_to_vec(scc_mir_x86_instr_vec_t *vec, scc_x86_operand_value_t dst, scc_x86_operand_value_t src_addr) { u8 dst_size = get_op_size(dst, false); u8 src_addr_size = get_op_size(src_addr, true); if (dst_size != src_addr_size) { LOG_FATAL("Mismatched sizes for load %d != %d", dst_size, src_addr_size); } Assert(dst.kind == SCC_X86_OPR_REG); scc_x86_operand_value_t mem_op; if (src_addr.kind == SCC_X86_OPR_REG) { mem_op = (scc_x86_operand_value_t){ .kind = SCC_X86_OPR_MEM, .mem = { .base = src_addr.reg, .index = SCC_X86_REG_INVALID, .scale = 1, .disp.displacement = 0, .disp.displacement_bits = src_addr_size * 8, }, .size = src_addr_size, }; } else if (src_addr.kind == SCC_X86_OPR_MEM) { mem_op = src_addr; } else { Panic("emit_load: src must be REG or MEM"); } scc_mir_x86_instr_t ins; scc_mir_x86_instr_2(&ins, scc_mir_x86_mov_reg_mem(dst, mem_op), dst, mem_op, scc_pos_create()); scc_vec_push(*vec, ins); } void scc_x86_emit_store_to_vec(scc_mir_x86_instr_vec_t *vec, scc_x86_operand_value_t dst_addr, scc_x86_operand_value_t src) { u8 dst_addr_size = get_op_size(dst_addr, true); u8 src_size = get_op_size(src, false); if (dst_addr_size != src_size) { LOG_FATAL("Mismatched sizes for store %d != %d", dst_addr_size, src_size); } scc_x86_operand_value_t mem_op; if (dst_addr.kind == SCC_X86_OPR_REG) { mem_op = (scc_x86_operand_value_t){ .kind = SCC_X86_OPR_MEM, .mem = { .base = dst_addr.reg, .index = SCC_X86_REG_INVALID, .scale = 1, .disp.displacement = 0, .disp.displacement_bits = dst_addr_size * 8, }, .size = dst_addr_size, }; } else if (dst_addr.kind == SCC_X86_OPR_MEM) { mem_op = dst_addr; } else { Panic("emit_store: dst_addr kind not supported %d", dst_addr.kind); } scc_mir_x86_instr_t ins; 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); }