refactor: move DataValue from cranelift-reader to cranelift-codegen
This is no change to functionality; the move is necessary in order to return InstructionData immediates in a structure way (see next commit).
This commit is contained in:
180
cranelift/codegen/src/data_value.rs
Normal file
180
cranelift/codegen/src/data_value.rs
Normal file
@@ -0,0 +1,180 @@
|
|||||||
|
//! This module gives users to instantiate values that Cranelift understands. These values are used,
|
||||||
|
//! for example, during interpretation and for wrapping immediates.
|
||||||
|
use crate::ir::immediates::{Ieee32, Ieee64, Imm64};
|
||||||
|
use crate::ir::{types, ConstantData, Type};
|
||||||
|
use core::convert::TryInto;
|
||||||
|
use core::fmt::{self, Display, Formatter};
|
||||||
|
use thiserror::Error;
|
||||||
|
|
||||||
|
/// Represent a data value. Where [Value] is an SSA reference, [DataValue] is the type + value
|
||||||
|
/// that would be referred to by a [Value].
|
||||||
|
///
|
||||||
|
/// [Value]: crate::ir::Value
|
||||||
|
#[allow(missing_docs)]
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub enum DataValue {
|
||||||
|
B(bool),
|
||||||
|
I8(i8),
|
||||||
|
I16(i16),
|
||||||
|
I32(i32),
|
||||||
|
I64(i64),
|
||||||
|
F32(f32),
|
||||||
|
F64(f64),
|
||||||
|
V128([u8; 16]),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DataValue {
|
||||||
|
/// Try to cast an immediate integer ([Imm64]) to the given Cranelift [Type].
|
||||||
|
pub fn from_integer(imm: Imm64, ty: Type) -> Result<DataValue, DataValueCastFailure> {
|
||||||
|
match ty {
|
||||||
|
types::I8 => Ok(DataValue::I8(imm.bits() as i8)),
|
||||||
|
types::I16 => Ok(DataValue::I16(imm.bits() as i16)),
|
||||||
|
types::I32 => Ok(DataValue::I32(imm.bits() as i32)),
|
||||||
|
types::I64 => Ok(DataValue::I64(imm.bits())),
|
||||||
|
_ => Err(DataValueCastFailure::FromImm64(imm, ty)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return the Cranelift IR [Type] for this [DataValue].
|
||||||
|
pub fn ty(&self) -> Type {
|
||||||
|
match self {
|
||||||
|
DataValue::B(_) => types::B8, // A default type.
|
||||||
|
DataValue::I8(_) => types::I8,
|
||||||
|
DataValue::I16(_) => types::I16,
|
||||||
|
DataValue::I32(_) => types::I32,
|
||||||
|
DataValue::I64(_) => types::I64,
|
||||||
|
DataValue::F32(_) => types::F32,
|
||||||
|
DataValue::F64(_) => types::F64,
|
||||||
|
DataValue::V128(_) => types::I8X16, // A default type.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return true if the value is a vector (i.e. `DataValue::V128`).
|
||||||
|
pub fn is_vector(&self) -> bool {
|
||||||
|
match self {
|
||||||
|
DataValue::V128(_) => true,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Record failures to cast [DataValue].
|
||||||
|
#[derive(Error, Debug, PartialEq)]
|
||||||
|
#[allow(missing_docs)]
|
||||||
|
pub enum DataValueCastFailure {
|
||||||
|
#[error("unable to cast data value of type {0} to type {1}")]
|
||||||
|
TryInto(Type, Type),
|
||||||
|
#[error("unable to cast Imm64({0}) to a data value of type {1}")]
|
||||||
|
FromImm64(Imm64, Type),
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Helper for creating conversion implementations for [DataValue].
|
||||||
|
macro_rules! build_conversion_impl {
|
||||||
|
( $rust_ty:ty, $data_value_ty:ident, $cranelift_ty:ident ) => {
|
||||||
|
impl From<$rust_ty> for DataValue {
|
||||||
|
fn from(data: $rust_ty) -> Self {
|
||||||
|
DataValue::$data_value_ty(data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryInto<$rust_ty> for DataValue {
|
||||||
|
type Error = DataValueCastFailure;
|
||||||
|
fn try_into(self) -> Result<$rust_ty, Self::Error> {
|
||||||
|
if let DataValue::$data_value_ty(v) = self {
|
||||||
|
Ok(v)
|
||||||
|
} else {
|
||||||
|
Err(DataValueCastFailure::TryInto(
|
||||||
|
self.ty(),
|
||||||
|
types::$cranelift_ty,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
build_conversion_impl!(bool, B, B8);
|
||||||
|
build_conversion_impl!(i8, I8, I8);
|
||||||
|
build_conversion_impl!(i16, I16, I16);
|
||||||
|
build_conversion_impl!(i32, I32, I32);
|
||||||
|
build_conversion_impl!(i64, I64, I64);
|
||||||
|
build_conversion_impl!(f32, F32, F32);
|
||||||
|
build_conversion_impl!(f64, F64, F64);
|
||||||
|
build_conversion_impl!([u8; 16], V128, I8X16);
|
||||||
|
|
||||||
|
impl Display for DataValue {
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||||
|
match self {
|
||||||
|
DataValue::B(dv) => write!(f, "{}", dv),
|
||||||
|
DataValue::I8(dv) => write!(f, "{}", dv),
|
||||||
|
DataValue::I16(dv) => write!(f, "{}", dv),
|
||||||
|
DataValue::I32(dv) => write!(f, "{}", dv),
|
||||||
|
DataValue::I64(dv) => write!(f, "{}", dv),
|
||||||
|
// Use the Ieee* wrappers here to maintain a consistent syntax.
|
||||||
|
DataValue::F32(dv) => write!(f, "{}", Ieee32::from(*dv)),
|
||||||
|
DataValue::F64(dv) => write!(f, "{}", Ieee64::from(*dv)),
|
||||||
|
// Again, for syntax consistency, use ConstantData, which in this case displays as hex.
|
||||||
|
DataValue::V128(dv) => write!(f, "{}", ConstantData::from(&dv[..])),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Helper structure for printing bracket-enclosed vectors of [DataValue]s.
|
||||||
|
/// - for empty vectors, display `[]`
|
||||||
|
/// - for single item vectors, display `42`, e.g.
|
||||||
|
/// - for multiple item vectors, display `[42, 43, 44]`, e.g.
|
||||||
|
pub struct DisplayDataValues<'a>(pub &'a [DataValue]);
|
||||||
|
|
||||||
|
impl<'a> Display for DisplayDataValues<'a> {
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||||
|
if self.0.len() == 1 {
|
||||||
|
write!(f, "{}", self.0[0])
|
||||||
|
} else {
|
||||||
|
write!(f, "[")?;
|
||||||
|
write_data_value_list(f, &self.0)?;
|
||||||
|
write!(f, "]")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Helper function for displaying `Vec<DataValue>`.
|
||||||
|
pub fn write_data_value_list(f: &mut Formatter<'_>, list: &[DataValue]) -> fmt::Result {
|
||||||
|
match list.len() {
|
||||||
|
0 => Ok(()),
|
||||||
|
1 => write!(f, "{}", list[0]),
|
||||||
|
_ => {
|
||||||
|
write!(f, "{}", list[0])?;
|
||||||
|
for dv in list.iter().skip(1) {
|
||||||
|
write!(f, ", {}", dv)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn type_conversions() {
|
||||||
|
assert_eq!(DataValue::B(true).ty(), types::B8);
|
||||||
|
assert_eq!(
|
||||||
|
TryInto::<bool>::try_into(DataValue::B(false)).unwrap(),
|
||||||
|
false
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
TryInto::<i32>::try_into(DataValue::B(false)).unwrap_err(),
|
||||||
|
DataValueCastFailure::TryInto(types::B8, types::I32)
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(DataValue::V128([0; 16]).ty(), types::I8X16);
|
||||||
|
assert_eq!(
|
||||||
|
TryInto::<[u8; 16]>::try_into(DataValue::V128([0; 16])).unwrap(),
|
||||||
|
[0; 16]
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
TryInto::<i32>::try_into(DataValue::V128([0; 16])).unwrap_err(),
|
||||||
|
DataValueCastFailure::TryInto(types::I8X16, types::I32)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -71,6 +71,7 @@ pub use cranelift_entity as entity;
|
|||||||
pub mod binemit;
|
pub mod binemit;
|
||||||
pub mod cfg_printer;
|
pub mod cfg_printer;
|
||||||
pub mod cursor;
|
pub mod cursor;
|
||||||
|
pub mod data_value;
|
||||||
pub mod dbg;
|
pub mod dbg;
|
||||||
pub mod dominator_tree;
|
pub mod dominator_tree;
|
||||||
pub mod flowgraph;
|
pub mod flowgraph;
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
//! Provides functionality for compiling and running CLIF IR for `run` tests.
|
//! Provides functionality for compiling and running CLIF IR for `run` tests.
|
||||||
use core::{mem, ptr};
|
use core::{mem, ptr};
|
||||||
use cranelift_codegen::binemit::{NullRelocSink, NullStackMapSink, NullTrapSink};
|
use cranelift_codegen::binemit::{NullRelocSink, NullStackMapSink, NullTrapSink};
|
||||||
|
use cranelift_codegen::data_value::DataValue;
|
||||||
use cranelift_codegen::ir::{condcodes::IntCC, Function, InstBuilder, Signature, Type};
|
use cranelift_codegen::ir::{condcodes::IntCC, Function, InstBuilder, Signature, Type};
|
||||||
use cranelift_codegen::isa::TargetIsa;
|
use cranelift_codegen::isa::TargetIsa;
|
||||||
use cranelift_codegen::{ir, settings, CodegenError, Context};
|
use cranelift_codegen::{ir, settings, CodegenError, Context};
|
||||||
use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext};
|
use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext};
|
||||||
use cranelift_native::builder as host_isa_builder;
|
use cranelift_native::builder as host_isa_builder;
|
||||||
use cranelift_reader::DataValue;
|
|
||||||
use log::trace;
|
use log::trace;
|
||||||
use memmap::{Mmap, MmapMut};
|
use memmap::{Mmap, MmapMut};
|
||||||
use std::cmp::max;
|
use std::cmp::max;
|
||||||
@@ -126,7 +126,8 @@ impl Trampoline {
|
|||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// use cranelift_filetests::SingleFunctionCompiler;
|
/// use cranelift_filetests::SingleFunctionCompiler;
|
||||||
/// use cranelift_reader::{parse_functions, DataValue};
|
/// use cranelift_reader::parse_functions;
|
||||||
|
/// use cranelift_codegen::data_value::DataValue;
|
||||||
///
|
///
|
||||||
/// let code = "test run \n function %add(i32, i32) -> i32 { block0(v0:i32, v1:i32): v2 = iadd v0, v1 return v2 }".into();
|
/// let code = "test run \n function %add(i32, i32) -> i32 { block0(v0:i32, v1:i32): v2 = iadd v0, v1 return v2 }".into();
|
||||||
/// let func = parse_functions(code).unwrap().into_iter().nth(0).unwrap();
|
/// let func = parse_functions(code).unwrap().into_iter().nth(0).unwrap();
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
//! Implements a call frame (activation record) for the Cranelift interpreter.
|
//! Implements a call frame (activation record) for the Cranelift interpreter.
|
||||||
|
|
||||||
|
use cranelift_codegen::data_value::DataValue;
|
||||||
use cranelift_codegen::ir::{Function, Value as ValueRef};
|
use cranelift_codegen::ir::{Function, Value as ValueRef};
|
||||||
use cranelift_reader::DataValue;
|
|
||||||
use log::trace;
|
use log::trace;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
@@ -78,9 +78,9 @@ impl<'a> Frame<'a> {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use cranelift_codegen::data_value::DataValue;
|
||||||
use cranelift_codegen::ir::InstBuilder;
|
use cranelift_codegen::ir::InstBuilder;
|
||||||
use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext};
|
use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext};
|
||||||
use cranelift_reader::DataValue;
|
|
||||||
|
|
||||||
/// Build an empty function with a single return.
|
/// Build an empty function with a single return.
|
||||||
fn empty_function() -> Function {
|
fn empty_function() -> Function {
|
||||||
|
|||||||
@@ -5,12 +5,12 @@
|
|||||||
use crate::environment::Environment;
|
use crate::environment::Environment;
|
||||||
use crate::frame::Frame;
|
use crate::frame::Frame;
|
||||||
use crate::interpreter::Trap::InvalidType;
|
use crate::interpreter::Trap::InvalidType;
|
||||||
|
use cranelift_codegen::data_value::{DataValue, DataValueCastFailure};
|
||||||
use cranelift_codegen::ir::condcodes::IntCC;
|
use cranelift_codegen::ir::condcodes::IntCC;
|
||||||
use cranelift_codegen::ir::{
|
use cranelift_codegen::ir::{
|
||||||
Block, FuncRef, Function, Inst, InstructionData, InstructionData::*, Opcode, Opcode::*, Type,
|
Block, FuncRef, Function, Inst, InstructionData, InstructionData::*, Opcode, Opcode::*, Type,
|
||||||
Value as ValueRef, ValueList,
|
Value as ValueRef, ValueList,
|
||||||
};
|
};
|
||||||
use cranelift_reader::{DataValue, DataValueCastFailure};
|
|
||||||
use log::trace;
|
use log::trace;
|
||||||
use std::ops::{Add, Div, Mul, Sub};
|
use std::ops::{Add, Div, Mul, Sub};
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|||||||
@@ -29,7 +29,7 @@
|
|||||||
pub use crate::error::{Location, ParseError, ParseResult};
|
pub use crate::error::{Location, ParseError, ParseResult};
|
||||||
pub use crate::isaspec::{parse_options, IsaSpec, ParseOptionError};
|
pub use crate::isaspec::{parse_options, IsaSpec, ParseOptionError};
|
||||||
pub use crate::parser::{parse_functions, parse_run_command, parse_test, ParseOptions};
|
pub use crate::parser::{parse_functions, parse_run_command, parse_test, ParseOptions};
|
||||||
pub use crate::run_command::{Comparison, DataValue, DataValueCastFailure, Invocation, RunCommand};
|
pub use crate::run_command::{Comparison, Invocation, RunCommand};
|
||||||
pub use crate::sourcemap::SourceMap;
|
pub use crate::sourcemap::SourceMap;
|
||||||
pub use crate::testcommand::{TestCommand, TestOption};
|
pub use crate::testcommand::{TestCommand, TestOption};
|
||||||
pub use crate::testfile::{Comment, Details, Feature, TestFile};
|
pub use crate::testfile::{Comment, Details, Feature, TestFile};
|
||||||
|
|||||||
@@ -3,10 +3,11 @@
|
|||||||
use crate::error::{Location, ParseError, ParseResult};
|
use crate::error::{Location, ParseError, ParseResult};
|
||||||
use crate::isaspec;
|
use crate::isaspec;
|
||||||
use crate::lexer::{LexError, Lexer, LocatedError, LocatedToken, Token};
|
use crate::lexer::{LexError, Lexer, LocatedError, LocatedToken, Token};
|
||||||
use crate::run_command::{Comparison, DataValue, Invocation, RunCommand};
|
use crate::run_command::{Comparison, Invocation, RunCommand};
|
||||||
use crate::sourcemap::SourceMap;
|
use crate::sourcemap::SourceMap;
|
||||||
use crate::testcommand::TestCommand;
|
use crate::testcommand::TestCommand;
|
||||||
use crate::testfile::{Comment, Details, Feature, TestFile};
|
use crate::testfile::{Comment, Details, Feature, TestFile};
|
||||||
|
use cranelift_codegen::data_value::DataValue;
|
||||||
use cranelift_codegen::entity::EntityRef;
|
use cranelift_codegen::entity::EntityRef;
|
||||||
use cranelift_codegen::ir;
|
use cranelift_codegen::ir;
|
||||||
use cranelift_codegen::ir::entities::AnyEntity;
|
use cranelift_codegen::ir::entities::AnyEntity;
|
||||||
|
|||||||
@@ -6,11 +6,8 @@
|
|||||||
//! - `; run`: this assumes the function has a signature like `() -> b*`.
|
//! - `; run`: this assumes the function has a signature like `() -> b*`.
|
||||||
//! - `; run: %fn(42, 4.2) == false`: this syntax specifies the parameters and return values.
|
//! - `; run: %fn(42, 4.2) == false`: this syntax specifies the parameters and return values.
|
||||||
|
|
||||||
use cranelift_codegen::ir::immediates::{Ieee32, Ieee64, Imm64};
|
use cranelift_codegen::data_value::{self, DataValue, DisplayDataValues};
|
||||||
use cranelift_codegen::ir::{self, types, ConstantData, Type};
|
|
||||||
use std::convert::TryInto;
|
|
||||||
use std::fmt::{self, Display, Formatter};
|
use std::fmt::{self, Display, Formatter};
|
||||||
use thiserror::Error;
|
|
||||||
|
|
||||||
/// A run command appearing in a test file.
|
/// A run command appearing in a test file.
|
||||||
///
|
///
|
||||||
@@ -88,156 +85,11 @@ impl Invocation {
|
|||||||
impl Display for Invocation {
|
impl Display for Invocation {
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||||
write!(f, "%{}(", self.func)?;
|
write!(f, "%{}(", self.func)?;
|
||||||
write_data_value_list(f, &self.args)?;
|
data_value::write_data_value_list(f, &self.args)?;
|
||||||
write!(f, ")")
|
write!(f, ")")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Represent a data value. Where [Value] is an SSA reference, [DataValue] is the type + value
|
|
||||||
/// that would be referred to by a [Value].
|
|
||||||
///
|
|
||||||
/// [Value]: cranelift_codegen::ir::Value
|
|
||||||
#[allow(missing_docs)]
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
|
||||||
pub enum DataValue {
|
|
||||||
B(bool),
|
|
||||||
I8(i8),
|
|
||||||
I16(i16),
|
|
||||||
I32(i32),
|
|
||||||
I64(i64),
|
|
||||||
F32(f32),
|
|
||||||
F64(f64),
|
|
||||||
V128([u8; 16]),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl DataValue {
|
|
||||||
/// Try to cast an immediate integer ([Imm64]) to the given Cranelift [Type].
|
|
||||||
pub fn from_integer(imm: Imm64, ty: Type) -> Result<DataValue, DataValueCastFailure> {
|
|
||||||
match ty {
|
|
||||||
types::I8 => Ok(DataValue::I8(imm.bits() as i8)),
|
|
||||||
types::I16 => Ok(DataValue::I16(imm.bits() as i16)),
|
|
||||||
types::I32 => Ok(DataValue::I32(imm.bits() as i32)),
|
|
||||||
types::I64 => Ok(DataValue::I64(imm.bits())),
|
|
||||||
_ => Err(DataValueCastFailure::FromImm64(imm, ty)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Return the Cranelift IR [Type] for this [DataValue].
|
|
||||||
pub fn ty(&self) -> Type {
|
|
||||||
match self {
|
|
||||||
DataValue::B(_) => ir::types::B8, // A default type.
|
|
||||||
DataValue::I8(_) => ir::types::I8,
|
|
||||||
DataValue::I16(_) => ir::types::I16,
|
|
||||||
DataValue::I32(_) => ir::types::I32,
|
|
||||||
DataValue::I64(_) => ir::types::I64,
|
|
||||||
DataValue::F32(_) => ir::types::F32,
|
|
||||||
DataValue::F64(_) => ir::types::F64,
|
|
||||||
DataValue::V128(_) => ir::types::I8X16, // A default type.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Return true if the value is a vector (i.e. `DataValue::V128`).
|
|
||||||
pub fn is_vector(&self) -> bool {
|
|
||||||
match self {
|
|
||||||
DataValue::V128(_) => true,
|
|
||||||
_ => false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Record failures to cast [DataValue].
|
|
||||||
#[derive(Error, Debug, PartialEq)]
|
|
||||||
#[allow(missing_docs)]
|
|
||||||
pub enum DataValueCastFailure {
|
|
||||||
#[error("unable to cast data value of type {0} to type {1}")]
|
|
||||||
TryInto(Type, Type),
|
|
||||||
#[error("unable to cast Imm64({0}) to a data value of type {1}")]
|
|
||||||
FromImm64(Imm64, Type),
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Helper for creating conversion implementations for [DataValue].
|
|
||||||
macro_rules! build_conversion_impl {
|
|
||||||
( $rust_ty:ty, $data_value_ty:ident, $cranelift_ty:ident ) => {
|
|
||||||
impl From<$rust_ty> for DataValue {
|
|
||||||
fn from(data: $rust_ty) -> Self {
|
|
||||||
DataValue::$data_value_ty(data)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl TryInto<$rust_ty> for DataValue {
|
|
||||||
type Error = DataValueCastFailure;
|
|
||||||
fn try_into(self) -> Result<$rust_ty, Self::Error> {
|
|
||||||
if let DataValue::$data_value_ty(v) = self {
|
|
||||||
Ok(v)
|
|
||||||
} else {
|
|
||||||
Err(DataValueCastFailure::TryInto(
|
|
||||||
self.ty(),
|
|
||||||
types::$cranelift_ty,
|
|
||||||
))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
build_conversion_impl!(bool, B, B8);
|
|
||||||
build_conversion_impl!(i8, I8, I8);
|
|
||||||
build_conversion_impl!(i16, I16, I16);
|
|
||||||
build_conversion_impl!(i32, I32, I32);
|
|
||||||
build_conversion_impl!(i64, I64, I64);
|
|
||||||
build_conversion_impl!(f32, F32, F32);
|
|
||||||
build_conversion_impl!(f64, F64, F64);
|
|
||||||
build_conversion_impl!([u8; 16], V128, I8X16);
|
|
||||||
|
|
||||||
impl Display for DataValue {
|
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
|
||||||
match self {
|
|
||||||
DataValue::B(dv) => write!(f, "{}", dv),
|
|
||||||
DataValue::I8(dv) => write!(f, "{}", dv),
|
|
||||||
DataValue::I16(dv) => write!(f, "{}", dv),
|
|
||||||
DataValue::I32(dv) => write!(f, "{}", dv),
|
|
||||||
DataValue::I64(dv) => write!(f, "{}", dv),
|
|
||||||
// Use the Ieee* wrappers here to maintain a consistent syntax.
|
|
||||||
DataValue::F32(dv) => write!(f, "{}", Ieee32::from(*dv)),
|
|
||||||
DataValue::F64(dv) => write!(f, "{}", Ieee64::from(*dv)),
|
|
||||||
// Again, for syntax consistency, use ConstantData, which in this case displays as hex.
|
|
||||||
DataValue::V128(dv) => write!(f, "{}", ConstantData::from(&dv[..])),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Helper structure for printing bracket-enclosed vectors of [DataValue]s.
|
|
||||||
/// - for empty vectors, display `[]`
|
|
||||||
/// - for single item vectors, display `42`, e.g.
|
|
||||||
/// - for multiple item vectors, display `[42, 43, 44]`, e.g.
|
|
||||||
struct DisplayDataValues<'a>(&'a [DataValue]);
|
|
||||||
|
|
||||||
impl<'a> Display for DisplayDataValues<'a> {
|
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
|
||||||
if self.0.len() == 1 {
|
|
||||||
write!(f, "{}", self.0[0])
|
|
||||||
} else {
|
|
||||||
write!(f, "[")?;
|
|
||||||
write_data_value_list(f, &self.0)?;
|
|
||||||
write!(f, "]")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Helper function for displaying `Vec<DataValue>`.
|
|
||||||
fn write_data_value_list(f: &mut Formatter<'_>, list: &[DataValue]) -> fmt::Result {
|
|
||||||
match list.len() {
|
|
||||||
0 => Ok(()),
|
|
||||||
1 => write!(f, "{}", list[0]),
|
|
||||||
_ => {
|
|
||||||
write!(f, "{}", list[0])?;
|
|
||||||
for dv in list.iter().skip(1) {
|
|
||||||
write!(f, ", {}", dv)?;
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A CLIF comparison operation; e.g. `==`.
|
/// A CLIF comparison operation; e.g. `==`.
|
||||||
#[allow(missing_docs)]
|
#[allow(missing_docs)]
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
@@ -273,27 +125,4 @@ mod test {
|
|||||||
assert!(command.run(|_, _| Ok(vec![DataValue::I32(42)])).is_ok());
|
assert!(command.run(|_, _| Ok(vec![DataValue::I32(42)])).is_ok());
|
||||||
assert!(command.run(|_, _| Ok(vec![DataValue::I32(43)])).is_err());
|
assert!(command.run(|_, _| Ok(vec![DataValue::I32(43)])).is_err());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn type_conversions() {
|
|
||||||
assert_eq!(DataValue::B(true).ty(), types::B8);
|
|
||||||
assert_eq!(
|
|
||||||
TryInto::<bool>::try_into(DataValue::B(false)).unwrap(),
|
|
||||||
false
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
TryInto::<i32>::try_into(DataValue::B(false)).unwrap_err(),
|
|
||||||
DataValueCastFailure::TryInto(types::B8, types::I32)
|
|
||||||
);
|
|
||||||
|
|
||||||
assert_eq!(DataValue::V128([0; 16]).ty(), types::I8X16);
|
|
||||||
assert_eq!(
|
|
||||||
TryInto::<[u8; 16]>::try_into(DataValue::V128([0; 16])).unwrap(),
|
|
||||||
[0; 16]
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
TryInto::<i32>::try_into(DataValue::V128([0; 16])).unwrap_err(),
|
|
||||||
DataValueCastFailure::TryInto(types::I8X16, types::I32)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user