cranelift-codegen: Add support for immediate to memory moves in x64 (#5461)
This change adds support for immediate to memory moves in x64 which are needed by Winch for zeroing local slots. This change follows the guideline in `isa/x64/inst/emit` and uses other instructions (immediate to register moves) as a base for the test cases. The instruction encoding expectation was derived by assembling each instruction and inspecting the assembly with `objdump`.
This commit is contained in:
@@ -126,6 +126,11 @@
|
|||||||
(src GprMem)
|
(src GprMem)
|
||||||
(dst WritableGpr))
|
(dst WritableGpr))
|
||||||
|
|
||||||
|
;; Immediate store.
|
||||||
|
(MovImmM (size OperandSize)
|
||||||
|
(simm64 u64)
|
||||||
|
(dst SyntheticAmode))
|
||||||
|
|
||||||
;; Integer stores: mov (b w l q) reg addr.
|
;; Integer stores: mov (b w l q) reg addr.
|
||||||
(MovRM (size OperandSize) ;; 1, 2, 4, or 8
|
(MovRM (size OperandSize) ;; 1, 2, 4, or 8
|
||||||
(src Gpr)
|
(src Gpr)
|
||||||
|
|||||||
@@ -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 } => {
|
Inst::MovRR { size, src, dst } => {
|
||||||
let src = allocs.next(src.to_reg());
|
let src = allocs.next(src.to_reg());
|
||||||
let dst = allocs.next(dst.to_reg().to_reg());
|
let dst = allocs.next(dst.to_reg().to_reg());
|
||||||
|
|||||||
@@ -2560,6 +2560,128 @@ fn test_x64_emit() {
|
|||||||
"movslq -7(%r11), %rdx",
|
"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.
|
// Mov_R_M. Byte stores are tricky. Check everything carefully.
|
||||||
insns.push((
|
insns.push((
|
||||||
|
|||||||
@@ -90,6 +90,7 @@ impl Inst {
|
|||||||
| Inst::LoadExtName { .. }
|
| Inst::LoadExtName { .. }
|
||||||
| Inst::LockCmpxchg { .. }
|
| Inst::LockCmpxchg { .. }
|
||||||
| Inst::Mov64MR { .. }
|
| Inst::Mov64MR { .. }
|
||||||
|
| Inst::MovImmM { .. }
|
||||||
| Inst::MovRM { .. }
|
| Inst::MovRM { .. }
|
||||||
| Inst::MovRR { .. }
|
| Inst::MovRR { .. }
|
||||||
| Inst::MovFromPReg { .. }
|
| 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 } => {
|
Inst::MovRR { size, src, dst } => {
|
||||||
let src = pretty_print_reg(src.to_reg(), size.to_bytes(), allocs);
|
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);
|
let dst = pretty_print_reg(dst.to_reg().to_reg(), size.to_bytes(), allocs);
|
||||||
@@ -1990,6 +2010,11 @@ fn x64_get_operands<F: Fn(VReg) -> VReg>(inst: &Inst, collector: &mut OperandCol
|
|||||||
collector.reg_early_def(tmp_xmm.to_writable_reg());
|
collector.reg_early_def(tmp_xmm.to_writable_reg());
|
||||||
collector.reg_early_def(tmp_xmm2.to_writable_reg());
|
collector.reg_early_def(tmp_xmm2.to_writable_reg());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Inst::MovImmM { dst, .. } => {
|
||||||
|
dst.get_operands(collector);
|
||||||
|
}
|
||||||
|
|
||||||
Inst::MovzxRmR { src, dst, .. } => {
|
Inst::MovzxRmR { src, dst, .. } => {
|
||||||
collector.reg_def(dst.to_writable_reg());
|
collector.reg_def(dst.to_writable_reg());
|
||||||
src.get_operands(collector);
|
src.get_operands(collector);
|
||||||
|
|||||||
Reference in New Issue
Block a user