[AArch64] Refactor Mov instructions (#4033)

Merge Mov32 and Mov64 into a single instruction parameterized by a new
OperandSize field. Also combine the Mov[K,N,Z] into a single instruction
with a new opcode to select between the operations.

Copyright (c) 2022, Arm Limited.
This commit is contained in:
Sam Parker
2022-04-14 22:51:12 +01:00
committed by GitHub
parent dd442a4d2f
commit 682ef7b470
7 changed files with 349 additions and 319 deletions

View File

@@ -185,25 +185,16 @@ fn enc_conditional_br(
}
}
const MOVE_WIDE_FIXED: u32 = 0x12800000;
#[repr(u32)]
enum MoveWideOpcode {
MOVN = 0b00,
MOVZ = 0b10,
MOVK = 0b11,
}
fn enc_move_wide(
op: MoveWideOpcode,
rd: Writable<Reg>,
imm: MoveWideConst,
size: OperandSize,
) -> u32 {
fn enc_move_wide(op: MoveWideOp, rd: Writable<Reg>, imm: MoveWideConst, size: OperandSize) -> u32 {
assert!(imm.shift <= 0b11);
MOVE_WIDE_FIXED
let op = match op {
MoveWideOp::MovN => 0b00,
MoveWideOp::MovZ => 0b10,
MoveWideOp::MovK => 0b11,
};
0x12800000
| size.sf_bit() << 31
| (op as u32) << 29
| op << 29
| u32::from(imm.shift) << 21
| u32::from(imm.bits) << 5
| machreg_to_gpr(rd.to_reg())
@@ -1315,51 +1306,45 @@ impl MachInstEmit for Inst {
}
}
}
&Inst::Mov64 { rd, rm } => {
&Inst::Mov { size, rd, rm } => {
let rd = allocs.next_writable(rd);
let rm = allocs.next(rm);
assert!(rd.to_reg().class() == rm.class());
assert!(rm.class() == RegClass::Int);
// MOV to SP is interpreted as MOV to XZR instead. And our codegen
// should never MOV to XZR.
assert!(rd.to_reg() != stack_reg());
match size {
OperandSize::Size64 => {
// MOV to SP is interpreted as MOV to XZR instead. And our codegen
// should never MOV to XZR.
assert!(rd.to_reg() != stack_reg());
if rm == stack_reg() {
// We can't use ORR here, so use an `add rd, sp, #0` instead.
let imm12 = Imm12::maybe_from_u64(0).unwrap();
sink.put4(enc_arith_rr_imm12(
0b100_10001,
imm12.shift_bits(),
imm12.imm_bits(),
rm,
rd,
));
} else {
// Encoded as ORR rd, rm, zero.
sink.put4(enc_arith_rrr(0b10101010_000, 0b000_000, rd, zero_reg(), rm));
if rm == stack_reg() {
// We can't use ORR here, so use an `add rd, sp, #0` instead.
let imm12 = Imm12::maybe_from_u64(0).unwrap();
sink.put4(enc_arith_rr_imm12(
0b100_10001,
imm12.shift_bits(),
imm12.imm_bits(),
rm,
rd,
));
} else {
// Encoded as ORR rd, rm, zero.
sink.put4(enc_arith_rrr(0b10101010_000, 0b000_000, rd, zero_reg(), rm));
}
}
OperandSize::Size32 => {
// MOV to SP is interpreted as MOV to XZR instead. And our codegen
// should never MOV to XZR.
assert!(machreg_to_gpr(rd.to_reg()) != 31);
// Encoded as ORR rd, rm, zero.
sink.put4(enc_arith_rrr(0b00101010_000, 0b000_000, rd, zero_reg(), rm));
}
}
}
&Inst::Mov32 { rd, rm } => {
&Inst::MovWide { op, rd, imm, size } => {
let rd = allocs.next_writable(rd);
let rm = allocs.next(rm);
// MOV to SP is interpreted as MOV to XZR instead. And our codegen
// should never MOV to XZR.
assert!(machreg_to_gpr(rd.to_reg()) != 31);
// Encoded as ORR rd, rm, zero.
sink.put4(enc_arith_rrr(0b00101010_000, 0b000_000, rd, zero_reg(), rm));
}
&Inst::MovZ { rd, imm, size } => {
let rd = allocs.next_writable(rd);
sink.put4(enc_move_wide(MoveWideOpcode::MOVZ, rd, imm, size))
}
&Inst::MovN { rd, imm, size } => {
let rd = allocs.next_writable(rd);
sink.put4(enc_move_wide(MoveWideOpcode::MOVN, rd, imm, size))
}
&Inst::MovK { rd, imm, size } => {
let rd = allocs.next_writable(rd);
sink.put4(enc_move_wide(MoveWideOpcode::MOVK, rd, imm, size))
sink.put4(enc_move_wide(op, rd, imm, size));
}
&Inst::CSel { rd, rn, rm, cond } => {
let rd = allocs.next_writable(rd);
@@ -2700,7 +2685,11 @@ impl MachInstEmit for Inst {
} => {
let rd = allocs.next_writable(rd);
let rn = allocs.next(rn);
let mov = Inst::Mov32 { rd, rm: rn };
let mov = Inst::Mov {
size: OperandSize::Size32,
rd,
rm: rn,
};
mov.emit(&[], sink, emit_info, state);
}
&Inst::Extend {
@@ -2980,7 +2969,11 @@ impl MachInstEmit for Inst {
add.emit(&[], sink, emit_info, state);
} else if offset == 0 {
if reg != rd.to_reg() {
let mov = Inst::Mov64 { rd, rm: reg };
let mov = Inst::Mov {
size: OperandSize::Size64,
rd,
rm: reg,
};
mov.emit(&[], sink, emit_info, state);
}

View File

@@ -1920,7 +1920,8 @@ fn test_aarch64_binemit() {
));
insns.push((
Inst::Mov64 {
Inst::Mov {
size: OperandSize::Size64,
rd: writable_xreg(8),
rm: xreg(9),
},
@@ -1928,7 +1929,8 @@ fn test_aarch64_binemit() {
"mov x8, x9",
));
insns.push((
Inst::Mov32 {
Inst::Mov {
size: OperandSize::Size32,
rd: writable_xreg(8),
rm: xreg(9),
},
@@ -1937,7 +1939,8 @@ fn test_aarch64_binemit() {
));
insns.push((
Inst::MovZ {
Inst::MovWide {
op: MoveWideOp::MovZ,
rd: writable_xreg(8),
imm: MoveWideConst::maybe_from_u64(0x0000_0000_0000_ffff).unwrap(),
size: OperandSize::Size64,
@@ -1946,7 +1949,8 @@ fn test_aarch64_binemit() {
"movz x8, #65535",
));
insns.push((
Inst::MovZ {
Inst::MovWide {
op: MoveWideOp::MovZ,
rd: writable_xreg(8),
imm: MoveWideConst::maybe_from_u64(0x0000_0000_ffff_0000).unwrap(),
size: OperandSize::Size64,
@@ -1955,7 +1959,8 @@ fn test_aarch64_binemit() {
"movz x8, #65535, LSL #16",
));
insns.push((
Inst::MovZ {
Inst::MovWide {
op: MoveWideOp::MovZ,
rd: writable_xreg(8),
imm: MoveWideConst::maybe_from_u64(0x0000_ffff_0000_0000).unwrap(),
size: OperandSize::Size64,
@@ -1964,7 +1969,8 @@ fn test_aarch64_binemit() {
"movz x8, #65535, LSL #32",
));
insns.push((
Inst::MovZ {
Inst::MovWide {
op: MoveWideOp::MovZ,
rd: writable_xreg(8),
imm: MoveWideConst::maybe_from_u64(0xffff_0000_0000_0000).unwrap(),
size: OperandSize::Size64,
@@ -1973,7 +1979,8 @@ fn test_aarch64_binemit() {
"movz x8, #65535, LSL #48",
));
insns.push((
Inst::MovZ {
Inst::MovWide {
op: MoveWideOp::MovZ,
rd: writable_xreg(8),
imm: MoveWideConst::maybe_from_u64(0x0000_0000_ffff_0000).unwrap(),
size: OperandSize::Size32,
@@ -1983,7 +1990,8 @@ fn test_aarch64_binemit() {
));
insns.push((
Inst::MovN {
Inst::MovWide {
op: MoveWideOp::MovN,
rd: writable_xreg(8),
imm: MoveWideConst::maybe_from_u64(0x0000_0000_0000_ffff).unwrap(),
size: OperandSize::Size64,
@@ -1992,7 +2000,8 @@ fn test_aarch64_binemit() {
"movn x8, #65535",
));
insns.push((
Inst::MovN {
Inst::MovWide {
op: MoveWideOp::MovN,
rd: writable_xreg(8),
imm: MoveWideConst::maybe_from_u64(0x0000_0000_ffff_0000).unwrap(),
size: OperandSize::Size64,
@@ -2001,7 +2010,8 @@ fn test_aarch64_binemit() {
"movn x8, #65535, LSL #16",
));
insns.push((
Inst::MovN {
Inst::MovWide {
op: MoveWideOp::MovN,
rd: writable_xreg(8),
imm: MoveWideConst::maybe_from_u64(0x0000_ffff_0000_0000).unwrap(),
size: OperandSize::Size64,
@@ -2010,7 +2020,8 @@ fn test_aarch64_binemit() {
"movn x8, #65535, LSL #32",
));
insns.push((
Inst::MovN {
Inst::MovWide {
op: MoveWideOp::MovN,
rd: writable_xreg(8),
imm: MoveWideConst::maybe_from_u64(0xffff_0000_0000_0000).unwrap(),
size: OperandSize::Size64,
@@ -2019,7 +2030,8 @@ fn test_aarch64_binemit() {
"movn x8, #65535, LSL #48",
));
insns.push((
Inst::MovN {
Inst::MovWide {
op: MoveWideOp::MovN,
rd: writable_xreg(8),
imm: MoveWideConst::maybe_from_u64(0x0000_0000_0000_ffff).unwrap(),
size: OperandSize::Size32,
@@ -2029,7 +2041,8 @@ fn test_aarch64_binemit() {
));
insns.push((
Inst::MovK {
Inst::MovWide {
op: MoveWideOp::MovK,
rd: writable_xreg(12),
imm: MoveWideConst::maybe_from_u64(0x0000_0000_0000_0000).unwrap(),
size: OperandSize::Size64,
@@ -2038,7 +2051,8 @@ fn test_aarch64_binemit() {
"movk x12, #0",
));
insns.push((
Inst::MovK {
Inst::MovWide {
op: MoveWideOp::MovK,
rd: writable_xreg(19),
imm: MoveWideConst::maybe_with_shift(0x0000, 16).unwrap(),
size: OperandSize::Size64,
@@ -2047,7 +2061,8 @@ fn test_aarch64_binemit() {
"movk x19, #0, LSL #16",
));
insns.push((
Inst::MovK {
Inst::MovWide {
op: MoveWideOp::MovK,
rd: writable_xreg(3),
imm: MoveWideConst::maybe_from_u64(0x0000_0000_0000_ffff).unwrap(),
size: OperandSize::Size64,
@@ -2056,7 +2071,8 @@ fn test_aarch64_binemit() {
"movk x3, #65535",
));
insns.push((
Inst::MovK {
Inst::MovWide {
op: MoveWideOp::MovK,
rd: writable_xreg(8),
imm: MoveWideConst::maybe_from_u64(0x0000_0000_ffff_0000).unwrap(),
size: OperandSize::Size64,
@@ -2065,7 +2081,8 @@ fn test_aarch64_binemit() {
"movk x8, #65535, LSL #16",
));
insns.push((
Inst::MovK {
Inst::MovWide {
op: MoveWideOp::MovK,
rd: writable_xreg(8),
imm: MoveWideConst::maybe_from_u64(0x0000_ffff_0000_0000).unwrap(),
size: OperandSize::Size64,
@@ -2074,7 +2091,8 @@ fn test_aarch64_binemit() {
"movk x8, #65535, LSL #32",
));
insns.push((
Inst::MovK {
Inst::MovWide {
op: MoveWideOp::MovK,
rd: writable_xreg(8),
imm: MoveWideConst::maybe_from_u64(0xffff_0000_0000_0000).unwrap(),
size: OperandSize::Size64,

View File

@@ -40,8 +40,8 @@ mod emit_tests;
pub use crate::isa::aarch64::lower::isle::generated_code::{
ALUOp, ALUOp3, AtomicRMWOp, BitOp, FPUOp1, FPUOp2, FPUOp3, FpuRoundMode, FpuToIntOp,
IntToFpuOp, MInst as Inst, VecALUOp, VecExtendOp, VecLanesOp, VecMisc2, VecPairOp, VecRRLongOp,
VecRRNarrowOp, VecRRPairLongOp, VecRRRLongOp, VecShiftImmOp,
IntToFpuOp, MInst as Inst, MoveWideOp, VecALUOp, VecExtendOp, VecLanesOp, VecMisc2, VecPairOp,
VecRRLongOp, VecRRNarrowOp, VecRRPairLongOp, VecRRRLongOp, VecShiftImmOp,
};
/// A floating-point unit (FPU) operation with two args, a register and an immediate.
@@ -130,14 +130,16 @@ impl Inst {
if let Some(imm) = MoveWideConst::maybe_from_u64(value) {
// 16-bit immediate (shifted by 0, 16, 32 or 48 bits) in MOVZ
smallvec![Inst::MovZ {
smallvec![Inst::MovWide {
op: MoveWideOp::MovZ,
rd,
imm,
size: OperandSize::Size64
}]
} else if let Some(imm) = MoveWideConst::maybe_from_u64(!value) {
// 16-bit immediate (shifted by 0, 16, 32 or 48 bits) in MOVN
smallvec![Inst::MovN {
smallvec![Inst::MovWide {
op: MoveWideOp::MovN,
rd,
imm,
size: OperandSize::Size64
@@ -178,15 +180,30 @@ impl Inst {
let imm =
MoveWideConst::maybe_with_shift(((!imm16) & 0xffff) as u16, i * 16)
.unwrap();
insts.push(Inst::MovN { rd, imm, size });
insts.push(Inst::MovWide {
op: MoveWideOp::MovN,
rd,
imm,
size,
});
} else {
let imm =
MoveWideConst::maybe_with_shift(imm16 as u16, i * 16).unwrap();
insts.push(Inst::MovZ { rd, imm, size });
insts.push(Inst::MovWide {
op: MoveWideOp::MovZ,
rd,
imm,
size,
});
}
} else {
let imm = MoveWideConst::maybe_with_shift(imm16 as u16, i * 16).unwrap();
insts.push(Inst::MovK { rd, imm, size });
insts.push(Inst::MovWide {
op: MoveWideOp::MovK,
rd,
imm,
size,
});
}
}
}
@@ -641,20 +658,14 @@ fn aarch64_get_operands<F: Fn(VReg) -> VReg>(inst: &Inst, collector: &mut Operan
collector.reg_def(rt2);
pairmemarg_operands(mem, collector);
}
&Inst::Mov64 { rd, rm } => {
&Inst::Mov { rd, rm, .. } => {
collector.reg_def(rd);
collector.reg_use(rm);
}
&Inst::Mov32 { rd, rm } => {
collector.reg_def(rd);
collector.reg_use(rm);
}
&Inst::MovZ { rd, .. } | &Inst::MovN { rd, .. } => {
collector.reg_def(rd);
}
&Inst::MovK { rd, .. } => {
collector.reg_mod(rd);
}
&Inst::MovWide { op, rd, .. } => match op {
MoveWideOp::MovK => collector.reg_mod(rd),
_ => collector.reg_def(rd),
},
&Inst::CSel { rd, rn, rm, .. } => {
collector.reg_def(rd);
collector.reg_use(rn);
@@ -1043,7 +1054,11 @@ impl MachInst for Inst {
fn is_move(&self) -> Option<(Writable<Reg>, Reg)> {
match self {
&Inst::Mov64 { rd, rm } => Some((rd, rm)),
&Inst::Mov {
size: OperandSize::Size64,
rd,
rm,
} => Some((rd, rm)),
&Inst::FpuMove64 { rd, rn } => Some((rd, rn)),
&Inst::FpuMove128 { rd, rn } => Some((rd, rn)),
_ => None,
@@ -1097,7 +1112,8 @@ impl MachInst for Inst {
assert!(bits <= 128);
assert!(to_reg.to_reg().class() == from_reg.class());
match from_reg.class() {
RegClass::Int => Inst::Mov64 {
RegClass::Int => Inst::Mov {
size: OperandSize::Size64,
rd: to_reg,
rm: from_reg,
},
@@ -1467,30 +1483,25 @@ impl Inst {
let mem = mem.pretty_print_default();
format!("ldp {}, {}, {}", rt, rt2, mem)
}
&Inst::Mov64 { rd, rm } => {
let rd = pretty_print_ireg(rd.to_reg(), OperandSize::Size64, allocs);
let rm = pretty_print_ireg(rm, OperandSize::Size64, allocs);
&Inst::Mov { size, rd, rm } => {
let rd = pretty_print_ireg(rd.to_reg(), size, allocs);
let rm = pretty_print_ireg(rm, size, allocs);
format!("mov {}, {}", rd, rm)
}
&Inst::Mov32 { rd, rm } => {
let rd = pretty_print_ireg(rd.to_reg(), OperandSize::Size32, allocs);
let rm = pretty_print_ireg(rm, OperandSize::Size32, allocs);
format!("mov {}, {}", rd, rm)
}
&Inst::MovZ { rd, ref imm, size } => {
&Inst::MovWide {
op,
rd,
ref imm,
size,
} => {
let op_str = match op {
MoveWideOp::MovZ => "movz",
MoveWideOp::MovN => "movn",
MoveWideOp::MovK => "movk",
};
let rd = pretty_print_ireg(rd.to_reg(), size, allocs);
let imm = imm.pretty_print(0, allocs);
format!("movz {}, {}", rd, imm)
}
&Inst::MovN { rd, ref imm, size } => {
let rd = pretty_print_ireg(rd.to_reg(), size, allocs);
let imm = imm.pretty_print(0, allocs);
format!("movn {}, {}", rd, imm)
}
&Inst::MovK { rd, ref imm, size } => {
let rd = pretty_print_ireg(rd.to_reg(), size, allocs);
let imm = imm.pretty_print(0, allocs);
format!("movk {}, {}", rd, imm)
format!("{} {}, {}", op_str, rd, imm)
}
&Inst::CSel { rd, rn, rm, cond } => {
let rd = pretty_print_ireg(rd.to_reg(), OperandSize::Size64, allocs);