Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Creation of basic quantities is not zero-cost #143

Closed
raimundomartins opened this issue May 30, 2019 · 2 comments · Fixed by #144
Closed

Creation of basic quantities is not zero-cost #143

raimundomartins opened this issue May 30, 2019 · 2 comments · Fixed by #144

Comments

@raimundomartins
Copy link

Compiling the following program produces an extra 0.0f + value operation in every Angle::new() call:

use uom::si::{SI, angle::{Angle, radian}};

#[inline(never)]
fn half_way(new: Angle::<SI<f64>, f64>) -> f64 {
    new.get::<radian>().sin().sin()
}
    
#[inline(never)]
fn value(new: f64) -> f64 {
    new.sin()
}

fn main() {
    let b1 = value(11111.0);
    let b2 = value(22222.0);
    let c1 = half_way(Angle::<SI<f64>, f64>::new::<radian>(b1));
    let c2 = half_way(Angle::<SI<f64>, f64>::new::<radian>(b2));
    println!("{}", b1 + b2 + c1 + c2);

The pertaining LLVM-IR output is:

; call uom_test::value
  %0 = tail call fastcc double @_ZN8uom_test5value17hc4ec51985f4bef61E(double 1.111100e+04)
; call uom_test::value
  %1 = tail call fastcc double @_ZN8uom_test5value17hc4ec51985f4bef61E(double 2.222200e+04)
  %2 = fadd double %0, 0.000000e+00
; call uom_test::half_way
  %3 = tail call fastcc double @_ZN8uom_test8half_way17ha0a6a5c0bfbcb7a8E(double %2)
  %4 = fadd double %1, 0.000000e+00
; call uom_test::half_way
  %5 = tail call fastcc double @_ZN8uom_test8half_way17ha0a6a5c0bfbcb7a8E(double %4)

I even tried compiling with -ffast-math but had no success.

@iliekturtles
Copy link
Owner

Thanks for such a detailed report, especially the LLVM-IR. My guess is that to_base isn't optimizing correctly. I'll need to do more review to find out why the + 0.0f isn't being optimized out.

uom/src/system.rs

Lines 291 to 305 in c02d306

fn to_base<D, U, V, N>(v: &V) -> V
where
D: Dimension + ?Sized,
U: Units<V> + ?Sized,
V: $crate::Conversion<V> + $crate::lib::ops::Mul<V, Output = V>,
N: $crate::Conversion<V, T = V::T>,
{
use $crate::typenum::Integer;
use $crate::Conversion;
use $crate::ConversionFactor;
((v.into_conversion() + N::constant()) * N::coefficient()
/ (V::coefficient() $(* U::$name::coefficient().powi(D::$symbol::to_i32()))+))
.value()
}

As an aside you don't need to explicitly reference the system and storage type all the time. Type aliases in the uom::si::<type> module can be used. e.g. uom::si::f64::Angle instead of uom::si::Angle:<SI<f64>, f64> (see https://github.com/iliekturtles/uom/blob/master/examples/si.rs).

@raimundomartins
Copy link
Author

Thank you, I'm familiar with uom::si::<type> but I started this in the context of generics (so f64 was a T) :)
I feel I should inform you that I found no such behaviour with .get::<unit>(), since it uses the similar from_base. Here's the LLVM-IR of half_way():

; Function Attrs: noinline nounwind nonlazybind readnone uwtable
define internal fastcc double @_ZN8uom_test8half_way17ha0a6a5c0bfbcb7a8E(double) unnamed_addr #2 personality i32 (i32, i32, i64, %"unwind::libunwind::_Unwind_Exception"*, %"unwind::libunwind::_Unwind_Context"*)* @rust_eh_personality {
start:
  %1 = tail call double @llvm.sin.f64(double %0) #7
  %2 = tail call double @llvm.sin.f64(double %1) #7
  ret double %2
}

iliekturtles added a commit that referenced this issue Jun 2, 2019
Use a default constant of `-0.0` to allow for floating point
optimizations. For a value, `v: Float`, adding `-0.0` is a no-op while
adding `0.0` will change the sign if `v` is `-0.0`. Resolves #143.

   v
 0.0 + -0.0 =  0.0
-0.0 +  0.0 =  0.0 # v + 0.0 != v
-0.0 + -0.0 = -0.0
iliekturtles added a commit that referenced this issue Jun 2, 2019
Use a default constant of `-0.0` to allow for floating point
optimizations. For a value, `v: Float`, adding `-0.0` is a no-op while
adding `0.0` will change the sign if `v` is `-0.0`. Resolves #143.

   v
 0.0 + -0.0 =  0.0
-0.0 +  0.0 =  0.0 # v + 0.0 != v
-0.0 + -0.0 = -0.0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants