From 22bf49bf8895c5c6d9c10dc0f7fecf15984c67a4 Mon Sep 17 00:00:00 2001 From: jubianchi Date: Wed, 3 Mar 2021 13:30:11 +0100 Subject: [PATCH] feat: Use llvm.experimental.constrained intrinsics This patch also makes NaN canonicalization a configurable behavior in LLVM Compiler. LLVM compiler now defaults to no canonicalization. This can be enable using the dedicated functions, either through the Rust API or C API. --- Cargo.lock | 8 +- lib/c-api/build.rs | 1 + lib/c-api/src/wasm_c_api/engine.rs | 5 + lib/c-api/src/wasm_c_api/unstable/engine.rs | 39 + lib/c-api/wasmer_wasm.h | 2 + lib/compiler-cranelift/src/config.rs | 17 +- lib/compiler-llvm/Cargo.toml | 3 +- lib/compiler-llvm/src/config.rs | 18 +- lib/compiler-llvm/src/translator/code.rs | 3617 +++++++++-------- .../src/translator/intrinsics.rs | 382 +- lib/compiler-llvm/src/translator/state.rs | 21 - lib/compiler-singlepass/src/config.rs | 18 +- lib/compiler/src/compiler.rs | 19 + tests/compilers/wast.rs | 9 +- 14 files changed, 2383 insertions(+), 1776 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4e0734b1d33..f3f9614c607 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -949,9 +949,8 @@ dependencies = [ [[package]] name = "inkwell" -version = "0.1.0-beta.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5fe0be1e47c0c0f3da4397693e08f5d78329ae095c25d529e12ade78420fb41" +version = "0.1.0" +source = "git+https://github.com/wasmerio/inkwell?branch=add-metadata-support#556ceb44ab788a6978bab73fc758bb705ecb5ada" dependencies = [ "either", "inkwell_internals", @@ -965,8 +964,7 @@ dependencies = [ [[package]] name = "inkwell_internals" version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2e1f71330ccec54ee62533ae88574c4169b67fb4b95cbb1196a1322582abd11" +source = "git+https://github.com/wasmerio/inkwell?branch=add-metadata-support#556ceb44ab788a6978bab73fc758bb705ecb5ada" dependencies = [ "proc-macro2", "quote", diff --git a/lib/c-api/build.rs b/lib/c-api/build.rs index aadbd66d8e6..6ee3b5d3049 100644 --- a/lib/c-api/build.rs +++ b/lib/c-api/build.rs @@ -476,6 +476,7 @@ fn exclude_items_from_wasm_c_api(builder: Builder) -> Builder { .exclude_item("wasi_version_t") .exclude_item("wasm_config_push_middleware") .exclude_item("wasm_config_set_compiler") + .exclude_item("wasm_config_canonicalize_nans") .exclude_item("wasm_config_set_engine") .exclude_item("wasm_config_set_features") .exclude_item("wasm_config_set_target") diff --git a/lib/c-api/src/wasm_c_api/engine.rs b/lib/c-api/src/wasm_c_api/engine.rs index e9014320292..255f6ccac7b 100644 --- a/lib/c-api/src/wasm_c_api/engine.rs +++ b/lib/c-api/src/wasm_c_api/engine.rs @@ -105,6 +105,7 @@ pub struct wasm_config_t { compiler: wasmer_compiler_t, #[cfg(feature = "middlewares")] pub(super) middlewares: Vec, + pub(super) nan_canonicalization: bool, pub(super) features: Option>, pub(super) target: Option>, } @@ -482,6 +483,10 @@ pub extern "C" fn wasm_engine_new_with_config( compiler_config.push_middleware(middleware.inner); } + if config.nan_canonicalization { + compiler_config.canonicalize_nans(true); + } + let inner: Arc = match config.engine { wasmer_engine_t::JIT => { cfg_if! { diff --git a/lib/c-api/src/wasm_c_api/unstable/engine.rs b/lib/c-api/src/wasm_c_api/unstable/engine.rs index f20d00742b8..d1e51de6f9c 100644 --- a/lib/c-api/src/wasm_c_api/unstable/engine.rs +++ b/lib/c-api/src/wasm_c_api/unstable/engine.rs @@ -95,6 +95,45 @@ pub extern "C" fn wasm_config_set_features( config.features = Some(features); } +/// Updates the configuration to enable NaN canonicalization. +/// +/// This is a Wasmer-specific function. +/// +/// # Example +/// +/// ```rust +/// # use inline_c::assert_c; +/// # fn main() { +/// # (assert_c! { +/// # #include "tests/wasmer_wasm.h" +/// # +/// int main() { +/// // Create the configuration. +/// wasm_config_t* config = wasm_config_new(); +/// +/// // Enable NaN canonicalization. +/// wasm_config_canonicalize_nans(config, true); +/// +/// // Create the engine. +/// wasm_engine_t* engine = wasm_engine_new_with_config(config); +/// +/// // Check we have an engine! +/// assert(engine); +/// +/// // Free everything. +/// wasm_engine_delete(engine); +/// +/// return 0; +/// } +/// # }) +/// # .success(); +/// # } +/// ``` +#[no_mangle] +pub extern "C" fn wasm_config_canonicalize_nans(config: &mut wasm_config_t, enable: bool) { + config.nan_canonicalization = enable; +} + /// Check whether the given compiler is available, i.e. part of this /// compiled library. #[no_mangle] diff --git a/lib/c-api/wasmer_wasm.h b/lib/c-api/wasmer_wasm.h index 0d013ebf8b3..eb5393ea1f6 100644 --- a/lib/c-api/wasmer_wasm.h +++ b/lib/c-api/wasmer_wasm.h @@ -772,6 +772,8 @@ bool wasi_get_unordered_imports(const wasm_store_t *store, enum wasi_version_t wasi_get_wasi_version(const wasm_module_t *module); #endif +void wasm_config_canonicalize_nans(wasm_config_t *config, bool enable); + void wasm_config_push_middleware(wasm_config_t *config, struct wasmer_middleware_t *middleware); #if defined(WASMER_COMPILER_ENABLED) diff --git a/lib/compiler-cranelift/src/config.rs b/lib/compiler-cranelift/src/config.rs index 6834e1d520d..f5c84b2f8b1 100644 --- a/lib/compiler-cranelift/src/config.rs +++ b/lib/compiler-cranelift/src/config.rs @@ -53,15 +53,6 @@ impl Cranelift { } } - /// Enable NaN canonicalization. - /// - /// NaN canonicalization is useful when trying to run WebAssembly - /// deterministically across different architectures. - pub fn canonicalize_nans(&mut self, enable: bool) -> &mut Self { - self.enable_nan_canonicalization = enable; - self - } - /// Enable SIMD support. pub fn enable_simd(&mut self, enable: bool) -> &mut Self { self.enable_simd = enable; @@ -197,6 +188,14 @@ impl CompilerConfig for Cranelift { self.enable_verifier = true; } + fn enable_nan_canonicalization(&mut self) { + self.enable_nan_canonicalization = true; + } + + fn canonicalize_nans(&mut self, enable: bool) { + self.enable_nan_canonicalization = enable; + } + /// Transform it into the compiler fn compiler(self: Box) -> Box { Box::new(CraneliftCompiler::new(*self)) diff --git a/lib/compiler-llvm/Cargo.toml b/lib/compiler-llvm/Cargo.toml index cd5465f7a03..d8533212891 100644 --- a/lib/compiler-llvm/Cargo.toml +++ b/lib/compiler-llvm/Cargo.toml @@ -25,7 +25,8 @@ rayon = "1.5" loupe = "0.1" [dependencies.inkwell] -version = "=0.1.0-beta.2" +git = "https://github.com/wasmerio/inkwell" +branch = "add-metadata-support" default-features = false features = ["llvm11-0", "target-x86", "target-aarch64"] diff --git a/lib/compiler-llvm/src/config.rs b/lib/compiler-llvm/src/config.rs index 245a27e92f6..c8c6cdd6a55 100644 --- a/lib/compiler-llvm/src/config.rs +++ b/lib/compiler-llvm/src/config.rs @@ -65,15 +65,6 @@ impl LLVM { } } - /// Enable NaN canonicalization. - /// - /// NaN canonicalization is useful when trying to run WebAssembly - /// deterministically across different architectures. - pub fn canonicalize_nans(&mut self, enable: bool) -> &mut Self { - self.enable_nan_canonicalization = enable; - self - } - /// The optimization levels when optimizing the IR. pub fn opt_level(&mut self, opt_level: LLVMOptLevel) -> &mut Self { self.opt_level = opt_level; @@ -209,6 +200,15 @@ impl CompilerConfig for LLVM { self.enable_verifier = true; } + /// Enable NaN canonicalization. + fn enable_nan_canonicalization(&mut self) { + self.enable_nan_canonicalization = true; + } + + fn canonicalize_nans(&mut self, enable: bool) { + self.enable_nan_canonicalization = enable; + } + /// Transform it into the compiler. fn compiler(self: Box) -> Box { Box::new(LLVMCompiler::new(*self)) diff --git a/lib/compiler-llvm/src/translator/code.rs b/lib/compiler-llvm/src/translator/code.rs index 742ec81a8f4..06daf90bfac 100644 --- a/lib/compiler-llvm/src/translator/code.rs +++ b/lib/compiler-llvm/src/translator/code.rs @@ -201,6 +201,7 @@ impl FuncTranslator { wasm_module, symbol_registry, abi: &*self.abi, + config, }; fcg.ctx.add_func( func_index, @@ -752,146 +753,47 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { fn v128_into_int_vec( &self, value: BasicValueEnum<'ctx>, - info: ExtraInfo, int_vec_ty: VectorType<'ctx>, - ) -> (VectorValue<'ctx>, ExtraInfo) { - let (value, info) = if info.has_pending_f32_nan() { - let value = self - .builder - .build_bitcast(value, self.intrinsics.f32x4_ty, ""); - (self.canonicalize_nans(value), info.strip_pending()) - } else if info.has_pending_f64_nan() { - let value = self - .builder - .build_bitcast(value, self.intrinsics.f64x2_ty, ""); - (self.canonicalize_nans(value), info.strip_pending()) - } else { - (value, info) - }; - ( - self.builder - .build_bitcast(value, int_vec_ty, "") - .into_vector_value(), - info, - ) - } - - fn v128_into_i8x16( - &self, - value: BasicValueEnum<'ctx>, - info: ExtraInfo, - ) -> (VectorValue<'ctx>, ExtraInfo) { - self.v128_into_int_vec(value, info, self.intrinsics.i8x16_ty) + ) -> VectorValue<'ctx> { + self.builder + .build_bitcast(value, int_vec_ty, "") + .into_vector_value() } - fn v128_into_i16x8( - &self, - value: BasicValueEnum<'ctx>, - info: ExtraInfo, - ) -> (VectorValue<'ctx>, ExtraInfo) { - self.v128_into_int_vec(value, info, self.intrinsics.i16x8_ty) + fn v128_into_i8x16(&self, value: BasicValueEnum<'ctx>) -> VectorValue<'ctx> { + self.v128_into_int_vec(value, self.intrinsics.i8x16_ty) } - fn v128_into_i32x4( - &self, - value: BasicValueEnum<'ctx>, - info: ExtraInfo, - ) -> (VectorValue<'ctx>, ExtraInfo) { - self.v128_into_int_vec(value, info, self.intrinsics.i32x4_ty) + fn v128_into_i16x8(&self, value: BasicValueEnum<'ctx>) -> VectorValue<'ctx> { + self.v128_into_int_vec(value, self.intrinsics.i16x8_ty) } - fn v128_into_i64x2( - &self, - value: BasicValueEnum<'ctx>, - info: ExtraInfo, - ) -> (VectorValue<'ctx>, ExtraInfo) { - self.v128_into_int_vec(value, info, self.intrinsics.i64x2_ty) + fn v128_into_i32x4(&self, value: BasicValueEnum<'ctx>) -> VectorValue<'ctx> { + self.v128_into_int_vec(value, self.intrinsics.i32x4_ty) } - // If the value is pending a 64-bit canonicalization, do it now. - // Return a f32x4 vector. - fn v128_into_f32x4( - &self, - value: BasicValueEnum<'ctx>, - info: ExtraInfo, - ) -> (VectorValue<'ctx>, ExtraInfo) { - let (value, info) = if info.has_pending_f64_nan() { - let value = self - .builder - .build_bitcast(value, self.intrinsics.f64x2_ty, ""); - (self.canonicalize_nans(value), info.strip_pending()) - } else { - (value, info) - }; - ( - self.builder - .build_bitcast(value, self.intrinsics.f32x4_ty, "") - .into_vector_value(), - info, - ) + fn v128_into_i64x2(&self, value: BasicValueEnum<'ctx>) -> VectorValue<'ctx> { + self.v128_into_int_vec(value, self.intrinsics.i64x2_ty) } - // If the value is pending a 32-bit canonicalization, do it now. - // Return a f64x2 vector. - fn v128_into_f64x2( - &self, - value: BasicValueEnum<'ctx>, - info: ExtraInfo, - ) -> (VectorValue<'ctx>, ExtraInfo) { - let (value, info) = if info.has_pending_f32_nan() { - let value = self - .builder - .build_bitcast(value, self.intrinsics.f32x4_ty, ""); - (self.canonicalize_nans(value), info.strip_pending()) - } else { - (value, info) - }; - ( - self.builder - .build_bitcast(value, self.intrinsics.f64x2_ty, "") - .into_vector_value(), - info, - ) + fn v128_into_f32x4(&self, value: BasicValueEnum<'ctx>) -> VectorValue<'ctx> { + self.builder + .build_bitcast(value, self.intrinsics.f32x4_ty, "") + .into_vector_value() } - fn apply_pending_canonicalization( - &self, - value: BasicValueEnum<'ctx>, - info: ExtraInfo, - ) -> BasicValueEnum<'ctx> { - if info.has_pending_f32_nan() { - if value.get_type().is_vector_type() - || value.get_type() == self.intrinsics.i128_ty.as_basic_type_enum() - { - let ty = value.get_type(); - let value = self - .builder - .build_bitcast(value, self.intrinsics.f32x4_ty, ""); - let value = self.canonicalize_nans(value); - self.builder.build_bitcast(value, ty, "") - } else { - self.canonicalize_nans(value) - } - } else if info.has_pending_f64_nan() { - if value.get_type().is_vector_type() - || value.get_type() == self.intrinsics.i128_ty.as_basic_type_enum() - { - let ty = value.get_type(); - let value = self - .builder - .build_bitcast(value, self.intrinsics.f64x2_ty, ""); - let value = self.canonicalize_nans(value); - self.builder.build_bitcast(value, ty, "") - } else { - self.canonicalize_nans(value) - } - } else { - value - } + fn v128_into_f64x2(&self, value: BasicValueEnum<'ctx>) -> VectorValue<'ctx> { + self.builder + .build_bitcast(value, self.intrinsics.f64x2_ty, "") + .into_vector_value() } // Replaces any NaN with the canonical QNaN, otherwise leaves the value alone. fn canonicalize_nans(&self, value: BasicValueEnum<'ctx>) -> BasicValueEnum<'ctx> { + if !self.config.enable_nan_canonicalization { + return value; + } + let f_ty = value.get_type(); if f_ty.is_vector_type() { let value = value.into_vector_value(); @@ -1147,9 +1049,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { let func_type = self.function.get_type(); let results = self.state.popn_save_extra(wasm_fn_type.results().len())?; - let results = results - .into_iter() - .map(|(v, i)| self.apply_pending_canonicalization(v, i)); + let results = results.into_iter().map(|(v, _)| v); if wasm_fn_type.results().is_empty() { self.builder.build_return(None); } else if self.abi.is_sret(wasm_fn_type)? { @@ -1300,6 +1200,7 @@ pub struct LLVMFunctionCodeGenerator<'ctx, 'a> { wasm_module: &'a ModuleInfo, symbol_registry: &'a dyn SymbolRegistry, abi: &'a dyn Abi, + config: &'a LLVM, } impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { @@ -1400,8 +1301,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { }) .collect::>()?; for phi in loop_phis.iter().rev() { - let (value, info) = self.state.pop1_extra()?; - let value = self.apply_pending_canonicalization(value, info); + let value = self.state.pop1()?; phi.add_incoming(&[(&value, pre_loop_block)]); } for phi in &loop_phis { @@ -1458,9 +1358,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { let len = phis.len(); let values = self.state.peekn_extra(len)?; - let values = values - .iter() - .map(|(v, info)| self.apply_pending_canonicalization(*v, *info)); + let values = values.iter().map(|(v, _)| *v); // For each result of the block we're branching to, // pop a value off the value stack and load it into @@ -1490,9 +1388,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { }; let param_stack = self.state.peekn_extra(phis.len())?; - let param_stack = param_stack - .iter() - .map(|(v, info)| self.apply_pending_canonicalization(*v, *info)); + let param_stack = param_stack.iter().map(|(v, _)| *v); for (phi, value) in phis.iter().zip(param_stack) { phi.add_incoming(&[(&value, current_block)]); @@ -1629,8 +1525,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { .map(|&ty| self.builder.build_phi(ty, "")) .collect(); for (else_phi, then_phi) in else_phis.iter().rev().zip(then_phis.iter().rev()) { - let (value, info) = self.state.pop1_extra()?; - let value = self.apply_pending_canonicalization(value, info); + let value = self.state.pop1()?; else_phi.add_incoming(&[(&value, current_block)]); then_phi.add_incoming(&[(&value, current_block)]); } @@ -1655,8 +1550,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { })?; for phi in frame.phis().to_vec().iter().rev() { - let (value, info) = self.state.pop1_extra()?; - let value = self.apply_pending_canonicalization(value, info); + let value = self.state.pop1()?; phi.add_incoming(&[(&value, current_block)]) } @@ -1697,8 +1591,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { if self.state.reachable { for phi in frame.phis().iter().rev() { - let (value, info) = self.state.pop1_extra()?; - let value = self.apply_pending_canonicalization(value, info); + let value = self.state.pop1()?; phi.add_incoming(&[(&value, current_block)]); } @@ -1747,8 +1640,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { let frame = self.state.outermost_frame()?; for phi in frame.phis().to_vec().iter().rev() { - let (arg, info) = self.state.pop1_extra()?; - let arg = self.apply_pending_canonicalization(arg, info); + let arg = self.state.pop1()?; phi.add_incoming(&[(&arg, current_block)]); } let frame = self.state.outermost_frame()?; @@ -1816,45 +1708,29 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { // Generate const values. Operator::I32Const { value } => { let i = self.intrinsics.i32_ty.const_int(value as u64, false); - let info = if is_f32_arithmetic(value as u32) { - ExtraInfo::arithmetic_f32() - } else { - Default::default() - }; - self.state.push1_extra(i, info); + + self.state.push1(i); } Operator::I64Const { value } => { let i = self.intrinsics.i64_ty.const_int(value as u64, false); - let info = if is_f64_arithmetic(value as u64) { - ExtraInfo::arithmetic_f64() - } else { - Default::default() - }; - self.state.push1_extra(i, info); + + self.state.push1(i); } Operator::F32Const { value } => { let bits = self.intrinsics.i32_ty.const_int(value.bits() as u64, false); - let info = if is_f32_arithmetic(value.bits()) { - ExtraInfo::arithmetic_f32() - } else { - Default::default() - }; + let f = self .builder .build_bitcast(bits, self.intrinsics.f32_ty, "f"); - self.state.push1_extra(f, info); + self.state.push1(f); } Operator::F64Const { value } => { let bits = self.intrinsics.i64_ty.const_int(value.bits(), false); - let info = if is_f64_arithmetic(value.bits()) { - ExtraInfo::arithmetic_f64() - } else { - Default::default() - }; + let f = self .builder .build_bitcast(bits, self.intrinsics.f64_ty, "f"); - self.state.push1_extra(f, info); + self.state.push1(f); } Operator::V128Const { value } => { let mut hi: [u8; 8] = Default::default(); @@ -1874,18 +1750,8 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { quad2.copy_from_slice(&value.bytes()[4..8]); quad3.copy_from_slice(&value.bytes()[8..12]); quad4.copy_from_slice(&value.bytes()[12..16]); - let mut info: ExtraInfo = Default::default(); - if is_f32_arithmetic(u32::from_le_bytes(quad1)) - && is_f32_arithmetic(u32::from_le_bytes(quad2)) - && is_f32_arithmetic(u32::from_le_bytes(quad3)) - && is_f32_arithmetic(u32::from_le_bytes(quad4)) - { - info |= ExtraInfo::arithmetic_f32(); - } - if is_f64_arithmetic(packed[0]) && is_f64_arithmetic(packed[1]) { - info |= ExtraInfo::arithmetic_f64(); - } - self.state.push1_extra(i, info); + + self.state.push1(i); } Operator::I8x16Splat => { @@ -1951,8 +1817,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { } Operator::LocalSet { local_index } => { let pointer_value = self.locals[local_index as usize]; - let (v, i) = self.state.pop1_extra()?; - let v = self.apply_pending_canonicalization(v, i); + let v = self.state.pop1()?; let store = self.builder.build_store(pointer_value, v); tbaa_label( &self.module, @@ -1963,8 +1828,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { } Operator::LocalTee { local_index } => { let pointer_value = self.locals[local_index as usize]; - let (v, i) = self.state.peek1_extra()?; - let v = self.apply_pending_canonicalization(v, i); + let (v, _) = self.state.peek1_extra()?; let store = self.builder.build_store(pointer_value, v); tbaa_label( &self.module, @@ -2009,8 +1873,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { } GlobalCache::Mut { ptr_to_value } => { let ptr_to_value = *ptr_to_value; - let (value, info) = self.state.pop1_extra()?; - let value = self.apply_pending_canonicalization(value, info); + let value = self.state.pop1()?; let store = self.builder.build_store(ptr_to_value, value); tbaa_label( self.module, @@ -2025,26 +1888,8 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { // `TypedSelect` must be used for extern refs so ref counting should // be done with TypedSelect. But otherwise they're the same. Operator::TypedSelect { .. } | Operator::Select => { - let ((v1, i1), (v2, i2), (cond, _)) = self.state.pop3_extra()?; - // We don't bother canonicalizing 'cond' here because we only - // compare it to zero, and that's invariant under - // canonicalization. - - // If the pending bits of v1 and v2 are the same, we can pass - // them along to the result. Otherwise, apply pending - // canonicalizations now. - let (v1, i1, v2, i2) = if i1.has_pending_f32_nan() != i2.has_pending_f32_nan() - || i1.has_pending_f64_nan() != i2.has_pending_f64_nan() - { - ( - self.apply_pending_canonicalization(v1, i1), - i1.strip_pending(), - self.apply_pending_canonicalization(v2, i2), - i2.strip_pending(), - ) - } else { - (v1, i1, v2, i2) - }; + let ((v1, _), (v2, _), (cond, _)) = self.state.pop3_extra()?; + let cond_value = self.builder.build_int_compare( IntPredicate::NE, cond.into_int_value(), @@ -2052,19 +1897,8 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { "", ); let res = self.builder.build_select(cond_value, v1, v2, ""); - let info = { - let mut info = i1.strip_pending() & i2.strip_pending(); - if i1.has_pending_f32_nan() { - debug_assert!(i2.has_pending_f32_nan()); - info |= ExtraInfo::pending_f32_nan(); - } - if i1.has_pending_f64_nan() { - debug_assert!(i2.has_pending_f64_nan()); - info |= ExtraInfo::pending_f64_nan(); - } - info - }; - self.state.push1_extra(res, info); + + self.state.push1(res); } Operator::Call { function_index } => { let func_index = FunctionIndex::from_u32(function_index); @@ -2108,18 +1942,9 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { params .iter() .zip(func_type.params().iter()) - .map(|((v, info), wasm_ty)| match wasm_ty { - Type::F32 => self.builder.build_bitcast( - self.apply_pending_canonicalization(*v, *info), - self.intrinsics.f32_ty, - "", - ), - Type::F64 => self.builder.build_bitcast( - self.apply_pending_canonicalization(*v, *info), - self.intrinsics.f64_ty, - "", - ), - Type::V128 => self.apply_pending_canonicalization(*v, *info), + .map(|((v, _), wasm_ty)| match wasm_ty { + Type::F32 => self.builder.build_bitcast(*v, self.intrinsics.f32_ty, ""), + Type::F64 => self.builder.build_bitcast(*v, self.intrinsics.f64_ty, ""), _ => *v, }); @@ -2155,6 +1980,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { for (attr, attr_loc) in attrs { call_site.add_attribute(attr_loc, attr); } + /* if self.track_state { if let Some(offset) = opcode_offset { @@ -2392,18 +2218,9 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { params .iter() .zip(func_type.params().iter()) - .map(|((v, info), wasm_ty)| match wasm_ty { - Type::F32 => self.builder.build_bitcast( - self.apply_pending_canonicalization(*v, *info), - self.intrinsics.f32_ty, - "", - ), - Type::F64 => self.builder.build_bitcast( - self.apply_pending_canonicalization(*v, *info), - self.intrinsics.f64_ty, - "", - ), - Type::V128 => self.apply_pending_canonicalization(*v, *info), + .map(|((v, _), wasm_ty)| match wasm_ty { + Type::F32 => self.builder.build_bitcast(*v, self.intrinsics.f32_ty, ""), + Type::F64 => self.builder.build_bitcast(*v, self.intrinsics.f64_ty, ""), _ => *v, }); @@ -2473,49 +2290,48 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { * https://github.com/sunfishcode/wasm-reference-manual/blob/master/WebAssembly.md#integer-arithmetic-instructions ***************************/ Operator::I32Add | Operator::I64Add => { - let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; - let v1 = self.apply_pending_canonicalization(v1, i1); - let v2 = self.apply_pending_canonicalization(v2, i2); - let (v1, v2) = (v1.into_int_value(), v2.into_int_value()); - let res = self.builder.build_int_add(v1, v2, ""); + let (v1, v2) = self.state.pop2()?; + let res = self + .builder + .build_int_add(v1.into_int_value(), v2.into_int_value(), ""); self.state.push1(res); } Operator::I8x16Add => { - let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; - let (v1, _) = self.v128_into_i8x16(v1, i1); - let (v2, _) = self.v128_into_i8x16(v2, i2); + let (v1, v2) = self.state.pop2()?; + let v1 = self.v128_into_i8x16(v1); + let v2 = self.v128_into_i8x16(v2); let res = self.builder.build_int_add(v1, v2, ""); let res = self.builder.build_bitcast(res, self.intrinsics.i128_ty, ""); self.state.push1(res); } Operator::I16x8Add => { - let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; - let (v1, _) = self.v128_into_i16x8(v1, i1); - let (v2, _) = self.v128_into_i16x8(v2, i2); + let (v1, v2) = self.state.pop2()?; + let v1 = self.v128_into_i16x8(v1); + let v2 = self.v128_into_i16x8(v2); let res = self.builder.build_int_add(v1, v2, ""); let res = self.builder.build_bitcast(res, self.intrinsics.i128_ty, ""); self.state.push1(res); } Operator::I32x4Add => { - let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; - let (v1, _) = self.v128_into_i32x4(v1, i1); - let (v2, _) = self.v128_into_i32x4(v2, i2); + let (v1, v2) = self.state.pop2()?; + let v1 = self.v128_into_i32x4(v1); + let v2 = self.v128_into_i32x4(v2); let res = self.builder.build_int_add(v1, v2, ""); let res = self.builder.build_bitcast(res, self.intrinsics.i128_ty, ""); self.state.push1(res); } Operator::I64x2Add => { - let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; - let (v1, _) = self.v128_into_i64x2(v1, i1); - let (v2, _) = self.v128_into_i64x2(v2, i2); + let (v1, v2) = self.state.pop2()?; + let v1 = self.v128_into_i64x2(v1); + let v2 = self.v128_into_i64x2(v2); let res = self.builder.build_int_add(v1, v2, ""); let res = self.builder.build_bitcast(res, self.intrinsics.i128_ty, ""); self.state.push1(res); } Operator::I8x16AddSatS => { - let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; - let (v1, _) = self.v128_into_i8x16(v1, i1); - let (v2, _) = self.v128_into_i8x16(v2, i2); + let (v1, v2) = self.state.pop2()?; + let v1 = self.v128_into_i8x16(v1); + let v2 = self.v128_into_i8x16(v2); let res = self .builder .build_call( @@ -2530,9 +2346,9 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { self.state.push1(res); } Operator::I16x8AddSatS => { - let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; - let (v1, _) = self.v128_into_i16x8(v1, i1); - let (v2, _) = self.v128_into_i16x8(v2, i2); + let (v1, v2) = self.state.pop2()?; + let v1 = self.v128_into_i16x8(v1); + let v2 = self.v128_into_i16x8(v2); let res = self .builder .build_call( @@ -2547,9 +2363,9 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { self.state.push1(res); } Operator::I8x16AddSatU => { - let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; - let (v1, _) = self.v128_into_i8x16(v1, i1); - let (v2, _) = self.v128_into_i8x16(v2, i2); + let (v1, v2) = self.state.pop2()?; + let v1 = self.v128_into_i8x16(v1); + let v2 = self.v128_into_i8x16(v2); let res = self .builder .build_call( @@ -2564,9 +2380,9 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { self.state.push1(res); } Operator::I16x8AddSatU => { - let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; - let (v1, _) = self.v128_into_i16x8(v1, i1); - let (v2, _) = self.v128_into_i16x8(v2, i2); + let (v1, v2) = self.state.pop2()?; + let v1 = self.v128_into_i16x8(v1); + let v2 = self.v128_into_i16x8(v2); let res = self .builder .build_call( @@ -2581,49 +2397,47 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { self.state.push1(res); } Operator::I32Sub | Operator::I64Sub => { - let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; - let v1 = self.apply_pending_canonicalization(v1, i1); - let v2 = self.apply_pending_canonicalization(v2, i2); + let (v1, v2) = self.state.pop2()?; let (v1, v2) = (v1.into_int_value(), v2.into_int_value()); let res = self.builder.build_int_sub(v1, v2, ""); self.state.push1(res); } Operator::I8x16Sub => { - let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; - let (v1, _) = self.v128_into_i8x16(v1, i1); - let (v2, _) = self.v128_into_i8x16(v2, i2); + let (v1, v2) = self.state.pop2()?; + let v1 = self.v128_into_i8x16(v1); + let v2 = self.v128_into_i8x16(v2); let res = self.builder.build_int_sub(v1, v2, ""); let res = self.builder.build_bitcast(res, self.intrinsics.i128_ty, ""); self.state.push1(res); } Operator::I16x8Sub => { - let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; - let (v1, _) = self.v128_into_i16x8(v1, i1); - let (v2, _) = self.v128_into_i16x8(v2, i2); + let (v1, v2) = self.state.pop2()?; + let v1 = self.v128_into_i16x8(v1); + let v2 = self.v128_into_i16x8(v2); let res = self.builder.build_int_sub(v1, v2, ""); let res = self.builder.build_bitcast(res, self.intrinsics.i128_ty, ""); self.state.push1(res); } Operator::I32x4Sub => { - let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; - let (v1, _) = self.v128_into_i32x4(v1, i1); - let (v2, _) = self.v128_into_i32x4(v2, i2); + let (v1, v2) = self.state.pop2()?; + let v1 = self.v128_into_i32x4(v1); + let v2 = self.v128_into_i32x4(v2); let res = self.builder.build_int_sub(v1, v2, ""); let res = self.builder.build_bitcast(res, self.intrinsics.i128_ty, ""); self.state.push1(res); } Operator::I64x2Sub => { - let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; - let (v1, _) = self.v128_into_i64x2(v1, i1); - let (v2, _) = self.v128_into_i64x2(v2, i2); + let (v1, v2) = self.state.pop2()?; + let v1 = self.v128_into_i64x2(v1); + let v2 = self.v128_into_i64x2(v2); let res = self.builder.build_int_sub(v1, v2, ""); let res = self.builder.build_bitcast(res, self.intrinsics.i128_ty, ""); self.state.push1(res); } Operator::I8x16SubSatS => { - let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; - let (v1, _) = self.v128_into_i8x16(v1, i1); - let (v2, _) = self.v128_into_i8x16(v2, i2); + let (v1, v2) = self.state.pop2()?; + let v1 = self.v128_into_i8x16(v1); + let v2 = self.v128_into_i8x16(v2); let res = self .builder .build_call( @@ -2638,9 +2452,9 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { self.state.push1(res); } Operator::I16x8SubSatS => { - let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; - let (v1, _) = self.v128_into_i16x8(v1, i1); - let (v2, _) = self.v128_into_i16x8(v2, i2); + let (v1, v2) = self.state.pop2()?; + let v1 = self.v128_into_i16x8(v1); + let v2 = self.v128_into_i16x8(v2); let res = self .builder .build_call( @@ -2655,9 +2469,9 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { self.state.push1(res); } Operator::I8x16SubSatU => { - let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; - let (v1, _) = self.v128_into_i8x16(v1, i1); - let (v2, _) = self.v128_into_i8x16(v2, i2); + let (v1, v2) = self.state.pop2()?; + let v1 = self.v128_into_i8x16(v1); + let v2 = self.v128_into_i8x16(v2); let res = self .builder .build_call( @@ -2672,9 +2486,9 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { self.state.push1(res); } Operator::I16x8SubSatU => { - let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; - let (v1, _) = self.v128_into_i16x8(v1, i1); - let (v2, _) = self.v128_into_i16x8(v2, i2); + let (v1, v2) = self.state.pop2()?; + let v1 = self.v128_into_i16x8(v1); + let v2 = self.v128_into_i16x8(v2); let res = self .builder .build_call( @@ -2689,41 +2503,37 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { self.state.push1(res); } Operator::I32Mul | Operator::I64Mul => { - let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; - let v1 = self.apply_pending_canonicalization(v1, i1); - let v2 = self.apply_pending_canonicalization(v2, i2); + let (v1, v2) = self.state.pop2()?; let (v1, v2) = (v1.into_int_value(), v2.into_int_value()); let res = self.builder.build_int_mul(v1, v2, ""); self.state.push1(res); } Operator::I16x8Mul => { - let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; - let (v1, _) = self.v128_into_i16x8(v1, i1); - let (v2, _) = self.v128_into_i16x8(v2, i2); + let (v1, v2) = self.state.pop2()?; + let v1 = self.v128_into_i16x8(v1); + let v2 = self.v128_into_i16x8(v2); let res = self.builder.build_int_mul(v1, v2, ""); let res = self.builder.build_bitcast(res, self.intrinsics.i128_ty, ""); self.state.push1(res); } Operator::I32x4Mul => { - let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; - let (v1, _) = self.v128_into_i32x4(v1, i1); - let (v2, _) = self.v128_into_i32x4(v2, i2); + let (v1, v2) = self.state.pop2()?; + let v1 = self.v128_into_i32x4(v1); + let v2 = self.v128_into_i32x4(v2); let res = self.builder.build_int_mul(v1, v2, ""); let res = self.builder.build_bitcast(res, self.intrinsics.i128_ty, ""); self.state.push1(res); } Operator::I64x2Mul => { - let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; - let (v1, _) = self.v128_into_i64x2(v1, i1); - let (v2, _) = self.v128_into_i64x2(v2, i2); + let (v1, v2) = self.state.pop2()?; + let v1 = self.v128_into_i64x2(v1); + let v2 = self.v128_into_i64x2(v2); let res = self.builder.build_int_mul(v1, v2, ""); let res = self.builder.build_bitcast(res, self.intrinsics.i128_ty, ""); self.state.push1(res); } Operator::I32DivS | Operator::I64DivS => { - let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; - let v1 = self.apply_pending_canonicalization(v1, i1); - let v2 = self.apply_pending_canonicalization(v2, i2); + let (v1, v2) = self.state.pop2()?; let (v1, v2) = (v1.into_int_value(), v2.into_int_value()); self.trap_if_zero_or_overflow(v1, v2); @@ -2732,9 +2542,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { self.state.push1(res); } Operator::I32DivU | Operator::I64DivU => { - let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; - let v1 = self.apply_pending_canonicalization(v1, i1); - let v2 = self.apply_pending_canonicalization(v2, i2); + let (v1, v2) = self.state.pop2()?; let (v1, v2) = (v1.into_int_value(), v2.into_int_value()); self.trap_if_zero(v2); @@ -2743,9 +2551,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { self.state.push1(res); } Operator::I32RemS | Operator::I64RemS => { - let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; - let v1 = self.apply_pending_canonicalization(v1, i1); - let v2 = self.apply_pending_canonicalization(v2, i2); + let (v1, v2) = self.state.pop2()?; let (v1, v2) = (v1.into_int_value(), v2.into_int_value()); let int_type = v1.get_type(); let (min_value, neg_one_value) = if int_type == self.intrinsics.i32_ty { @@ -2792,9 +2598,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { self.state.push1(res); } Operator::I32RemU | Operator::I64RemU => { - let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; - let v1 = self.apply_pending_canonicalization(v1, i1); - let v2 = self.apply_pending_canonicalization(v2, i2); + let (v1, v2) = self.state.pop2()?; let (v1, v2) = (v1.into_int_value(), v2.into_int_value()); self.trap_if_zero(v2); @@ -2803,43 +2607,37 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { self.state.push1(res); } Operator::I32And | Operator::I64And | Operator::V128And => { - let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; - let v1 = self.apply_pending_canonicalization(v1, i1); - let v2 = self.apply_pending_canonicalization(v2, i2); + let (v1, v2) = self.state.pop2()?; + let (v1, v2) = (v1.into_int_value(), v2.into_int_value()); let res = self.builder.build_and(v1, v2, ""); self.state.push1(res); } Operator::I32Or | Operator::I64Or | Operator::V128Or => { - let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; - let v1 = self.apply_pending_canonicalization(v1, i1); - let v2 = self.apply_pending_canonicalization(v2, i2); + let (v1, v2) = self.state.pop2()?; + let (v1, v2) = (v1.into_int_value(), v2.into_int_value()); let res = self.builder.build_or(v1, v2, ""); self.state.push1(res); } Operator::I32Xor | Operator::I64Xor | Operator::V128Xor => { - let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; - let v1 = self.apply_pending_canonicalization(v1, i1); - let v2 = self.apply_pending_canonicalization(v2, i2); + let (v1, v2) = self.state.pop2()?; + let (v1, v2) = (v1.into_int_value(), v2.into_int_value()); let res = self.builder.build_xor(v1, v2, ""); self.state.push1(res); } Operator::V128AndNot => { - let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; - let v1 = self.apply_pending_canonicalization(v1, i1); - let v2 = self.apply_pending_canonicalization(v2, i2); + let (v1, v2) = self.state.pop2()?; + let (v1, v2) = (v1.into_int_value(), v2.into_int_value()); let v2 = self.builder.build_not(v2, ""); let res = self.builder.build_and(v1, v2, ""); self.state.push1(res); } Operator::V128Bitselect => { - let ((v1, i1), (v2, i2), (cond, cond_info)) = self.state.pop3_extra()?; - let v1 = self.apply_pending_canonicalization(v1, i1); - let v2 = self.apply_pending_canonicalization(v2, i2); - let cond = self.apply_pending_canonicalization(cond, cond_info); + let ((v1, _), (v2, _), (cond, _)) = self.state.pop3_extra()?; + let v1 = self .builder .build_bitcast(v1, self.intrinsics.i1x128_ty, "") @@ -2857,9 +2655,8 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { self.state.push1(res); } Operator::I32Shl => { - let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; - let v1 = self.apply_pending_canonicalization(v1, i1); - let v2 = self.apply_pending_canonicalization(v2, i2); + let (v1, v2) = self.state.pop2()?; + let (v1, v2) = (v1.into_int_value(), v2.into_int_value()); let mask = self.intrinsics.i32_ty.const_int(31u64, false); let v2 = self.builder.build_and(v2, mask, ""); @@ -2867,9 +2664,8 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { self.state.push1(res); } Operator::I64Shl => { - let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; - let v1 = self.apply_pending_canonicalization(v1, i1); - let v2 = self.apply_pending_canonicalization(v2, i2); + let (v1, v2) = self.state.pop2()?; + let (v1, v2) = (v1.into_int_value(), v2.into_int_value()); let mask = self.intrinsics.i64_ty.const_int(63u64, false); let v2 = self.builder.build_and(v2, mask, ""); @@ -2877,9 +2673,8 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { self.state.push1(res); } Operator::I8x16Shl => { - let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; - let (v1, _) = self.v128_into_i8x16(v1, i1); - let v2 = self.apply_pending_canonicalization(v2, i2); + let (v1, v2) = self.state.pop2()?; + let v1 = self.v128_into_i8x16(v1); let v2 = v2.into_int_value(); let v2 = self .builder @@ -2893,9 +2688,8 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { self.state.push1(res); } Operator::I16x8Shl => { - let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; - let (v1, _) = self.v128_into_i16x8(v1, i1); - let v2 = self.apply_pending_canonicalization(v2, i2); + let (v1, v2) = self.state.pop2()?; + let v1 = self.v128_into_i16x8(v1); let v2 = v2.into_int_value(); let v2 = self.builder @@ -2909,9 +2703,8 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { self.state.push1(res); } Operator::I32x4Shl => { - let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; - let (v1, _) = self.v128_into_i32x4(v1, i1); - let v2 = self.apply_pending_canonicalization(v2, i2); + let (v1, v2) = self.state.pop2()?; + let v1 = self.v128_into_i32x4(v1); let v2 = v2.into_int_value(); let v2 = self.builder @@ -2922,9 +2715,8 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { self.state.push1(res); } Operator::I64x2Shl => { - let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; - let (v1, _) = self.v128_into_i64x2(v1, i1); - let v2 = self.apply_pending_canonicalization(v2, i2); + let (v1, v2) = self.state.pop2()?; + let v1 = self.v128_into_i64x2(v1); let v2 = v2.into_int_value(); let v2 = self.builder @@ -2938,9 +2730,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { self.state.push1(res); } Operator::I32ShrS => { - let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; - let v1 = self.apply_pending_canonicalization(v1, i1); - let v2 = self.apply_pending_canonicalization(v2, i2); + let (v1, v2) = self.state.pop2()?; let (v1, v2) = (v1.into_int_value(), v2.into_int_value()); let mask = self.intrinsics.i32_ty.const_int(31u64, false); let v2 = self.builder.build_and(v2, mask, ""); @@ -2948,9 +2738,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { self.state.push1(res); } Operator::I64ShrS => { - let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; - let v1 = self.apply_pending_canonicalization(v1, i1); - let v2 = self.apply_pending_canonicalization(v2, i2); + let (v1, v2) = self.state.pop2()?; let (v1, v2) = (v1.into_int_value(), v2.into_int_value()); let mask = self.intrinsics.i64_ty.const_int(63u64, false); let v2 = self.builder.build_and(v2, mask, ""); @@ -2958,9 +2746,8 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { self.state.push1(res); } Operator::I8x16ShrS => { - let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; - let (v1, _) = self.v128_into_i8x16(v1, i1); - let v2 = self.apply_pending_canonicalization(v2, i2); + let (v1, v2) = self.state.pop2()?; + let v1 = self.v128_into_i8x16(v1); let v2 = v2.into_int_value(); let v2 = self .builder @@ -2974,9 +2761,8 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { self.state.push1(res); } Operator::I16x8ShrS => { - let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; - let (v1, _) = self.v128_into_i16x8(v1, i1); - let v2 = self.apply_pending_canonicalization(v2, i2); + let (v1, v2) = self.state.pop2()?; + let v1 = self.v128_into_i16x8(v1); let v2 = v2.into_int_value(); let v2 = self.builder @@ -2990,9 +2776,8 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { self.state.push1(res); } Operator::I32x4ShrS => { - let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; - let (v1, _) = self.v128_into_i32x4(v1, i1); - let v2 = self.apply_pending_canonicalization(v2, i2); + let (v1, v2) = self.state.pop2()?; + let v1 = self.v128_into_i32x4(v1); let v2 = v2.into_int_value(); let v2 = self.builder @@ -3003,9 +2788,8 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { self.state.push1(res); } Operator::I64x2ShrS => { - let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; - let (v1, _) = self.v128_into_i64x2(v1, i1); - let v2 = self.apply_pending_canonicalization(v2, i2); + let (v1, v2) = self.state.pop2()?; + let v1 = self.v128_into_i64x2(v1); let v2 = v2.into_int_value(); let v2 = self.builder @@ -3019,9 +2803,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { self.state.push1(res); } Operator::I32ShrU => { - let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; - let v1 = self.apply_pending_canonicalization(v1, i1); - let v2 = self.apply_pending_canonicalization(v2, i2); + let (v1, v2) = self.state.pop2()?; let (v1, v2) = (v1.into_int_value(), v2.into_int_value()); let mask = self.intrinsics.i32_ty.const_int(31u64, false); let v2 = self.builder.build_and(v2, mask, ""); @@ -3029,9 +2811,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { self.state.push1(res); } Operator::I64ShrU => { - let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; - let v1 = self.apply_pending_canonicalization(v1, i1); - let v2 = self.apply_pending_canonicalization(v2, i2); + let (v1, v2) = self.state.pop2()?; let (v1, v2) = (v1.into_int_value(), v2.into_int_value()); let mask = self.intrinsics.i64_ty.const_int(63u64, false); let v2 = self.builder.build_and(v2, mask, ""); @@ -3039,9 +2819,8 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { self.state.push1(res); } Operator::I8x16ShrU => { - let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; - let (v1, _) = self.v128_into_i8x16(v1, i1); - let v2 = self.apply_pending_canonicalization(v2, i2); + let (v1, v2) = self.state.pop2()?; + let v1 = self.v128_into_i8x16(v1); let v2 = v2.into_int_value(); let v2 = self .builder @@ -3055,9 +2834,8 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { self.state.push1(res); } Operator::I16x8ShrU => { - let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; - let (v1, _) = self.v128_into_i16x8(v1, i1); - let v2 = self.apply_pending_canonicalization(v2, i2); + let (v1, v2) = self.state.pop2()?; + let v1 = self.v128_into_i16x8(v1); let v2 = v2.into_int_value(); let v2 = self.builder @@ -3071,9 +2849,8 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { self.state.push1(res); } Operator::I32x4ShrU => { - let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; - let (v1, _) = self.v128_into_i32x4(v1, i1); - let v2 = self.apply_pending_canonicalization(v2, i2); + let (v1, v2) = self.state.pop2()?; + let v1 = self.v128_into_i32x4(v1); let v2 = v2.into_int_value(); let v2 = self.builder @@ -3084,9 +2861,8 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { self.state.push1(res); } Operator::I64x2ShrU => { - let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; - let (v1, _) = self.v128_into_i64x2(v1, i1); - let v2 = self.apply_pending_canonicalization(v2, i2); + let (v1, v2) = self.state.pop2()?; + let v1 = self.v128_into_i64x2(v1); let v2 = v2.into_int_value(); let v2 = self.builder @@ -3100,9 +2876,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { self.state.push1(res); } Operator::I32Rotl => { - let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; - let v1 = self.apply_pending_canonicalization(v1, i1); - let v2 = self.apply_pending_canonicalization(v2, i2); + let (v1, v2) = self.state.pop2()?; let (v1, v2) = (v1.into_int_value(), v2.into_int_value()); let mask = self.intrinsics.i32_ty.const_int(31u64, false); let v2 = self.builder.build_and(v2, mask, ""); @@ -3116,9 +2890,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { self.state.push1(res); } Operator::I64Rotl => { - let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; - let v1 = self.apply_pending_canonicalization(v1, i1); - let v2 = self.apply_pending_canonicalization(v2, i2); + let (v1, v2) = self.state.pop2()?; let (v1, v2) = (v1.into_int_value(), v2.into_int_value()); let mask = self.intrinsics.i64_ty.const_int(63u64, false); let v2 = self.builder.build_and(v2, mask, ""); @@ -3132,9 +2904,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { self.state.push1(res); } Operator::I32Rotr => { - let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; - let v1 = self.apply_pending_canonicalization(v1, i1); - let v2 = self.apply_pending_canonicalization(v2, i2); + let (v1, v2) = self.state.pop2()?; let (v1, v2) = (v1.into_int_value(), v2.into_int_value()); let mask = self.intrinsics.i32_ty.const_int(31u64, false); let v2 = self.builder.build_and(v2, mask, ""); @@ -3148,9 +2918,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { self.state.push1(res); } Operator::I64Rotr => { - let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; - let v1 = self.apply_pending_canonicalization(v1, i1); - let v2 = self.apply_pending_canonicalization(v2, i2); + let (v1, v2) = self.state.pop2()?; let (v1, v2) = (v1.into_int_value(), v2.into_int_value()); let mask = self.intrinsics.i64_ty.const_int(63u64, false); let v2 = self.builder.build_and(v2, mask, ""); @@ -3164,8 +2932,8 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { self.state.push1(res); } Operator::I32Clz => { - let (input, info) = self.state.pop1_extra()?; - let input = self.apply_pending_canonicalization(input, info); + let input = self.state.pop1()?; + let is_zero_undef = self.intrinsics.i1_zero.as_basic_value_enum(); let res = self .builder @@ -3173,11 +2941,11 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { .try_as_basic_value() .left() .unwrap(); - self.state.push1_extra(res, ExtraInfo::arithmetic_f32()); + self.state.push1(res); } Operator::I64Clz => { - let (input, info) = self.state.pop1_extra()?; - let input = self.apply_pending_canonicalization(input, info); + let input = self.state.pop1()?; + let is_zero_undef = self.intrinsics.i1_zero.as_basic_value_enum(); let res = self .builder @@ -3185,11 +2953,11 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { .try_as_basic_value() .left() .unwrap(); - self.state.push1_extra(res, ExtraInfo::arithmetic_f64()); + self.state.push1(res); } Operator::I32Ctz => { - let (input, info) = self.state.pop1_extra()?; - let input = self.apply_pending_canonicalization(input, info); + let input = self.state.pop1()?; + let is_zero_undef = self.intrinsics.i1_zero.as_basic_value_enum(); let res = self .builder @@ -3197,11 +2965,11 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { .try_as_basic_value() .left() .unwrap(); - self.state.push1_extra(res, ExtraInfo::arithmetic_f32()); + self.state.push1(res); } Operator::I64Ctz => { - let (input, info) = self.state.pop1_extra()?; - let input = self.apply_pending_canonicalization(input, info); + let input = self.state.pop1()?; + let is_zero_undef = self.intrinsics.i1_zero.as_basic_value_enum(); let res = self .builder @@ -3209,29 +2977,29 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { .try_as_basic_value() .left() .unwrap(); - self.state.push1_extra(res, ExtraInfo::arithmetic_f64()); + self.state.push1(res); } Operator::I32Popcnt => { - let (input, info) = self.state.pop1_extra()?; - let input = self.apply_pending_canonicalization(input, info); + let input = self.state.pop1()?; + let res = self .builder .build_call(self.intrinsics.ctpop_i32, &[input], "") .try_as_basic_value() .left() .unwrap(); - self.state.push1_extra(res, ExtraInfo::arithmetic_f32()); + self.state.push1(res); } Operator::I64Popcnt => { - let (input, info) = self.state.pop1_extra()?; - let input = self.apply_pending_canonicalization(input, info); + let input = self.state.pop1()?; + let res = self .builder .build_call(self.intrinsics.ctpop_i64, &[input], "") .try_as_basic_value() .left() .unwrap(); - self.state.push1_extra(res, ExtraInfo::arithmetic_f64()); + self.state.push1(res); } Operator::I32Eqz => { let input = self.state.pop1()?.into_int_value(); @@ -3244,7 +3012,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { let res = self .builder .build_int_z_extend(cond, self.intrinsics.i32_ty, ""); - self.state.push1_extra(res, ExtraInfo::arithmetic_f32()); + self.state.push1(res); } Operator::I64Eqz => { let input = self.state.pop1()?.into_int_value(); @@ -3257,11 +3025,11 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { let res = self .builder .build_int_z_extend(cond, self.intrinsics.i32_ty, ""); - self.state.push1_extra(res, ExtraInfo::arithmetic_f64()); + self.state.push1(res); } Operator::I8x16Abs => { - let (v, i) = self.state.pop1_extra()?; - let (v, _) = self.v128_into_i8x16(v, i); + let v = self.state.pop1()?; + let v = self.v128_into_i8x16(v); let seven = self.intrinsics.i8_ty.const_int(7, false); let seven = VectorType::const_vector(&[seven; 16]); @@ -3272,8 +3040,8 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { self.state.push1(res); } Operator::I16x8Abs => { - let (v, i) = self.state.pop1_extra()?; - let (v, _) = self.v128_into_i16x8(v, i); + let v = self.state.pop1()?; + let v = self.v128_into_i16x8(v); let fifteen = self.intrinsics.i16_ty.const_int(15, false); let fifteen = VectorType::const_vector(&[fifteen; 8]); @@ -3284,8 +3052,8 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { self.state.push1(res); } Operator::I32x4Abs => { - let (v, i) = self.state.pop1_extra()?; - let (v, _) = self.v128_into_i32x4(v, i); + let v = self.state.pop1()?; + let v = self.v128_into_i32x4(v); let thirtyone = self.intrinsics.i32_ty.const_int(31, false); let thirtyone = VectorType::const_vector(&[thirtyone; 4]); @@ -3296,9 +3064,9 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { self.state.push1(res); } Operator::I8x16MinS => { - let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; - let (v1, _) = self.v128_into_i8x16(v1, i1); - let (v2, _) = self.v128_into_i8x16(v2, i2); + let (v1, v2) = self.state.pop2()?; + let v1 = self.v128_into_i8x16(v1); + let v2 = self.v128_into_i8x16(v2); let cmp = self .builder .build_int_compare(IntPredicate::SLT, v1, v2, ""); @@ -3307,9 +3075,9 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { self.state.push1(res); } Operator::I8x16MinU => { - let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; - let (v1, _) = self.v128_into_i8x16(v1, i1); - let (v2, _) = self.v128_into_i8x16(v2, i2); + let (v1, v2) = self.state.pop2()?; + let v1 = self.v128_into_i8x16(v1); + let v2 = self.v128_into_i8x16(v2); let cmp = self .builder .build_int_compare(IntPredicate::ULT, v1, v2, ""); @@ -3318,9 +3086,9 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { self.state.push1(res); } Operator::I8x16MaxS => { - let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; - let (v1, _) = self.v128_into_i8x16(v1, i1); - let (v2, _) = self.v128_into_i8x16(v2, i2); + let (v1, v2) = self.state.pop2()?; + let v1 = self.v128_into_i8x16(v1); + let v2 = self.v128_into_i8x16(v2); let cmp = self .builder .build_int_compare(IntPredicate::SGT, v1, v2, ""); @@ -3329,9 +3097,9 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { self.state.push1(res); } Operator::I8x16MaxU => { - let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; - let (v1, _) = self.v128_into_i8x16(v1, i1); - let (v2, _) = self.v128_into_i8x16(v2, i2); + let (v1, v2) = self.state.pop2()?; + let v1 = self.v128_into_i8x16(v1); + let v2 = self.v128_into_i8x16(v2); let cmp = self .builder .build_int_compare(IntPredicate::UGT, v1, v2, ""); @@ -3340,9 +3108,9 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { self.state.push1(res); } Operator::I16x8MinS => { - let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; - let (v1, _) = self.v128_into_i16x8(v1, i1); - let (v2, _) = self.v128_into_i16x8(v2, i2); + let (v1, v2) = self.state.pop2()?; + let v1 = self.v128_into_i16x8(v1); + let v2 = self.v128_into_i16x8(v2); let cmp = self .builder .build_int_compare(IntPredicate::SLT, v1, v2, ""); @@ -3351,9 +3119,9 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { self.state.push1(res); } Operator::I16x8MinU => { - let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; - let (v1, _) = self.v128_into_i16x8(v1, i1); - let (v2, _) = self.v128_into_i16x8(v2, i2); + let (v1, v2) = self.state.pop2()?; + let v1 = self.v128_into_i16x8(v1); + let v2 = self.v128_into_i16x8(v2); let cmp = self .builder .build_int_compare(IntPredicate::ULT, v1, v2, ""); @@ -3362,9 +3130,9 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { self.state.push1(res); } Operator::I16x8MaxS => { - let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; - let (v1, _) = self.v128_into_i16x8(v1, i1); - let (v2, _) = self.v128_into_i16x8(v2, i2); + let (v1, v2) = self.state.pop2()?; + let v1 = self.v128_into_i16x8(v1); + let v2 = self.v128_into_i16x8(v2); let cmp = self .builder .build_int_compare(IntPredicate::SGT, v1, v2, ""); @@ -3373,9 +3141,9 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { self.state.push1(res); } Operator::I16x8MaxU => { - let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; - let (v1, _) = self.v128_into_i16x8(v1, i1); - let (v2, _) = self.v128_into_i16x8(v2, i2); + let (v1, v2) = self.state.pop2()?; + let v1 = self.v128_into_i16x8(v1); + let v2 = self.v128_into_i16x8(v2); let cmp = self .builder .build_int_compare(IntPredicate::UGT, v1, v2, ""); @@ -3384,9 +3152,9 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { self.state.push1(res); } Operator::I32x4MinS => { - let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; - let (v1, _) = self.v128_into_i32x4(v1, i1); - let (v2, _) = self.v128_into_i32x4(v2, i2); + let (v1, v2) = self.state.pop2()?; + let v1 = self.v128_into_i32x4(v1); + let v2 = self.v128_into_i32x4(v2); let cmp = self .builder .build_int_compare(IntPredicate::SLT, v1, v2, ""); @@ -3395,9 +3163,9 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { self.state.push1(res); } Operator::I32x4MinU => { - let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; - let (v1, _) = self.v128_into_i32x4(v1, i1); - let (v2, _) = self.v128_into_i32x4(v2, i2); + let (v1, v2) = self.state.pop2()?; + let v1 = self.v128_into_i32x4(v1); + let v2 = self.v128_into_i32x4(v2); let cmp = self .builder .build_int_compare(IntPredicate::ULT, v1, v2, ""); @@ -3406,9 +3174,9 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { self.state.push1(res); } Operator::I32x4MaxS => { - let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; - let (v1, _) = self.v128_into_i32x4(v1, i1); - let (v2, _) = self.v128_into_i32x4(v2, i2); + let (v1, v2) = self.state.pop2()?; + let v1 = self.v128_into_i32x4(v1); + let v2 = self.v128_into_i32x4(v2); let cmp = self .builder .build_int_compare(IntPredicate::SGT, v1, v2, ""); @@ -3417,9 +3185,9 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { self.state.push1(res); } Operator::I32x4MaxU => { - let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; - let (v1, _) = self.v128_into_i32x4(v1, i1); - let (v2, _) = self.v128_into_i32x4(v2, i2); + let (v1, v2) = self.state.pop2()?; + let v1 = self.v128_into_i32x4(v1); + let v2 = self.v128_into_i32x4(v2); let cmp = self .builder .build_int_compare(IntPredicate::UGT, v1, v2, ""); @@ -3428,9 +3196,9 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { self.state.push1(res); } Operator::I8x16RoundingAverageU => { - let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; - let (v1, _) = self.v128_into_i8x16(v1, i1); - let (v2, _) = self.v128_into_i8x16(v2, i2); + let (v1, v2) = self.state.pop2()?; + let v1 = self.v128_into_i8x16(v1); + let v2 = self.v128_into_i8x16(v2); // This approach is faster on x86-64 when the PAVG[BW] // instructions are available. On other platforms, an alternative @@ -3459,9 +3227,9 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { self.state.push1(res); } Operator::I16x8RoundingAverageU => { - let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; - let (v1, _) = self.v128_into_i16x8(v1, i1); - let (v2, _) = self.v128_into_i16x8(v2, i2); + let (v1, v2) = self.state.pop2()?; + let v1 = self.v128_into_i16x8(v1); + let v2 = self.v128_into_i16x8(v2); // This approach is faster on x86-64 when the PAVG[BW] // instructions are available. On other platforms, an alternative @@ -3495,420 +3263,667 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { * https://github.com/sunfishcode/wasm-reference-manual/blob/master/WebAssembly.md#floating-point-arithmetic-instructions ***************************/ Operator::F32Add => { - let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; - let (v1, v2) = (v1.into_float_value(), v2.into_float_value()); - let res = self.builder.build_float_add(v1, v2, ""); - self.state.push1_extra( - res, - (i1.strip_pending() & i2.strip_pending()) | ExtraInfo::pending_f32_nan(), - ); + let (v1, v2) = self.state.pop2()?; + let v1 = self.canonicalize_nans(v1); + let v2 = self.canonicalize_nans(v2); + let res = self + .builder + .build_call( + self.intrinsics.add_f32, + &[ + v1, + v2, + self.intrinsics.fp_rounding_md, + self.intrinsics.fp_exception_md, + ], + "", + ) + .try_as_basic_value() + .left() + .unwrap(); + + self.state.push1(res); } Operator::F64Add => { - let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; - let (v1, v2) = (v1.into_float_value(), v2.into_float_value()); - let res = self.builder.build_float_add(v1, v2, ""); - self.state.push1_extra( - res, - (i1.strip_pending() & i2.strip_pending()) | ExtraInfo::pending_f64_nan(), - ); + let (v1, v2) = self.state.pop2()?; + let v1 = self.canonicalize_nans(v1); + let v2 = self.canonicalize_nans(v2); + let res = self + .builder + .build_call( + self.intrinsics.add_f64, + &[ + v1.as_basic_value_enum(), + v2.as_basic_value_enum(), + self.intrinsics.fp_rounding_md, + self.intrinsics.fp_exception_md, + ], + "", + ) + .try_as_basic_value() + .left() + .unwrap(); + + self.state.push1(res); } Operator::F32x4Add => { - let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; - let (v1, i1) = self.v128_into_f32x4(v1, i1); - let (v2, i2) = self.v128_into_f32x4(v2, i2); - let res = self.builder.build_float_add(v1, v2, ""); + let (v1, v2) = self.state.pop2()?; + let v1 = self.v128_into_f32x4(v1); + let v2 = self.v128_into_f32x4(v2); + + let res = self + .builder + .build_call( + self.intrinsics.add_f32x4, + &[ + v1.as_basic_value_enum(), + v2.as_basic_value_enum(), + self.intrinsics.fp_rounding_md, + self.intrinsics.fp_exception_md, + ], + "", + ) + .try_as_basic_value() + .left() + .unwrap(); + let res = self.builder.build_bitcast(res, self.intrinsics.i128_ty, ""); - self.state.push1_extra( - res, - (i1.strip_pending() & i2.strip_pending()) | ExtraInfo::pending_f32_nan(), - ); + self.state.push1(res); } Operator::F64x2Add => { - let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; - let (v1, i1) = self.v128_into_f64x2(v1, i1); - let (v2, i2) = self.v128_into_f64x2(v2, i2); - let res = self.builder.build_float_add(v1, v2, ""); - let res = self.builder.build_bitcast(res, self.intrinsics.i128_ty, ""); - self.state.push1_extra( - res, - (i1.strip_pending() & i2.strip_pending()) | ExtraInfo::pending_f64_nan(), - ); - } - Operator::F32Sub => { - let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; - let (v1, v2) = (v1.into_float_value(), v2.into_float_value()); - let res = self.builder.build_float_sub(v1, v2, ""); - self.state.push1_extra( - res, - (i1.strip_pending() & i2.strip_pending()) | ExtraInfo::pending_f32_nan(), - ); + let (v1, v2) = self.state.pop2()?; + let v1 = self.v128_into_f64x2(v1); + let v2 = self.v128_into_f64x2(v2); + + let res = self + .builder + .build_call( + self.intrinsics.add_f64x2, + &[ + v1.as_basic_value_enum(), + v2.as_basic_value_enum(), + self.intrinsics.fp_rounding_md, + self.intrinsics.fp_exception_md, + ], + "", + ) + .try_as_basic_value() + .left() + .unwrap(); + + let res = self.builder.build_bitcast(res, self.intrinsics.i128_ty, ""); + self.state.push1(res); + } + + Operator::F32Sub => { + let (v1, v2) = self.state.pop2()?; + let v1 = self.canonicalize_nans(v1); + let v2 = self.canonicalize_nans(v2); + let res = self + .builder + .build_call( + self.intrinsics.sub_f32, + &[ + v1.as_basic_value_enum(), + v2.as_basic_value_enum(), + self.intrinsics.fp_rounding_md, + self.intrinsics.fp_exception_md, + ], + "", + ) + .try_as_basic_value() + .left() + .unwrap(); + + self.state.push1(res); } Operator::F64Sub => { - let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; - let (v1, v2) = (v1.into_float_value(), v2.into_float_value()); - let res = self.builder.build_float_sub(v1, v2, ""); - self.state.push1_extra( - res, - (i1.strip_pending() & i2.strip_pending()) | ExtraInfo::pending_f64_nan(), - ); + let (v1, v2) = self.state.pop2()?; + let v1 = self.canonicalize_nans(v1); + let v2 = self.canonicalize_nans(v2); + let res = self + .builder + .build_call( + self.intrinsics.sub_f64, + &[ + v1.as_basic_value_enum(), + v2.as_basic_value_enum(), + self.intrinsics.fp_rounding_md, + self.intrinsics.fp_exception_md, + ], + "", + ) + .try_as_basic_value() + .left() + .unwrap(); + + self.state.push1(res); } Operator::F32x4Sub => { - let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; - let (v1, i1) = self.v128_into_f32x4(v1, i1); - let (v2, i2) = self.v128_into_f32x4(v2, i2); - let res = self.builder.build_float_sub(v1, v2, ""); + let (v1, v2) = self.state.pop2()?; + let v1 = self.v128_into_f32x4(v1); + let v2 = self.v128_into_f32x4(v2); + + let res = self + .builder + .build_call( + self.intrinsics.sub_f32x4, + &[ + v1.as_basic_value_enum(), + v2.as_basic_value_enum(), + self.intrinsics.fp_rounding_md, + self.intrinsics.fp_exception_md, + ], + "", + ) + .try_as_basic_value() + .left() + .unwrap(); + let res = self.builder.build_bitcast(res, self.intrinsics.i128_ty, ""); - self.state.push1_extra( - res, - (i1.strip_pending() & i2.strip_pending()) | ExtraInfo::pending_f32_nan(), - ); + self.state.push1(res); } Operator::F64x2Sub => { - let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; - let (v1, i1) = self.v128_into_f64x2(v1, i1); - let (v2, i2) = self.v128_into_f64x2(v2, i2); - let res = self.builder.build_float_sub(v1, v2, ""); + let (v1, v2) = self.state.pop2()?; + let v1 = self.v128_into_f64x2(v1); + let v2 = self.v128_into_f64x2(v2); + + let res = self + .builder + .build_call( + self.intrinsics.sub_f64x2, + &[ + self.canonicalize_nans(v1.as_basic_value_enum()), + self.canonicalize_nans(v2.as_basic_value_enum()), + self.intrinsics.fp_rounding_md, + self.intrinsics.fp_exception_md, + ], + "", + ) + .try_as_basic_value() + .left() + .unwrap(); + let res = self.builder.build_bitcast(res, self.intrinsics.i128_ty, ""); - self.state.push1_extra( - res, - (i1.strip_pending() & i2.strip_pending()) | ExtraInfo::pending_f64_nan(), - ); + self.state.push1(res); } + Operator::F32Mul => { - let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; - let (v1, v2) = (v1.into_float_value(), v2.into_float_value()); - let res = self.builder.build_float_mul(v1, v2, ""); - self.state.push1_extra( - res, - (i1.strip_pending() & i2.strip_pending()) | ExtraInfo::pending_f32_nan(), - ); + let (v1, v2) = self.state.pop2()?; + let v1 = self.canonicalize_nans(v1); + let v2 = self.canonicalize_nans(v2); + let res = self + .builder + .build_call( + self.intrinsics.mul_f32, + &[ + v1.as_basic_value_enum(), + v2.as_basic_value_enum(), + self.intrinsics.fp_rounding_md, + self.intrinsics.fp_exception_md, + ], + "", + ) + .try_as_basic_value() + .left() + .unwrap(); + + self.state.push1(res); } Operator::F64Mul => { - let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; - let (v1, v2) = (v1.into_float_value(), v2.into_float_value()); - let res = self.builder.build_float_mul(v1, v2, ""); - self.state.push1_extra( - res, - (i1.strip_pending() & i2.strip_pending()) | ExtraInfo::pending_f64_nan(), - ); + let (v1, v2) = self.state.pop2()?; + let v1 = self.canonicalize_nans(v1); + let v2 = self.canonicalize_nans(v2); + let res = self + .builder + .build_call( + self.intrinsics.mul_f64, + &[ + v1.as_basic_value_enum(), + v2.as_basic_value_enum(), + self.intrinsics.fp_rounding_md, + self.intrinsics.fp_exception_md, + ], + "", + ) + .try_as_basic_value() + .left() + .unwrap(); + + self.state.push1(res); } Operator::F32x4Mul => { - let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; - let (v1, i1) = self.v128_into_f32x4(v1, i1); - let (v2, i2) = self.v128_into_f32x4(v2, i2); - let res = self.builder.build_float_mul(v1, v2, ""); + let (v1, v2) = self.state.pop2()?; + let v1 = self.v128_into_f32x4(v1); + let v2 = self.v128_into_f32x4(v2); + + let res = self + .builder + .build_call( + self.intrinsics.mul_f32x4, + &[ + v1.as_basic_value_enum(), + v2.as_basic_value_enum(), + self.intrinsics.fp_rounding_md, + self.intrinsics.fp_exception_md, + ], + "", + ) + .try_as_basic_value() + .left() + .unwrap(); + let res = self.builder.build_bitcast(res, self.intrinsics.i128_ty, ""); - self.state.push1_extra( - res, - (i1.strip_pending() & i2.strip_pending()) | ExtraInfo::pending_f32_nan(), - ); + self.state.push1(res); } Operator::F64x2Mul => { - let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; - let (v1, i1) = self.v128_into_f64x2(v1, i1); - let (v2, i2) = self.v128_into_f64x2(v2, i2); - let res = self.builder.build_float_mul(v1, v2, ""); + let (v1, v2) = self.state.pop2()?; + let v1 = self.v128_into_f64x2(v1); + let v2 = self.v128_into_f64x2(v2); + + let res = self + .builder + .build_call( + self.intrinsics.mul_f64x2, + &[ + v1.as_basic_value_enum(), + v2.as_basic_value_enum(), + self.intrinsics.fp_rounding_md, + self.intrinsics.fp_exception_md, + ], + "", + ) + .try_as_basic_value() + .left() + .unwrap(); + let res = self.builder.build_bitcast(res, self.intrinsics.i128_ty, ""); - self.state.push1_extra( - res, - (i1.strip_pending() & i2.strip_pending()) | ExtraInfo::pending_f64_nan(), - ); + self.state.push1(res); } + Operator::F32Div => { let (v1, v2) = self.state.pop2()?; - let (v1, v2) = (v1.into_float_value(), v2.into_float_value()); - let res = self.builder.build_float_div(v1, v2, ""); - self.state.push1_extra(res, ExtraInfo::pending_f32_nan()); + let v1 = self.canonicalize_nans(v1); + let v2 = self.canonicalize_nans(v2); + let res = self + .builder + .build_call( + self.intrinsics.div_f32, + &[ + v1.as_basic_value_enum(), + v2.as_basic_value_enum(), + self.intrinsics.fp_rounding_md, + self.intrinsics.fp_exception_md, + ], + "", + ) + .try_as_basic_value() + .left() + .unwrap(); + + self.state.push1(res); } Operator::F64Div => { let (v1, v2) = self.state.pop2()?; - let (v1, v2) = (v1.into_float_value(), v2.into_float_value()); - let res = self.builder.build_float_div(v1, v2, ""); - self.state.push1_extra(res, ExtraInfo::pending_f64_nan()); + let v1 = self.canonicalize_nans(v1); + let v2 = self.canonicalize_nans(v2); + let res = self + .builder + .build_call( + self.intrinsics.div_f64, + &[ + v1.as_basic_value_enum(), + v2.as_basic_value_enum(), + self.intrinsics.fp_rounding_md, + self.intrinsics.fp_exception_md, + ], + "", + ) + .try_as_basic_value() + .left() + .unwrap(); + + self.state.push1(res); } Operator::F32x4Div => { - let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; - let (v1, _) = self.v128_into_f32x4(v1, i1); - let (v2, _) = self.v128_into_f32x4(v2, i2); - let res = self.builder.build_float_div(v1, v2, ""); + let (v1, v2) = self.state.pop2()?; + let v1 = self.v128_into_f32x4(v1); + let v2 = self.v128_into_f32x4(v2); + + let res = self + .builder + .build_call( + self.intrinsics.div_f32x4, + &[ + v1.as_basic_value_enum(), + v2.as_basic_value_enum(), + self.intrinsics.fp_rounding_md, + self.intrinsics.fp_exception_md, + ], + "", + ) + .try_as_basic_value() + .left() + .unwrap(); + let res = self.builder.build_bitcast(res, self.intrinsics.i128_ty, ""); - self.state.push1_extra(res, ExtraInfo::pending_f32_nan()); + self.state.push1(res); } Operator::F64x2Div => { - let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; - let (v1, _) = self.v128_into_f64x2(v1, i1); - let (v2, _) = self.v128_into_f64x2(v2, i2); - let res = self.builder.build_float_div(v1, v2, ""); + let (v1, v2) = self.state.pop2()?; + let v1 = self.v128_into_f64x2(v1); + let v2 = self.v128_into_f64x2(v2); + + let res = self + .builder + .build_call( + self.intrinsics.div_f64x2, + &[ + v1.as_basic_value_enum(), + v2.as_basic_value_enum(), + self.intrinsics.fp_rounding_md, + self.intrinsics.fp_exception_md, + ], + "", + ) + .try_as_basic_value() + .left() + .unwrap(); + let res = self.builder.build_bitcast(res, self.intrinsics.i128_ty, ""); - self.state.push1_extra(res, ExtraInfo::pending_f64_nan()); + self.state.push1(res); } + Operator::F32Sqrt => { let input = self.state.pop1()?; + let input = self.canonicalize_nans(input); let res = self .builder - .build_call(self.intrinsics.sqrt_f32, &[input], "") + .build_call( + self.intrinsics.sqrt_f32, + &[ + input, + self.intrinsics.fp_rounding_md, + self.intrinsics.fp_exception_md, + ], + "", + ) .try_as_basic_value() .left() .unwrap(); - self.state.push1_extra(res, ExtraInfo::pending_f32_nan()); + + self.state.push1(res); } Operator::F64Sqrt => { let input = self.state.pop1()?; + let input = self.canonicalize_nans(input); let res = self .builder - .build_call(self.intrinsics.sqrt_f64, &[input], "") + .build_call( + self.intrinsics.sqrt_f64, + &[ + input, + self.intrinsics.fp_rounding_md, + self.intrinsics.fp_exception_md, + ], + "", + ) .try_as_basic_value() .left() .unwrap(); - self.state.push1_extra(res, ExtraInfo::pending_f64_nan()); + + self.state.push1(res); } Operator::F32x4Sqrt => { - let (v, i) = self.state.pop1_extra()?; - let (v, _) = self.v128_into_f32x4(v, i); + let v = self.state.pop1()?; + let v = self.v128_into_f32x4(v); + let res = self .builder - .build_call(self.intrinsics.sqrt_f32x4, &[v.as_basic_value_enum()], "") + .build_call( + self.intrinsics.sqrt_f32x4, + &[ + v.as_basic_value_enum(), + self.intrinsics.fp_rounding_md, + self.intrinsics.fp_exception_md, + ], + "", + ) .try_as_basic_value() .left() .unwrap(); - let bits = self - .builder - .build_bitcast(res, self.intrinsics.i128_ty, "bits"); - self.state.push1_extra(bits, ExtraInfo::pending_f32_nan()); + + let res = self.builder.build_bitcast(res, self.intrinsics.i128_ty, ""); + self.state.push1(res); } Operator::F64x2Sqrt => { - let (v, i) = self.state.pop1_extra()?; - let (v, _) = self.v128_into_f64x2(v, i); + let v = self.state.pop1()?; + let v = self.v128_into_f64x2(v); + let res = self .builder - .build_call(self.intrinsics.sqrt_f64x2, &[v.as_basic_value_enum()], "") + .build_call( + self.intrinsics.sqrt_f64x2, + &[ + v.as_basic_value_enum(), + self.intrinsics.fp_rounding_md, + self.intrinsics.fp_exception_md, + ], + "", + ) .try_as_basic_value() .left() .unwrap(); - let bits = self - .builder - .build_bitcast(res, self.intrinsics.i128_ty, "bits"); + + let bits = self.builder.build_bitcast(res, self.intrinsics.i128_ty, ""); self.state.push1(bits); } + Operator::F32Min => { // This implements the same logic as LLVM's @llvm.minimum // intrinsic would, but x86 lowering of that intrinsic - // encounters a fatal error in LLVM 8 and LLVM 9. + // encounters a fatal error in LLVM 11. let (v1, v2) = self.state.pop2()?; - // To detect min(-0.0, 0.0), we check whether the integer - // representations are equal. There's one other case where that - // can happen: non-canonical NaNs. Here we unconditionally - // canonicalize the NaNs. - let v1 = self.canonicalize_nans(v1); - let v2 = self.canonicalize_nans(v2); - - let (v1, v2) = (v1.into_float_value(), v2.into_float_value()); - let v1_is_nan = self.builder.build_float_compare( - FloatPredicate::UNO, - v1, - self.intrinsics.f32_zero, - "nan", - ); - let v2_is_not_nan = self.builder.build_float_compare( - FloatPredicate::ORD, - v2, - self.intrinsics.f32_zero, - "notnan", - ); - let v1_repr = self + let v1_is_nan = self .builder - .build_bitcast(v1, self.intrinsics.i32_ty, "") + .build_call( + self.intrinsics.cmp_f32, + &[ + v1, + self.intrinsics.f32_zero.as_basic_value_enum(), + self.intrinsics.fp_uno_md, + self.intrinsics.fp_exception_md, + ], + "", + ) + .try_as_basic_value() + .left() + .unwrap() .into_int_value(); - let v2_repr = self + let v2_is_nan = self .builder - .build_bitcast(v2, self.intrinsics.i32_ty, "") + .build_call( + self.intrinsics.cmp_f32, + &[ + v2, + self.intrinsics.f32_zero.as_basic_value_enum(), + self.intrinsics.fp_uno_md, + self.intrinsics.fp_exception_md, + ], + "", + ) + .try_as_basic_value() + .left() + .unwrap() .into_int_value(); - let repr_ne = - self.builder - .build_int_compare(IntPredicate::NE, v1_repr, v2_repr, ""); - let float_eq = self - .builder - .build_float_compare(FloatPredicate::OEQ, v1, v2, ""); - let min_cmp = self + let v1_lt_v2 = self .builder - .build_float_compare(FloatPredicate::OLT, v1, v2, ""); - let negative_zero = self.intrinsics.f32_ty.const_float(-0.0); - let v2 = self + .build_call( + self.intrinsics.cmp_f32, + &[ + v1, + v2, + self.intrinsics.fp_olt_md, + self.intrinsics.fp_exception_md, + ], + "", + ) + .try_as_basic_value() + .left() + .unwrap() + .into_int_value(); + let v1_gt_v2 = self .builder - .build_select( - self.builder.build_and( - self.builder.build_and(float_eq, repr_ne, ""), - v2_is_not_nan, - "", - ), - negative_zero, - v2, + .build_call( + self.intrinsics.cmp_f32, + &[ + v1, + v2, + self.intrinsics.fp_ogt_md, + self.intrinsics.fp_exception_md, + ], "", ) - .into_float_value(); + .try_as_basic_value() + .left() + .unwrap() + .into_int_value(); + let res = self.builder.build_select( - self.builder.build_or(v1_is_nan, min_cmp, ""), - v1, - v2, + v1_is_nan, + self.canonicalize_nans(v1), + self.builder.build_select( + v2_is_nan, + self.canonicalize_nans(v2), + self.builder.build_select( + v1_lt_v2, + v1, + self.builder.build_select( + v1_gt_v2, + v2, + self.builder.build_bitcast( + self.builder.build_or( + self.builder + .build_bitcast(v1, self.intrinsics.i32_ty, "") + .into_int_value(), + self.builder + .build_bitcast(v2, self.intrinsics.i32_ty, "") + .into_int_value(), + "", + ), + self.intrinsics.f32_ty, + "", + ), + "", + ), + "", + ), + "", + ), "", ); - // Because inputs were canonicalized, we always produce - // canonical NaN outputs. No pending NaN cleanup. - self.state.push1_extra(res, ExtraInfo::arithmetic_f32()); + + self.state.push1(res); } Operator::F64Min => { // This implements the same logic as LLVM's @llvm.minimum // intrinsic would, but x86 lowering of that intrinsic - // encounters a fatal error in LLVM 8 and LLVM 9. + // encounters a fatal error in LLVM 11. let (v1, v2) = self.state.pop2()?; - // To detect min(-0.0, 0.0), we check whether the integer - // representations are equal. There's one other case where that - // can happen: non-canonical NaNs. Here we unconditionally - // canonicalize the NaNs. - let v1 = self.canonicalize_nans(v1); - let v2 = self.canonicalize_nans(v2); - - let (v1, v2) = (v1.into_float_value(), v2.into_float_value()); - let v1_is_nan = self.builder.build_float_compare( - FloatPredicate::UNO, - v1, - self.intrinsics.f64_zero, - "nan", - ); - let v2_is_not_nan = self.builder.build_float_compare( - FloatPredicate::ORD, - v2, - self.intrinsics.f64_zero, - "notnan", - ); - let v1_repr = self + let v1_is_nan = self .builder - .build_bitcast(v1, self.intrinsics.i64_ty, "") + .build_call( + self.intrinsics.cmp_f64, + &[ + v1, + self.intrinsics.f64_zero.as_basic_value_enum(), + self.intrinsics.fp_uno_md, + self.intrinsics.fp_exception_md, + ], + "", + ) + .try_as_basic_value() + .left() + .unwrap() .into_int_value(); - let v2_repr = self + let v2_is_nan = self .builder - .build_bitcast(v2, self.intrinsics.i64_ty, "") + .build_call( + self.intrinsics.cmp_f64, + &[ + v2, + self.intrinsics.f64_zero.as_basic_value_enum(), + self.intrinsics.fp_uno_md, + self.intrinsics.fp_exception_md, + ], + "", + ) + .try_as_basic_value() + .left() + .unwrap() .into_int_value(); - let repr_ne = - self.builder - .build_int_compare(IntPredicate::NE, v1_repr, v2_repr, ""); - let float_eq = self - .builder - .build_float_compare(FloatPredicate::OEQ, v1, v2, ""); - let min_cmp = self - .builder - .build_float_compare(FloatPredicate::OLT, v1, v2, ""); - let negative_zero = self.intrinsics.f64_ty.const_float(-0.0); - let v2 = self + let v1_lt_v2 = self .builder - .build_select( - self.builder.build_and( - self.builder.build_and(float_eq, repr_ne, ""), - v2_is_not_nan, - "", - ), - negative_zero, - v2, + .build_call( + self.intrinsics.cmp_f64, + &[ + v1, + v2, + self.intrinsics.fp_olt_md, + self.intrinsics.fp_exception_md, + ], "", ) - .into_float_value(); - let res = self.builder.build_select( - self.builder.build_or(v1_is_nan, min_cmp, ""), - v1, - v2, - "", - ); - // Because inputs were canonicalized, we always produce - // canonical NaN outputs. No pending NaN cleanup. - self.state.push1_extra(res, ExtraInfo::arithmetic_f64()); - } - Operator::F32x4Min => { - // a) check v1 and v2 for NaN - // b) check v2 for zero - // c) check v1 for sign - // - // We pick v1 iff - // v1 is NaN or - // v2 is not NaN and either - // v1 < v2 or - // v2 is ±zero and v1 is negative. - - let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; - let (v1, i1) = self.v128_into_f32x4(v1, i1); - let (v2, i2) = self.v128_into_f32x4(v2, i2); - let v1 = if !i1.is_arithmetic_f32() { - self.canonicalize_nans(v1.as_basic_value_enum()) - .into_vector_value() - } else { - v1 - }; - let v2 = if !i2.is_arithmetic_f32() { - self.canonicalize_nans(v2.as_basic_value_enum()) - .into_vector_value() - } else { - v2 - }; - - let v1_is_nan = self.builder.build_float_compare( - FloatPredicate::UNO, - v1, - self.intrinsics.f32x4_zero, - "v1nan", - ); - let v2_is_notnan = self.builder.build_float_compare( - FloatPredicate::ORD, - v2, - self.intrinsics.f32x4_zero, - "v2notnan", - ); - - let v2_is_zero = self.builder.build_float_compare( - FloatPredicate::OEQ, - v2, - self.intrinsics.f32x4_zero, - "v2zero", - ); - - let v1_is_negative = self.builder.build_float_compare( - FloatPredicate::OLT, - self.builder - .build_call( - self.intrinsics.copysign_f32x4, - &[ - VectorType::const_vector( - &[self - .intrinsics - .f32_ty - .const_float(1.0) - .as_basic_value_enum(); - 4], - ) - .as_basic_value_enum(), - v1.as_basic_value_enum(), - ], - "", - ) - .try_as_basic_value() - .left() - .unwrap() - .into_vector_value(), - self.intrinsics.f32x4_zero, - "v1neg", - ); - - let v1_lt_v2 = self + .try_as_basic_value() + .left() + .unwrap() + .into_int_value(); + let v1_gt_v2 = self .builder - .build_float_compare(FloatPredicate::OLT, v1, v2, ""); + .build_call( + self.intrinsics.cmp_f64, + &[ + v1, + v2, + self.intrinsics.fp_ogt_md, + self.intrinsics.fp_exception_md, + ], + "", + ) + .try_as_basic_value() + .left() + .unwrap() + .into_int_value(); - let pick_v1 = self.builder.build_or( + let res = self.builder.build_select( v1_is_nan, - self.builder.build_and( - v2_is_notnan, - self.builder.build_or( + self.canonicalize_nans(v1), + self.builder.build_select( + v2_is_nan, + self.canonicalize_nans(v2), + self.builder.build_select( v1_lt_v2, - self.builder.build_and(v1_is_negative, v2_is_zero, ""), + v1, + self.builder.build_select( + v1_gt_v2, + v2, + self.builder.build_bitcast( + self.builder.build_or( + self.builder + .build_bitcast(v1, self.intrinsics.i64_ty, "") + .into_int_value(), + self.builder + .build_bitcast(v2, self.intrinsics.i64_ty, "") + .into_int_value(), + "", + ), + self.intrinsics.f64_ty, + "", + ), + "", + ), "", ), "", @@ -3916,558 +3931,850 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { "", ); - let res = self.builder.build_select(pick_v1, v1, v2, ""); - let res = self.builder.build_bitcast(res, self.intrinsics.i128_ty, ""); self.state.push1(res); } - Operator::F64x2Min => { - // a) check v1 and v2 for NaN - // b) check v2 for zero - // c) check v1 for sign - // - // We pick v1 iff - // v1 is NaN or - // v2 is not NaN and either - // v1 < v2 or - // v2 is ±zero and v1 is negative. - - let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; - let (v1, i1) = self.v128_into_f64x2(v1, i1); - let (v2, i2) = self.v128_into_f64x2(v2, i2); - let v1 = if !i1.is_arithmetic_f64() { - self.canonicalize_nans(v1.as_basic_value_enum()) - .into_vector_value() - } else { - v1 - }; - let v2 = if !i2.is_arithmetic_f64() { - self.canonicalize_nans(v2.as_basic_value_enum()) - .into_vector_value() - } else { - v2 - }; - - let v1_is_nan = self.builder.build_float_compare( - FloatPredicate::UNO, - v1, - self.intrinsics.f64x2_zero, - "v1nan", - ); - let v2_is_notnan = self.builder.build_float_compare( - FloatPredicate::ORD, - v2, - self.intrinsics.f64x2_zero, - "v2notnan", - ); + Operator::F32x4Min => { + // This implements the same logic as LLVM's @llvm.minimum + // intrinsic would, but x86 lowering of that intrinsic + // encounters a fatal error in LLVM 11. + let (v1, v2) = self.state.pop2()?; + let v1 = self.v128_into_f32x4(v1).as_basic_value_enum(); + let v2 = self.v128_into_f32x4(v2).as_basic_value_enum(); - let v2_is_zero = self.builder.build_float_compare( - FloatPredicate::OEQ, - v2, - self.intrinsics.f64x2_zero, - "v2zero", - ); + let v1_is_nan = self + .builder + .build_call( + self.intrinsics.cmp_f32x4, + &[ + v1, + self.intrinsics.f32x4_zero.as_basic_value_enum(), + self.intrinsics.fp_uno_md, + self.intrinsics.fp_exception_md, + ], + "", + ) + .try_as_basic_value() + .left() + .unwrap() + .into_vector_value(); + let v2_is_nan = self + .builder + .build_call( + self.intrinsics.cmp_f32x4, + &[ + v2, + self.intrinsics.f32x4_zero.as_basic_value_enum(), + self.intrinsics.fp_uno_md, + self.intrinsics.fp_exception_md, + ], + "", + ) + .try_as_basic_value() + .left() + .unwrap() + .into_vector_value(); + let v1_lt_v2 = self + .builder + .build_call( + self.intrinsics.cmp_f32x4, + &[ + v1, + v2, + self.intrinsics.fp_olt_md, + self.intrinsics.fp_exception_md, + ], + "", + ) + .try_as_basic_value() + .left() + .unwrap() + .into_vector_value(); + let v1_gt_v2 = self + .builder + .build_call( + self.intrinsics.cmp_f32x4, + &[ + v1, + v2, + self.intrinsics.fp_ogt_md, + self.intrinsics.fp_exception_md, + ], + "", + ) + .try_as_basic_value() + .left() + .unwrap() + .into_vector_value(); - let v1_is_negative = self.builder.build_float_compare( - FloatPredicate::OLT, + let res = self.builder.build_select( + v1_is_nan, + self.canonicalize_nans(v1).into_vector_value(), self.builder - .build_call( - self.intrinsics.copysign_f64x2, - &[ - VectorType::const_vector( - &[self - .intrinsics - .f64_ty - .const_float(1.0) - .as_basic_value_enum(); - 2], + .build_select( + v2_is_nan, + self.canonicalize_nans(v2).into_vector_value(), + self.builder + .build_select( + v1_lt_v2, + v1, + self.builder.build_select( + v1_gt_v2, + v2, + self.builder.build_bitcast( + self.builder.build_or( + self.builder + .build_bitcast(v1, self.intrinsics.i32x4_ty, "") + .into_vector_value(), + self.builder + .build_bitcast(v2, self.intrinsics.i32x4_ty, "") + .into_vector_value(), + "", + ), + self.intrinsics.f32x4_ty, + "", + ), + "", + ), + "", ) - .as_basic_value_enum(), - v1.as_basic_value_enum(), - ], + .into_vector_value(), "", ) - .try_as_basic_value() - .left() - .unwrap() .into_vector_value(), - self.intrinsics.f64x2_zero, - "v1neg", - ); - - let v1_lt_v2 = self - .builder - .build_float_compare(FloatPredicate::OLT, v1, v2, ""); - - let pick_v1 = self.builder.build_or( - v1_is_nan, - self.builder.build_and( - v2_is_notnan, - self.builder.build_or( - v1_lt_v2, - self.builder.build_and(v1_is_negative, v2_is_zero, ""), - "", - ), - "", - ), "", ); - let res = self.builder.build_select(pick_v1, v1, v2, ""); let res = self.builder.build_bitcast(res, self.intrinsics.i128_ty, ""); self.state.push1(res); } - Operator::F32Max => { - // This implements the same logic as LLVM's @llvm.maximum + Operator::F64x2Min => { + // This implements the same logic as LLVM's @llvm.minimum // intrinsic would, but x86 lowering of that intrinsic - // encounters a fatal error in LLVM 8 and LLVM 9. + // encounters a fatal error in LLVM 11. let (v1, v2) = self.state.pop2()?; + let v1 = self.v128_into_f64x2(v1).as_basic_value_enum(); + let v2 = self.v128_into_f64x2(v2).as_basic_value_enum(); - // To detect min(-0.0, 0.0), we check whether the integer - // representations are equal. There's one other case where that - // can happen: non-canonical NaNs. Here we unconditionally - // canonicalize the NaNs. - let v1 = self.canonicalize_nans(v1); - let v2 = self.canonicalize_nans(v2); - - let (v1, v2) = (v1.into_float_value(), v2.into_float_value()); - let v1_is_nan = self.builder.build_float_compare( - FloatPredicate::UNO, - v1, - self.intrinsics.f32_zero, - "nan", - ); - let v2_is_not_nan = self.builder.build_float_compare( - FloatPredicate::ORD, - v2, - self.intrinsics.f32_zero, - "notnan", - ); - let v1_repr = self - .builder - .build_bitcast(v1, self.intrinsics.i32_ty, "") - .into_int_value(); - let v2_repr = self - .builder - .build_bitcast(v2, self.intrinsics.i32_ty, "") - .into_int_value(); - let repr_ne = - self.builder - .build_int_compare(IntPredicate::NE, v1_repr, v2_repr, ""); - let float_eq = self - .builder - .build_float_compare(FloatPredicate::OEQ, v1, v2, ""); - let min_cmp = self - .builder - .build_float_compare(FloatPredicate::OGT, v1, v2, ""); - let v2 = self + let v1_is_nan = self .builder - .build_select( - self.builder.build_and( - self.builder.build_and(float_eq, repr_ne, ""), - v2_is_not_nan, - "", - ), - self.intrinsics.f32_zero, - v2, + .build_call( + self.intrinsics.cmp_f64x2, + &[ + v1, + self.intrinsics.f64x2_zero.as_basic_value_enum(), + self.intrinsics.fp_uno_md, + self.intrinsics.fp_exception_md, + ], "", ) - .into_float_value(); + .try_as_basic_value() + .left() + .unwrap() + .into_vector_value(); + let v2_is_nan = self + .builder + .build_call( + self.intrinsics.cmp_f64x2, + &[ + v2, + self.intrinsics.f64x2_zero.as_basic_value_enum(), + self.intrinsics.fp_uno_md, + self.intrinsics.fp_exception_md, + ], + "", + ) + .try_as_basic_value() + .left() + .unwrap() + .into_vector_value(); + let v1_lt_v2 = self + .builder + .build_call( + self.intrinsics.cmp_f64x2, + &[ + v1, + v2, + self.intrinsics.fp_olt_md, + self.intrinsics.fp_exception_md, + ], + "", + ) + .try_as_basic_value() + .left() + .unwrap() + .into_vector_value(); + let v1_gt_v2 = self + .builder + .build_call( + self.intrinsics.cmp_f64x2, + &[ + v1, + v2, + self.intrinsics.fp_ogt_md, + self.intrinsics.fp_exception_md, + ], + "", + ) + .try_as_basic_value() + .left() + .unwrap() + .into_vector_value(); + let res = self.builder.build_select( - self.builder.build_or(v1_is_nan, min_cmp, ""), - v1, - v2, + v1_is_nan, + self.canonicalize_nans(v1).into_vector_value(), + self.builder + .build_select( + v2_is_nan, + self.canonicalize_nans(v2).into_vector_value(), + self.builder + .build_select( + v1_lt_v2, + v1, + self.builder.build_select( + v1_gt_v2, + v2, + self.builder.build_bitcast( + self.builder.build_or( + self.builder + .build_bitcast(v1, self.intrinsics.i64x2_ty, "") + .into_vector_value(), + self.builder + .build_bitcast(v2, self.intrinsics.i64x2_ty, "") + .into_vector_value(), + "", + ), + self.intrinsics.f64x2_ty, + "", + ), + "", + ), + "", + ) + .into_vector_value(), + "", + ) + .into_vector_value(), "", ); - // Because inputs were canonicalized, we always produce - // canonical NaN outputs. No pending NaN cleanup. - self.state.push1_extra(res, ExtraInfo::arithmetic_f32()); + + let res = self.builder.build_bitcast(res, self.intrinsics.i128_ty, ""); + self.state.push1(res); } - Operator::F64Max => { - // This implements the same logic as LLVM's @llvm.maximum + + Operator::F32Max => { + // This implements the same logic as LLVM's @llvm.minimum // intrinsic would, but x86 lowering of that intrinsic - // encounters a fatal error in LLVM 8 and LLVM 9. + // encounters a fatal error in LLVM 11. let (v1, v2) = self.state.pop2()?; - // To detect min(-0.0, 0.0), we check whether the integer - // representations are equal. There's one other case where that - // can happen: non-canonical NaNs. Here we unconditionally - // canonicalize the NaNs. - let v1 = self.canonicalize_nans(v1); - let v2 = self.canonicalize_nans(v2); - - let (v1, v2) = (v1.into_float_value(), v2.into_float_value()); - let v1_is_nan = self.builder.build_float_compare( - FloatPredicate::UNO, - v1, - self.intrinsics.f64_zero, - "nan", - ); - let v2_is_not_nan = self.builder.build_float_compare( - FloatPredicate::ORD, - v2, - self.intrinsics.f64_zero, - "notnan", - ); - let v1_repr = self + let v1_is_nan = self .builder - .build_bitcast(v1, self.intrinsics.i64_ty, "") + .build_call( + self.intrinsics.cmp_f32, + &[ + v1, + self.intrinsics.f32_zero.as_basic_value_enum(), + self.intrinsics.fp_uno_md, + self.intrinsics.fp_exception_md, + ], + "", + ) + .try_as_basic_value() + .left() + .unwrap() .into_int_value(); - let v2_repr = self + let v2_is_nan = self .builder - .build_bitcast(v2, self.intrinsics.i64_ty, "") + .build_call( + self.intrinsics.cmp_f32, + &[ + v2, + self.intrinsics.f32_zero.as_basic_value_enum(), + self.intrinsics.fp_uno_md, + self.intrinsics.fp_exception_md, + ], + "", + ) + .try_as_basic_value() + .left() + .unwrap() .into_int_value(); - let repr_ne = - self.builder - .build_int_compare(IntPredicate::NE, v1_repr, v2_repr, ""); - let float_eq = self - .builder - .build_float_compare(FloatPredicate::OEQ, v1, v2, ""); - let min_cmp = self + let v1_lt_v2 = self .builder - .build_float_compare(FloatPredicate::OGT, v1, v2, ""); - let v2 = self + .build_call( + self.intrinsics.cmp_f32, + &[ + v1, + v2, + self.intrinsics.fp_olt_md, + self.intrinsics.fp_exception_md, + ], + "", + ) + .try_as_basic_value() + .left() + .unwrap() + .into_int_value(); + let v1_gt_v2 = self .builder - .build_select( - self.builder.build_and( - self.builder.build_and(float_eq, repr_ne, ""), - v2_is_not_nan, - "", - ), - self.intrinsics.f64_zero, - v2, + .build_call( + self.intrinsics.cmp_f32, + &[ + v1, + v2, + self.intrinsics.fp_ogt_md, + self.intrinsics.fp_exception_md, + ], "", ) - .into_float_value(); + .try_as_basic_value() + .left() + .unwrap() + .into_int_value(); + let res = self.builder.build_select( - self.builder.build_or(v1_is_nan, min_cmp, ""), - v1, - v2, + v1_is_nan, + self.canonicalize_nans(v1), + self.builder.build_select( + v2_is_nan, + self.canonicalize_nans(v2), + self.builder.build_select( + v1_lt_v2, + v2, + self.builder.build_select( + v1_gt_v2, + v1, + self.builder.build_bitcast( + self.builder.build_and( + self.builder + .build_bitcast(v1, self.intrinsics.i32_ty, "") + .into_int_value(), + self.builder + .build_bitcast(v2, self.intrinsics.i32_ty, "") + .into_int_value(), + "", + ), + self.intrinsics.f32_ty, + "", + ), + "", + ), + "", + ), + "", + ), "", ); - // Because inputs were canonicalized, we always produce - // canonical NaN outputs. No pending NaN cleanup. - self.state.push1_extra(res, ExtraInfo::arithmetic_f64()); - } - Operator::F32x4Max => { - // a) check v1 and v2 for NaN - // b) check v2 for zero - // c) check v1 for sign - // - // We pick v1 iff - // v1 is NaN or - // v2 is not NaN and either - // v1 > v2 or - // v1 is ±zero and v2 is negative. - - let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; - let (v1, i1) = self.v128_into_f32x4(v1, i1); - let (v2, i2) = self.v128_into_f32x4(v2, i2); - let v1 = if !i1.is_arithmetic_f32() { - self.canonicalize_nans(v1.as_basic_value_enum()) - .into_vector_value() - } else { - v1 - }; - let v2 = if !i2.is_arithmetic_f32() { - self.canonicalize_nans(v2.as_basic_value_enum()) - .into_vector_value() - } else { - v2 - }; - let v1_is_nan = self.builder.build_float_compare( - FloatPredicate::UNO, - v1, - self.intrinsics.f32x4_zero, - "v1nan", - ); - let v2_is_notnan = self.builder.build_float_compare( - FloatPredicate::ORD, - v2, - self.intrinsics.f32x4_zero, - "v2notnan", - ); + self.state.push1(res); + } + Operator::F64Max => { + // This implements the same logic as LLVM's @llvm.minimum + // intrinsic would, but x86 lowering of that intrinsic + // encounters a fatal error in LLVM 11. + let (v1, v2) = self.state.pop2()?; - let v1_is_zero = self.builder.build_float_compare( - FloatPredicate::OEQ, - v1, - self.intrinsics.f32x4_zero, - "v1zero", - ); + let v1_is_nan = self + .builder + .build_call( + self.intrinsics.cmp_f64, + &[ + v1, + self.intrinsics.f64_zero.as_basic_value_enum(), + self.intrinsics.fp_uno_md, + self.intrinsics.fp_exception_md, + ], + "", + ) + .try_as_basic_value() + .left() + .unwrap() + .into_int_value(); + let v2_is_nan = self + .builder + .build_call( + self.intrinsics.cmp_f64, + &[ + v2, + self.intrinsics.f64_zero.as_basic_value_enum(), + self.intrinsics.fp_uno_md, + self.intrinsics.fp_exception_md, + ], + "", + ) + .try_as_basic_value() + .left() + .unwrap() + .into_int_value(); + let v1_lt_v2 = self + .builder + .build_call( + self.intrinsics.cmp_f64, + &[ + v1, + v2, + self.intrinsics.fp_olt_md, + self.intrinsics.fp_exception_md, + ], + "", + ) + .try_as_basic_value() + .left() + .unwrap() + .into_int_value(); + let v1_gt_v2 = self + .builder + .build_call( + self.intrinsics.cmp_f64, + &[ + v1, + v2, + self.intrinsics.fp_ogt_md, + self.intrinsics.fp_exception_md, + ], + "", + ) + .try_as_basic_value() + .left() + .unwrap() + .into_int_value(); - let v2_is_negative = self.builder.build_float_compare( - FloatPredicate::OLT, - self.builder - .build_call( - self.intrinsics.copysign_f32x4, - &[ - VectorType::const_vector( - &[self - .intrinsics - .f32_ty - .const_float(1.0) - .as_basic_value_enum(); - 4], - ) - .as_basic_value_enum(), - v2.as_basic_value_enum(), - ], + let res = self.builder.build_select( + v1_is_nan, + self.canonicalize_nans(v1), + self.builder.build_select( + v2_is_nan, + self.canonicalize_nans(v2), + self.builder.build_select( + v1_lt_v2, + v2, + self.builder.build_select( + v1_gt_v2, + v1, + self.builder.build_bitcast( + self.builder.build_and( + self.builder + .build_bitcast(v1, self.intrinsics.i64_ty, "") + .into_int_value(), + self.builder + .build_bitcast(v2, self.intrinsics.i64_ty, "") + .into_int_value(), + "", + ), + self.intrinsics.f64_ty, + "", + ), + "", + ), "", - ) - .try_as_basic_value() - .left() - .unwrap() - .into_vector_value(), - self.intrinsics.f32x4_zero, - "v2neg", + ), + "", + ), + "", ); + self.state.push1(res); + } + Operator::F32x4Max => { + // This implements the same logic as LLVM's @llvm.minimum + // intrinsic would, but x86 lowering of that intrinsic + // encounters a fatal error in LLVM 11. + let (v1, v2) = self.state.pop2()?; + let v1 = self.v128_into_f32x4(v1).as_basic_value_enum(); + let v2 = self.v128_into_f32x4(v2).as_basic_value_enum(); + + let v1_is_nan = self + .builder + .build_call( + self.intrinsics.cmp_f32x4, + &[ + v1, + self.intrinsics.f32x4_zero.as_basic_value_enum(), + self.intrinsics.fp_uno_md, + self.intrinsics.fp_exception_md, + ], + "", + ) + .try_as_basic_value() + .left() + .unwrap() + .into_vector_value(); + let v2_is_nan = self + .builder + .build_call( + self.intrinsics.cmp_f32x4, + &[ + v2, + self.intrinsics.f32x4_zero.as_basic_value_enum(), + self.intrinsics.fp_uno_md, + self.intrinsics.fp_exception_md, + ], + "", + ) + .try_as_basic_value() + .left() + .unwrap() + .into_vector_value(); + let v1_lt_v2 = self + .builder + .build_call( + self.intrinsics.cmp_f32x4, + &[ + v1, + v2, + self.intrinsics.fp_olt_md, + self.intrinsics.fp_exception_md, + ], + "", + ) + .try_as_basic_value() + .left() + .unwrap() + .into_vector_value(); let v1_gt_v2 = self .builder - .build_float_compare(FloatPredicate::OGT, v1, v2, ""); + .build_call( + self.intrinsics.cmp_f32x4, + &[ + v1, + v2, + self.intrinsics.fp_ogt_md, + self.intrinsics.fp_exception_md, + ], + "", + ) + .try_as_basic_value() + .left() + .unwrap() + .into_vector_value(); - let pick_v1 = self.builder.build_or( + let res = self.builder.build_select( v1_is_nan, - self.builder.build_and( - v2_is_notnan, - self.builder.build_or( - v1_gt_v2, - self.builder.build_and(v1_is_zero, v2_is_negative, ""), + self.canonicalize_nans(v1).into_vector_value(), + self.builder + .build_select( + v2_is_nan, + self.canonicalize_nans(v2).into_vector_value(), + self.builder + .build_select( + v1_lt_v2, + v2, + self.builder.build_select( + v1_gt_v2, + v1, + self.builder.build_bitcast( + self.builder.build_and( + self.builder + .build_bitcast(v1, self.intrinsics.i32x4_ty, "") + .into_vector_value(), + self.builder + .build_bitcast(v2, self.intrinsics.i32x4_ty, "") + .into_vector_value(), + "", + ), + self.intrinsics.f32x4_ty, + "", + ), + "", + ), + "", + ) + .into_vector_value(), "", - ), - "", - ), + ) + .into_vector_value(), "", ); - let res = self.builder.build_select(pick_v1, v1, v2, ""); let res = self.builder.build_bitcast(res, self.intrinsics.i128_ty, ""); self.state.push1(res); } Operator::F64x2Max => { - // a) check v1 and v2 for NaN - // b) check v2 for zero - // c) check v1 for sign - // - // We pick v1 iff - // v1 is NaN or - // v2 is not NaN and either - // v1 > v2 or - // v1 is ±zero and v2 is negative. - - let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; - let (v1, i1) = self.v128_into_f64x2(v1, i1); - let (v2, i2) = self.v128_into_f64x2(v2, i2); - let v1 = if !i1.is_arithmetic_f64() { - self.canonicalize_nans(v1.as_basic_value_enum()) - .into_vector_value() - } else { - v1 - }; - let v2 = if !i2.is_arithmetic_f64() { - self.canonicalize_nans(v2.as_basic_value_enum()) - .into_vector_value() - } else { - v2 - }; - - let v1_is_nan = self.builder.build_float_compare( - FloatPredicate::UNO, - v1, - self.intrinsics.f64x2_zero, - "v1nan", - ); - let v2_is_notnan = self.builder.build_float_compare( - FloatPredicate::ORD, - v2, - self.intrinsics.f64x2_zero, - "v2notnan", - ); + // This implements the same logic as LLVM's @llvm.minimum + // intrinsic would, but x86 lowering of that intrinsic + // encounters a fatal error in LLVM 11. + let (v1, v2) = self.state.pop2()?; + let v1 = self.v128_into_f64x2(v1).as_basic_value_enum(); + let v2 = self.v128_into_f64x2(v2).as_basic_value_enum(); - let v1_is_zero = self.builder.build_float_compare( - FloatPredicate::OEQ, - v1, - self.intrinsics.f64x2_zero, - "v1zero", - ); + let v1_is_nan = self + .builder + .build_call( + self.intrinsics.cmp_f64x2, + &[ + v1, + self.intrinsics.f64x2_zero.as_basic_value_enum(), + self.intrinsics.fp_uno_md, + self.intrinsics.fp_exception_md, + ], + "", + ) + .try_as_basic_value() + .left() + .unwrap() + .into_vector_value(); + let v2_is_nan = self + .builder + .build_call( + self.intrinsics.cmp_f64x2, + &[ + v2, + self.intrinsics.f64x2_zero.as_basic_value_enum(), + self.intrinsics.fp_uno_md, + self.intrinsics.fp_exception_md, + ], + "", + ) + .try_as_basic_value() + .left() + .unwrap() + .into_vector_value(); + let v1_lt_v2 = self + .builder + .build_call( + self.intrinsics.cmp_f64x2, + &[ + v1, + v2, + self.intrinsics.fp_olt_md, + self.intrinsics.fp_exception_md, + ], + "", + ) + .try_as_basic_value() + .left() + .unwrap() + .into_vector_value(); + let v1_gt_v2 = self + .builder + .build_call( + self.intrinsics.cmp_f64x2, + &[ + v1, + v2, + self.intrinsics.fp_ogt_md, + self.intrinsics.fp_exception_md, + ], + "", + ) + .try_as_basic_value() + .left() + .unwrap() + .into_vector_value(); - let v2_is_negative = self.builder.build_float_compare( - FloatPredicate::OLT, + let res = self.builder.build_select( + v1_is_nan, + self.canonicalize_nans(v1).into_vector_value(), self.builder - .build_call( - self.intrinsics.copysign_f64x2, - &[ - VectorType::const_vector( - &[self - .intrinsics - .f64_ty - .const_float(1.0) - .as_basic_value_enum(); - 2], + .build_select( + v2_is_nan, + self.canonicalize_nans(v2).into_vector_value(), + self.builder + .build_select( + v1_lt_v2, + v2, + self.builder.build_select( + v1_gt_v2, + v1, + self.builder.build_bitcast( + self.builder.build_and( + self.builder + .build_bitcast(v1, self.intrinsics.i64x2_ty, "") + .into_vector_value(), + self.builder + .build_bitcast(v2, self.intrinsics.i64x2_ty, "") + .into_vector_value(), + "", + ), + self.intrinsics.f64x2_ty, + "", + ), + "", + ), + "", ) - .as_basic_value_enum(), - v2.as_basic_value_enum(), - ], + .into_vector_value(), "", ) - .try_as_basic_value() - .left() - .unwrap() .into_vector_value(), - self.intrinsics.f64x2_zero, - "v2neg", - ); - - let v1_gt_v2 = self - .builder - .build_float_compare(FloatPredicate::OGT, v1, v2, ""); - - let pick_v1 = self.builder.build_or( - v1_is_nan, - self.builder.build_and( - v2_is_notnan, - self.builder.build_or( - v1_gt_v2, - self.builder.build_and(v1_is_zero, v2_is_negative, ""), - "", - ), - "", - ), "", ); - let res = self.builder.build_select(pick_v1, v1, v2, ""); let res = self.builder.build_bitcast(res, self.intrinsics.i128_ty, ""); self.state.push1(res); } + Operator::F32Ceil => { - let (input, info) = self.state.pop1_extra()?; + let input = self.state.pop1()?; + let input = self.canonicalize_nans(input); let res = self .builder - .build_call(self.intrinsics.ceil_f32, &[input], "") + .build_call( + self.intrinsics.ceil_f32, + &[input, self.intrinsics.fp_exception_md], + "", + ) .try_as_basic_value() .left() .unwrap(); - self.state - .push1_extra(res, info | ExtraInfo::pending_f32_nan()); + + self.state.push1(res); } Operator::F64Ceil => { - let (input, info) = self.state.pop1_extra()?; + let input = self.state.pop1()?; + let input = self.canonicalize_nans(input); let res = self .builder - .build_call(self.intrinsics.ceil_f64, &[input], "") + .build_call( + self.intrinsics.ceil_f64, + &[input, self.intrinsics.fp_exception_md], + "", + ) .try_as_basic_value() .left() .unwrap(); - self.state - .push1_extra(res, info | ExtraInfo::pending_f64_nan()); + + self.state.push1(res); } + Operator::F32Floor => { - let (input, info) = self.state.pop1_extra()?; + let input = self.state.pop1()?; + let input = self.canonicalize_nans(input); let res = self .builder - .build_call(self.intrinsics.floor_f32, &[input], "") + .build_call( + self.intrinsics.floor_f32, + &[input, self.intrinsics.fp_exception_md], + "", + ) .try_as_basic_value() .left() .unwrap(); - self.state - .push1_extra(res, info | ExtraInfo::pending_f32_nan()); + + self.state.push1(res); } Operator::F64Floor => { - let (input, info) = self.state.pop1_extra()?; + let input = self.state.pop1()?; + let input = self.canonicalize_nans(input); let res = self .builder - .build_call(self.intrinsics.floor_f64, &[input], "") + .build_call( + self.intrinsics.floor_f64, + &[input, self.intrinsics.fp_exception_md], + "", + ) .try_as_basic_value() .left() .unwrap(); - self.state - .push1_extra(res, info | ExtraInfo::pending_f64_nan()); + + self.state.push1(res); } + Operator::F32Trunc => { - let (v, i) = self.state.pop1_extra()?; + let input = self.state.pop1()?; + let input = self.canonicalize_nans(input); let res = self .builder - .build_call(self.intrinsics.trunc_f32, &[v.as_basic_value_enum()], "") + .build_call( + self.intrinsics.trunc_f32, + &[input, self.intrinsics.fp_exception_md], + "", + ) .try_as_basic_value() .left() .unwrap(); - self.state - .push1_extra(res, i | ExtraInfo::pending_f32_nan()); + + self.state.push1(res); } Operator::F64Trunc => { - let (v, i) = self.state.pop1_extra()?; + let input = self.state.pop1()?; + let input = self.canonicalize_nans(input); let res = self .builder - .build_call(self.intrinsics.trunc_f64, &[v.as_basic_value_enum()], "") + .build_call( + self.intrinsics.trunc_f64, + &[input, self.intrinsics.fp_exception_md], + "", + ) .try_as_basic_value() .left() .unwrap(); - self.state - .push1_extra(res, i | ExtraInfo::pending_f64_nan()); + + self.state.push1(res); } + Operator::F32Nearest => { - let (v, i) = self.state.pop1_extra()?; + let input = self.state.pop1()?; + let input = self.canonicalize_nans(input); let res = self .builder .build_call( self.intrinsics.nearbyint_f32, - &[v.as_basic_value_enum()], + &[ + input, + self.intrinsics.fp_rounding_md, + self.intrinsics.fp_exception_md, + ], "", ) .try_as_basic_value() .left() .unwrap(); - self.state - .push1_extra(res, i | ExtraInfo::pending_f32_nan()); + + self.state.push1(res); } Operator::F64Nearest => { - let (v, i) = self.state.pop1_extra()?; + let input = self.state.pop1()?; + let input = self.canonicalize_nans(input); let res = self .builder .build_call( self.intrinsics.nearbyint_f64, - &[v.as_basic_value_enum()], + &[ + input, + self.intrinsics.fp_rounding_md, + self.intrinsics.fp_exception_md, + ], "", ) .try_as_basic_value() .left() .unwrap(); - self.state - .push1_extra(res, i | ExtraInfo::pending_f64_nan()); + + self.state.push1(res); } + Operator::F32Abs => { - let (v, i) = self.state.pop1_extra()?; - let v = self.apply_pending_canonicalization(v, i); + let v = self.state.pop1()?; + let res = self .builder .build_call(self.intrinsics.fabs_f32, &[v.as_basic_value_enum()], "") .try_as_basic_value() .left() .unwrap(); - // The exact NaN returned by F32Abs is fully defined. Do not - // adjust. - self.state.push1_extra(res, i.strip_pending()); + + self.state.push1(res); } Operator::F64Abs => { - let (v, i) = self.state.pop1_extra()?; - let v = self.apply_pending_canonicalization(v, i); + let v = self.state.pop1()?; + let res = self .builder .build_call(self.intrinsics.fabs_f64, &[v.as_basic_value_enum()], "") .try_as_basic_value() .left() .unwrap(); - // The exact NaN returned by F64Abs is fully defined. Do not - // adjust. - self.state.push1_extra(res, i.strip_pending()); + + self.state.push1(res); } Operator::F32x4Abs => { - let (v, i) = self.state.pop1_extra()?; + let v = self.state.pop1()?; let v = self.builder .build_bitcast(v.into_int_value(), self.intrinsics.f32x4_ty, ""); - let v = self.apply_pending_canonicalization(v, i); + let res = self .builder .build_call(self.intrinsics.fabs_f32x4, &[v.as_basic_value_enum()], "") @@ -4475,16 +4782,14 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { .left() .unwrap(); let res = self.builder.build_bitcast(res, self.intrinsics.i128_ty, ""); - // The exact NaN returned by F32x4Abs is fully defined. Do not - // adjust. - self.state.push1_extra(res, i.strip_pending()); + + self.state.push1(res); } Operator::F64x2Abs => { - let (v, i) = self.state.pop1_extra()?; + let v = self.state.pop1()?; let v = self.builder .build_bitcast(v.into_int_value(), self.intrinsics.f64x2_ty, ""); - let v = self.apply_pending_canonicalization(v, i); let res = self .builder .build_call(self.intrinsics.fabs_f64x2, &[v], "") @@ -4492,73 +4797,65 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { .left() .unwrap(); let res = self.builder.build_bitcast(res, self.intrinsics.i128_ty, ""); - // The exact NaN returned by F32x4Abs is fully defined. Do not - // adjust. - self.state.push1_extra(res, i.strip_pending()); + + self.state.push1(res); + } + + Operator::F32Neg | Operator::F64Neg => { + let v = self.state.pop1()?; + + let res = self.builder.build_float_neg(v.into_float_value(), ""); + + self.state.push1(res); } Operator::F32x4Neg => { - let (v, i) = self.state.pop1_extra()?; - let v = - self.builder - .build_bitcast(v.into_int_value(), self.intrinsics.f32x4_ty, ""); + let v = self.state.pop1()?; let v = self - .apply_pending_canonicalization(v, i) + .builder + .build_bitcast(v.into_int_value(), self.intrinsics.f32x4_ty, "") .into_vector_value(); + let res = self.builder.build_float_neg(v, ""); let res = self.builder.build_bitcast(res, self.intrinsics.i128_ty, ""); - // The exact NaN returned by F32x4Neg is fully defined. Do not - // adjust. - self.state.push1_extra(res, i.strip_pending()); + + self.state.push1(res); } Operator::F64x2Neg => { - let (v, i) = self.state.pop1_extra()?; - let v = - self.builder - .build_bitcast(v.into_int_value(), self.intrinsics.f64x2_ty, ""); + let v = self.state.pop1()?; let v = self - .apply_pending_canonicalization(v, i) + .builder + .build_bitcast(v.into_int_value(), self.intrinsics.f64x2_ty, "") .into_vector_value(); + let res = self.builder.build_float_neg(v, ""); let res = self.builder.build_bitcast(res, self.intrinsics.i128_ty, ""); - // The exact NaN returned by F64x2Neg is fully defined. Do not - // adjust. - self.state.push1_extra(res, i.strip_pending()); - } - Operator::F32Neg | Operator::F64Neg => { - let (v, i) = self.state.pop1_extra()?; - let v = self.apply_pending_canonicalization(v, i).into_float_value(); - let res = self.builder.build_float_neg(v, ""); - // The exact NaN returned by F32Neg and F64Neg are fully defined. - // Do not adjust. - self.state.push1_extra(res, i.strip_pending()); + + self.state.push1(res); } + Operator::F32Copysign => { - let ((mag, mag_info), (sgn, sgn_info)) = self.state.pop2_extra()?; - let mag = self.apply_pending_canonicalization(mag, mag_info); - let sgn = self.apply_pending_canonicalization(sgn, sgn_info); + let (mag, sgn) = self.state.pop2()?; + let res = self .builder .build_call(self.intrinsics.copysign_f32, &[mag, sgn], "") .try_as_basic_value() .left() .unwrap(); - // The exact NaN returned by F32Copysign is fully defined. - // Do not adjust. - self.state.push1_extra(res, mag_info.strip_pending()); + + self.state.push1(res); } Operator::F64Copysign => { - let ((mag, mag_info), (sgn, sgn_info)) = self.state.pop2_extra()?; - let mag = self.apply_pending_canonicalization(mag, mag_info); - let sgn = self.apply_pending_canonicalization(sgn, sgn_info); + let (mag, sgn) = self.state.pop2()?; + let res = self .builder .build_call(self.intrinsics.copysign_f64, &[mag, sgn], "") .try_as_basic_value() .left() .unwrap(); - // The exact NaN returned by F32Copysign is fully defined. - // Do not adjust. - self.state.push1_extra(res, mag_info.strip_pending()); + + self.state.push1(res); } /*************************** @@ -4566,23 +4863,20 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { * https://github.com/sunfishcode/wasm-reference-manual/blob/master/WebAssembly.md#integer-comparison-instructions ***************************/ Operator::I32Eq | Operator::I64Eq => { - let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; - let v1 = self.apply_pending_canonicalization(v1, i1); - let v2 = self.apply_pending_canonicalization(v2, i2); + let (v1, v2) = self.state.pop2()?; let (v1, v2) = (v1.into_int_value(), v2.into_int_value()); + let cond = self.builder.build_int_compare(IntPredicate::EQ, v1, v2, ""); + let res = self .builder .build_int_z_extend(cond, self.intrinsics.i32_ty, ""); - self.state.push1_extra( - res, - ExtraInfo::arithmetic_f32() | ExtraInfo::arithmetic_f64(), - ); + self.state.push1(res); } Operator::I8x16Eq => { - let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; - let (v1, _) = self.v128_into_i8x16(v1, i1); - let (v2, _) = self.v128_into_i8x16(v2, i2); + let (v1, v2) = self.state.pop2()?; + let v1 = self.v128_into_i8x16(v1); + let v2 = self.v128_into_i8x16(v2); let res = self.builder.build_int_compare(IntPredicate::EQ, v1, v2, ""); let res = self .builder @@ -4591,9 +4885,9 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { self.state.push1(res); } Operator::I16x8Eq => { - let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; - let (v1, _) = self.v128_into_i16x8(v1, i1); - let (v2, _) = self.v128_into_i16x8(v2, i2); + let (v1, v2) = self.state.pop2()?; + let v1 = self.v128_into_i16x8(v1); + let v2 = self.v128_into_i16x8(v2); let res = self.builder.build_int_compare(IntPredicate::EQ, v1, v2, ""); let res = self .builder @@ -4602,9 +4896,9 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { self.state.push1(res); } Operator::I32x4Eq => { - let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; - let (v1, _) = self.v128_into_i32x4(v1, i1); - let (v2, _) = self.v128_into_i32x4(v2, i2); + let (v1, v2) = self.state.pop2()?; + let v1 = self.v128_into_i32x4(v1); + let v2 = self.v128_into_i32x4(v2); let res = self.builder.build_int_compare(IntPredicate::EQ, v1, v2, ""); let res = self .builder @@ -4613,23 +4907,20 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { self.state.push1(res); } Operator::I32Ne | Operator::I64Ne => { - let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; - let v1 = self.apply_pending_canonicalization(v1, i1); - let v2 = self.apply_pending_canonicalization(v2, i2); + let (v1, v2) = self.state.pop2()?; let (v1, v2) = (v1.into_int_value(), v2.into_int_value()); + let cond = self.builder.build_int_compare(IntPredicate::NE, v1, v2, ""); + let res = self .builder .build_int_z_extend(cond, self.intrinsics.i32_ty, ""); - self.state.push1_extra( - res, - ExtraInfo::arithmetic_f32() | ExtraInfo::arithmetic_f64(), - ); + self.state.push1(res); } Operator::I8x16Ne => { - let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; - let (v1, _) = self.v128_into_i8x16(v1, i1); - let (v2, _) = self.v128_into_i8x16(v2, i2); + let (v1, v2) = self.state.pop2()?; + let v1 = self.v128_into_i8x16(v1); + let v2 = self.v128_into_i8x16(v2); let res = self.builder.build_int_compare(IntPredicate::NE, v1, v2, ""); let res = self .builder @@ -4638,9 +4929,9 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { self.state.push1(res); } Operator::I16x8Ne => { - let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; - let (v1, _) = self.v128_into_i16x8(v1, i1); - let (v2, _) = self.v128_into_i16x8(v2, i2); + let (v1, v2) = self.state.pop2()?; + let v1 = self.v128_into_i16x8(v1); + let v2 = self.v128_into_i16x8(v2); let res = self.builder.build_int_compare(IntPredicate::NE, v1, v2, ""); let res = self .builder @@ -4649,9 +4940,9 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { self.state.push1(res); } Operator::I32x4Ne => { - let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; - let (v1, _) = self.v128_into_i32x4(v1, i1); - let (v2, _) = self.v128_into_i32x4(v2, i2); + let (v1, v2) = self.state.pop2()?; + let v1 = self.v128_into_i32x4(v1); + let v2 = self.v128_into_i32x4(v2); let res = self.builder.build_int_compare(IntPredicate::NE, v1, v2, ""); let res = self .builder @@ -4660,25 +4951,22 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { self.state.push1(res); } Operator::I32LtS | Operator::I64LtS => { - let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; - let v1 = self.apply_pending_canonicalization(v1, i1); - let v2 = self.apply_pending_canonicalization(v2, i2); + let (v1, v2) = self.state.pop2()?; let (v1, v2) = (v1.into_int_value(), v2.into_int_value()); + let cond = self .builder .build_int_compare(IntPredicate::SLT, v1, v2, ""); let res = self .builder .build_int_z_extend(cond, self.intrinsics.i32_ty, ""); - self.state.push1_extra( - res, - ExtraInfo::arithmetic_f32() | ExtraInfo::arithmetic_f64(), - ); + + self.state.push1(res); } Operator::I8x16LtS => { - let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; - let (v1, _) = self.v128_into_i8x16(v1, i1); - let (v2, _) = self.v128_into_i8x16(v2, i2); + let (v1, v2) = self.state.pop2()?; + let v1 = self.v128_into_i8x16(v1); + let v2 = self.v128_into_i8x16(v2); let res = self .builder .build_int_compare(IntPredicate::SLT, v1, v2, ""); @@ -4689,9 +4977,9 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { self.state.push1(res); } Operator::I16x8LtS => { - let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; - let (v1, _) = self.v128_into_i16x8(v1, i1); - let (v2, _) = self.v128_into_i16x8(v2, i2); + let (v1, v2) = self.state.pop2()?; + let v1 = self.v128_into_i16x8(v1); + let v2 = self.v128_into_i16x8(v2); let res = self .builder .build_int_compare(IntPredicate::SLT, v1, v2, ""); @@ -4702,9 +4990,9 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { self.state.push1(res); } Operator::I32x4LtS => { - let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; - let (v1, _) = self.v128_into_i32x4(v1, i1); - let (v2, _) = self.v128_into_i32x4(v2, i2); + let (v1, v2) = self.state.pop2()?; + let v1 = self.v128_into_i32x4(v1); + let v2 = self.v128_into_i32x4(v2); let res = self .builder .build_int_compare(IntPredicate::SLT, v1, v2, ""); @@ -4715,22 +5003,22 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { self.state.push1(res); } Operator::I32LtU | Operator::I64LtU => { - let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; - let v1 = self.apply_pending_canonicalization(v1, i1); - let v2 = self.apply_pending_canonicalization(v2, i2); + let (v1, v2) = self.state.pop2()?; let (v1, v2) = (v1.into_int_value(), v2.into_int_value()); + let cond = self .builder .build_int_compare(IntPredicate::ULT, v1, v2, ""); + let res = self .builder .build_int_z_extend(cond, self.intrinsics.i32_ty, ""); self.state.push1(res); } Operator::I8x16LtU => { - let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; - let (v1, _) = self.v128_into_i8x16(v1, i1); - let (v2, _) = self.v128_into_i8x16(v2, i2); + let (v1, v2) = self.state.pop2()?; + let v1 = self.v128_into_i8x16(v1); + let v2 = self.v128_into_i8x16(v2); let res = self .builder .build_int_compare(IntPredicate::ULT, v1, v2, ""); @@ -4741,9 +5029,9 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { self.state.push1(res); } Operator::I16x8LtU => { - let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; - let (v1, _) = self.v128_into_i16x8(v1, i1); - let (v2, _) = self.v128_into_i16x8(v2, i2); + let (v1, v2) = self.state.pop2()?; + let v1 = self.v128_into_i16x8(v1); + let v2 = self.v128_into_i16x8(v2); let res = self .builder .build_int_compare(IntPredicate::ULT, v1, v2, ""); @@ -4754,9 +5042,9 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { self.state.push1(res); } Operator::I32x4LtU => { - let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; - let (v1, _) = self.v128_into_i32x4(v1, i1); - let (v2, _) = self.v128_into_i32x4(v2, i2); + let (v1, v2) = self.state.pop2()?; + let v1 = self.v128_into_i32x4(v1); + let v2 = self.v128_into_i32x4(v2); let res = self .builder .build_int_compare(IntPredicate::ULT, v1, v2, ""); @@ -4767,25 +5055,22 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { self.state.push1(res); } Operator::I32LeS | Operator::I64LeS => { - let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; - let v1 = self.apply_pending_canonicalization(v1, i1); - let v2 = self.apply_pending_canonicalization(v2, i2); + let (v1, v2) = self.state.pop2()?; let (v1, v2) = (v1.into_int_value(), v2.into_int_value()); + let cond = self .builder .build_int_compare(IntPredicate::SLE, v1, v2, ""); + let res = self .builder .build_int_z_extend(cond, self.intrinsics.i32_ty, ""); - self.state.push1_extra( - res, - ExtraInfo::arithmetic_f32() | ExtraInfo::arithmetic_f64(), - ); + self.state.push1(res); } Operator::I8x16LeS => { - let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; - let (v1, _) = self.v128_into_i8x16(v1, i1); - let (v2, _) = self.v128_into_i8x16(v2, i2); + let (v1, v2) = self.state.pop2()?; + let v1 = self.v128_into_i8x16(v1); + let v2 = self.v128_into_i8x16(v2); let res = self .builder .build_int_compare(IntPredicate::SLE, v1, v2, ""); @@ -4796,9 +5081,9 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { self.state.push1(res); } Operator::I16x8LeS => { - let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; - let (v1, _) = self.v128_into_i16x8(v1, i1); - let (v2, _) = self.v128_into_i16x8(v2, i2); + let (v1, v2) = self.state.pop2()?; + let v1 = self.v128_into_i16x8(v1); + let v2 = self.v128_into_i16x8(v2); let res = self .builder .build_int_compare(IntPredicate::SLE, v1, v2, ""); @@ -4809,9 +5094,9 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { self.state.push1(res); } Operator::I32x4LeS => { - let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; - let (v1, _) = self.v128_into_i32x4(v1, i1); - let (v2, _) = self.v128_into_i32x4(v2, i2); + let (v1, v2) = self.state.pop2()?; + let v1 = self.v128_into_i32x4(v1); + let v2 = self.v128_into_i32x4(v2); let res = self .builder .build_int_compare(IntPredicate::SLE, v1, v2, ""); @@ -4822,25 +5107,22 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { self.state.push1(res); } Operator::I32LeU | Operator::I64LeU => { - let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; - let v1 = self.apply_pending_canonicalization(v1, i1); - let v2 = self.apply_pending_canonicalization(v2, i2); + let (v1, v2) = self.state.pop2()?; let (v1, v2) = (v1.into_int_value(), v2.into_int_value()); + let cond = self .builder .build_int_compare(IntPredicate::ULE, v1, v2, ""); + let res = self .builder .build_int_z_extend(cond, self.intrinsics.i32_ty, ""); - self.state.push1_extra( - res, - ExtraInfo::arithmetic_f32() | ExtraInfo::arithmetic_f64(), - ); + self.state.push1(res); } Operator::I8x16LeU => { - let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; - let (v1, _) = self.v128_into_i8x16(v1, i1); - let (v2, _) = self.v128_into_i8x16(v2, i2); + let (v1, v2) = self.state.pop2()?; + let v1 = self.v128_into_i8x16(v1); + let v2 = self.v128_into_i8x16(v2); let res = self .builder .build_int_compare(IntPredicate::ULE, v1, v2, ""); @@ -4851,9 +5133,9 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { self.state.push1(res); } Operator::I16x8LeU => { - let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; - let (v1, _) = self.v128_into_i16x8(v1, i1); - let (v2, _) = self.v128_into_i16x8(v2, i2); + let (v1, v2) = self.state.pop2()?; + let v1 = self.v128_into_i16x8(v1); + let v2 = self.v128_into_i16x8(v2); let res = self .builder .build_int_compare(IntPredicate::ULE, v1, v2, ""); @@ -4864,9 +5146,9 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { self.state.push1(res); } Operator::I32x4LeU => { - let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; - let (v1, _) = self.v128_into_i32x4(v1, i1); - let (v2, _) = self.v128_into_i32x4(v2, i2); + let (v1, v2) = self.state.pop2()?; + let v1 = self.v128_into_i32x4(v1); + let v2 = self.v128_into_i32x4(v2); let res = self .builder .build_int_compare(IntPredicate::ULE, v1, v2, ""); @@ -4877,25 +5159,22 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { self.state.push1(res); } Operator::I32GtS | Operator::I64GtS => { - let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; - let v1 = self.apply_pending_canonicalization(v1, i1); - let v2 = self.apply_pending_canonicalization(v2, i2); + let (v1, v2) = self.state.pop2()?; let (v1, v2) = (v1.into_int_value(), v2.into_int_value()); + let cond = self .builder .build_int_compare(IntPredicate::SGT, v1, v2, ""); + let res = self .builder .build_int_z_extend(cond, self.intrinsics.i32_ty, ""); - self.state.push1_extra( - res, - ExtraInfo::arithmetic_f32() | ExtraInfo::arithmetic_f64(), - ); + self.state.push1(res); } Operator::I8x16GtS => { - let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; - let (v1, _) = self.v128_into_i8x16(v1, i1); - let (v2, _) = self.v128_into_i8x16(v2, i2); + let (v1, v2) = self.state.pop2()?; + let v1 = self.v128_into_i8x16(v1); + let v2 = self.v128_into_i8x16(v2); let res = self .builder .build_int_compare(IntPredicate::SGT, v1, v2, ""); @@ -4906,9 +5185,9 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { self.state.push1(res); } Operator::I16x8GtS => { - let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; - let (v1, _) = self.v128_into_i16x8(v1, i1); - let (v2, _) = self.v128_into_i16x8(v2, i2); + let (v1, v2) = self.state.pop2()?; + let v1 = self.v128_into_i16x8(v1); + let v2 = self.v128_into_i16x8(v2); let res = self .builder .build_int_compare(IntPredicate::SGT, v1, v2, ""); @@ -4919,9 +5198,9 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { self.state.push1(res); } Operator::I32x4GtS => { - let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; - let (v1, _) = self.v128_into_i32x4(v1, i1); - let (v2, _) = self.v128_into_i32x4(v2, i2); + let (v1, v2) = self.state.pop2()?; + let v1 = self.v128_into_i32x4(v1); + let v2 = self.v128_into_i32x4(v2); let res = self .builder .build_int_compare(IntPredicate::SGT, v1, v2, ""); @@ -4932,25 +5211,22 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { self.state.push1(res); } Operator::I32GtU | Operator::I64GtU => { - let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; - let v1 = self.apply_pending_canonicalization(v1, i1); - let v2 = self.apply_pending_canonicalization(v2, i2); + let (v1, v2) = self.state.pop2()?; let (v1, v2) = (v1.into_int_value(), v2.into_int_value()); + let cond = self .builder .build_int_compare(IntPredicate::UGT, v1, v2, ""); let res = self .builder .build_int_z_extend(cond, self.intrinsics.i32_ty, ""); - self.state.push1_extra( - res, - ExtraInfo::arithmetic_f32() | ExtraInfo::arithmetic_f64(), - ); + + self.state.push1(res); } Operator::I8x16GtU => { - let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; - let (v1, _) = self.v128_into_i8x16(v1, i1); - let (v2, _) = self.v128_into_i8x16(v2, i2); + let (v1, v2) = self.state.pop2()?; + let v1 = self.v128_into_i8x16(v1); + let v2 = self.v128_into_i8x16(v2); let res = self .builder .build_int_compare(IntPredicate::UGT, v1, v2, ""); @@ -4961,9 +5237,9 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { self.state.push1(res); } Operator::I16x8GtU => { - let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; - let (v1, _) = self.v128_into_i16x8(v1, i1); - let (v2, _) = self.v128_into_i16x8(v2, i2); + let (v1, v2) = self.state.pop2()?; + let v1 = self.v128_into_i16x8(v1); + let v2 = self.v128_into_i16x8(v2); let res = self .builder .build_int_compare(IntPredicate::UGT, v1, v2, ""); @@ -4974,9 +5250,9 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { self.state.push1(res); } Operator::I32x4GtU => { - let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; - let (v1, _) = self.v128_into_i32x4(v1, i1); - let (v2, _) = self.v128_into_i32x4(v2, i2); + let (v1, v2) = self.state.pop2()?; + let v1 = self.v128_into_i32x4(v1); + let v2 = self.v128_into_i32x4(v2); let res = self .builder .build_int_compare(IntPredicate::UGT, v1, v2, ""); @@ -4987,22 +5263,22 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { self.state.push1(res); } Operator::I32GeS | Operator::I64GeS => { - let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; - let v1 = self.apply_pending_canonicalization(v1, i1); - let v2 = self.apply_pending_canonicalization(v2, i2); + let (v1, v2) = self.state.pop2()?; let (v1, v2) = (v1.into_int_value(), v2.into_int_value()); + let cond = self .builder .build_int_compare(IntPredicate::SGE, v1, v2, ""); + let res = self .builder .build_int_z_extend(cond, self.intrinsics.i32_ty, ""); self.state.push1(res); } Operator::I8x16GeS => { - let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; - let (v1, _) = self.v128_into_i8x16(v1, i1); - let (v2, _) = self.v128_into_i8x16(v2, i2); + let (v1, v2) = self.state.pop2()?; + let v1 = self.v128_into_i8x16(v1); + let v2 = self.v128_into_i8x16(v2); let res = self .builder .build_int_compare(IntPredicate::SGE, v1, v2, ""); @@ -5013,9 +5289,9 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { self.state.push1(res); } Operator::I16x8GeS => { - let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; - let (v1, _) = self.v128_into_i16x8(v1, i1); - let (v2, _) = self.v128_into_i16x8(v2, i2); + let (v1, v2) = self.state.pop2()?; + let v1 = self.v128_into_i16x8(v1); + let v2 = self.v128_into_i16x8(v2); let res = self .builder .build_int_compare(IntPredicate::SGE, v1, v2, ""); @@ -5026,9 +5302,9 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { self.state.push1(res); } Operator::I32x4GeS => { - let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; - let (v1, _) = self.v128_into_i32x4(v1, i1); - let (v2, _) = self.v128_into_i32x4(v2, i2); + let (v1, v2) = self.state.pop2()?; + let v1 = self.v128_into_i32x4(v1); + let v2 = self.v128_into_i32x4(v2); let res = self .builder .build_int_compare(IntPredicate::SGE, v1, v2, ""); @@ -5039,25 +5315,22 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { self.state.push1(res); } Operator::I32GeU | Operator::I64GeU => { - let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; - let v1 = self.apply_pending_canonicalization(v1, i1); - let v2 = self.apply_pending_canonicalization(v2, i2); + let (v1, v2) = self.state.pop2()?; let (v1, v2) = (v1.into_int_value(), v2.into_int_value()); + let cond = self .builder .build_int_compare(IntPredicate::UGE, v1, v2, ""); + let res = self .builder .build_int_z_extend(cond, self.intrinsics.i32_ty, ""); - self.state.push1_extra( - res, - ExtraInfo::arithmetic_f32() | ExtraInfo::arithmetic_f64(), - ); + self.state.push1(res); } Operator::I8x16GeU => { - let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; - let (v1, _) = self.v128_into_i8x16(v1, i1); - let (v2, _) = self.v128_into_i8x16(v2, i2); + let (v1, v2) = self.state.pop2()?; + let v1 = self.v128_into_i8x16(v1); + let v2 = self.v128_into_i8x16(v2); let res = self .builder .build_int_compare(IntPredicate::UGE, v1, v2, ""); @@ -5068,9 +5341,9 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { self.state.push1(res); } Operator::I16x8GeU => { - let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; - let (v1, _) = self.v128_into_i16x8(v1, i1); - let (v2, _) = self.v128_into_i16x8(v2, i2); + let (v1, v2) = self.state.pop2()?; + let v1 = self.v128_into_i16x8(v1); + let v2 = self.v128_into_i16x8(v2); let res = self .builder .build_int_compare(IntPredicate::UGE, v1, v2, ""); @@ -5081,9 +5354,9 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { self.state.push1(res); } Operator::I32x4GeU => { - let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; - let (v1, _) = self.v128_into_i32x4(v1, i1); - let (v2, _) = self.v128_into_i32x4(v2, i2); + let (v1, v2) = self.state.pop2()?; + let v1 = self.v128_into_i32x4(v1); + let v2 = self.v128_into_i32x4(v2); let res = self .builder .build_int_compare(IntPredicate::UGE, v1, v2, ""); @@ -5107,15 +5380,12 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { let res = self .builder .build_int_z_extend(cond, self.intrinsics.i32_ty, ""); - self.state.push1_extra( - res, - ExtraInfo::arithmetic_f32() | ExtraInfo::arithmetic_f64(), - ); + self.state.push1(res); } Operator::F32x4Eq => { - let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; - let (v1, _) = self.v128_into_f32x4(v1, i1); - let (v2, _) = self.v128_into_f32x4(v2, i2); + let (v1, v2) = self.state.pop2()?; + let v1 = self.v128_into_f32x4(v1); + let v2 = self.v128_into_f32x4(v2); let res = self .builder .build_float_compare(FloatPredicate::OEQ, v1, v2, ""); @@ -5126,9 +5396,9 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { self.state.push1(res); } Operator::F64x2Eq => { - let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; - let (v1, _) = self.v128_into_f64x2(v1, i1); - let (v2, _) = self.v128_into_f64x2(v2, i2); + let (v1, v2) = self.state.pop2()?; + let v1 = self.v128_into_f64x2(v1); + let v2 = self.v128_into_f64x2(v2); let res = self .builder .build_float_compare(FloatPredicate::OEQ, v1, v2, ""); @@ -5147,15 +5417,12 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { let res = self .builder .build_int_z_extend(cond, self.intrinsics.i32_ty, ""); - self.state.push1_extra( - res, - ExtraInfo::arithmetic_f32() | ExtraInfo::arithmetic_f64(), - ); + self.state.push1(res); } Operator::F32x4Ne => { - let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; - let (v1, _) = self.v128_into_f32x4(v1, i1); - let (v2, _) = self.v128_into_f32x4(v2, i2); + let (v1, v2) = self.state.pop2()?; + let v1 = self.v128_into_f32x4(v1); + let v2 = self.v128_into_f32x4(v2); let res = self .builder .build_float_compare(FloatPredicate::UNE, v1, v2, ""); @@ -5166,9 +5433,9 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { self.state.push1(res); } Operator::F64x2Ne => { - let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; - let (v1, _) = self.v128_into_f64x2(v1, i1); - let (v2, _) = self.v128_into_f64x2(v2, i2); + let (v1, v2) = self.state.pop2()?; + let v1 = self.v128_into_f64x2(v1); + let v2 = self.v128_into_f64x2(v2); let res = self .builder .build_float_compare(FloatPredicate::UNE, v1, v2, ""); @@ -5187,15 +5454,12 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { let res = self .builder .build_int_z_extend(cond, self.intrinsics.i32_ty, ""); - self.state.push1_extra( - res, - ExtraInfo::arithmetic_f32() | ExtraInfo::arithmetic_f64(), - ); + self.state.push1(res); } Operator::F32x4Lt => { - let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; - let (v1, _) = self.v128_into_f32x4(v1, i1); - let (v2, _) = self.v128_into_f32x4(v2, i2); + let (v1, v2) = self.state.pop2()?; + let v1 = self.v128_into_f32x4(v1); + let v2 = self.v128_into_f32x4(v2); let res = self .builder .build_float_compare(FloatPredicate::OLT, v1, v2, ""); @@ -5206,9 +5470,9 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { self.state.push1(res); } Operator::F64x2Lt => { - let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; - let (v1, _) = self.v128_into_f64x2(v1, i1); - let (v2, _) = self.v128_into_f64x2(v2, i2); + let (v1, v2) = self.state.pop2()?; + let v1 = self.v128_into_f64x2(v1); + let v2 = self.v128_into_f64x2(v2); let res = self .builder .build_float_compare(FloatPredicate::OLT, v1, v2, ""); @@ -5233,9 +5497,9 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { ); } Operator::F32x4Le => { - let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; - let (v1, _) = self.v128_into_f32x4(v1, i1); - let (v2, _) = self.v128_into_f32x4(v2, i2); + let (v1, v2) = self.state.pop2()?; + let v1 = self.v128_into_f32x4(v1); + let v2 = self.v128_into_f32x4(v2); let res = self .builder .build_float_compare(FloatPredicate::OLE, v1, v2, ""); @@ -5246,9 +5510,9 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { self.state.push1(res); } Operator::F64x2Le => { - let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; - let (v1, _) = self.v128_into_f64x2(v1, i1); - let (v2, _) = self.v128_into_f64x2(v2, i2); + let (v1, v2) = self.state.pop2()?; + let v1 = self.v128_into_f64x2(v1); + let v2 = self.v128_into_f64x2(v2); let res = self .builder .build_float_compare(FloatPredicate::OLE, v1, v2, ""); @@ -5267,15 +5531,12 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { let res = self .builder .build_int_z_extend(cond, self.intrinsics.i32_ty, ""); - self.state.push1_extra( - res, - ExtraInfo::arithmetic_f32() | ExtraInfo::arithmetic_f64(), - ); + self.state.push1(res); } Operator::F32x4Gt => { - let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; - let (v1, _) = self.v128_into_f32x4(v1, i1); - let (v2, _) = self.v128_into_f32x4(v2, i2); + let (v1, v2) = self.state.pop2()?; + let v1 = self.v128_into_f32x4(v1); + let v2 = self.v128_into_f32x4(v2); let res = self .builder .build_float_compare(FloatPredicate::OGT, v1, v2, ""); @@ -5286,9 +5547,9 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { self.state.push1(res); } Operator::F64x2Gt => { - let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; - let (v1, _) = self.v128_into_f64x2(v1, i1); - let (v2, _) = self.v128_into_f64x2(v2, i2); + let (v1, v2) = self.state.pop2()?; + let v1 = self.v128_into_f64x2(v1); + let v2 = self.v128_into_f64x2(v2); let res = self .builder .build_float_compare(FloatPredicate::OGT, v1, v2, ""); @@ -5307,15 +5568,12 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { let res = self .builder .build_int_z_extend(cond, self.intrinsics.i32_ty, ""); - self.state.push1_extra( - res, - ExtraInfo::arithmetic_f32() | ExtraInfo::arithmetic_f64(), - ); + self.state.push1(res); } Operator::F32x4Ge => { - let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; - let (v1, _) = self.v128_into_f32x4(v1, i1); - let (v2, _) = self.v128_into_f32x4(v2, i2); + let (v1, v2) = self.state.pop2()?; + let v1 = self.v128_into_f32x4(v1); + let v2 = self.v128_into_f32x4(v2); let res = self .builder .build_float_compare(FloatPredicate::OGE, v1, v2, ""); @@ -5326,9 +5584,9 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { self.state.push1(res); } Operator::F64x2Ge => { - let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; - let (v1, _) = self.v128_into_f64x2(v1, i1); - let (v2, _) = self.v128_into_f64x2(v2, i2); + let (v1, v2) = self.state.pop2()?; + let v1 = self.v128_into_f64x2(v1); + let v2 = self.v128_into_f64x2(v2); let res = self .builder .build_float_compare(FloatPredicate::OGE, v1, v2, ""); @@ -5344,8 +5602,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { * https://github.com/sunfishcode/wasm-reference-manual/blob/master/WebAssembly.md#conversion-instructions ***************************/ Operator::I32WrapI64 => { - let (v, i) = self.state.pop1_extra()?; - let v = self.apply_pending_canonicalization(v, i); + let v = self.state.pop1()?; let v = v.into_int_value(); let res = self .builder @@ -5353,8 +5610,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { self.state.push1(res); } Operator::I64ExtendI32S => { - let (v, i) = self.state.pop1_extra()?; - let v = self.apply_pending_canonicalization(v, i); + let v = self.state.pop1()?; let v = v.into_int_value(); let res = self .builder @@ -5362,17 +5618,16 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { self.state.push1(res); } Operator::I64ExtendI32U => { - let (v, i) = self.state.pop1_extra()?; - let v = self.apply_pending_canonicalization(v, i); + let v = self.state.pop1()?; let v = v.into_int_value(); let res = self .builder .build_int_z_extend(v, self.intrinsics.i64_ty, ""); - self.state.push1_extra(res, ExtraInfo::arithmetic_f64()); + self.state.push1(res); } Operator::I16x8ExtendLowI8x16S => { - let (v, i) = self.state.pop1_extra()?; - let (v, _) = self.v128_into_i8x16(v, i); + let v = self.state.pop1()?; + let v = self.v128_into_i8x16(v); let low = self.builder.build_shuffle_vector( v, v.get_type().get_undef(), @@ -5395,8 +5650,8 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { self.state.push1(res); } Operator::I16x8ExtendHighI8x16S => { - let (v, i) = self.state.pop1_extra()?; - let (v, _) = self.v128_into_i8x16(v, i); + let v = self.state.pop1()?; + let v = self.v128_into_i8x16(v); let low = self.builder.build_shuffle_vector( v, v.get_type().get_undef(), @@ -5419,8 +5674,8 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { self.state.push1(res); } Operator::I16x8ExtendLowI8x16U => { - let (v, i) = self.state.pop1_extra()?; - let (v, _) = self.v128_into_i8x16(v, i); + let v = self.state.pop1()?; + let v = self.v128_into_i8x16(v); let low = self.builder.build_shuffle_vector( v, v.get_type().get_undef(), @@ -5443,8 +5698,8 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { self.state.push1(res); } Operator::I16x8ExtendHighI8x16U => { - let (v, i) = self.state.pop1_extra()?; - let (v, _) = self.v128_into_i8x16(v, i); + let v = self.state.pop1()?; + let v = self.v128_into_i8x16(v); let low = self.builder.build_shuffle_vector( v, v.get_type().get_undef(), @@ -5467,8 +5722,8 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { self.state.push1(res); } Operator::I32x4ExtendLowI16x8S => { - let (v, i) = self.state.pop1_extra()?; - let (v, _) = self.v128_into_i16x8(v, i); + let v = self.state.pop1()?; + let v = self.v128_into_i16x8(v); let low = self.builder.build_shuffle_vector( v, v.get_type().get_undef(), @@ -5487,8 +5742,8 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { self.state.push1(res); } Operator::I32x4ExtendHighI16x8S => { - let (v, i) = self.state.pop1_extra()?; - let (v, _) = self.v128_into_i16x8(v, i); + let v = self.state.pop1()?; + let v = self.v128_into_i16x8(v); let low = self.builder.build_shuffle_vector( v, v.get_type().get_undef(), @@ -5507,8 +5762,8 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { self.state.push1(res); } Operator::I32x4ExtendLowI16x8U => { - let (v, i) = self.state.pop1_extra()?; - let (v, _) = self.v128_into_i16x8(v, i); + let v = self.state.pop1()?; + let v = self.v128_into_i16x8(v); let low = self.builder.build_shuffle_vector( v, v.get_type().get_undef(), @@ -5527,8 +5782,8 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { self.state.push1(res); } Operator::I32x4ExtendHighI16x8U => { - let (v, i) = self.state.pop1_extra()?; - let (v, _) = self.v128_into_i16x8(v, i); + let v = self.state.pop1()?; + let v = self.v128_into_i16x8(v); let low = self.builder.build_shuffle_vector( v, v.get_type().get_undef(), @@ -5547,9 +5802,9 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { self.state.push1(res); } Operator::I8x16NarrowI16x8S => { - let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; - let (v1, _) = self.v128_into_i16x8(v1, i1); - let (v2, _) = self.v128_into_i16x8(v2, i2); + let (v1, v2) = self.state.pop2()?; + let v1 = self.v128_into_i16x8(v1); + let v2 = self.v128_into_i16x8(v2); let min = self.intrinsics.i16_ty.const_int(0xff80, false); let max = self.intrinsics.i16_ty.const_int(0x007f, false); let min = VectorType::const_vector(&[min; 8]); @@ -5615,9 +5870,9 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { self.state.push1(res); } Operator::I8x16NarrowI16x8U => { - let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; - let (v1, _) = self.v128_into_i16x8(v1, i1); - let (v2, _) = self.v128_into_i16x8(v2, i2); + let (v1, v2) = self.state.pop2()?; + let v1 = self.v128_into_i16x8(v1); + let v2 = self.v128_into_i16x8(v2); let min = self.intrinsics.i16x8_ty.const_zero(); let max = self.intrinsics.i16_ty.const_int(0x00ff, false); let max = VectorType::const_vector(&[max; 8]); @@ -5682,9 +5937,9 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { self.state.push1(res); } Operator::I16x8NarrowI32x4S => { - let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; - let (v1, _) = self.v128_into_i32x4(v1, i1); - let (v2, _) = self.v128_into_i32x4(v2, i2); + let (v1, v2) = self.state.pop2()?; + let v1 = self.v128_into_i32x4(v1); + let v2 = self.v128_into_i32x4(v2); let min = self.intrinsics.i32_ty.const_int(0xffff8000, false); let max = self.intrinsics.i32_ty.const_int(0x00007fff, false); let min = VectorType::const_vector(&[min; 4]); @@ -5742,9 +5997,9 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { self.state.push1(res); } Operator::I16x8NarrowI32x4U => { - let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; - let (v1, _) = self.v128_into_i32x4(v1, i1); - let (v2, _) = self.v128_into_i32x4(v2, i2); + let (v1, v2) = self.state.pop2()?; + let v1 = self.v128_into_i32x4(v1); + let v2 = self.v128_into_i32x4(v2); let min = self.intrinsics.i32x4_ty.const_zero(); let max = self.intrinsics.i32_ty.const_int(0xffff, false); let max = VectorType::const_vector(&[max; 4]); @@ -5801,8 +6056,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { self.state.push1(res); } Operator::I32x4TruncSatF32x4S => { - let (v, i) = self.state.pop1_extra()?; - let v = self.apply_pending_canonicalization(v, i); + let v = self.state.pop1()?; let v = v.into_int_value(); let res = self.trunc_sat( self.intrinsics.f32x4_ty, @@ -5816,8 +6070,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { self.state.push1(res); } Operator::I32x4TruncSatF32x4U => { - let (v, i) = self.state.pop1_extra()?; - let v = self.apply_pending_canonicalization(v, i); + let v = self.state.pop1()?; let v = v.into_int_value(); let res = self.trunc_sat( self.intrinsics.f32x4_ty, @@ -5832,7 +6085,6 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { } // Operator::I64x2TruncSatF64x2S => { // let (v, i) = self.state.pop1_extra()?; - // let v = self.apply_pending_canonicalization(v, i); // let v = v.into_int_value(); // let res = self.trunc_sat( // self.intrinsics.f64x2_ty, @@ -5847,7 +6099,6 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { // } // Operator::I64x2TruncSatF64x2U => { // let (v, i) = self.state.pop1_extra()?; - // let v = self.apply_pending_canonicalization(v, i); // let v = v.into_int_value(); // let res = self.trunc_sat( // self.intrinsics.f64x2_ty, @@ -5885,8 +6136,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { self.state.push1(res); } Operator::I32TruncSatF32S => { - let (v, i) = self.state.pop1_extra()?; - let v = self.apply_pending_canonicalization(v, i); + let v = self.state.pop1()?; let v = v.into_float_value(); let res = self.trunc_sat_scalar( self.intrinsics.i32_ty, @@ -5899,8 +6149,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { self.state.push1(res); } Operator::I32TruncSatF64S => { - let (v, i) = self.state.pop1_extra()?; - let v = self.apply_pending_canonicalization(v, i); + let v = self.state.pop1()?; let v = v.into_float_value(); let res = self.trunc_sat_scalar( self.intrinsics.i32_ty, @@ -5937,8 +6186,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { self.state.push1(res); } Operator::I64TruncSatF32S => { - let (v, i) = self.state.pop1_extra()?; - let v = self.apply_pending_canonicalization(v, i); + let v = self.state.pop1()?; let v = v.into_float_value(); let res = self.trunc_sat_scalar( self.intrinsics.i64_ty, @@ -5951,8 +6199,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { self.state.push1(res); } Operator::I64TruncSatF64S => { - let (v, i) = self.state.pop1_extra()?; - let v = self.apply_pending_canonicalization(v, i); + let v = self.state.pop1()?; let v = v.into_float_value(); let res = self.trunc_sat_scalar( self.intrinsics.i64_ty, @@ -5989,8 +6236,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { self.state.push1(res); } Operator::I32TruncSatF32U => { - let (v, i) = self.state.pop1_extra()?; - let v = self.apply_pending_canonicalization(v, i); + let v = self.state.pop1()?; let v = v.into_float_value(); let res = self.trunc_sat_scalar( self.intrinsics.i32_ty, @@ -6003,8 +6249,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { self.state.push1(res); } Operator::I32TruncSatF64U => { - let (v, i) = self.state.pop1_extra()?; - let v = self.apply_pending_canonicalization(v, i); + let v = self.state.pop1()?; let v = v.into_float_value(); let res = self.trunc_sat_scalar( self.intrinsics.i32_ty, @@ -6041,8 +6286,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { self.state.push1(res); } Operator::I64TruncSatF32U => { - let (v, i) = self.state.pop1_extra()?; - let v = self.apply_pending_canonicalization(v, i); + let v = self.state.pop1()?; let v = v.into_float_value(); let res = self.trunc_sat_scalar( self.intrinsics.i64_ty, @@ -6055,8 +6299,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { self.state.push1(res); } Operator::I64TruncSatF64U => { - let (v, i) = self.state.pop1_extra()?; - let v = self.apply_pending_canonicalization(v, i); + let v = self.state.pop1()?; let v = v.into_float_value(); let res = self.trunc_sat_scalar( self.intrinsics.i64_ty, @@ -6070,52 +6313,79 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { } Operator::F32DemoteF64 => { let v = self.state.pop1()?; - let v = v.into_float_value(); + let res = self .builder - .build_float_trunc(v, self.intrinsics.f32_ty, ""); - self.state.push1_extra(res, ExtraInfo::pending_f32_nan()); + .build_call( + self.intrinsics.fptrunc_f64, + &[ + v, + self.intrinsics.fp_rounding_md, + self.intrinsics.fp_exception_md, + ], + "", + ) + .try_as_basic_value() + .left() + .unwrap(); + + self.state.push1(res); } Operator::F64PromoteF32 => { let v = self.state.pop1()?; - let v = v.into_float_value(); - let res = self.builder.build_float_ext(v, self.intrinsics.f64_ty, ""); - self.state.push1_extra(res, ExtraInfo::pending_f64_nan()); + + let res = self + .builder + .build_call( + self.intrinsics.fpext_f32, + &[v, self.intrinsics.fp_exception_md], + "", + ) + .try_as_basic_value() + .left() + .unwrap(); + + self.state.push1(res); } + Operator::F32ConvertI32S | Operator::F32ConvertI64S => { - let (v, i) = self.state.pop1_extra()?; - let v = self.apply_pending_canonicalization(v, i); + let v = self.state.pop1()?; let v = v.into_int_value(); + let res = self .builder .build_signed_int_to_float(v, self.intrinsics.f32_ty, ""); + self.state.push1(res); } Operator::F64ConvertI32S | Operator::F64ConvertI64S => { - let (v, i) = self.state.pop1_extra()?; - let v = self.apply_pending_canonicalization(v, i); + let v = self.state.pop1()?; let v = v.into_int_value(); + let res = self .builder .build_signed_int_to_float(v, self.intrinsics.f64_ty, ""); + self.state.push1(res); } Operator::F32ConvertI32U | Operator::F32ConvertI64U => { - let (v, i) = self.state.pop1_extra()?; - let v = self.apply_pending_canonicalization(v, i); + let v = self.state.pop1()?; let v = v.into_int_value(); + let res = self .builder .build_unsigned_int_to_float(v, self.intrinsics.f32_ty, ""); + self.state.push1(res); } Operator::F64ConvertI32U | Operator::F64ConvertI64U => { - let (v, i) = self.state.pop1_extra()?; - let v = self.apply_pending_canonicalization(v, i); + let v = self.state.pop1()?; let v = v.into_int_value(); + let res = self .builder .build_unsigned_int_to_float(v, self.intrinsics.f64_ty, ""); + self.state.push1(res); } Operator::F32x4ConvertI32x4S => { @@ -6167,26 +6437,32 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { // self.state.push1(res); // } Operator::I32ReinterpretF32 => { - let (v, i) = self.state.pop1_extra()?; - let v = self.apply_pending_canonicalization(v, i); + let v = self.state.pop1()?; + let ret = self.builder.build_bitcast(v, self.intrinsics.i32_ty, ""); - self.state.push1_extra(ret, ExtraInfo::arithmetic_f32()); + + self.state.push1(ret); } Operator::I64ReinterpretF64 => { - let (v, i) = self.state.pop1_extra()?; - let v = self.apply_pending_canonicalization(v, i); + let v = self.state.pop1()?; + let ret = self.builder.build_bitcast(v, self.intrinsics.i64_ty, ""); - self.state.push1_extra(ret, ExtraInfo::arithmetic_f64()); + + self.state.push1(ret); } Operator::F32ReinterpretI32 => { - let (v, i) = self.state.pop1_extra()?; + let v = self.state.pop1()?; + let ret = self.builder.build_bitcast(v, self.intrinsics.f32_ty, ""); - self.state.push1_extra(ret, i); + + self.state.push1(ret); } Operator::F64ReinterpretI64 => { - let (v, i) = self.state.pop1_extra()?; + let v = self.state.pop1()?; + let ret = self.builder.build_bitcast(v, self.intrinsics.f64_ty, ""); - self.state.push1_extra(ret, i); + + self.state.push1(ret); } /*************************** @@ -6387,8 +6663,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { self.annotate_user_memaccess(memory_index, memarg, 1, store)?; } Operator::F32Store { ref memarg } => { - let (v, i) = self.state.pop1_extra()?; - let v = self.apply_pending_canonicalization(v, i); + let v = self.state.pop1()?; let offset = self.state.pop1()?.into_int_value(); let memory_index = MemoryIndex::from_u32(0); let effective_address = self.resolve_memory_ptr( @@ -6409,8 +6684,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { self.annotate_user_memaccess(memory_index, memarg, 1, store)?; } Operator::F64Store { ref memarg } => { - let (v, i) = self.state.pop1_extra()?; - let v = self.apply_pending_canonicalization(v, i); + let v = self.state.pop1()?; let offset = self.state.pop1()?.into_int_value(); let memory_index = MemoryIndex::from_u32(0); let effective_address = self.resolve_memory_ptr( @@ -6431,8 +6705,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { self.annotate_user_memaccess(memory_index, memarg, 1, store)?; } Operator::V128Store { ref memarg } => { - let (v, i) = self.state.pop1_extra()?; - let v = self.apply_pending_canonicalization(v, i); + let v = self.state.pop1()?; let offset = self.state.pop1()?.into_int_value(); let memory_index = MemoryIndex::from_u32(0); let effective_address = self.resolve_memory_ptr( @@ -6597,7 +6870,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { self.intrinsics.i32_ty, "", ); - self.state.push1_extra(result, ExtraInfo::arithmetic_f32()); + self.state.push1(result); } Operator::I32Load16U { ref memarg } => { let offset = self.state.pop1()?.into_int_value(); @@ -6621,7 +6894,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { self.intrinsics.i32_ty, "", ); - self.state.push1_extra(result, ExtraInfo::arithmetic_f32()); + self.state.push1(result); } Operator::I64Load8U { ref memarg } => { let offset = self.state.pop1()?.into_int_value(); @@ -6645,7 +6918,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { self.intrinsics.i64_ty, "", ); - self.state.push1_extra(result, ExtraInfo::arithmetic_f64()); + self.state.push1(result); } Operator::I64Load16U { ref memarg } => { let offset = self.state.pop1()?.into_int_value(); @@ -6669,7 +6942,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { self.intrinsics.i64_ty, "", ); - self.state.push1_extra(result, ExtraInfo::arithmetic_f64()); + self.state.push1(result); } Operator::I64Load32U { ref memarg } => { let offset = self.state.pop1()?.into_int_value(); @@ -6693,7 +6966,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { self.intrinsics.i64_ty, "", ); - self.state.push1_extra(result, ExtraInfo::arithmetic_f64()); + self.state.push1(result); } Operator::I32Store8 { ref memarg } | Operator::I64Store8 { ref memarg } => { @@ -6769,37 +7042,38 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { self.annotate_user_memaccess(memory_index, memarg, 1, store)?; } Operator::I8x16Neg => { - let (v, i) = self.state.pop1_extra()?; - let (v, _) = self.v128_into_i8x16(v, i); + let v = self.state.pop1()?; + let v = self.v128_into_i8x16(v); let res = self.builder.build_int_sub(v.get_type().const_zero(), v, ""); let res = self.builder.build_bitcast(res, self.intrinsics.i128_ty, ""); self.state.push1(res); } Operator::I16x8Neg => { - let (v, i) = self.state.pop1_extra()?; - let (v, _) = self.v128_into_i16x8(v, i); + let v = self.state.pop1()?; + let v = self.v128_into_i16x8(v); let res = self.builder.build_int_sub(v.get_type().const_zero(), v, ""); let res = self.builder.build_bitcast(res, self.intrinsics.i128_ty, ""); self.state.push1(res); } Operator::I32x4Neg => { - let (v, i) = self.state.pop1_extra()?; - let (v, _) = self.v128_into_i32x4(v, i); + let v = self.state.pop1()?; + let v = self.v128_into_i32x4(v); let res = self.builder.build_int_sub(v.get_type().const_zero(), v, ""); let res = self.builder.build_bitcast(res, self.intrinsics.i128_ty, ""); self.state.push1(res); } Operator::I64x2Neg => { - let (v, i) = self.state.pop1_extra()?; - let (v, _) = self.v128_into_i64x2(v, i); + let v = self.state.pop1()?; + let v = self.v128_into_i64x2(v); let res = self.builder.build_int_sub(v.get_type().const_zero(), v, ""); let res = self.builder.build_bitcast(res, self.intrinsics.i128_ty, ""); self.state.push1(res); } Operator::V128Not => { - let (v, i) = self.state.pop1_extra()?; - let v = self.apply_pending_canonicalization(v, i).into_int_value(); - let res = self.builder.build_not(v, ""); + let v = self.state.pop1()?; + + let res = self.builder.build_not(v.into_int_value(), ""); + self.state.push1(res); } Operator::V128AnyTrue => { @@ -6815,10 +7089,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { let res = self .builder .build_int_z_extend(res, self.intrinsics.i32_ty, ""); - self.state.push1_extra( - res, - ExtraInfo::arithmetic_f32() | ExtraInfo::arithmetic_f64(), - ); + self.state.push1(res); } Operator::I8x16AllTrue | Operator::I16x8AllTrue | Operator::I32x4AllTrue => { // | Operator::I64x2AllTrue @@ -6829,8 +7100,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { // Operator::I64x2AllTrue => self.intrinsics.i64x2_ty, _ => unreachable!(), }; - let (v, i) = self.state.pop1_extra()?; - let v = self.apply_pending_canonicalization(v, i).into_int_value(); + let v = self.state.pop1()?; let lane_int_ty = self.context.custom_width_int_type(vec_ty.get_size()); let vec = self .builder @@ -6855,14 +7125,11 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { let res = self .builder .build_int_z_extend(res, self.intrinsics.i32_ty, ""); - self.state.push1_extra( - res, - ExtraInfo::arithmetic_f32() | ExtraInfo::arithmetic_f64(), - ); + self.state.push1(res); } Operator::I8x16ExtractLaneS { lane } => { - let (v, i) = self.state.pop1_extra()?; - let (v, _) = self.v128_into_i8x16(v, i); + let v = self.state.pop1()?; + let v = self.v128_into_i8x16(v); let idx = self.intrinsics.i32_ty.const_int(lane.into(), false); let res = self .builder @@ -6874,8 +7141,8 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { self.state.push1(res); } Operator::I8x16ExtractLaneU { lane } => { - let (v, i) = self.state.pop1_extra()?; - let (v, _) = self.v128_into_i8x16(v, i); + let v = self.state.pop1()?; + let v = self.v128_into_i8x16(v); let idx = self.intrinsics.i32_ty.const_int(lane.into(), false); let res = self .builder @@ -6884,11 +7151,11 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { let res = self .builder .build_int_z_extend(res, self.intrinsics.i32_ty, ""); - self.state.push1_extra(res, ExtraInfo::arithmetic_f32()); + self.state.push1(res); } Operator::I16x8ExtractLaneS { lane } => { - let (v, i) = self.state.pop1_extra()?; - let (v, _) = self.v128_into_i16x8(v, i); + let v = self.state.pop1()?; + let v = self.v128_into_i16x8(v); let idx = self.intrinsics.i32_ty.const_int(lane.into(), false); let res = self .builder @@ -6900,8 +7167,8 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { self.state.push1(res); } Operator::I16x8ExtractLaneU { lane } => { - let (v, i) = self.state.pop1_extra()?; - let (v, _) = self.v128_into_i16x8(v, i); + let v = self.state.pop1()?; + let v = self.v128_into_i16x8(v); let idx = self.intrinsics.i32_ty.const_int(lane.into(), false); let res = self .builder @@ -6910,39 +7177,39 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { let res = self .builder .build_int_z_extend(res, self.intrinsics.i32_ty, ""); - self.state.push1_extra(res, ExtraInfo::arithmetic_f32()); + self.state.push1(res); } Operator::I32x4ExtractLane { lane } => { - let (v, i) = self.state.pop1_extra()?; - let (v, i) = self.v128_into_i32x4(v, i); + let v = self.state.pop1()?; + let v = self.v128_into_i32x4(v); let idx = self.intrinsics.i32_ty.const_int(lane.into(), false); let res = self.builder.build_extract_element(v, idx, ""); - self.state.push1_extra(res, i); + self.state.push1(res); } Operator::I64x2ExtractLane { lane } => { - let (v, i) = self.state.pop1_extra()?; - let (v, i) = self.v128_into_i64x2(v, i); + let v = self.state.pop1()?; + let v = self.v128_into_i64x2(v); let idx = self.intrinsics.i32_ty.const_int(lane.into(), false); let res = self.builder.build_extract_element(v, idx, ""); - self.state.push1_extra(res, i); + self.state.push1(res); } Operator::F32x4ExtractLane { lane } => { - let (v, i) = self.state.pop1_extra()?; - let (v, i) = self.v128_into_f32x4(v, i); + let v = self.state.pop1()?; + let v = self.v128_into_f32x4(v); let idx = self.intrinsics.i32_ty.const_int(lane.into(), false); let res = self.builder.build_extract_element(v, idx, ""); - self.state.push1_extra(res, i); + self.state.push1(res); } Operator::F64x2ExtractLane { lane } => { - let (v, i) = self.state.pop1_extra()?; - let (v, i) = self.v128_into_f64x2(v, i); + let v = self.state.pop1()?; + let v = self.v128_into_f64x2(v); let idx = self.intrinsics.i32_ty.const_int(lane.into(), false); let res = self.builder.build_extract_element(v, idx, ""); - self.state.push1_extra(res, i); + self.state.push1(res); } Operator::I8x16ReplaceLane { lane } => { - let ((v1, i1), (v2, _)) = self.state.pop2_extra()?; - let (v1, _) = self.v128_into_i8x16(v1, i1); + let (v1, v2) = self.state.pop2()?; + let v1 = self.v128_into_i8x16(v1); let v2 = v2.into_int_value(); let v2 = self.builder.build_int_cast(v2, self.intrinsics.i8_ty, ""); let idx = self.intrinsics.i32_ty.const_int(lane.into(), false); @@ -6951,8 +7218,8 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { self.state.push1(res); } Operator::I16x8ReplaceLane { lane } => { - let ((v1, i1), (v2, _)) = self.state.pop2_extra()?; - let (v1, _) = self.v128_into_i16x8(v1, i1); + let (v1, v2) = self.state.pop2()?; + let v1 = self.v128_into_i16x8(v1); let v2 = v2.into_int_value(); let v2 = self.builder.build_int_cast(v2, self.intrinsics.i16_ty, ""); let idx = self.intrinsics.i32_ty.const_int(lane.into(), false); @@ -6961,87 +7228,51 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { self.state.push1(res); } Operator::I32x4ReplaceLane { lane } => { - let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; - let (v1, i1) = self.v128_into_i32x4(v1, i1); - let v2 = self.apply_pending_canonicalization(v2, i2); + let (v1, v2) = self.state.pop2()?; + let v1 = self.v128_into_i32x4(v1); let v2 = v2.into_int_value(); - let i2 = i2.strip_pending(); let idx = self.intrinsics.i32_ty.const_int(lane.into(), false); + let res = self.builder.build_insert_element(v1, v2, idx, ""); + let res = self.builder.build_bitcast(res, self.intrinsics.i128_ty, ""); - self.state - .push1_extra(res, i1 & i2 & ExtraInfo::arithmetic_f32()); + self.state.push1(res); } Operator::I64x2ReplaceLane { lane } => { - let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; - let (v1, i1) = self.v128_into_i64x2(v1, i1); - let v2 = self.apply_pending_canonicalization(v2, i2); + let (v1, v2) = self.state.pop2()?; + let v1 = self.v128_into_i64x2(v1); let v2 = v2.into_int_value(); - let i2 = i2.strip_pending(); let idx = self.intrinsics.i32_ty.const_int(lane.into(), false); + let res = self.builder.build_insert_element(v1, v2, idx, ""); + let res = self.builder.build_bitcast(res, self.intrinsics.i128_ty, ""); - self.state - .push1_extra(res, i1 & i2 & ExtraInfo::arithmetic_f64()); + self.state.push1(res); } Operator::F32x4ReplaceLane { lane } => { - let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; - let (v1, i1) = self.v128_into_f32x4(v1, i1); - let push_pending_f32_nan_to_result = - i1.has_pending_f32_nan() && i2.has_pending_f32_nan(); - let (v1, v2) = if !push_pending_f32_nan_to_result { - ( - self.apply_pending_canonicalization(v1.as_basic_value_enum(), i1) - .into_vector_value(), - self.apply_pending_canonicalization(v2.as_basic_value_enum(), i2) - .into_float_value(), - ) - } else { - (v1, v2.into_float_value()) - }; + let (v1, v2) = self.state.pop2()?; + let v1 = self.v128_into_f32x4(v1); + let v2 = v2.into_float_value(); let idx = self.intrinsics.i32_ty.const_int(lane.into(), false); let res = self.builder.build_insert_element(v1, v2, idx, ""); let res = self.builder.build_bitcast(res, self.intrinsics.i128_ty, ""); - let info = if push_pending_f32_nan_to_result { - ExtraInfo::pending_f32_nan() - } else { - i1.strip_pending() & i2.strip_pending() - }; - self.state.push1_extra(res, info); + self.state.push1(res); } Operator::F64x2ReplaceLane { lane } => { - let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; - let (v1, i1) = self.v128_into_f64x2(v1, i1); - let push_pending_f64_nan_to_result = - i1.has_pending_f64_nan() && i2.has_pending_f64_nan(); - let (v1, v2) = if !push_pending_f64_nan_to_result { - ( - self.apply_pending_canonicalization(v1.as_basic_value_enum(), i1) - .into_vector_value(), - self.apply_pending_canonicalization(v2.as_basic_value_enum(), i2) - .into_float_value(), - ) - } else { - (v1, v2.into_float_value()) - }; + let (v1, v2) = self.state.pop2()?; + let v1 = self.v128_into_f64x2(v1); + let v2 = v2.into_float_value(); let idx = self.intrinsics.i32_ty.const_int(lane.into(), false); let res = self.builder.build_insert_element(v1, v2, idx, ""); let res = self.builder.build_bitcast(res, self.intrinsics.i128_ty, ""); - let info = if push_pending_f64_nan_to_result { - ExtraInfo::pending_f64_nan() - } else { - i1.strip_pending() & i2.strip_pending() - }; - self.state.push1_extra(res, info); + self.state.push1(res); } Operator::I8x16Swizzle => { - let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; - let v1 = self.apply_pending_canonicalization(v1, i1); + let (v1, v2) = self.state.pop2()?; let v1 = self .builder .build_bitcast(v1, self.intrinsics.i8x16_ty, "") .into_vector_value(); - let v2 = self.apply_pending_canonicalization(v2, i2); let v2 = self .builder .build_bitcast(v2, self.intrinsics.i8x16_ty, "") @@ -7103,13 +7334,11 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { self.state.push1(res); } Operator::I8x16Shuffle { lanes } => { - let ((v1, i1), (v2, i2)) = self.state.pop2_extra()?; - let v1 = self.apply_pending_canonicalization(v1, i1); + let (v1, v2) = self.state.pop2()?; let v1 = self .builder .build_bitcast(v1, self.intrinsics.i8x16_ty, "") .into_vector_value(); - let v2 = self.apply_pending_canonicalization(v2, i2); let v2 = self .builder .build_bitcast(v2, self.intrinsics.i8x16_ty, "") @@ -7450,7 +7679,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { let result = self.builder .build_int_z_extend(narrow_result, self.intrinsics.i32_ty, ""); - self.state.push1_extra(result, ExtraInfo::arithmetic_f32()); + self.state.push1(result); } Operator::I32AtomicLoad16U { ref memarg } => { let offset = self.state.pop1()?.into_int_value(); @@ -7474,7 +7703,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { let result = self.builder .build_int_z_extend(narrow_result, self.intrinsics.i32_ty, ""); - self.state.push1_extra(result, ExtraInfo::arithmetic_f32()); + self.state.push1(result); } Operator::I64AtomicLoad8U { ref memarg } => { let offset = self.state.pop1()?.into_int_value(); @@ -7498,7 +7727,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { let result = self.builder .build_int_z_extend(narrow_result, self.intrinsics.i64_ty, ""); - self.state.push1_extra(result, ExtraInfo::arithmetic_f64()); + self.state.push1(result); } Operator::I64AtomicLoad16U { ref memarg } => { let offset = self.state.pop1()?.into_int_value(); @@ -7522,7 +7751,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { let result = self.builder .build_int_z_extend(narrow_result, self.intrinsics.i64_ty, ""); - self.state.push1_extra(result, ExtraInfo::arithmetic_f64()); + self.state.push1(result); } Operator::I64AtomicLoad32U { ref memarg } => { let offset = self.state.pop1()?.into_int_value(); @@ -7546,7 +7775,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { let result = self.builder .build_int_z_extend(narrow_result, self.intrinsics.i64_ty, ""); - self.state.push1_extra(result, ExtraInfo::arithmetic_f64()); + self.state.push1(result); } Operator::I32AtomicStore { ref memarg } => { let value = self.state.pop1()?; @@ -7681,7 +7910,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { let old = self .builder .build_int_z_extend(old, self.intrinsics.i32_ty, ""); - self.state.push1_extra(old, ExtraInfo::arithmetic_f32()); + self.state.push1(old); } Operator::I32AtomicRmw16AddU { ref memarg } => { let value = self.state.pop1()?.into_int_value(); @@ -7716,7 +7945,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { let old = self .builder .build_int_z_extend(old, self.intrinsics.i32_ty, ""); - self.state.push1_extra(old, ExtraInfo::arithmetic_f32()); + self.state.push1(old); } Operator::I32AtomicRmwAdd { ref memarg } => { let value = self.state.pop1()?.into_int_value(); @@ -7780,7 +8009,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { let old = self .builder .build_int_z_extend(old, self.intrinsics.i64_ty, ""); - self.state.push1_extra(old, ExtraInfo::arithmetic_f64()); + self.state.push1(old); } Operator::I64AtomicRmw16AddU { ref memarg } => { let value = self.state.pop1()?.into_int_value(); @@ -7815,7 +8044,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { let old = self .builder .build_int_z_extend(old, self.intrinsics.i64_ty, ""); - self.state.push1_extra(old, ExtraInfo::arithmetic_f64()); + self.state.push1(old); } Operator::I64AtomicRmw32AddU { ref memarg } => { let value = self.state.pop1()?.into_int_value(); @@ -7850,7 +8079,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { let old = self .builder .build_int_z_extend(old, self.intrinsics.i64_ty, ""); - self.state.push1_extra(old, ExtraInfo::arithmetic_f64()); + self.state.push1(old); } Operator::I64AtomicRmwAdd { ref memarg } => { let value = self.state.pop1()?.into_int_value(); @@ -7914,7 +8143,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { let old = self .builder .build_int_z_extend(old, self.intrinsics.i32_ty, ""); - self.state.push1_extra(old, ExtraInfo::arithmetic_f32()); + self.state.push1(old); } Operator::I32AtomicRmw16SubU { ref memarg } => { let value = self.state.pop1()?.into_int_value(); @@ -7949,7 +8178,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { let old = self .builder .build_int_z_extend(old, self.intrinsics.i32_ty, ""); - self.state.push1_extra(old, ExtraInfo::arithmetic_f32()); + self.state.push1(old); } Operator::I32AtomicRmwSub { ref memarg } => { let value = self.state.pop1()?.into_int_value(); @@ -8013,7 +8242,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { let old = self .builder .build_int_z_extend(old, self.intrinsics.i64_ty, ""); - self.state.push1_extra(old, ExtraInfo::arithmetic_f32()); + self.state.push1(old); } Operator::I64AtomicRmw16SubU { ref memarg } => { let value = self.state.pop1()?.into_int_value(); @@ -8048,7 +8277,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { let old = self .builder .build_int_z_extend(old, self.intrinsics.i64_ty, ""); - self.state.push1_extra(old, ExtraInfo::arithmetic_f64()); + self.state.push1(old); } Operator::I64AtomicRmw32SubU { ref memarg } => { let value = self.state.pop1()?.into_int_value(); @@ -8083,7 +8312,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { let old = self .builder .build_int_z_extend(old, self.intrinsics.i64_ty, ""); - self.state.push1_extra(old, ExtraInfo::arithmetic_f64()); + self.state.push1(old); } Operator::I64AtomicRmwSub { ref memarg } => { let value = self.state.pop1()?.into_int_value(); @@ -8147,7 +8376,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { let old = self .builder .build_int_z_extend(old, self.intrinsics.i32_ty, ""); - self.state.push1_extra(old, ExtraInfo::arithmetic_f32()); + self.state.push1(old); } Operator::I32AtomicRmw16AndU { ref memarg } => { let value = self.state.pop1()?.into_int_value(); @@ -8182,7 +8411,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { let old = self .builder .build_int_z_extend(old, self.intrinsics.i32_ty, ""); - self.state.push1_extra(old, ExtraInfo::arithmetic_f32()); + self.state.push1(old); } Operator::I32AtomicRmwAnd { ref memarg } => { let value = self.state.pop1()?.into_int_value(); @@ -8246,7 +8475,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { let old = self .builder .build_int_z_extend(old, self.intrinsics.i64_ty, ""); - self.state.push1_extra(old, ExtraInfo::arithmetic_f64()); + self.state.push1(old); } Operator::I64AtomicRmw16AndU { ref memarg } => { let value = self.state.pop1()?.into_int_value(); @@ -8281,7 +8510,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { let old = self .builder .build_int_z_extend(old, self.intrinsics.i64_ty, ""); - self.state.push1_extra(old, ExtraInfo::arithmetic_f64()); + self.state.push1(old); } Operator::I64AtomicRmw32AndU { ref memarg } => { let value = self.state.pop1()?.into_int_value(); @@ -8316,7 +8545,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { let old = self .builder .build_int_z_extend(old, self.intrinsics.i64_ty, ""); - self.state.push1_extra(old, ExtraInfo::arithmetic_f64()); + self.state.push1(old); } Operator::I64AtomicRmwAnd { ref memarg } => { let value = self.state.pop1()?.into_int_value(); @@ -8380,7 +8609,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { let old = self .builder .build_int_z_extend(old, self.intrinsics.i32_ty, ""); - self.state.push1_extra(old, ExtraInfo::arithmetic_f32()); + self.state.push1(old); } Operator::I32AtomicRmw16OrU { ref memarg } => { let value = self.state.pop1()?.into_int_value(); @@ -8415,7 +8644,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { let old = self .builder .build_int_z_extend(old, self.intrinsics.i32_ty, ""); - self.state.push1_extra(old, ExtraInfo::arithmetic_f32()); + self.state.push1(old); } Operator::I32AtomicRmwOr { ref memarg } => { let value = self.state.pop1()?.into_int_value(); @@ -8447,7 +8676,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { let old = self .builder .build_int_z_extend(old, self.intrinsics.i32_ty, ""); - self.state.push1_extra(old, ExtraInfo::arithmetic_f32()); + self.state.push1(old); } Operator::I64AtomicRmw8OrU { ref memarg } => { let value = self.state.pop1()?.into_int_value(); @@ -8482,7 +8711,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { let old = self .builder .build_int_z_extend(old, self.intrinsics.i64_ty, ""); - self.state.push1_extra(old, ExtraInfo::arithmetic_f64()); + self.state.push1(old); } Operator::I64AtomicRmw16OrU { ref memarg } => { let value = self.state.pop1()?.into_int_value(); @@ -8517,7 +8746,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { let old = self .builder .build_int_z_extend(old, self.intrinsics.i64_ty, ""); - self.state.push1_extra(old, ExtraInfo::arithmetic_f64()); + self.state.push1(old); } Operator::I64AtomicRmw32OrU { ref memarg } => { let value = self.state.pop1()?.into_int_value(); @@ -8552,7 +8781,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { let old = self .builder .build_int_z_extend(old, self.intrinsics.i64_ty, ""); - self.state.push1_extra(old, ExtraInfo::arithmetic_f64()); + self.state.push1(old); } Operator::I64AtomicRmwOr { ref memarg } => { let value = self.state.pop1()?.into_int_value(); @@ -8616,7 +8845,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { let old = self .builder .build_int_z_extend(old, self.intrinsics.i32_ty, ""); - self.state.push1_extra(old, ExtraInfo::arithmetic_f32()); + self.state.push1(old); } Operator::I32AtomicRmw16XorU { ref memarg } => { let value = self.state.pop1()?.into_int_value(); @@ -8651,7 +8880,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { let old = self .builder .build_int_z_extend(old, self.intrinsics.i32_ty, ""); - self.state.push1_extra(old, ExtraInfo::arithmetic_f32()); + self.state.push1(old); } Operator::I32AtomicRmwXor { ref memarg } => { let value = self.state.pop1()?.into_int_value(); @@ -8715,7 +8944,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { let old = self .builder .build_int_z_extend(old, self.intrinsics.i64_ty, ""); - self.state.push1_extra(old, ExtraInfo::arithmetic_f64()); + self.state.push1(old); } Operator::I64AtomicRmw16XorU { ref memarg } => { let value = self.state.pop1()?.into_int_value(); @@ -8750,7 +8979,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { let old = self .builder .build_int_z_extend(old, self.intrinsics.i64_ty, ""); - self.state.push1_extra(old, ExtraInfo::arithmetic_f64()); + self.state.push1(old); } Operator::I64AtomicRmw32XorU { ref memarg } => { let value = self.state.pop1()?.into_int_value(); @@ -8785,7 +9014,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { let old = self .builder .build_int_z_extend(old, self.intrinsics.i64_ty, ""); - self.state.push1_extra(old, ExtraInfo::arithmetic_f64()); + self.state.push1(old); } Operator::I64AtomicRmwXor { ref memarg } => { let value = self.state.pop1()?.into_int_value(); @@ -8849,7 +9078,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { let old = self .builder .build_int_z_extend(old, self.intrinsics.i32_ty, ""); - self.state.push1_extra(old, ExtraInfo::arithmetic_f32()); + self.state.push1(old); } Operator::I32AtomicRmw16XchgU { ref memarg } => { let value = self.state.pop1()?.into_int_value(); @@ -8884,7 +9113,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { let old = self .builder .build_int_z_extend(old, self.intrinsics.i32_ty, ""); - self.state.push1_extra(old, ExtraInfo::arithmetic_f32()); + self.state.push1(old); } Operator::I32AtomicRmwXchg { ref memarg } => { let value = self.state.pop1()?.into_int_value(); @@ -8948,7 +9177,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { let old = self .builder .build_int_z_extend(old, self.intrinsics.i64_ty, ""); - self.state.push1_extra(old, ExtraInfo::arithmetic_f64()); + self.state.push1(old); } Operator::I64AtomicRmw16XchgU { ref memarg } => { let value = self.state.pop1()?.into_int_value(); @@ -8983,7 +9212,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { let old = self .builder .build_int_z_extend(old, self.intrinsics.i64_ty, ""); - self.state.push1_extra(old, ExtraInfo::arithmetic_f64()); + self.state.push1(old); } Operator::I64AtomicRmw32XchgU { ref memarg } => { let value = self.state.pop1()?.into_int_value(); @@ -9018,7 +9247,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { let old = self .builder .build_int_z_extend(old, self.intrinsics.i64_ty, ""); - self.state.push1_extra(old, ExtraInfo::arithmetic_f64()); + self.state.push1(old); } Operator::I64AtomicRmwXchg { ref memarg } => { let value = self.state.pop1()?.into_int_value(); @@ -9050,9 +9279,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { self.state.push1(old); } Operator::I32AtomicRmw8CmpxchgU { ref memarg } => { - let ((cmp, cmp_info), (new, new_info)) = self.state.pop2_extra()?; - let cmp = self.apply_pending_canonicalization(cmp, cmp_info); - let new = self.apply_pending_canonicalization(new, new_info); + let (cmp, new) = self.state.pop2()?; let (cmp, new) = (cmp.into_int_value(), new.into_int_value()); let offset = self.state.pop1()?.into_int_value(); let memory_index = MemoryIndex::from_u32(0); @@ -9094,12 +9321,10 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { let old = self .builder .build_int_z_extend(old, self.intrinsics.i32_ty, ""); - self.state.push1_extra(old, ExtraInfo::arithmetic_f32()); + self.state.push1(old); } Operator::I32AtomicRmw16CmpxchgU { ref memarg } => { - let ((cmp, cmp_info), (new, new_info)) = self.state.pop2_extra()?; - let cmp = self.apply_pending_canonicalization(cmp, cmp_info); - let new = self.apply_pending_canonicalization(new, new_info); + let (cmp, new) = self.state.pop2()?; let (cmp, new) = (cmp.into_int_value(), new.into_int_value()); let offset = self.state.pop1()?.into_int_value(); let memory_index = MemoryIndex::from_u32(0); @@ -9141,12 +9366,10 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { let old = self .builder .build_int_z_extend(old, self.intrinsics.i32_ty, ""); - self.state.push1_extra(old, ExtraInfo::arithmetic_f32()); + self.state.push1(old); } Operator::I32AtomicRmwCmpxchg { ref memarg } => { - let ((cmp, cmp_info), (new, new_info)) = self.state.pop2_extra()?; - let cmp = self.apply_pending_canonicalization(cmp, cmp_info); - let new = self.apply_pending_canonicalization(new, new_info); + let (cmp, new) = self.state.pop2()?; let (cmp, new) = (cmp.into_int_value(), new.into_int_value()); let offset = self.state.pop1()?.into_int_value(); let memory_index = MemoryIndex::from_u32(0); @@ -9178,9 +9401,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { self.state.push1(old); } Operator::I64AtomicRmw8CmpxchgU { ref memarg } => { - let ((cmp, cmp_info), (new, new_info)) = self.state.pop2_extra()?; - let cmp = self.apply_pending_canonicalization(cmp, cmp_info); - let new = self.apply_pending_canonicalization(new, new_info); + let (cmp, new) = self.state.pop2()?; let (cmp, new) = (cmp.into_int_value(), new.into_int_value()); let offset = self.state.pop1()?.into_int_value(); let memory_index = MemoryIndex::from_u32(0); @@ -9222,12 +9443,10 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { let old = self .builder .build_int_z_extend(old, self.intrinsics.i64_ty, ""); - self.state.push1_extra(old, ExtraInfo::arithmetic_f64()); + self.state.push1(old); } Operator::I64AtomicRmw16CmpxchgU { ref memarg } => { - let ((cmp, cmp_info), (new, new_info)) = self.state.pop2_extra()?; - let cmp = self.apply_pending_canonicalization(cmp, cmp_info); - let new = self.apply_pending_canonicalization(new, new_info); + let (cmp, new) = self.state.pop2()?; let (cmp, new) = (cmp.into_int_value(), new.into_int_value()); let offset = self.state.pop1()?.into_int_value(); let memory_index = MemoryIndex::from_u32(0); @@ -9269,12 +9488,10 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { let old = self .builder .build_int_z_extend(old, self.intrinsics.i64_ty, ""); - self.state.push1_extra(old, ExtraInfo::arithmetic_f64()); + self.state.push1(old); } Operator::I64AtomicRmw32CmpxchgU { ref memarg } => { - let ((cmp, cmp_info), (new, new_info)) = self.state.pop2_extra()?; - let cmp = self.apply_pending_canonicalization(cmp, cmp_info); - let new = self.apply_pending_canonicalization(new, new_info); + let (cmp, new) = self.state.pop2()?; let (cmp, new) = (cmp.into_int_value(), new.into_int_value()); let offset = self.state.pop1()?.into_int_value(); let memory_index = MemoryIndex::from_u32(0); @@ -9316,12 +9533,10 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { let old = self .builder .build_int_z_extend(old, self.intrinsics.i64_ty, ""); - self.state.push1_extra(old, ExtraInfo::arithmetic_f64()); + self.state.push1(old); } Operator::I64AtomicRmwCmpxchg { ref memarg } => { - let ((cmp, cmp_info), (new, new_info)) = self.state.pop2_extra()?; - let cmp = self.apply_pending_canonicalization(cmp, cmp_info); - let new = self.apply_pending_canonicalization(new, new_info); + let (cmp, new) = self.state.pop2()?; let (cmp, new) = (cmp.into_int_value(), new.into_int_value()); let offset = self.state.pop1()?.into_int_value(); let memory_index = MemoryIndex::from_u32(0); @@ -9353,7 +9568,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { self.state.push1(old); } - Operator::MemoryGrow { mem, mem_byte: _ } => { + Operator::MemoryGrow { mem, .. } => { let memory_index = MemoryIndex::from_u32(mem); let delta = self.state.pop1()?; let grow_fn_ptr = self.ctx.memory_grow(memory_index, self.intrinsics); @@ -9371,7 +9586,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { ); self.state.push1(grow.try_as_basic_value().left().unwrap()); } - Operator::MemorySize { mem, mem_byte: _ } => { + Operator::MemorySize { mem, .. } => { let memory_index = MemoryIndex::from_u32(mem); let size_fn_ptr = self.ctx.memory_size(memory_index, self.intrinsics); let size = self.builder.build_call( @@ -9388,6 +9603,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { size.add_attribute(AttributeLoc::Function, self.intrinsics.readonly); self.state.push1(size.try_as_basic_value().left().unwrap()); } + /*************************** * Reference types. * https://github.com/WebAssembly/reference-types/blob/master/proposals/reference-types/Overview.md @@ -9597,6 +9813,7 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { .unwrap(); self.state.push1(size); } + _ => { return Err(CompileError::Codegen(format!( "Operator {:?} unimplemented", @@ -9609,18 +9826,6 @@ impl<'ctx, 'a> LLVMFunctionCodeGenerator<'ctx, 'a> { } } -fn is_f32_arithmetic(bits: u32) -> bool { - // Mask off sign bit. - let bits = bits & 0x7FFF_FFFF; - bits < 0x7FC0_0000 -} - -fn is_f64_arithmetic(bits: u64) -> bool { - // Mask off sign bit. - let bits = bits & 0x7FFF_FFFF_FFFF_FFFF; - bits < 0x7FF8_0000_0000_0000 -} - // Constants for the bounds of truncation operations. These are the least or // greatest exact floats in either f32 or f64 representation // greater-than-or-equal-to (for least) or less-than-or-equal-to (for greatest) diff --git a/lib/compiler-llvm/src/translator/intrinsics.rs b/lib/compiler-llvm/src/translator/intrinsics.rs index a2274cac5a7..9c8cd64caed 100644 --- a/lib/compiler-llvm/src/translator/intrinsics.rs +++ b/lib/compiler-llvm/src/translator/intrinsics.rs @@ -70,11 +70,62 @@ pub struct Intrinsics<'ctx> { pub ctpop_i32: FunctionValue<'ctx>, pub ctpop_i64: FunctionValue<'ctx>, + pub fp_rounding_md: BasicValueEnum<'ctx>, + pub fp_exception_md: BasicValueEnum<'ctx>, + pub fp_oeq_md: BasicValueEnum<'ctx>, + pub fp_ogt_md: BasicValueEnum<'ctx>, + pub fp_oge_md: BasicValueEnum<'ctx>, + pub fp_olt_md: BasicValueEnum<'ctx>, + pub fp_ole_md: BasicValueEnum<'ctx>, + pub fp_one_md: BasicValueEnum<'ctx>, + pub fp_ord_md: BasicValueEnum<'ctx>, + pub fp_ueq_md: BasicValueEnum<'ctx>, + pub fp_ugt_md: BasicValueEnum<'ctx>, + pub fp_ult_md: BasicValueEnum<'ctx>, + pub fp_ule_md: BasicValueEnum<'ctx>, + pub fp_une_md: BasicValueEnum<'ctx>, + pub fp_uno_md: BasicValueEnum<'ctx>, + + pub add_f32: FunctionValue<'ctx>, + pub add_f64: FunctionValue<'ctx>, + pub add_f32x4: FunctionValue<'ctx>, + pub add_f64x2: FunctionValue<'ctx>, + + pub sub_f32: FunctionValue<'ctx>, + pub sub_f64: FunctionValue<'ctx>, + pub sub_f32x4: FunctionValue<'ctx>, + pub sub_f64x2: FunctionValue<'ctx>, + + pub mul_f32: FunctionValue<'ctx>, + pub mul_f64: FunctionValue<'ctx>, + pub mul_f32x4: FunctionValue<'ctx>, + pub mul_f64x2: FunctionValue<'ctx>, + + pub div_f32: FunctionValue<'ctx>, + pub div_f64: FunctionValue<'ctx>, + pub div_f32x4: FunctionValue<'ctx>, + pub div_f64x2: FunctionValue<'ctx>, + pub sqrt_f32: FunctionValue<'ctx>, pub sqrt_f64: FunctionValue<'ctx>, pub sqrt_f32x4: FunctionValue<'ctx>, pub sqrt_f64x2: FunctionValue<'ctx>, + pub max_f32: FunctionValue<'ctx>, + pub max_f64: FunctionValue<'ctx>, + pub max_f32x4: FunctionValue<'ctx>, + pub max_f64x2: FunctionValue<'ctx>, + + pub min_f32: FunctionValue<'ctx>, + pub min_f64: FunctionValue<'ctx>, + pub min_f32x4: FunctionValue<'ctx>, + pub min_f64x2: FunctionValue<'ctx>, + + pub cmp_f32: FunctionValue<'ctx>, + pub cmp_f64: FunctionValue<'ctx>, + pub cmp_f32x4: FunctionValue<'ctx>, + pub cmp_f64x2: FunctionValue<'ctx>, + pub ceil_f32: FunctionValue<'ctx>, pub ceil_f64: FunctionValue<'ctx>, @@ -84,6 +135,9 @@ pub struct Intrinsics<'ctx> { pub trunc_f32: FunctionValue<'ctx>, pub trunc_f64: FunctionValue<'ctx>, + pub fpext_f32: FunctionValue<'ctx>, + pub fptrunc_f64: FunctionValue<'ctx>, + pub nearbyint_f32: FunctionValue<'ctx>, pub nearbyint_f64: FunctionValue<'ctx>, @@ -216,6 +270,8 @@ impl<'ctx> Intrinsics<'ctx> { let f32_ty = context.f32_type(); let f64_ty = context.f64_type(); + let i1x4_ty = i1_ty.vec_type(4); + let i1x2_ty = i1_ty.vec_type(2); let i1x128_ty = i1_ty.vec_type(128); let i8x16_ty = i8_ty.vec_type(16); let i16x8_ty = i16_ty.vec_type(8); @@ -270,6 +326,9 @@ impl<'ctx> Intrinsics<'ctx> { let externref_ty = funcref_ty; let anyref_ty = i8_ptr_ty; + let md_ty = context.metadata_type(); + let md_ty_basic = md_ty.as_basic_type_enum(); + let ret_i8x16_take_i8x16_i8x16 = i8x16_ty.fn_type(&[i8x16_ty_basic, i8x16_ty_basic], false); let ret_i16x8_take_i16x8_i16x8 = i16x8_ty.fn_type(&[i16x8_ty_basic, i16x8_ty_basic], false); @@ -284,6 +343,82 @@ impl<'ctx> Intrinsics<'ctx> { let ret_f32x4_take_f32x4 = f32x4_ty.fn_type(&[f32x4_ty_basic], false); let ret_f64x2_take_f64x2 = f64x2_ty.fn_type(&[f64x2_ty_basic], false); + let ret_f32_take_f32_md = f32_ty.fn_type(&[f32_ty_basic, md_ty_basic], false); + let ret_f64_take_f64_md = f64_ty.fn_type(&[f64_ty_basic, md_ty_basic], false); + + let ret_f32_take_f64_md_md = + f32_ty.fn_type(&[f64_ty_basic, md_ty_basic, md_ty_basic], false); + let ret_f64_take_f32_md = f64_ty.fn_type(&[f32_ty_basic, md_ty_basic], false); + + let ret_i1_take_f32_f32_md_md = i1_ty.fn_type( + &[f32_ty_basic, f32_ty_basic, md_ty_basic, md_ty_basic], + false, + ); + let ret_i1_take_f64_f64_md_md = i1_ty.fn_type( + &[f64_ty_basic, f64_ty_basic, md_ty_basic, md_ty_basic], + false, + ); + let ret_i1x4_take_f32x4_f32x4_md_md = i1x4_ty.fn_type( + &[f32x4_ty_basic, f32x4_ty_basic, md_ty_basic, md_ty_basic], + false, + ); + let ret_i1x2_take_f64x2_f64x2_md_md = i1x2_ty.fn_type( + &[f64x2_ty_basic, f64x2_ty_basic, md_ty_basic, md_ty_basic], + false, + ); + + let ret_f32_take_f32_md_md = + f32_ty.fn_type(&[f32_ty_basic, md_ty_basic, md_ty_basic], false); + let ret_f64_take_f64_md_md = + f64_ty.fn_type(&[f64_ty_basic, md_ty_basic, md_ty_basic], false); + let ret_f32x4_take_f32x4_md_md = + f32x4_ty.fn_type(&[f32x4_ty_basic, md_ty_basic, md_ty_basic], false); + let ret_f64x2_take_f64x2_md_md = + f64x2_ty.fn_type(&[f64x2_ty_basic, md_ty_basic, md_ty_basic], false); + + let ret_f32_take_f32_f32_md = + f32_ty.fn_type(&[f32_ty_basic, f32_ty_basic, md_ty_basic], false); + let ret_f64_take_f64_f64_md = + f64_ty.fn_type(&[f64_ty_basic, f64_ty_basic, md_ty_basic], false); + let ret_f32x4_take_f32x4_f32x4_md = + f32x4_ty.fn_type(&[f32x4_ty_basic, f32x4_ty_basic, md_ty_basic], false); + let ret_f64x2_take_f64x2_f64x2_md = + f64x2_ty.fn_type(&[f64x2_ty_basic, f64x2_ty_basic, md_ty_basic], false); + + let ret_f32_take_f32_f32_md_md = f32_ty.fn_type( + &[f32_ty_basic, f32_ty_basic, md_ty_basic, md_ty_basic], + false, + ); + let ret_f64_take_f64_f64_md_md = f64_ty.fn_type( + &[f64_ty_basic, f64_ty_basic, md_ty_basic, md_ty_basic], + false, + ); + let ret_f32x4_take_f32x4_f32x4_md_md = f32x4_ty.fn_type( + &[f32x4_ty_basic, f32x4_ty_basic, md_ty_basic, md_ty_basic], + false, + ); + let ret_f64x2_take_f64x2_f64x2_md_md = f64x2_ty.fn_type( + &[f64x2_ty_basic, f64x2_ty_basic, md_ty_basic, md_ty_basic], + false, + ); + + let fp_rounding_md = context.metadata_string("round.tonearest"); + let fp_exception_md = context.metadata_string("fpexcept.strict"); + + let fp_oeq_md = context.metadata_string("oeq"); + let fp_ogt_md = context.metadata_string("ogt"); + let fp_oge_md = context.metadata_string("oge"); + let fp_olt_md = context.metadata_string("olt"); + let fp_ole_md = context.metadata_string("ole"); + let fp_one_md = context.metadata_string("one"); + let fp_ord_md = context.metadata_string("ord"); + let fp_ueq_md = context.metadata_string("ueq"); + let fp_ugt_md = context.metadata_string("ugt"); + let fp_ult_md = context.metadata_string("ult"); + let fp_ule_md = context.metadata_string("ule"); + let fp_une_md = context.metadata_string("une"); + let fp_uno_md = context.metadata_string("uno"); + let ret_f32_take_f32_f32 = f32_ty.fn_type(&[f32_ty_basic, f32_ty_basic], false); let ret_f64_take_f64_f64 = f64_ty.fn_type(&[f64_ty_basic, f64_ty_basic], false); let ret_f32x4_take_f32x4_f32x4 = f32x4_ty.fn_type(&[f32x4_ty_basic, f32x4_ty_basic], false); @@ -300,22 +435,245 @@ impl<'ctx> Intrinsics<'ctx> { ctpop_i32: module.add_function("llvm.ctpop.i32", ret_i32_take_i32, None), ctpop_i64: module.add_function("llvm.ctpop.i64", ret_i64_take_i64, None), - sqrt_f32: module.add_function("llvm.sqrt.f32", ret_f32_take_f32, None), - sqrt_f64: module.add_function("llvm.sqrt.f64", ret_f64_take_f64, None), - sqrt_f32x4: module.add_function("llvm.sqrt.v4f32", ret_f32x4_take_f32x4, None), - sqrt_f64x2: module.add_function("llvm.sqrt.v2f64", ret_f64x2_take_f64x2, None), + fp_rounding_md: fp_rounding_md.as_basic_value_enum(), + fp_exception_md: fp_exception_md.as_basic_value_enum(), + + fp_oeq_md: fp_oeq_md.as_basic_value_enum(), + fp_ogt_md: fp_ogt_md.as_basic_value_enum(), + fp_oge_md: fp_oge_md.as_basic_value_enum(), + fp_olt_md: fp_olt_md.as_basic_value_enum(), + fp_ole_md: fp_ole_md.as_basic_value_enum(), + fp_one_md: fp_one_md.as_basic_value_enum(), + fp_ord_md: fp_ord_md.as_basic_value_enum(), + fp_ueq_md: fp_ueq_md.as_basic_value_enum(), + fp_ugt_md: fp_ugt_md.as_basic_value_enum(), + fp_ult_md: fp_ult_md.as_basic_value_enum(), + fp_ule_md: fp_ule_md.as_basic_value_enum(), + fp_une_md: fp_une_md.as_basic_value_enum(), + fp_uno_md: fp_uno_md.as_basic_value_enum(), + + add_f32: module.add_function( + "llvm.experimental.constrained.fadd.f32", + ret_f32_take_f32_f32_md_md, + None, + ), + add_f64: module.add_function( + "llvm.experimental.constrained.fadd.f64", + ret_f64_take_f64_f64_md_md, + None, + ), + add_f32x4: module.add_function( + "llvm.experimental.constrained.fadd.v4f32", + ret_f32x4_take_f32x4_f32x4_md_md, + None, + ), + add_f64x2: module.add_function( + "llvm.experimental.constrained.fadd.v2f64", + ret_f64x2_take_f64x2_f64x2_md_md, + None, + ), - ceil_f32: module.add_function("llvm.ceil.f32", ret_f32_take_f32, None), - ceil_f64: module.add_function("llvm.ceil.f64", ret_f64_take_f64, None), + sub_f32: module.add_function( + "llvm.experimental.constrained.fsub.f32", + ret_f32_take_f32_f32_md_md, + None, + ), + sub_f64: module.add_function( + "llvm.experimental.constrained.fsub.f64", + ret_f64_take_f64_f64_md_md, + None, + ), + sub_f32x4: module.add_function( + "llvm.experimental.constrained.fsub.v4f32", + ret_f32x4_take_f32x4_f32x4_md_md, + None, + ), + sub_f64x2: module.add_function( + "llvm.experimental.constrained.fsub.v2f64", + ret_f64x2_take_f64x2_f64x2_md_md, + None, + ), - floor_f32: module.add_function("llvm.floor.f32", ret_f32_take_f32, None), - floor_f64: module.add_function("llvm.floor.f64", ret_f64_take_f64, None), + mul_f32: module.add_function( + "llvm.experimental.constrained.fmul.f32", + ret_f32_take_f32_f32_md_md, + None, + ), + mul_f64: module.add_function( + "llvm.experimental.constrained.fmul.f64", + ret_f64_take_f64_f64_md_md, + None, + ), + mul_f32x4: module.add_function( + "llvm.experimental.constrained.fmul.v4f32", + ret_f32x4_take_f32x4_f32x4_md_md, + None, + ), + mul_f64x2: module.add_function( + "llvm.experimental.constrained.fmul.v2f64", + ret_f64x2_take_f64x2_f64x2_md_md, + None, + ), - trunc_f32: module.add_function("llvm.trunc.f32", ret_f32_take_f32, None), - trunc_f64: module.add_function("llvm.trunc.f64", ret_f64_take_f64, None), + div_f32: module.add_function( + "llvm.experimental.constrained.fdiv.f32", + ret_f32_take_f32_f32_md_md, + None, + ), + div_f64: module.add_function( + "llvm.experimental.constrained.fdiv.f64", + ret_f64_take_f64_f64_md_md, + None, + ), + div_f32x4: module.add_function( + "llvm.experimental.constrained.fdiv.v4f32", + ret_f32x4_take_f32x4_f32x4_md_md, + None, + ), + div_f64x2: module.add_function( + "llvm.experimental.constrained.fdiv.v2f64", + ret_f64x2_take_f64x2_f64x2_md_md, + None, + ), - nearbyint_f32: module.add_function("llvm.nearbyint.f32", ret_f32_take_f32, None), - nearbyint_f64: module.add_function("llvm.nearbyint.f64", ret_f64_take_f64, None), + sqrt_f32: module.add_function( + "llvm.experimental.constrained.sqrt.f32", + ret_f32_take_f32_md_md, + None, + ), + sqrt_f64: module.add_function( + "llvm.experimental.constrained.sqrt.f64", + ret_f64_take_f64_md_md, + None, + ), + sqrt_f32x4: module.add_function( + "llvm.experimental.constrained.sqrt.v4f32", + ret_f32x4_take_f32x4_md_md, + None, + ), + sqrt_f64x2: module.add_function( + "llvm.experimental.constrained.sqrt.v2f64", + ret_f64x2_take_f64x2_md_md, + None, + ), + + max_f32: module.add_function( + "llvm.experimental.constrained.maximum.f32", + ret_f32_take_f32_f32_md, + None, + ), + max_f64: module.add_function( + "llvm.experimental.constrained.maximum.f64", + ret_f64_take_f64_f64_md, + None, + ), + max_f32x4: module.add_function( + "llvm.experimental.constrained.maximum.v4f32", + ret_f32x4_take_f32x4_f32x4_md, + None, + ), + max_f64x2: module.add_function( + "llvm.experimental.constrained.maximum.v2f64", + ret_f64x2_take_f64x2_f64x2_md, + None, + ), + + min_f32: module.add_function( + "llvm.experimental.constrained.minimum.f32", + ret_f32_take_f32_f32_md, + None, + ), + min_f64: module.add_function( + "llvm.experimental.constrained.minimum.f64", + ret_f64_take_f64_f64_md, + None, + ), + min_f32x4: module.add_function( + "llvm.experimental.constrained.minimum.v4f32", + ret_f32x4_take_f32x4_f32x4_md, + None, + ), + min_f64x2: module.add_function( + "llvm.experimental.constrained.minimum.v2f64", + ret_f64x2_take_f64x2_f64x2_md, + None, + ), + + cmp_f32: module.add_function( + "llvm.experimental.constrained.fcmp.f32", + ret_i1_take_f32_f32_md_md, + None, + ), + cmp_f64: module.add_function( + "llvm.experimental.constrained.fcmp.f64", + ret_i1_take_f64_f64_md_md, + None, + ), + cmp_f32x4: module.add_function( + "llvm.experimental.constrained.fcmp.v4f32", + ret_i1x4_take_f32x4_f32x4_md_md, + None, + ), + cmp_f64x2: module.add_function( + "llvm.experimental.constrained.fcmp.v2f64", + ret_i1x2_take_f64x2_f64x2_md_md, + None, + ), + + ceil_f32: module.add_function( + "llvm.experimental.constrained.ceil.f32", + ret_f32_take_f32_md, + None, + ), + ceil_f64: module.add_function( + "llvm.experimental.constrained.ceil.f64", + ret_f64_take_f64_md, + None, + ), + + floor_f32: module.add_function( + "llvm.experimental.constrained.floor.f32", + ret_f32_take_f32_md, + None, + ), + floor_f64: module.add_function( + "llvm.experimental.constrained.floor.f64", + ret_f64_take_f64_md, + None, + ), + + trunc_f32: module.add_function( + "llvm.experimental.constrained.trunc.f32", + ret_f32_take_f32_md, + None, + ), + trunc_f64: module.add_function( + "llvm.experimental.constrained.trunc.f64", + ret_f64_take_f64_md, + None, + ), + + fpext_f32: module.add_function( + "llvm.experimental.constrained.fpext.f64.f32", + ret_f64_take_f32_md, + None, + ), + fptrunc_f64: module.add_function( + "llvm.experimental.constrained.fptrunc.f32.f64", + ret_f32_take_f64_md_md, + None, + ), + + nearbyint_f32: module.add_function( + "llvm.experimental.constrained.nearbyint.f32", + ret_f32_take_f32_md_md, + None, + ), + nearbyint_f64: module.add_function( + "llvm.experimental.constrained.nearbyint.f64", + ret_f64_take_f64_md_md, + None, + ), fabs_f32: module.add_function("llvm.fabs.f32", ret_f32_take_f32, None), fabs_f64: module.add_function("llvm.fabs.f64", ret_f64_take_f64, None), diff --git a/lib/compiler-llvm/src/translator/state.rs b/lib/compiler-llvm/src/translator/state.rs index e3046a09d09..48c1a2909ed 100644 --- a/lib/compiler-llvm/src/translator/state.rs +++ b/lib/compiler-llvm/src/translator/state.rs @@ -129,13 +129,6 @@ impl ExtraInfo { pub const fn is_arithmetic_f64(&self) -> bool { self.state & ExtraInfo::arithmetic_f64().state != 0 } - - pub const fn strip_pending(&self) -> ExtraInfo { - ExtraInfo { - state: self.state - & !(ExtraInfo::pending_f32_nan().state | ExtraInfo::pending_f64_nan().state), - } - } } // Union two ExtraInfos. @@ -301,20 +294,6 @@ impl<'ctx> State<'ctx> { Ok((v1, v2)) } - pub fn pop2_extra( - &mut self, - ) -> Result< - ( - (BasicValueEnum<'ctx>, ExtraInfo), - (BasicValueEnum<'ctx>, ExtraInfo), - ), - CompileError, - > { - let v2 = self.pop1_extra()?; - let v1 = self.pop1_extra()?; - Ok((v1, v2)) - } - pub fn pop3( &mut self, ) -> Result< diff --git a/lib/compiler-singlepass/src/config.rs b/lib/compiler-singlepass/src/config.rs index d788478a9b9..982f6a37f8b 100644 --- a/lib/compiler-singlepass/src/config.rs +++ b/lib/compiler-singlepass/src/config.rs @@ -37,21 +37,15 @@ impl Singlepass { self.enable_stack_check = enable; self } - - /// Enable NaN canonicalization. - /// - /// NaN canonicalization is useful when trying to run WebAssembly - /// deterministically across different architectures. - pub fn canonicalize_nans(&mut self, enable: bool) -> &mut Self { - self.enable_nan_canonicalization = enable; - self - } } impl CompilerConfig for Singlepass { - fn enable_pic(&mut self) { - // Do nothing, since singlepass already emits - // PIC code. + fn enable_nan_canonicalization(&mut self) { + self.enable_nan_canonicalization = true; + } + + fn canonicalize_nans(&mut self, enable: bool) { + self.enable_nan_canonicalization = enable; } /// Transform it into the compiler diff --git a/lib/compiler/src/compiler.rs b/lib/compiler/src/compiler.rs index 9ae25798f64..e36641ea400 100644 --- a/lib/compiler/src/compiler.rs +++ b/lib/compiler/src/compiler.rs @@ -37,6 +37,25 @@ pub trait CompilerConfig { // in case they create an IR that they can verify. } + /// Enable NaN canonicalization. + /// + /// NaN canonicalization is useful when trying to run WebAssembly + /// deterministically across different architectures. + #[deprecated(note = "Please use the canonicalize_nans instead")] + fn enable_nan_canonicalization(&mut self) { + // By default we do nothing, each backend will need to customize this + // in case they create an IR that they can verify. + } + + /// Enable NaN canonicalization. + /// + /// NaN canonicalization is useful when trying to run WebAssembly + /// deterministically across different architectures. + fn canonicalize_nans(&mut self, _enable: bool) { + // By default we do nothing, each backend will need to customize this + // in case they create an IR that they can verify. + } + /// Gets the custom compiler config fn compiler(self: Box) -> Box; diff --git a/tests/compilers/wast.rs b/tests/compilers/wast.rs index 902fb48a28d..190a3affe46 100644 --- a/tests/compilers/wast.rs +++ b/tests/compilers/wast.rs @@ -45,7 +45,14 @@ pub fn run_wast(wast_path: &str, compiler: &str) -> anyhow::Result<()> { "Running wast `{}` with the {} compiler", wast_path, compiler ); - let try_nan_canonicalization = wast_path.contains("nan-canonicalization"); + + cfg_if::cfg_if! { + if #[cfg(feature = "test-llvm")] { + let try_nan_canonicalization = wast_path.contains("nan-canonicalization") || wast_path.contains("f32") || wast_path.contains("f64") || wast_path.contains("float"); + } else { + let try_nan_canonicalization = wast_path.contains("nan-canonicalization"); + } + } let mut features = Features::default(); let is_bulkmemory = wast_path.contains("bulk-memory"); let is_simd = wast_path.contains("simd");