Add an Offset32 immediate operand kind.
This will be used to represent an immediate 32-bit signed address offset for load/store instructions.
This commit is contained in:
@@ -249,6 +249,13 @@ indicate the different kinds of immediate operands on an instruction.
|
|||||||
In the textual format, :type:`imm64` immediates appear as decimal or
|
In the textual format, :type:`imm64` immediates appear as decimal or
|
||||||
hexadecimal literals using the same syntax as C.
|
hexadecimal literals using the same syntax as C.
|
||||||
|
|
||||||
|
.. type:: offset32
|
||||||
|
|
||||||
|
A signed 32-bit immediate address offset.
|
||||||
|
|
||||||
|
In the textual format, :type:`offset32` immediates always have an explicit
|
||||||
|
sign, and a 0 offset may beomitted.
|
||||||
|
|
||||||
.. type:: ieee32
|
.. type:: ieee32
|
||||||
|
|
||||||
A 32-bit immediate floating point number in the IEEE 754-2008 binary32
|
A 32-bit immediate floating point number in the IEEE 754-2008 binary32
|
||||||
@@ -259,13 +266,6 @@ indicate the different kinds of immediate operands on an instruction.
|
|||||||
A 64-bit immediate floating point number in the IEEE 754-2008 binary64
|
A 64-bit immediate floating point number in the IEEE 754-2008 binary64
|
||||||
interchange format. All bit patterns are allowed.
|
interchange format. All bit patterns are allowed.
|
||||||
|
|
||||||
.. type:: immvector
|
|
||||||
|
|
||||||
An immediate SIMD vector. This operand supplies all the bits of a SIMD
|
|
||||||
type, so it can have different sizes depending on the type produced. The
|
|
||||||
bits of the operand are interpreted as if the SIMD vector was loaded from
|
|
||||||
memory containing the immediate.
|
|
||||||
|
|
||||||
.. type:: intcc
|
.. type:: intcc
|
||||||
|
|
||||||
An integer condition code. See the :inst:`icmp` instruction for details.
|
An integer condition code. See the :inst:`icmp` instruction for details.
|
||||||
|
|||||||
@@ -17,6 +17,12 @@ imm64 = ImmediateKind('imm64', 'A 64-bit immediate integer.')
|
|||||||
#: immediate bit counts on shift instructions.
|
#: immediate bit counts on shift instructions.
|
||||||
uimm8 = ImmediateKind('uimm8', 'An 8-bit immediate unsigned integer.')
|
uimm8 = ImmediateKind('uimm8', 'An 8-bit immediate unsigned integer.')
|
||||||
|
|
||||||
|
#: A 32-bit immediate signed offset.
|
||||||
|
#:
|
||||||
|
#: This is used to represent an immediate address offset in load/store
|
||||||
|
#: instructions.
|
||||||
|
offset32 = ImmediateKind('offset32', 'A 32-bit immediate signed offset.')
|
||||||
|
|
||||||
#: A 32-bit immediate floating point operand.
|
#: A 32-bit immediate floating point operand.
|
||||||
#:
|
#:
|
||||||
#: IEEE 754-2008 binary32 interchange format.
|
#: IEEE 754-2008 binary32 interchange format.
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
//! module in the meta language.
|
//! module in the meta language.
|
||||||
|
|
||||||
use std::fmt::{self, Display, Formatter};
|
use std::fmt::{self, Display, Formatter};
|
||||||
|
use std::i32;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
@@ -35,19 +36,13 @@ impl From<i64> for Imm64 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for Imm64 {
|
|
||||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
|
||||||
let x = self.0;
|
|
||||||
if -10_000 < x && x < 10_000 {
|
|
||||||
// Use decimal for small numbers.
|
|
||||||
write!(f, "{}", x)
|
|
||||||
} else {
|
|
||||||
// Hexadecimal with a multiple of 4 digits and group separators:
|
// Hexadecimal with a multiple of 4 digits and group separators:
|
||||||
//
|
//
|
||||||
// 0xfff0
|
// 0xfff0
|
||||||
// 0x0001_ffff
|
// 0x0001_ffff
|
||||||
// 0xffff_ffff_fff8_4400
|
// 0xffff_ffff_fff8_4400
|
||||||
//
|
//
|
||||||
|
fn write_hex(x: i64, f: &mut Formatter) -> fmt::Result {
|
||||||
let mut pos = (64 - x.leading_zeros() - 1) & 0xf0;
|
let mut pos = (64 - x.leading_zeros() - 1) & 0xf0;
|
||||||
write!(f, "0x{:04x}", (x >> pos) & 0xffff)?;
|
write!(f, "0x{:04x}", (x >> pos) & 0xffff)?;
|
||||||
while pos > 0 {
|
while pos > 0 {
|
||||||
@@ -56,18 +51,29 @@ impl Display for Imm64 {
|
|||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Display for Imm64 {
|
||||||
|
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||||
|
let x = self.0;
|
||||||
|
if -10_000 < x && x < 10_000 {
|
||||||
|
// Use decimal for small numbers.
|
||||||
|
write!(f, "{}", x)
|
||||||
|
} else {
|
||||||
|
write_hex(x, f)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FromStr for Imm64 {
|
/// Parse a 64-bit number.
|
||||||
type Err = &'static str;
|
fn parse_i64(s: &str) -> Result<i64, &'static str> {
|
||||||
|
|
||||||
// Parse a decimal or hexadecimal `Imm64`, formatted as above.
|
|
||||||
fn from_str(s: &str) -> Result<Imm64, &'static str> {
|
|
||||||
let mut value: u64 = 0;
|
let mut value: u64 = 0;
|
||||||
let mut digits = 0;
|
let mut digits = 0;
|
||||||
let negative = s.starts_with('-');
|
let negative = s.starts_with('-');
|
||||||
let s2 = if negative { &s[1..] } else { s };
|
let s2 = if negative || s.starts_with('+') {
|
||||||
|
&s[1..]
|
||||||
|
} else {
|
||||||
|
s
|
||||||
|
};
|
||||||
|
|
||||||
if s2.starts_with("0x") {
|
if s2.starts_with("0x") {
|
||||||
// Hexadecimal.
|
// Hexadecimal.
|
||||||
@@ -76,7 +82,7 @@ impl FromStr for Imm64 {
|
|||||||
Some(digit) => {
|
Some(digit) => {
|
||||||
digits += 1;
|
digits += 1;
|
||||||
if digits > 16 {
|
if digits > 16 {
|
||||||
return Err("Too many hexadecimal digits in Imm64");
|
return Err("Too many hexadecimal digits");
|
||||||
}
|
}
|
||||||
// This can't overflow given the digit limit.
|
// This can't overflow given the digit limit.
|
||||||
value = (value << 4) | digit as u64;
|
value = (value << 4) | digit as u64;
|
||||||
@@ -84,7 +90,7 @@ impl FromStr for Imm64 {
|
|||||||
None => {
|
None => {
|
||||||
// Allow embedded underscores, but fail on anything else.
|
// Allow embedded underscores, but fail on anything else.
|
||||||
if ch != '_' {
|
if ch != '_' {
|
||||||
return Err("Invalid character in hexadecimal Imm64");
|
return Err("Invalid character in hexadecimal number");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -96,18 +102,18 @@ impl FromStr for Imm64 {
|
|||||||
Some(digit) => {
|
Some(digit) => {
|
||||||
digits += 1;
|
digits += 1;
|
||||||
match value.checked_mul(10) {
|
match value.checked_mul(10) {
|
||||||
None => return Err("Too large decimal Imm64"),
|
None => return Err("Too large decimal number"),
|
||||||
Some(v) => value = v,
|
Some(v) => value = v,
|
||||||
}
|
}
|
||||||
match value.checked_add(digit as u64) {
|
match value.checked_add(digit as u64) {
|
||||||
None => return Err("Too large decimal Imm64"),
|
None => return Err("Too large decimal number"),
|
||||||
Some(v) => value = v,
|
Some(v) => value = v,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
// Allow embedded underscores, but fail on anything else.
|
// Allow embedded underscores, but fail on anything else.
|
||||||
if ch != '_' {
|
if ch != '_' {
|
||||||
return Err("Invalid character in decimal Imm64");
|
return Err("Invalid character in decimal number");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -115,7 +121,7 @@ impl FromStr for Imm64 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if digits == 0 {
|
if digits == 0 {
|
||||||
return Err("No digits in Imm64");
|
return Err("No digits in number");
|
||||||
}
|
}
|
||||||
|
|
||||||
// We support the range-and-a-half from -2^63 .. 2^64-1.
|
// We support the range-and-a-half from -2^63 .. 2^64-1.
|
||||||
@@ -123,10 +129,18 @@ impl FromStr for Imm64 {
|
|||||||
value = value.wrapping_neg();
|
value = value.wrapping_neg();
|
||||||
// Don't allow large negative values to wrap around and become positive.
|
// Don't allow large negative values to wrap around and become positive.
|
||||||
if value as i64 > 0 {
|
if value as i64 > 0 {
|
||||||
return Err("Negative number too small for Imm64");
|
return Err("Negative number too small");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(Imm64::new(value as i64))
|
Ok(value as i64)
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromStr for Imm64 {
|
||||||
|
type Err = &'static str;
|
||||||
|
|
||||||
|
// Parse a decimal or hexadecimal `Imm64`, formatted as above.
|
||||||
|
fn from_str(s: &str) -> Result<Imm64, &'static str> {
|
||||||
|
parse_i64(s).map(Imm64::new)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -135,6 +149,68 @@ impl FromStr for Imm64 {
|
|||||||
/// This is used to indicate lane indexes typically.
|
/// This is used to indicate lane indexes typically.
|
||||||
pub type Uimm8 = u8;
|
pub type Uimm8 = u8;
|
||||||
|
|
||||||
|
/// 32-bit signed immediate offset.
|
||||||
|
///
|
||||||
|
/// This is used to encode an immediate offset for load/store instructions. All supported ISAs have
|
||||||
|
/// a maximum load/store offset that fits in an `i32`.
|
||||||
|
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
||||||
|
pub struct Offset32(i32);
|
||||||
|
|
||||||
|
impl Offset32 {
|
||||||
|
/// Create a new `Offset32` representing the signed number `x`.
|
||||||
|
pub fn new(x: i32) -> Offset32 {
|
||||||
|
Offset32(x)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Into<i32> for Offset32 {
|
||||||
|
fn into(self) -> i32 {
|
||||||
|
self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<i32> for Offset32 {
|
||||||
|
fn from(x: i32) -> Self {
|
||||||
|
Offset32(x)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for Offset32 {
|
||||||
|
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||||
|
// 0 displays as an empty offset.
|
||||||
|
if self.0 == 0 {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Always include a sign.
|
||||||
|
write!(f, "{}", if self.0 < 0 { '-' } else { '+' })?;
|
||||||
|
|
||||||
|
let val = (self.0 as i64).abs();
|
||||||
|
if val < 10_000 {
|
||||||
|
write!(f, "{}", val)
|
||||||
|
} else {
|
||||||
|
write_hex(val, f)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromStr for Offset32 {
|
||||||
|
type Err = &'static str;
|
||||||
|
|
||||||
|
// Parse a decimal or hexadecimal `Offset32`, formatted as above.
|
||||||
|
fn from_str(s: &str) -> Result<Offset32, &'static str> {
|
||||||
|
if !(s.starts_with('-') || s.starts_with('+')) {
|
||||||
|
return Err("Offset must begin with sign");
|
||||||
|
}
|
||||||
|
parse_i64(s).and_then(|x| if i32::MIN as i64 <= x && x <= i32::MAX as i64 {
|
||||||
|
Ok(Offset32::new(x as i32))
|
||||||
|
} else {
|
||||||
|
Err("Offset out of range")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// An IEEE binary32 immediate floating point value.
|
/// An IEEE binary32 immediate floating point value.
|
||||||
///
|
///
|
||||||
/// All bit patterns are allowed.
|
/// All bit patterns are allowed.
|
||||||
@@ -486,15 +562,13 @@ mod tests {
|
|||||||
parse_ok::<Imm64>("0xffffffff_ffffffff", "-1");
|
parse_ok::<Imm64>("0xffffffff_ffffffff", "-1");
|
||||||
parse_ok::<Imm64>("0x80000000_00000000", "0x8000_0000_0000_0000");
|
parse_ok::<Imm64>("0x80000000_00000000", "0x8000_0000_0000_0000");
|
||||||
parse_ok::<Imm64>("-0x80000000_00000000", "0x8000_0000_0000_0000");
|
parse_ok::<Imm64>("-0x80000000_00000000", "0x8000_0000_0000_0000");
|
||||||
parse_err::<Imm64>("-0x80000000_00000001",
|
parse_err::<Imm64>("-0x80000000_00000001", "Negative number too small");
|
||||||
"Negative number too small for Imm64");
|
|
||||||
parse_ok::<Imm64>("18446744073709551615", "-1");
|
parse_ok::<Imm64>("18446744073709551615", "-1");
|
||||||
parse_ok::<Imm64>("-9223372036854775808", "0x8000_0000_0000_0000");
|
parse_ok::<Imm64>("-9223372036854775808", "0x8000_0000_0000_0000");
|
||||||
// Overflow both the `checked_add` and `checked_mul`.
|
// Overflow both the `checked_add` and `checked_mul`.
|
||||||
parse_err::<Imm64>("18446744073709551616", "Too large decimal Imm64");
|
parse_err::<Imm64>("18446744073709551616", "Too large decimal number");
|
||||||
parse_err::<Imm64>("184467440737095516100", "Too large decimal Imm64");
|
parse_err::<Imm64>("184467440737095516100", "Too large decimal number");
|
||||||
parse_err::<Imm64>("-9223372036854775809",
|
parse_err::<Imm64>("-9223372036854775809", "Negative number too small");
|
||||||
"Negative number too small for Imm64");
|
|
||||||
|
|
||||||
// Underscores are allowed where digits go.
|
// Underscores are allowed where digits go.
|
||||||
parse_ok::<Imm64>("0_0", "0");
|
parse_ok::<Imm64>("0_0", "0");
|
||||||
@@ -503,21 +577,47 @@ mod tests {
|
|||||||
parse_ok::<Imm64>("0x97_88_bb", "0x0097_88bb");
|
parse_ok::<Imm64>("0x97_88_bb", "0x0097_88bb");
|
||||||
parse_ok::<Imm64>("0x_97_", "151");
|
parse_ok::<Imm64>("0x_97_", "151");
|
||||||
|
|
||||||
parse_err::<Imm64>("", "No digits in Imm64");
|
parse_err::<Imm64>("", "No digits in number");
|
||||||
parse_err::<Imm64>("-", "No digits in Imm64");
|
parse_err::<Imm64>("-", "No digits in number");
|
||||||
parse_err::<Imm64>("_", "No digits in Imm64");
|
parse_err::<Imm64>("_", "No digits in number");
|
||||||
parse_err::<Imm64>("0x", "No digits in Imm64");
|
parse_err::<Imm64>("0x", "No digits in number");
|
||||||
parse_err::<Imm64>("0x_", "No digits in Imm64");
|
parse_err::<Imm64>("0x_", "No digits in number");
|
||||||
parse_err::<Imm64>("-0x", "No digits in Imm64");
|
parse_err::<Imm64>("-0x", "No digits in number");
|
||||||
parse_err::<Imm64>(" ", "Invalid character in decimal Imm64");
|
parse_err::<Imm64>(" ", "Invalid character in decimal number");
|
||||||
parse_err::<Imm64>("0 ", "Invalid character in decimal Imm64");
|
parse_err::<Imm64>("0 ", "Invalid character in decimal number");
|
||||||
parse_err::<Imm64>(" 0", "Invalid character in decimal Imm64");
|
parse_err::<Imm64>(" 0", "Invalid character in decimal number");
|
||||||
parse_err::<Imm64>("--", "Invalid character in decimal Imm64");
|
parse_err::<Imm64>("--", "Invalid character in decimal number");
|
||||||
parse_err::<Imm64>("-0x-", "Invalid character in hexadecimal Imm64");
|
parse_err::<Imm64>("-0x-", "Invalid character in hexadecimal number");
|
||||||
|
|
||||||
// Hex count overflow.
|
// Hex count overflow.
|
||||||
parse_err::<Imm64>("0x0_0000_0000_0000_0000",
|
parse_err::<Imm64>("0x0_0000_0000_0000_0000", "Too many hexadecimal digits");
|
||||||
"Too many hexadecimal digits in Imm64");
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn format_offset32() {
|
||||||
|
assert_eq!(Offset32(0).to_string(), "");
|
||||||
|
assert_eq!(Offset32(1).to_string(), "+1");
|
||||||
|
assert_eq!(Offset32(-1).to_string(), "-1");
|
||||||
|
assert_eq!(Offset32(9999).to_string(), "+9999");
|
||||||
|
assert_eq!(Offset32(10000).to_string(), "+0x2710");
|
||||||
|
assert_eq!(Offset32(-9999).to_string(), "-9999");
|
||||||
|
assert_eq!(Offset32(-10000).to_string(), "-0x2710");
|
||||||
|
assert_eq!(Offset32(0xffff).to_string(), "+0xffff");
|
||||||
|
assert_eq!(Offset32(0x10000).to_string(), "+0x0001_0000");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn parse_offset32() {
|
||||||
|
parse_ok::<Offset32>("+0", "");
|
||||||
|
parse_ok::<Offset32>("+1", "+1");
|
||||||
|
parse_ok::<Offset32>("-0", "");
|
||||||
|
parse_ok::<Offset32>("-1", "-1");
|
||||||
|
parse_ok::<Offset32>("+0x0", "");
|
||||||
|
parse_ok::<Offset32>("+0xf", "+15");
|
||||||
|
parse_ok::<Offset32>("-0x9", "-9");
|
||||||
|
parse_ok::<Offset32>("-0x8000_0000", "-0x8000_0000");
|
||||||
|
|
||||||
|
parse_err::<Offset32>("+0x8000_0000", "Offset out of range");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
Reference in New Issue
Block a user