diff --git a/cranelift/codegen/src/isa/x64/inst.isle b/cranelift/codegen/src/isa/x64/inst.isle index fdf15a147c..c0ba9a1171 100644 --- a/cranelift/codegen/src/isa/x64/inst.isle +++ b/cranelift/codegen/src/isa/x64/inst.isle @@ -126,6 +126,11 @@ (src GprMem) (dst WritableGpr)) + ;; Immediate store. + (MovImmM (size OperandSize) + (simm64 u64) + (dst SyntheticAmode)) + ;; Integer stores: mov (b w l q) reg addr. (MovRM (size OperandSize) ;; 1, 2, 4, or 8 (src Gpr) diff --git a/cranelift/codegen/src/isa/x64/inst/emit.rs b/cranelift/codegen/src/isa/x64/inst/emit.rs index 6c22bb0453..fc4f740a42 100644 --- a/cranelift/codegen/src/isa/x64/inst/emit.rs +++ b/cranelift/codegen/src/isa/x64/inst/emit.rs @@ -670,6 +670,38 @@ pub(crate) fn emit( } } + Inst::MovImmM { size, simm64, dst } => { + let dst = &dst.finalize(state, sink).with_allocs(allocs); + let default_rex = RexFlags::clear_w(); + let default_opcode = 0xC7; + let bytes = size.to_bytes(); + let prefix = LegacyPrefixes::None; + + let (opcode, rex, size, prefix) = match *size { + // In the 8-bit case, we don't need to enforce REX flags via + // `always_emit_if_8bit_needed()` since the destination + // operand is a memory operand, not a possibly 8-bit register. + OperandSize::Size8 => (0xC6, default_rex, bytes, prefix), + OperandSize::Size16 => (0xC7, default_rex, bytes, LegacyPrefixes::_66), + OperandSize::Size64 => { + if !low32_will_sign_extend_to_64(*simm64) { + panic!("Immediate-to-memory moves require immediate operand to sign-extend to 64 bits."); + } + + (default_opcode, RexFlags::from(*size), bytes, prefix) + } + + _ => (default_opcode, default_rex, bytes, prefix), + }; + + // 8-bit C6 /0 ib + // 16-bit 0x66 C7 /0 iw + // 32-bit C7 /0 id + // 64-bit REX.W C7 /0 id + emit_std_enc_mem(sink, prefix, opcode, 1, /*subopcode*/ 0, dst, rex, 0); + emit_simm(sink, size, *simm64 as u32); + } + Inst::MovRR { size, src, dst } => { let src = allocs.next(src.to_reg()); let dst = allocs.next(dst.to_reg().to_reg()); diff --git a/cranelift/codegen/src/isa/x64/inst/emit_tests.rs b/cranelift/codegen/src/isa/x64/inst/emit_tests.rs index 3428b31cf4..3b9250329a 100644 --- a/cranelift/codegen/src/isa/x64/inst/emit_tests.rs +++ b/cranelift/codegen/src/isa/x64/inst/emit_tests.rs @@ -2560,6 +2560,128 @@ fn test_x64_emit() { "movslq -7(%r11), %rdx", )); + // Mov_Imm_M. + + insns.push(( + Inst::MovImmM { + size: OperandSize::Size8, + simm64: i8::MIN as u64, + dst: Amode::imm_reg(99u32, rax).into(), + }, + "C6406380", + "movb $-128, 99(%rax)", + )); + + insns.push(( + Inst::MovImmM { + size: OperandSize::Size8, + simm64: i8::MAX as u64, + dst: Amode::imm_reg(99u32, r8).into(), + }, + "41C640637F", + "movb $127, 99(%r8)", + )); + + insns.push(( + Inst::MovImmM { + size: OperandSize::Size16, + simm64: i16::MIN as u64, + dst: Amode::imm_reg(99u32, rcx).into(), + }, + "66C741630080", + "movw $-32768, 99(%rcx)", + )); + + insns.push(( + Inst::MovImmM { + size: OperandSize::Size16, + simm64: i16::MAX as u64, + dst: Amode::imm_reg(99u32, r9).into(), + }, + "6641C74163FF7F", + "movw $32767, 99(%r9)", + )); + + insns.push(( + Inst::MovImmM { + size: OperandSize::Size32, + simm64: i32::MIN as u64, + dst: Amode::imm_reg(99u32, rdx).into(), + }, + "C7426300000080", + "movl $-2147483648, 99(%rdx)", + )); + + insns.push(( + Inst::MovImmM { + size: OperandSize::Size32, + simm64: i32::MAX as u64, + dst: Amode::imm_reg(99u32, r10).into(), + }, + "41C74263FFFFFF7F", + "movl $2147483647, 99(%r10)", + )); + + insns.push(( + Inst::MovImmM { + size: OperandSize::Size64, + simm64: i32::MIN as u64, + dst: Amode::imm_reg(99u32, rbx).into(), + }, + "48C7436300000080", + "movq $-2147483648, 99(%rbx)", + )); + + insns.push(( + Inst::MovImmM { + size: OperandSize::Size64, + simm64: i32::MAX as u64, + dst: Amode::imm_reg(99u32, r11).into(), + }, + "49C74363FFFFFF7F", + "movq $2147483647, 99(%r11)", + )); + + insns.push(( + Inst::MovImmM { + size: OperandSize::Size8, + simm64: 0u64, + dst: Amode::imm_reg(99u32, rsp).into(), + }, + "C644246300", + "movb $0, 99(%rsp)", + )); + + insns.push(( + Inst::MovImmM { + size: OperandSize::Size16, + simm64: 0u64, + dst: Amode::imm_reg(99u32, r12).into(), + }, + "6641C74424630000", + "movw $0, 99(%r12)", + )); + + insns.push(( + Inst::MovImmM { + size: OperandSize::Size32, + simm64: 0u64, + dst: Amode::imm_reg(99u32, rbp).into(), + }, + "C7456300000000", + "movl $0, 99(%rbp)", + )); + + insns.push(( + Inst::MovImmM { + size: OperandSize::Size64, + simm64: 0u64, + dst: Amode::imm_reg(99u32, r13).into(), + }, + "49C7456300000000", + "movq $0, 99(%r13)", + )); + // ======================================================== // Mov_R_M. Byte stores are tricky. Check everything carefully. insns.push(( diff --git a/cranelift/codegen/src/isa/x64/inst/mod.rs b/cranelift/codegen/src/isa/x64/inst/mod.rs index ade4ef0a83..3a000b7218 100644 --- a/cranelift/codegen/src/isa/x64/inst/mod.rs +++ b/cranelift/codegen/src/isa/x64/inst/mod.rs @@ -90,6 +90,7 @@ impl Inst { | Inst::LoadExtName { .. } | Inst::LockCmpxchg { .. } | Inst::Mov64MR { .. } + | Inst::MovImmM { .. } | Inst::MovRM { .. } | Inst::MovRR { .. } | Inst::MovFromPReg { .. } @@ -1252,6 +1253,25 @@ impl PrettyPrint for Inst { } } + Inst::MovImmM { size, simm64, dst } => { + let dst = dst.pretty_print(size.to_bytes(), allocs); + let suffix = suffix_bwlq(*size); + let instruction = ljustify2("mov".to_string(), suffix); + + match *size { + OperandSize::Size8 => { + format!("{} ${}, {}", instruction, (*simm64 as u8) as i8, dst) + } + OperandSize::Size16 => { + format!("{} ${}, {}", instruction, (*simm64 as u16) as i16, dst) + } + OperandSize::Size32 => { + format!("{} ${}, {}", instruction, (*simm64 as u32) as i32, dst) + } + OperandSize::Size64 => format!("{} ${}, {}", instruction, *simm64 as i64, dst), + } + } + Inst::MovRR { size, src, dst } => { let src = pretty_print_reg(src.to_reg(), size.to_bytes(), allocs); let dst = pretty_print_reg(dst.to_reg().to_reg(), size.to_bytes(), allocs); @@ -1990,6 +2010,11 @@ fn x64_get_operands VReg>(inst: &Inst, collector: &mut OperandCol collector.reg_early_def(tmp_xmm.to_writable_reg()); collector.reg_early_def(tmp_xmm2.to_writable_reg()); } + + Inst::MovImmM { dst, .. } => { + dst.get_operands(collector); + } + Inst::MovzxRmR { src, dst, .. } => { collector.reg_def(dst.to_writable_reg()); src.get_operands(collector);