Merge pull request #195 from tpdickso/ungenerate-nans
Add feature flag to disable floating point exceptions in unexceptional code
This commit is contained in:
@@ -20,6 +20,7 @@ default = [ "dim2", "f64", "default-sets" ]
|
|||||||
dim2 = [ ]
|
dim2 = [ ]
|
||||||
f64 = [ ]
|
f64 = [ ]
|
||||||
default-sets = [ ]
|
default-sets = [ ]
|
||||||
|
avoid-fe-exceptions = [ ]
|
||||||
parallel = [ "rayon" ]
|
parallel = [ "rayon" ]
|
||||||
simd-stable = [ "simba/wide", "simd-is-enabled" ]
|
simd-stable = [ "simba/wide", "simd-is-enabled" ]
|
||||||
simd-nightly = [ "simba/packed_simd", "simd-is-enabled" ]
|
simd-nightly = [ "simba/packed_simd", "simd-is-enabled" ]
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ default = [ "dim2", "f32", "default-sets" ]
|
|||||||
dim2 = [ ]
|
dim2 = [ ]
|
||||||
f32 = [ ]
|
f32 = [ ]
|
||||||
default-sets = [ ]
|
default-sets = [ ]
|
||||||
|
avoid-fe-exceptions = [ ]
|
||||||
parallel = [ "rayon" ]
|
parallel = [ "rayon" ]
|
||||||
simd-stable = [ "simba/wide", "simd-is-enabled" ]
|
simd-stable = [ "simba/wide", "simd-is-enabled" ]
|
||||||
simd-nightly = [ "simba/packed_simd", "simd-is-enabled" ]
|
simd-nightly = [ "simba/packed_simd", "simd-is-enabled" ]
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ default = [ "dim3", "f64", "default-sets" ]
|
|||||||
dim3 = [ ]
|
dim3 = [ ]
|
||||||
f64 = [ ]
|
f64 = [ ]
|
||||||
default-sets = [ ]
|
default-sets = [ ]
|
||||||
|
avoid-fe-exceptions = [ ]
|
||||||
parallel = [ "rayon" ]
|
parallel = [ "rayon" ]
|
||||||
simd-stable = [ "parry3d-f64/simd-stable", "simba/wide", "simd-is-enabled" ]
|
simd-stable = [ "parry3d-f64/simd-stable", "simba/wide", "simd-is-enabled" ]
|
||||||
simd-nightly = [ "parry3d-f64/simd-nightly", "simba/packed_simd", "simd-is-enabled" ]
|
simd-nightly = [ "parry3d-f64/simd-nightly", "simba/packed_simd", "simd-is-enabled" ]
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ default = [ "dim3", "f32", "default-sets" ]
|
|||||||
dim3 = [ ]
|
dim3 = [ ]
|
||||||
f32 = [ ]
|
f32 = [ ]
|
||||||
default-sets = [ ]
|
default-sets = [ ]
|
||||||
|
avoid-fe-exceptions = [ ]
|
||||||
parallel = [ "rayon" ]
|
parallel = [ "rayon" ]
|
||||||
simd-stable = [ "parry3d/simd-stable", "simba/wide", "simd-is-enabled" ]
|
simd-stable = [ "parry3d/simd-stable", "simba/wide", "simd-is-enabled" ]
|
||||||
simd-nightly = [ "parry3d/simd-nightly", "simba/packed_simd", "simd-is-enabled" ]
|
simd-nightly = [ "parry3d/simd-nightly", "simba/packed_simd", "simd-is-enabled" ]
|
||||||
|
|||||||
@@ -385,7 +385,13 @@ where
|
|||||||
let relative_linvel = linvel1 - linvel2;
|
let relative_linvel = linvel1 - linvel2;
|
||||||
let mut tangent_relative_linvel =
|
let mut tangent_relative_linvel =
|
||||||
relative_linvel - force_dir1 * (force_dir1.dot(&relative_linvel));
|
relative_linvel - force_dir1 * (force_dir1.dot(&relative_linvel));
|
||||||
let tangent_linvel_norm = tangent_relative_linvel.normalize_mut();
|
|
||||||
|
let tangent_linvel_norm = {
|
||||||
|
let _disable_fe_except =
|
||||||
|
crate::utils::DisableFloatingPointExceptionsFlags::disable_floating_point_exceptions();
|
||||||
|
tangent_relative_linvel.normalize_mut()
|
||||||
|
};
|
||||||
|
|
||||||
let threshold: N::Element = na::convert(1.0e-4);
|
let threshold: N::Element = na::convert(1.0e-4);
|
||||||
let use_fallback = tangent_linvel_norm.simd_lt(N::splat(threshold));
|
let use_fallback = tangent_linvel_norm.simd_lt(N::splat(threshold));
|
||||||
let tangent_fallback = force_dir1.orthonormal_vector();
|
let tangent_fallback = force_dir1.orthonormal_vector();
|
||||||
|
|||||||
@@ -99,7 +99,13 @@ impl<N: SimdRealField> VelocityConstraintTangentPart<N> {
|
|||||||
self.impulse[0] - self.r[0] * dimpulse_0,
|
self.impulse[0] - self.r[0] * dimpulse_0,
|
||||||
self.impulse[1] - self.r[1] * dimpulse_1,
|
self.impulse[1] - self.r[1] * dimpulse_1,
|
||||||
);
|
);
|
||||||
let new_impulse = new_impulse.simd_cap_magnitude(limit);
|
let new_impulse = {
|
||||||
|
let _disable_fe_except =
|
||||||
|
crate::utils::DisableFloatingPointExceptionsFlags::
|
||||||
|
disable_floating_point_exceptions();
|
||||||
|
new_impulse.simd_cap_magnitude(limit)
|
||||||
|
};
|
||||||
|
|
||||||
let dlambda = new_impulse - self.impulse;
|
let dlambda = new_impulse - self.impulse;
|
||||||
self.impulse = new_impulse;
|
self.impulse = new_impulse;
|
||||||
|
|
||||||
|
|||||||
@@ -78,7 +78,12 @@ impl<N: SimdRealField> VelocityGroundConstraintTangentPart<N> {
|
|||||||
self.impulse[0] - self.r[0] * dimpulse_0,
|
self.impulse[0] - self.r[0] * dimpulse_0,
|
||||||
self.impulse[1] - self.r[1] * dimpulse_1,
|
self.impulse[1] - self.r[1] * dimpulse_1,
|
||||||
);
|
);
|
||||||
let new_impulse = new_impulse.simd_cap_magnitude(limit);
|
let new_impulse = {
|
||||||
|
let _disable_fe_except =
|
||||||
|
crate::utils::DisableFloatingPointExceptionsFlags::
|
||||||
|
disable_floating_point_exceptions();
|
||||||
|
new_impulse.simd_cap_magnitude(limit)
|
||||||
|
};
|
||||||
let dlambda = new_impulse - self.impulse;
|
let dlambda = new_impulse - self.impulse;
|
||||||
|
|
||||||
self.impulse = new_impulse;
|
self.impulse = new_impulse;
|
||||||
|
|||||||
46
src/utils.rs
46
src/utils.rs
@@ -670,6 +670,52 @@ impl Drop for FlushToZeroDenormalsAreZeroFlags {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This is an RAII structure that disables floating point exceptions while
|
||||||
|
// it is alive, so that operations which generate NaNs and infinite values
|
||||||
|
// intentionally will not trip an exception when debugging problematic
|
||||||
|
// code that is generating NaNs and infinite values erroneously.
|
||||||
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
|
pub(crate) struct DisableFloatingPointExceptionsFlags {
|
||||||
|
#[cfg(feature = "avoid-fe-exceptions")]
|
||||||
|
// We can't get a precise size for this, because it's of type
|
||||||
|
// `fenv_t`, which is a definition that doesn't exist in rust
|
||||||
|
// (not even in the libc crate, as of the time of writing.)
|
||||||
|
// But since the state is intended to be stored on the stack,
|
||||||
|
// 256 bytes should be more than enough.
|
||||||
|
original_flags: [u8; 256],
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "avoid-fe-exceptions")]
|
||||||
|
extern "C" {
|
||||||
|
fn feholdexcept(env: *mut std::ffi::c_void);
|
||||||
|
fn fesetenv(env: *const std::ffi::c_void);
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DisableFloatingPointExceptionsFlags {
|
||||||
|
#[cfg(not(feature = "avoid-fe-exceptions"))]
|
||||||
|
pub fn disable_floating_point_exceptions() -> Self {
|
||||||
|
Self { }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "avoid-fe-exceptions")]
|
||||||
|
pub fn disable_floating_point_exceptions() -> Self {
|
||||||
|
unsafe {
|
||||||
|
let mut original_flags = [0; 256];
|
||||||
|
feholdexcept(original_flags.as_mut_ptr() as *mut _);
|
||||||
|
Self { original_flags }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "avoid-fe-exceptions")]
|
||||||
|
impl Drop for DisableFloatingPointExceptionsFlags {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
unsafe {
|
||||||
|
fesetenv(self.original_flags.as_ptr() as *const _);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn select_other<T: PartialEq>(pair: (T, T), elt: T) -> T {
|
pub(crate) fn select_other<T: PartialEq>(pair: (T, T), elt: T) -> T {
|
||||||
if pair.0 == elt {
|
if pair.0 == elt {
|
||||||
pair.1
|
pair.1
|
||||||
|
|||||||
Reference in New Issue
Block a user