Refactor the InstSize enum in the AArch64 backend

The main issue with the InstSize enum was that it was used both for
GPR and SIMD & FP operands, even though machine instructions do not
mix them in general (as in a destination register is either a GPR
or not). As a result it had methods such as sf_bit() that made
sense only for one type of operand.

Another issue was that the enum name was not reflecting its purpose
accurately - it was meant to represent an instruction operand size,
not an instruction size, which is fixed in A64 (always 4 bytes).

Now the enum is split into one for GPR operands and another for
scalar SIMD & FP operands.

Copyright (c) 2020, Arm Limited.
This commit is contained in:
Anton Kirilov
2020-06-11 14:20:49 +01:00
parent 85ffc8f595
commit 79dfac5514
7 changed files with 268 additions and 231 deletions

View File

@@ -403,8 +403,8 @@ impl ShowWithRRU for MemArg {
&MemArg::RegScaledExtended(r1, r2, ty, op) => {
let shift = shift_for_type(ty);
let size = match op {
ExtendOp::SXTW | ExtendOp::UXTW => InstSize::Size32,
_ => InstSize::Size64,
ExtendOp::SXTW | ExtendOp::UXTW => OperandSize::Size32,
_ => OperandSize::Size64,
};
let op = op.show_rru(mb_rru);
format!(
@@ -417,8 +417,8 @@ impl ShowWithRRU for MemArg {
}
&MemArg::RegExtended(r1, r2, op) => {
let size = match op {
ExtendOp::SXTW | ExtendOp::UXTW => InstSize::Size32,
_ => InstSize::Size64,
ExtendOp::SXTW | ExtendOp::UXTW => OperandSize::Size32,
_ => OperandSize::Size64,
};
let op = op.show_rru(mb_rru);
format!(
@@ -492,67 +492,98 @@ impl ShowWithRRU for BranchTarget {
}
/// Type used to communicate the operand size of a machine instruction, as AArch64 has 32- and
/// 64-bit variants of many instructions (and integer and floating-point registers) and 128-bit
/// variants of vector instructions.
/// TODO: Create a separate type for SIMD & floating-point operands.
/// 64-bit variants of many instructions (and integer registers).
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum InstSize {
pub enum OperandSize {
Size32,
Size64,
Size128,
}
impl InstSize {
impl OperandSize {
/// 32-bit case?
pub fn is32(self) -> bool {
self == InstSize::Size32
self == OperandSize::Size32
}
/// 64-bit case?
pub fn is64(self) -> bool {
self == InstSize::Size64
self == OperandSize::Size64
}
/// Convert from an `is32` boolean flag to an `InstSize`.
pub fn from_is32(is32: bool) -> InstSize {
/// Convert from an `is32` boolean flag to an `OperandSize`.
pub fn from_is32(is32: bool) -> OperandSize {
if is32 {
InstSize::Size32
OperandSize::Size32
} else {
InstSize::Size64
OperandSize::Size64
}
}
/// Convert from a needed width to the smallest size that fits.
pub fn from_bits<I: Into<usize>>(bits: I) -> InstSize {
pub fn from_bits<I: Into<usize>>(bits: I) -> OperandSize {
let bits: usize = bits.into();
assert!(bits <= 128);
assert!(bits <= 64);
if bits <= 32 {
InstSize::Size32
} else if bits <= 64 {
InstSize::Size64
OperandSize::Size32
} else {
InstSize::Size128
OperandSize::Size64
}
}
/// Convert from an integer type into the smallest size that fits.
pub fn from_ty(ty: Type) -> InstSize {
pub fn from_ty(ty: Type) -> OperandSize {
Self::from_bits(ty_bits(ty))
}
/// Convert to I32, I64, or I128.
pub fn to_ty(self) -> Type {
match self {
InstSize::Size32 => I32,
InstSize::Size64 => I64,
InstSize::Size128 => I128,
OperandSize::Size32 => I32,
OperandSize::Size64 => I64,
}
}
pub fn sf_bit(&self) -> u32 {
match self {
InstSize::Size32 => 0,
InstSize::Size64 => 1,
_ => {
panic!("Unexpected size");
}
OperandSize::Size32 => 0,
OperandSize::Size64 => 1,
}
}
}
/// Type used to communicate the size of a scalar SIMD & FP operand.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum ScalarSize {
Size8,
Size16,
Size32,
Size64,
Size128,
}
impl ScalarSize {
/// Convert from a needed width to the smallest size that fits.
pub fn from_bits<I: Into<usize>>(bits: I) -> ScalarSize {
match bits.into().next_power_of_two() {
8 => ScalarSize::Size8,
16 => ScalarSize::Size16,
32 => ScalarSize::Size32,
64 => ScalarSize::Size64,
128 => ScalarSize::Size128,
_ => panic!("Unexpected type width"),
}
}
/// Convert from a type into the smallest size that fits.
pub fn from_ty(ty: Type) -> ScalarSize {
Self::from_bits(ty_bits(ty))
}
/// Return the encoding bits that are used by some scalar FP instructions
/// for a particular operand size.
pub fn ftype(&self) -> u32 {
match self {
ScalarSize::Size16 => 0b11,
ScalarSize::Size32 => 0b00,
ScalarSize::Size64 => 0b01,
_ => panic!("Unexpected scalar FP operand size"),
}
}
}