Add a Uoffset32 immediate operand kind.
WebAssembly memory instructions encode a 32-bit unsigned offset that is used to compute an effective address.
This commit is contained in:
@@ -26,6 +26,15 @@ offset32 = ImmediateKind(
|
|||||||
'A 32-bit immediate signed offset.',
|
'A 32-bit immediate signed offset.',
|
||||||
default_member='offset')
|
default_member='offset')
|
||||||
|
|
||||||
|
#: A 32-bit immediate unsigned offset.
|
||||||
|
#:
|
||||||
|
#: This is used to represent an immediate address offset in WebAssembly memory
|
||||||
|
#: instructions.
|
||||||
|
uoffset32 = ImmediateKind(
|
||||||
|
'uoffset32',
|
||||||
|
'A 32-bit immediate unsigned offset.',
|
||||||
|
default_member='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,7 +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::{i32, u32};
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
@@ -169,6 +169,12 @@ impl Into<i32> for Offset32 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Into<i64> for Offset32 {
|
||||||
|
fn into(self) -> i64 {
|
||||||
|
self.0 as i64
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl From<i32> for Offset32 {
|
impl From<i32> for Offset32 {
|
||||||
fn from(x: i32) -> Self {
|
fn from(x: i32) -> Self {
|
||||||
Offset32(x)
|
Offset32(x)
|
||||||
@@ -211,6 +217,71 @@ impl FromStr for Offset32 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 32-bit unsigned immediate offset.
|
||||||
|
///
|
||||||
|
/// This is used to encode an immediate offset for WebAssembly heap_load/heap_store instructions.
|
||||||
|
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
||||||
|
pub struct Uoffset32(u32);
|
||||||
|
|
||||||
|
impl Uoffset32 {
|
||||||
|
/// Create a new `Uoffset32` representing the number `x`.
|
||||||
|
pub fn new(x: u32) -> Uoffset32 {
|
||||||
|
Uoffset32(x)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Into<u32> for Uoffset32 {
|
||||||
|
fn into(self) -> u32 {
|
||||||
|
self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Into<i64> for Uoffset32 {
|
||||||
|
fn into(self) -> i64 {
|
||||||
|
self.0 as i64
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<u32> for Uoffset32 {
|
||||||
|
fn from(x: u32) -> Self {
|
||||||
|
Uoffset32(x)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for Uoffset32 {
|
||||||
|
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||||
|
// 0 displays as an empty offset.
|
||||||
|
if self.0 == 0 {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Always include a sign.
|
||||||
|
if self.0 < 10_000 {
|
||||||
|
write!(f, "+{}", self.0)
|
||||||
|
} else {
|
||||||
|
write!(f, "+")?;
|
||||||
|
write_hex(self.0 as i64, f)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromStr for Uoffset32 {
|
||||||
|
type Err = &'static str;
|
||||||
|
|
||||||
|
// Parse a decimal or hexadecimal `Uoffset32`, formatted as above.
|
||||||
|
fn from_str(s: &str) -> Result<Uoffset32, &'static str> {
|
||||||
|
if !s.starts_with('+') {
|
||||||
|
return Err("Unsigned offset must begin with '+' sign");
|
||||||
|
}
|
||||||
|
parse_i64(s).and_then(|x| if 0 <= x && x <= u32::MAX as i64 {
|
||||||
|
Ok(Uoffset32::new(x as u32))
|
||||||
|
} 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.
|
||||||
@@ -620,6 +691,28 @@ mod tests {
|
|||||||
parse_err::<Offset32>("+0x8000_0000", "Offset out of range");
|
parse_err::<Offset32>("+0x8000_0000", "Offset out of range");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn format_uoffset32() {
|
||||||
|
assert_eq!(Uoffset32(0).to_string(), "");
|
||||||
|
assert_eq!(Uoffset32(1).to_string(), "+1");
|
||||||
|
assert_eq!(Uoffset32(9999).to_string(), "+9999");
|
||||||
|
assert_eq!(Uoffset32(10000).to_string(), "+0x2710");
|
||||||
|
assert_eq!(Uoffset32(0xffff).to_string(), "+0xffff");
|
||||||
|
assert_eq!(Uoffset32(0x10000).to_string(), "+0x0001_0000");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn parse_uoffset32() {
|
||||||
|
parse_ok::<Uoffset32>("+0", "");
|
||||||
|
parse_ok::<Uoffset32>("+1", "+1");
|
||||||
|
parse_ok::<Uoffset32>("+0x0", "");
|
||||||
|
parse_ok::<Uoffset32>("+0xf", "+15");
|
||||||
|
parse_ok::<Uoffset32>("+0x8000_0000", "+0x8000_0000");
|
||||||
|
parse_ok::<Uoffset32>("+0xffff_ffff", "+0xffff_ffff");
|
||||||
|
|
||||||
|
parse_err::<Uoffset32>("+0x1_0000_0000", "Offset out of range");
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn format_ieee32() {
|
fn format_ieee32() {
|
||||||
assert_eq!(Ieee32::new(0.0).to_string(), "0.0");
|
assert_eq!(Ieee32::new(0.0).to_string(), "0.0");
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ use cretonne::ir::{Function, Ebb, Opcode, Value, Type, FunctionName, StackSlotDa
|
|||||||
JumpTableData, Signature, ArgumentType, ArgumentExtension, ExtFuncData, SigRef,
|
JumpTableData, Signature, ArgumentType, ArgumentExtension, ExtFuncData, SigRef,
|
||||||
FuncRef, StackSlot, ValueLoc, ArgumentLoc};
|
FuncRef, StackSlot, ValueLoc, ArgumentLoc};
|
||||||
use cretonne::ir::types::VOID;
|
use cretonne::ir::types::VOID;
|
||||||
use cretonne::ir::immediates::{Imm64, Offset32, Ieee32, Ieee64};
|
use cretonne::ir::immediates::{Imm64, Offset32, Uoffset32, Ieee32, Ieee64};
|
||||||
use cretonne::ir::entities::AnyEntity;
|
use cretonne::ir::entities::AnyEntity;
|
||||||
use cretonne::ir::instructions::{InstructionFormat, InstructionData, VariableArgs};
|
use cretonne::ir::instructions::{InstructionFormat, InstructionData, VariableArgs};
|
||||||
use cretonne::isa::{self, TargetIsa, Encoding};
|
use cretonne::isa::{self, TargetIsa, Encoding};
|
||||||
@@ -523,6 +523,22 @@ impl<'a> Parser<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Match and consume an optional uoffset32 immediate.
|
||||||
|
//
|
||||||
|
// Note that that this will match an empty string as an empty offset, and that if an offset is
|
||||||
|
// present, it must contain a `+` sign.
|
||||||
|
fn optional_uoffset32(&mut self) -> Result<Uoffset32> {
|
||||||
|
if let Some(Token::Integer(text)) = self.token() {
|
||||||
|
self.consume();
|
||||||
|
// Lexer just gives us raw text that looks like an integer.
|
||||||
|
// Parse it as a `Uoffset32` to check for overflow and other issues.
|
||||||
|
text.parse().map_err(|e| self.error(e))
|
||||||
|
} else {
|
||||||
|
// A uoffset32 operand can be absent.
|
||||||
|
Ok(Uoffset32::new(0))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Match and consume an Ieee32 immediate.
|
// Match and consume an Ieee32 immediate.
|
||||||
fn match_ieee32(&mut self, err_msg: &str) -> Result<Ieee32> {
|
fn match_ieee32(&mut self, err_msg: &str) -> Result<Ieee32> {
|
||||||
if let Some(Token::Float(text)) = self.token() {
|
if let Some(Token::Float(text)) = self.token() {
|
||||||
|
|||||||
Reference in New Issue
Block a user