Add unsigned 128-bit immediate

This commit is contained in:
Andrew Brown
2019-07-23 10:52:38 -07:00
committed by Dan Gohman
parent 7b2d055f78
commit 5ded38ce3e

View File

@@ -264,6 +264,74 @@ impl FromStr for Uimm32 {
} }
} }
/// A 128-bit unsigned integer immediate operand.
///
/// This is used as an immediate value in SIMD instructions
#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
pub struct Uimm128(pub [u8; 16]);
impl Display for Uimm128 {
// print a 128-bit vector in hexadecimal, e.g. 0x000102030405060708090a0b0c0d0e0f
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
write!(f, "0x")?;
let mut anything_written = false;
for &b in self.0.iter() {
if b == 0 && !anything_written {
continue;
} else {
anything_written = true;
write!(f, "{:02x}", b)?;
}
}
if !anything_written {
write!(f, "00")?;
}
Ok(())
}
}
impl From<u64> for Uimm128 {
fn from(x: u64) -> Self {
let mut buffer: [u8; 16] = [0; 16]; // zero-fill
(0..8).for_each(|byte| buffer[15 - byte] = (x >> (byte as u64 * 8) & 0xff) as u8); // insert each byte from the u64 into v after byte position 8
Uimm128(buffer)
}
}
impl From<&[u8]> for Uimm128 {
fn from(slice: &[u8]) -> Self {
assert_eq!(slice.len(), 16);
let mut buffer = [0; 16];
buffer.copy_from_slice(slice);
Uimm128(buffer)
}
}
impl FromStr for Uimm128 {
type Err = &'static str;
// parse a 128-bit vector from a hexadecimal string, formatted as above
fn from_str(s: &str) -> Result<Self, &'static str> {
if s.len() <= 2 || &s[0..2] != "0x" {
Err("Expected a hexadecimal string, e.g. 0x1234")
} else if s.len() % 2 != 0 {
Err("Hexadecimal string must have an even number of digits")
} else if s.len() > 32 {
Err("Hexadecimal string has too many digits to fit in a 128-bit vector")
} else {
let mut buffer = [0; 16]; // zero-fill
let start_at = 16 - s.len() / 2;
for i in (2..s.len()).step_by(2) {
let byte = u8::from_str_radix(&s[i..i + 2], 16)
.or_else(|_| Err("Unable to parse as hexadecimal"))?;
let position = start_at + (i / 2);
buffer[position] = byte;
}
Ok(Uimm128(buffer))
}
}
}
/// 32-bit signed immediate offset. /// 32-bit signed immediate offset.
/// ///
/// This is used to encode an immediate offset for load/store instructions. All supported ISAs have /// This is used to encode an immediate offset for load/store instructions. All supported ISAs have
@@ -884,6 +952,38 @@ mod tests {
parse_err::<Uimm64>("0x0_0000_0000_0000_0000", "Too many hexadecimal digits"); parse_err::<Uimm64>("0x0_0000_0000_0000_0000", "Too many hexadecimal digits");
} }
#[test]
fn format_uimm128() {
assert_eq!(Uimm128::from(0).to_string(), "0x00");
assert_eq!(Uimm128::from(42).to_string(), "0x2a");
assert_eq!(Uimm128::from(3735928559).to_string(), "0xdeadbeef");
assert_eq!(
Uimm128::from(0x0102030405060708).to_string(),
"0x0102030405060708"
);
}
#[test]
fn parse_uimm128() {
parse_ok::<Uimm128>("0x00", "0x00");
parse_ok::<Uimm128>("0x00000042", "0x42");
parse_ok::<Uimm128>(
"0x0102030405060708090a0b0c0d0e0f",
"0x0102030405060708090a0b0c0d0e0f",
);
parse_err::<Uimm128>("", "Expected a hexadecimal string, e.g. 0x1234");
parse_err::<Uimm128>("0x", "Expected a hexadecimal string, e.g. 0x1234");
parse_err::<Uimm128>(
"0x042",
"Hexadecimal string must have an even number of digits",
);
parse_err::<Uimm128>(
"0x00000000000000000000000000000000000000000000000000",
"Hexadecimal string has too many digits to fit in a 128-bit vector",
);
}
#[test] #[test]
fn format_offset32() { fn format_offset32() {
assert_eq!(Offset32(0).to_string(), ""); assert_eq!(Offset32(0).to_string(), "");