mirror of
https://github.com/fluencelabs/wasmer
synced 2024-12-13 14:25:32 +00:00
Merge #934
934: In LLVM backend, track which floats are guaranteed to be arithmetic, which makes the canonicalization a no-op. r=nlewycky a=nlewycky # Description This is a reimplementation of the patch in PR #651. Extend state.rs ExtraInfo to track more information about floats. In addition to tracking whether the value has a pending canonicalization of NaNs, also track whether the value is known to be arithmetic (which includes infinities, regular values, and non-signalling NaNs (aka. "arithmetic NaNs" in the webassembly spec)). When the value is arithmetic, the correct sequence of operations to canonicalize the value is a no-op. Therefore, we create a lattice where pending+arithmetic=arithmetic. Also, this extends the tracking to track all values, including non-SIMD integers. That's why there are more places where pending canonicalizations are applied. Looking at c-wasm-simd128-example, this provides no performance change to the non-SIMD case (takes 58s on my noisy dev machine). The SIMD case drops from 46s to 29s. # Review - [ ] Add a short description of the the change to the CHANGELOG.md file Co-authored-by: Nick Lewycky <nick@wasmer.io>
This commit is contained in:
commit
53f0a9cecf
@ -13,6 +13,7 @@
|
||||
- [#990](https://github.com/wasmerio/wasmer/pull/990) Default wasmer CLI to `run`. Wasmer will now attempt to parse unrecognized command line options as if they were applied to the run command: `wasmer mywasm.wasm --dir=.` now works!
|
||||
- [#987](https://github.com/wasmerio/wasmer/pull/987) Fix `runtime-c-api` header files when compiled by gnuc.
|
||||
- [#957](https://github.com/wasmerio/wasmer/pull/957) Change the meaning of `wasmer_wasi::is_wasi_module` to detect any type of WASI module, add support for new wasi snapshot_preview1
|
||||
- [#934](https://github.com/wasmerio/wasmer/pull/934) Simplify float expressions in the LLVM backend.
|
||||
|
||||
## 0.10.2 - 2019-11-18
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -4,6 +4,7 @@ use inkwell::{
|
||||
};
|
||||
use smallvec::SmallVec;
|
||||
use std::cell::Cell;
|
||||
use std::ops::{BitAnd, BitOr, BitOrAssign};
|
||||
use wasmparser::BinaryReaderError;
|
||||
|
||||
#[derive(Debug)]
|
||||
@ -67,23 +68,127 @@ impl ControlFrame {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Copy, Clone, Hash)]
|
||||
pub enum ExtraInfo {
|
||||
None,
|
||||
|
||||
// This values is required to be arithmetic 32-bit NaN (or 32x4) by the WAsm
|
||||
// machine, but which might not be in the LLVM value. The conversion to
|
||||
// arithmetic NaN is pending. It is required for correctness.
|
||||
PendingF32NaN,
|
||||
|
||||
// This values is required to be arithmetic 64-bit NaN (or 64x2) by the WAsm
|
||||
// machine, but which might not be in the LLVM value. The conversion to
|
||||
// arithmetic NaN is pending. It is required for correctness.
|
||||
PendingF64NaN,
|
||||
#[derive(Debug, Default, Eq, PartialEq, Copy, Clone, Hash)]
|
||||
pub struct ExtraInfo {
|
||||
state: u8,
|
||||
}
|
||||
impl Default for ExtraInfo {
|
||||
fn default() -> Self {
|
||||
ExtraInfo::None
|
||||
impl ExtraInfo {
|
||||
// This value is required to be arithmetic 32-bit NaN (or 32x4) by the WAsm
|
||||
// machine, but which might not be in the LLVM value. The conversion to
|
||||
// arithmetic NaN is pending. It is required for correctness.
|
||||
//
|
||||
// When applied to a 64-bit value, this flag has no meaning and must be
|
||||
// ignored. It may be set in such cases to allow for common handling of
|
||||
// 32 and 64-bit operations.
|
||||
pub const fn pending_f32_nan() -> ExtraInfo {
|
||||
ExtraInfo { state: 1 }
|
||||
}
|
||||
|
||||
// This value is required to be arithmetic 64-bit NaN (or 64x2) by the WAsm
|
||||
// machine, but which might not be in the LLVM value. The conversion to
|
||||
// arithmetic NaN is pending. It is required for correctness.
|
||||
//
|
||||
// When applied to a 32-bit value, this flag has no meaning and must be
|
||||
// ignored. It may be set in such cases to allow for common handling of
|
||||
// 32 and 64-bit operations.
|
||||
pub const fn pending_f64_nan() -> ExtraInfo {
|
||||
ExtraInfo { state: 2 }
|
||||
}
|
||||
|
||||
// This value either does not contain a 32-bit NaN, or it contains an
|
||||
// arithmetic NaN. In SIMD, applies to all 4 lanes.
|
||||
pub const fn arithmetic_f32() -> ExtraInfo {
|
||||
ExtraInfo { state: 4 }
|
||||
}
|
||||
|
||||
// This value either does not contain a 64-bit NaN, or it contains an
|
||||
// arithmetic NaN. In SIMD, applies to both lanes.
|
||||
pub const fn arithmetic_f64() -> ExtraInfo {
|
||||
ExtraInfo { state: 8 }
|
||||
}
|
||||
|
||||
pub const fn has_pending_f32_nan(&self) -> bool {
|
||||
self.state & ExtraInfo::pending_f32_nan().state != 0
|
||||
}
|
||||
pub const fn has_pending_f64_nan(&self) -> bool {
|
||||
self.state & ExtraInfo::pending_f64_nan().state != 0
|
||||
}
|
||||
pub const fn is_arithmetic_f32(&self) -> bool {
|
||||
self.state & ExtraInfo::arithmetic_f32().state != 0
|
||||
}
|
||||
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.
|
||||
impl BitOr for ExtraInfo {
|
||||
type Output = Self;
|
||||
|
||||
fn bitor(self, other: Self) -> Self {
|
||||
debug_assert!(!(self.has_pending_f32_nan() && other.has_pending_f64_nan()));
|
||||
debug_assert!(!(self.has_pending_f64_nan() && other.has_pending_f32_nan()));
|
||||
ExtraInfo {
|
||||
state: if self.is_arithmetic_f32() || other.is_arithmetic_f32() {
|
||||
ExtraInfo::arithmetic_f32().state
|
||||
} else if self.has_pending_f32_nan() || other.has_pending_f32_nan() {
|
||||
ExtraInfo::pending_f32_nan().state
|
||||
} else {
|
||||
0
|
||||
} + if self.is_arithmetic_f64() || other.is_arithmetic_f64() {
|
||||
ExtraInfo::arithmetic_f64().state
|
||||
} else if self.has_pending_f64_nan() || other.has_pending_f64_nan() {
|
||||
ExtraInfo::pending_f64_nan().state
|
||||
} else {
|
||||
0
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
impl BitOrAssign for ExtraInfo {
|
||||
fn bitor_assign(&mut self, other: Self) {
|
||||
*self = *self | other;
|
||||
}
|
||||
}
|
||||
|
||||
// Intersection for ExtraInfo.
|
||||
impl BitAnd for ExtraInfo {
|
||||
type Output = Self;
|
||||
fn bitand(self, other: Self) -> Self {
|
||||
// Pending canonicalizations are not safe to discard, or even reorder.
|
||||
assert!(
|
||||
self.has_pending_f32_nan() == other.has_pending_f32_nan()
|
||||
|| self.is_arithmetic_f32()
|
||||
|| other.is_arithmetic_f32()
|
||||
);
|
||||
assert!(
|
||||
self.has_pending_f64_nan() == other.has_pending_f64_nan()
|
||||
|| self.is_arithmetic_f64()
|
||||
|| other.is_arithmetic_f64()
|
||||
);
|
||||
let info = match (
|
||||
self.is_arithmetic_f32() && other.is_arithmetic_f32(),
|
||||
self.is_arithmetic_f64() && other.is_arithmetic_f64(),
|
||||
) {
|
||||
(false, false) => Default::default(),
|
||||
(true, false) => ExtraInfo::arithmetic_f32(),
|
||||
(false, true) => ExtraInfo::arithmetic_f64(),
|
||||
(true, true) => ExtraInfo::arithmetic_f32() | ExtraInfo::arithmetic_f64(),
|
||||
};
|
||||
let info = match (self.has_pending_f32_nan(), self.has_pending_f64_nan()) {
|
||||
(false, false) => info,
|
||||
(true, false) => info | ExtraInfo::pending_f32_nan(),
|
||||
(false, true) => info | ExtraInfo::pending_f64_nan(),
|
||||
(true, true) => unreachable!("Can't form ExtraInfo with two pending canonicalizations"),
|
||||
};
|
||||
info
|
||||
}
|
||||
}
|
||||
|
||||
@ -165,7 +270,7 @@ impl State {
|
||||
}
|
||||
|
||||
pub fn push1<T: BasicValue>(&mut self, value: T) {
|
||||
self.push1_extra(value, ExtraInfo::None);
|
||||
self.push1_extra(value, Default::default());
|
||||
}
|
||||
|
||||
pub fn push1_extra<T: BasicValue>(&mut self, value: T, info: ExtraInfo) {
|
||||
@ -197,15 +302,6 @@ impl State {
|
||||
Ok((v1, v2))
|
||||
}
|
||||
|
||||
pub fn pop3(
|
||||
&mut self,
|
||||
) -> Result<(BasicValueEnum, BasicValueEnum, BasicValueEnum), BinaryReaderError> {
|
||||
let v3 = self.pop1()?;
|
||||
let v2 = self.pop1()?;
|
||||
let v1 = self.pop1()?;
|
||||
Ok((v1, v2, v3))
|
||||
}
|
||||
|
||||
pub fn pop3_extra(
|
||||
&mut self,
|
||||
) -> Result<
|
||||
|
Loading…
Reference in New Issue
Block a user