diff --git a/src/emit.rs b/src/emit.rs index 25367b78..e5861499 100644 --- a/src/emit.rs +++ b/src/emit.rs @@ -89,7 +89,7 @@ macro_rules! define_get_push_index { #[inline] pub(crate) fn $push_name(&mut self, id: $id_ty) { let idx = self.$member.len() as u32; - log::trace!(concat!(stringify!($push_name),": assigning index {} to {:?}"), idx, id); + //log::trace!(concat!(stringify!($push_name),": assigning index {} to {:?}"), idx, id); self.$member.insert(id, idx); } )* diff --git a/src/ir/mod.rs b/src/ir/mod.rs index 83b1b0c8..4e604539 100644 --- a/src/ir/mod.rs +++ b/src/ir/mod.rs @@ -44,6 +44,12 @@ impl Local { pub fn ty(&self) -> ValType { self.ty } + + /// Indicate if the Local is a floating point + #[inline(always)] + pub fn is_float(&self) -> bool { + self.ty.is_float() + } } /// The identifier for a `InstrSeq` within some `LocalFunction`. @@ -630,6 +636,12 @@ impl Value { } } } + + /// Indicate if the Value is a floating point + #[inline(always)] + pub fn is_float(&self) -> bool { + matches!(self, Self::F32(_) | Self::F64(_)) + } } impl fmt::Display for Value { @@ -884,6 +896,73 @@ pub enum BinaryOp { I64x2ExtMulHighI32x4U, } +impl BinaryOp { + /// Indicate if the BinOp is a floating point + #[inline(always)] + pub fn is_float(&self) -> bool { + use BinaryOp::*; + matches!( + self, + F32Eq + | F32Ne + | F32Lt + | F32Gt + | F32Le + | F32Ge + | F64Eq + | F64Ne + | F64Lt + | F64Gt + | F64Le + | F64Ge + | F32Add + | F32Sub + | F32Mul + | F32Div + | F32Min + | F32Max + | F32Copysign + | F64Add + | F64Sub + | F64Mul + | F64Div + | F64Min + | F64Max + | F64Copysign + | F32x4ReplaceLane { .. } + | F64x2ReplaceLane { .. } + | F32x4Eq + | F32x4Ne + | F32x4Lt + | F32x4Gt + | F32x4Le + | F32x4Ge + | F64x2Eq + | F64x2Ne + | F64x2Lt + | F64x2Gt + | F64x2Le + | F64x2Ge + | F32x4Add + | F32x4Sub + | F32x4Mul + | F32x4Div + | F32x4Min + | F32x4Max + | F32x4PMin + | F32x4PMax + | F64x2Add + | F64x2Sub + | F64x2Mul + | F64x2Div + | F64x2Min + | F64x2Max + | F64x2PMin + | F64x2PMax + ) + } +} + /// Possible unary operations in wasm #[allow(missing_docs)] #[derive(Copy, Clone, Debug)] @@ -1038,6 +1117,89 @@ pub enum UnaryOp { I32x4WidenHighI16x8U, } +impl UnaryOp { + /// Indicate if the UnaryOp is a floating point + #[inline(always)] + pub fn is_float(&self) -> bool { + use UnaryOp::*; + matches!( + self, + F32Abs + | F32Neg + | F32Ceil + | F32Floor + | F32Trunc + | F32Nearest + | F32Sqrt + | F64Abs + | F64Neg + | F64Ceil + | F64Floor + | F64Trunc + | F64Nearest + | F64Sqrt + | I32TruncSF32 + | I32TruncUF32 + | I32TruncSF64 + | I32TruncUF64 + | I64TruncSF32 + | I64TruncUF32 + | I64TruncSF64 + | I64TruncUF64 + | F32ConvertSI32 + | F32ConvertUI32 + | F32ConvertSI64 + | F32ConvertUI64 + | F32DemoteF64 + | F64ConvertSI32 + | F64ConvertUI32 + | F64ConvertSI64 + | F64ConvertUI64 + | F64PromoteF32 + | I32ReinterpretF32 + | I64ReinterpretF64 + | F32ReinterpretI32 + | F64ReinterpretI64 + | F32x4Splat + | F32x4ExtractLane { .. } + | F64x2Splat + | F64x2ExtractLane { .. } + | F32x4Abs + | F32x4Neg + | F32x4Sqrt + | F32x4Ceil + | F32x4Floor + | F32x4Trunc + | F32x4Nearest + | F64x2Abs + | F64x2Neg + | F64x2Sqrt + | F64x2Ceil + | F64x2Floor + | F64x2Trunc + | F64x2Nearest + | I32x4TruncSatF64x2SZero + | I32x4TruncSatF64x2UZero + | F64x2ConvertLowI32x4S + | F64x2ConvertLowI32x4U + | F32x4DemoteF64x2Zero + | F64x2PromoteLowF32x4 + | I32x4TruncSatF32x4S + | I32x4TruncSatF32x4U + | F32x4ConvertI32x4S + | F32x4ConvertI32x4U + | I32TruncSSatF32 + | I32TruncUSatF32 + | I32TruncSSatF64 + | I32TruncUSatF64 + | I64TruncSSatF32 + | I64TruncUSatF32 + | I64TruncSSatF64 + | I64TruncUSatF64 + ) + } +} + /// The different kinds of load instructions that are part of a `Load` IR node #[derive(Debug, Copy, Clone)] #[allow(missing_docs)] @@ -1121,6 +1283,12 @@ impl LoadKind { F32 | F64 | V128 => false, } } + + /// Indicate if the LoadKind is a floating point + #[inline(always)] + pub fn is_float(&self) -> bool { + matches!(self, Self::F32 | Self::F64) + } } impl ExtendedLoad { @@ -1177,6 +1345,12 @@ impl StoreKind { F32 | F64 | V128 => false, } } + + /// Indicate if the LoadKind is a floating point + #[inline(always)] + pub fn is_float(&self) -> bool { + matches!(self, Self::F32 | Self::F64) + } } /// Arguments to memory operations, containing a constant offset from a dynamic diff --git a/src/ir/traversals.rs b/src/ir/traversals.rs index 6362bdbd..4fae82db 100644 --- a/src/ir/traversals.rs +++ b/src/ir/traversals.rs @@ -80,12 +80,12 @@ pub fn dfs_in_order<'instr>( 'traversing_instrs: for (index, (instr, loc)) in seq.instrs.iter().enumerate().skip(index) { // Visit this instruction. - log::trace!("dfs_in_order: visit_instr({:?})", instr); + //log::trace!("dfs_in_order: visit_instr({:?})", instr); visitor.visit_instr(instr, loc); // Visit every other resource that this instruction references, // e.g. `MemoryId`s, `FunctionId`s and all that. - log::trace!("dfs_in_order: ({:?}).visit(..)", instr); + //log::trace!("dfs_in_order: ({:?}).visit(..)", instr); instr.visit(visitor); match instr { diff --git a/src/module/data.rs b/src/module/data.rs index 58acd1d6..716650d2 100644 --- a/src/module/data.rs +++ b/src/module/data.rs @@ -168,7 +168,7 @@ impl Module { /// they're actually passive or not, and that property is checked during /// validation. pub(crate) fn reserve_data(&mut self, count: u32, ids: &mut IndicesToIds) { - log::debug!("reserving space for {} data segments", count); + //log::debug!("reserving space for {} data segments", count); for _ in 0..count { ids.push_data(self.data.arena.alloc_with_id(|id| Data { id, @@ -186,7 +186,7 @@ impl Module { section: wasmparser::DataSectionReader, ids: &IndicesToIds, ) -> Result<()> { - log::debug!("parse data section"); + //log::debug!("parse data section"); let preallocated = self.data.arena.len() > 0; for (i, segment) in section.into_iter().enumerate() { let segment = segment?; @@ -244,7 +244,7 @@ impl Module { impl Emit for ModuleData { fn emit(&self, cx: &mut EmitContext) { - log::debug!("emit data section"); + //log::debug!("emit data section"); if self.arena.len() == 0 { return; } diff --git a/src/module/elements.rs b/src/module/elements.rs index 2518211c..cf7f29ae 100644 --- a/src/module/elements.rs +++ b/src/module/elements.rs @@ -107,7 +107,7 @@ impl Module { section: wasmparser::ElementSectionReader, ids: &mut IndicesToIds, ) -> Result<()> { - log::debug!("parse element section"); + //log::debug!("parse element section"); for (i, segment) in section.into_iter().enumerate() { let segment = segment?; let ty = ValType::parse(&segment.ty)?; diff --git a/src/module/exports.rs b/src/module/exports.rs index 17bbab2b..fc4d77ef 100644 --- a/src/module/exports.rs +++ b/src/module/exports.rs @@ -132,7 +132,7 @@ impl Module { section: wasmparser::ExportSectionReader, ids: &IndicesToIds, ) -> Result<()> { - log::debug!("parse export section"); + //log::debug!("parse export section"); use wasmparser::ExternalKind::*; for entry in section { @@ -161,7 +161,7 @@ impl Module { impl Emit for ModuleExports { fn emit(&self, cx: &mut EmitContext) { - log::debug!("emit export section"); + //log::debug!("emit export section"); // NB: exports are always considered used. They are the roots that the // used analysis searches out from. diff --git a/src/module/functions/local_function/mod.rs b/src/module/functions/local_function/mod.rs index c4507c9d..28f00a7c 100644 --- a/src/module/functions/local_function/mod.rs +++ b/src/module/functions/local_function/mod.rs @@ -104,6 +104,16 @@ impl LocalFunction { &self.builder.arena[id] } + /// Iterate over all the blocks in the function + pub fn blocks(&self) -> impl Iterator { + self.builder.arena.iter() + } + + /// Mutably iterate over all the blocks in the function + pub fn blocks_mut(&mut self) -> impl Iterator { + self.builder.arena.iter_mut() + } + /// Get the block associated with the given id. pub fn block_mut(&mut self, id: InstrSeqId) -> &mut InstrSeq { &mut self.builder.arena[id] @@ -288,7 +298,7 @@ fn append_instruction<'context>( // should succeed. use crate::ir::ExtendedLoad::*; - log::trace!("validate instruction: {:?}", inst); + //log::trace!("validate instruction: {:?}", inst); let const_ = |ctx: &mut ValidationContext, value| { ctx.alloc_instr(Const { value }, loc); diff --git a/src/module/functions/mod.rs b/src/module/functions/mod.rs index e782240b..5440e73e 100644 --- a/src/module/functions/mod.rs +++ b/src/module/functions/mod.rs @@ -275,7 +275,7 @@ impl ModuleFunctions { } pub(crate) fn emit_func_section(&self, cx: &mut EmitContext) { - log::debug!("emit function section"); + //log::debug!("emit function section"); let functions = used_local_functions(cx); if functions.len() == 0 { return; @@ -304,7 +304,7 @@ impl Module { section: wasmparser::FunctionSectionReader, ids: &mut IndicesToIds, ) -> Result<()> { - log::debug!("parse function section"); + //log::debug!("parse function section"); for func in section { let ty = ids.get_type(func?)?; let id = self @@ -327,7 +327,7 @@ impl Module { indices: &mut IndicesToIds, on_instr_pos: Option<&(dyn Fn(&usize) -> InstrLocId + Sync + Send + 'static)>, ) -> Result<()> { - log::debug!("parse code section"); + //log::debug!("parse code section"); let num_imports = self.funcs.arena.len() - functions.len(); // First up serially create corresponding `LocalId` instances for all @@ -455,7 +455,7 @@ fn collect_non_default_code_offsets( impl Emit for ModuleFunctions { fn emit(&self, cx: &mut EmitContext) { - log::debug!("emit code section"); + //log::debug!("emit code section"); let functions = used_local_functions(cx); if functions.len() == 0 { return; @@ -471,7 +471,7 @@ impl Emit for ModuleFunctions { // functions together. let bytes = maybe_parallel!(functions.(into_iter | into_par_iter)) .map(|(id, func, _size)| { - log::debug!("emit function {:?} {:?}", id, cx.module.funcs.get(id).name); + //log::debug!("emit function {:?} {:?}", id, cx.module.funcs.get(id).name); let mut wasm = Vec::new(); let mut encoder = Encoder::new(&mut wasm); let mut map = if generate_map { Some(Vec::new()) } else { None }; diff --git a/src/module/globals.rs b/src/module/globals.rs index fba8402a..76362602 100644 --- a/src/module/globals.rs +++ b/src/module/globals.rs @@ -40,6 +40,12 @@ impl Global { pub fn id(&self) -> GlobalId { self.id } + + /// Indicate if the Global is a floating point + #[inline(always)] + pub fn is_float(&self) -> bool { + self.ty.is_float() + } } impl Emit for Global { @@ -109,7 +115,7 @@ impl Module { section: wasmparser::GlobalSectionReader, ids: &mut IndicesToIds, ) -> Result<()> { - log::debug!("parse global section"); + //log::debug!("parse global section"); for g in section { let g = g?; let id = self.globals.add_local( @@ -125,7 +131,7 @@ impl Module { impl Emit for ModuleGlobals { fn emit(&self, cx: &mut EmitContext) { - log::debug!("emit global section"); + //log::debug!("emit global section"); fn get_local(global: &Global) -> Option<(&Global, &InitExpr)> { match &global.kind { GlobalKind::Import(_) => None, diff --git a/src/module/imports.rs b/src/module/imports.rs index 7ac5816d..f74c4ae4 100644 --- a/src/module/imports.rs +++ b/src/module/imports.rs @@ -112,7 +112,7 @@ impl Module { section: wasmparser::ImportSectionReader, ids: &mut IndicesToIds, ) -> Result<()> { - log::debug!("parse import section"); + //log::debug!("parse import section"); for entry in section { let entry = entry?; match entry.ty { @@ -234,7 +234,7 @@ impl Module { impl Emit for ModuleImports { fn emit(&self, cx: &mut EmitContext) { - log::debug!("emit import section"); + //log::debug!("emit import section"); let count = self.iter().count(); if count == 0 { return; diff --git a/src/module/memories.rs b/src/module/memories.rs index 3ce6659c..b0927237 100644 --- a/src/module/memories.rs +++ b/src/module/memories.rs @@ -132,7 +132,7 @@ impl Module { section: wasmparser::MemorySectionReader, ids: &mut IndicesToIds, ) -> Result<()> { - log::debug!("parse memory section"); + //log::debug!("parse memory section"); for m in section { let (shared, limits) = match m? { wasmparser::MemoryType::M32 { shared, limits } => (shared, limits), @@ -149,7 +149,7 @@ impl Module { impl Emit for ModuleMemories { fn emit(&self, cx: &mut EmitContext) { - log::debug!("emit memory section"); + //log::debug!("emit memory section"); // imported memories are emitted earlier let memories = self.iter().filter(|m| m.import.is_none()).count(); if memories == 0 { diff --git a/src/module/mod.rs b/src/module/mod.rs index ba76476a..09410f0e 100644 --- a/src/module/mod.rs +++ b/src/module/mod.rs @@ -18,6 +18,7 @@ use crate::emit::{Emit, EmitContext, IdsToIndices, Section}; use crate::encode::Encoder; use crate::error::Result; pub use crate::ir::InstrLocId; +use crate::ir::InstrSeq; pub use crate::module::custom::{ CustomSection, CustomSectionId, ModuleCustomSections, RawCustomSection, TypedCustomSectionId, UntypedCustomSectionId, @@ -37,7 +38,7 @@ pub use crate::module::tables::{ModuleTables, Table, TableId}; pub use crate::module::types::ModuleTypes; use crate::parse::IndicesToIds; use anyhow::{bail, Context}; -use log::warn; +//use log::warn; use std::fs; use std::mem; use std::path::Path; @@ -218,7 +219,7 @@ impl Module { .map_err(anyhow::Error::from) .and_then(|r| ret.parse_name_section(r, &indices)), _ => { - log::debug!("parsing custom section `{}`", name); + //log::debug!("parsing custom section `{}`", name); ret.customs.add(RawCustomSection { name: name.to_string(), data: data.to_vec(), @@ -227,7 +228,7 @@ impl Module { } }; if let Err(e) = result { - log::warn!("failed to parse `{}` custom section {}", name, e); + //log::warn!("failed to parse `{}` custom section {}", name, e); } } Payload::UnknownSection { id, range, .. } => { @@ -284,7 +285,7 @@ impl Module { on_parse(&mut ret, &indices)?; } - log::debug!("parse complete"); + //log::debug!("parse complete"); Ok(ret) } @@ -300,7 +301,7 @@ impl Module { /// Emit this module into an in-memory wasm buffer. pub fn emit_wasm(&mut self) -> Vec { - log::debug!("start emit"); + //log::debug!("start emit"); let indices = &mut IdsToIndices::default(); let mut wasm = Vec::new(); @@ -343,11 +344,11 @@ impl Module { for (_id, section) in customs.iter_mut() { if !self.config.generate_dwarf && section.name().starts_with(".debug") { - log::debug!("skipping DWARF custom section {}", section.name()); + //log::debug!("skipping DWARF custom section {}", section.name()); continue; } - log::debug!("emitting custom section {}", section.name()); + //log::debug!("emitting custom section {}", section.name()); if self.config.preserve_code_transform { section.apply_code_transform(&cx.code_transform); @@ -358,7 +359,7 @@ impl Module { .raw(§ion.data(&indices)); } - log::debug!("emission finished"); + //log::debug!("emission finished"); wasm } @@ -372,7 +373,7 @@ impl Module { names: wasmparser::NameSectionReader, indices: &IndicesToIds, ) -> Result<()> { - log::debug!("parse name section"); + //log::debug!("parse name section"); for name in names { match name? { wasmparser::Name::Module(m) => { @@ -387,7 +388,7 @@ impl Module { // If some tool fails to GC function names properly, // it doesn't really hurt anything to ignore the // broken references and keep going. - Err(e) => warn!("in name section: {}", e), + Err(e) => {} //warn!("in name section: {}", e), } } } @@ -415,20 +416,87 @@ impl Module { // It looks like emscripten leaves broken // function references in the locals subsection // sometimes. - Err(e) => warn!("in name section: {}", e), + Err(e) => {}//warn!("in name section: {}", e), } } } } - wasmparser::Name::Unknown { ty, .. } => warn!("unknown name subsection {}", ty), + wasmparser::Name::Unknown { ty, .. } => {},//warn!("unknown name subsection {}", ty), } } Ok(()) } + + /// Indicate if the Module uses any floating point operation + pub fn has_floats(&self) -> bool { + for func in self.funcs.iter() { + use crate::FunctionKind::*; + + match &func.kind { + Local(func) => { + for local in &func.args { + if self.locals.get(*local).is_float() { + return true; + } + } + for (_block_id, block) in func.blocks() { + if self.block_has_floats(block) { + return true; + } + } + } + Import(crate::ImportedFunction { ty, .. }) | Uninitialized(ty) => { + let ty = self.types.get(*ty); + for val_type in ty.params().iter().chain(ty.results()) { + if val_type.is_float() { + return true; + }; + } + } + } + } + + false + } + + /// Check if the block uses any floating point operations. + /// + /// The block must be an InstrSeq that is owned by one of the module's + /// local functions. + #[inline(always)] + pub fn block_has_floats(&self, block: &InstrSeq) -> bool { + use crate::ir::*; + for (instr, _instr_loc_id) in &block.instrs { + let is_float = match instr { + Instr::LocalGet(LocalGet { local }) + | Instr::LocalSet(LocalSet { local }) + | Instr::LocalTee(LocalTee { local }) => self.locals.get(*local).is_float(), + Instr::GlobalGet(GlobalGet { global }) | Instr::GlobalSet(GlobalSet { global }) => { + self.globals.get(*global).is_float() + } + Instr::Const(Const { value }) => value.is_float(), + Instr::Binop(Binop { op }) => op.is_float(), + Instr::Unop(Unop { op }) => op.is_float(), + Instr::Select(Select { ty: Some(ty) }) | Instr::RefNull(RefNull { ty }) => { + ty.is_float() + } + Instr::Load(Load { kind, .. }) => kind.is_float(), + Instr::Store(Store { kind, .. }) => kind.is_float(), + + _ => false, + }; + + if is_float { + return true; + } + } + + false + } } fn emit_name_section(cx: &mut EmitContext) { - log::debug!("emit name section"); + //log::debug!("emit name section"); let mut funcs = cx .module .funcs diff --git a/src/module/producers.rs b/src/module/producers.rs index 53061424..dac00a70 100644 --- a/src/module/producers.rs +++ b/src/module/producers.rs @@ -78,7 +78,7 @@ impl Module { &mut self, data: wasmparser::ProducersSectionReader, ) -> Result<()> { - log::debug!("parse producers section"); + //log::debug!("parse producers section"); for field in data { let field = field?; @@ -100,7 +100,7 @@ impl Module { impl Emit for ModuleProducers { fn emit(&self, cx: &mut EmitContext) { - log::debug!("emit producers section"); + //log::debug!("emit producers section"); if self.fields.len() > 0 { cx.custom_section("producers").list(&self.fields); } diff --git a/src/module/tables.rs b/src/module/tables.rs index 9195f466..4138037c 100644 --- a/src/module/tables.rs +++ b/src/module/tables.rs @@ -147,7 +147,7 @@ impl Module { section: wasmparser::TableSectionReader, ids: &mut IndicesToIds, ) -> Result<()> { - log::debug!("parse table section"); + //log::debug!("parse table section"); for t in section { let t = t?; let id = self.tables.add_local( @@ -163,7 +163,7 @@ impl Module { impl Emit for ModuleTables { fn emit(&self, cx: &mut EmitContext) { - log::debug!("emit table section"); + //log::debug!("emit table section"); // Skip imported tables because those are emitted in the import section. let tables = self.iter().filter(|t| t.import.is_none()).count(); if tables == 0 { diff --git a/src/module/types.rs b/src/module/types.rs index a44c4670..573fa52e 100644 --- a/src/module/types.rs +++ b/src/module/types.rs @@ -117,7 +117,7 @@ impl Module { section: wasmparser::TypeSectionReader, ids: &mut IndicesToIds, ) -> Result<()> { - log::debug!("parsing type section"); + //log::debug!("parsing type section"); for ty in section { let fun_ty = match ty? { wasmparser::TypeDef::Func(ty) => ty, @@ -146,7 +146,7 @@ impl Module { impl Emit for ModuleTypes { fn emit(&self, cx: &mut EmitContext) { - log::debug!("emitting type section"); + //log::debug!("emitting type section"); let mut tys = self .arena diff --git a/src/passes/used.rs b/src/passes/used.rs index 163e5329..8a3000a0 100644 --- a/src/passes/used.rs +++ b/src/passes/used.rs @@ -26,7 +26,7 @@ impl Roots { /// Adds a new function to the set of roots pub fn push_func(&mut self, func: FunctionId) -> &mut Roots { if self.used.funcs.insert(func) { - log::trace!("function is used: {:?}", func); + //log::trace!("function is used: {:?}", func); self.funcs.push(func); } self @@ -35,7 +35,7 @@ impl Roots { /// Adds a new table to the set of roots pub fn push_table(&mut self, table: TableId) -> &mut Roots { if self.used.tables.insert(table) { - log::trace!("table is used: {:?}", table); + //log::trace!("table is used: {:?}", table); self.tables.push(table); } self @@ -44,7 +44,7 @@ impl Roots { /// Adds a new memory to the set of roots pub fn push_memory(&mut self, memory: MemoryId) -> &mut Roots { if self.used.memories.insert(memory) { - log::trace!("memory is used: {:?}", memory); + //log::trace!("memory is used: {:?}", memory); self.memories.push(memory); } self @@ -53,7 +53,7 @@ impl Roots { /// Adds a new global to the set of roots pub fn push_global(&mut self, global: GlobalId) -> &mut Roots { if self.used.globals.insert(global) { - log::trace!("global is used: {:?}", global); + //log::trace!("global is used: {:?}", global); self.globals.push(global); } self @@ -61,7 +61,7 @@ impl Roots { fn push_data(&mut self, data: DataId) -> &mut Roots { if self.used.data.insert(data) { - log::trace!("data is used: {:?}", data); + //log::trace!("data is used: {:?}", data); self.datas.push(data); } self @@ -69,7 +69,7 @@ impl Roots { fn push_element(&mut self, element: ElementId) -> &mut Roots { if self.used.elements.insert(element) { - log::trace!("element is used: {:?}", element); + //log::trace!("element is used: {:?}", element); self.elements.push(element); } self @@ -102,7 +102,7 @@ pub struct Used { impl Used { /// Construct a new `Used` set for the given module. pub fn new(module: &Module) -> Used { - log::debug!("starting to calculate used set"); + //log::debug!("starting to calculate used set"); let mut stack = Roots::default(); // All exports are roots diff --git a/src/ty.rs b/src/ty.rs index 09e869f4..b70082e6 100644 --- a/src/ty.rs +++ b/src/ty.rs @@ -185,6 +185,12 @@ impl ValType { ValType::Externref => encoder.byte(0x6f), } } + + /// Indicate if the ValType is a floating point + #[inline(always)] + pub fn is_float(&self) -> bool { + matches!(self, Self::F32 | Self::F64) + } } impl fmt::Display for ValType {