The Wayback Machine - https://web.archive.org/web/20250831053437/https://github.com/JuliaLang/julia/pull/40514
Skip to content

Conversation

vchuravy
Copy link
Member

The llvm.rint intrinsic is sensitive to the floating-point
environment, so determined enough users can change the definition
of round(x, RoundNearest) to not be rount to even.

julia> round(2.5, RoundNearest)
2.0
julia> Base.Rounding.setrounding_raw(Float64, Base.Rounding.to_fenv(RoundUp))
julia> round(2.5, RoundNearest)
3.0
julia> roundeven(x::Float64) = ccall("llvm.roundeven.f64", llvmcall, Float64, (Float64,), x)
round_even (generic function with 1 method)
julia> roundeven(2.5)
2.0

The intrinsic was introduced with LLVM 11, and roundeven will be part
of the C23 standard (problematic for us due to runtime_intrinsics.cpp).

Sadly performance isn't looking to hot. Using @simonbyrne benchmark from
#8750 (comment)

julia> roundeven_llvm(x::Float64) = ccall("llvm.roundeven.f64", llvmcall, Float64, (Float64,), x)
roundeven_llvm (generic function with 1 method)

julia> rint_llvm(x::Float64) = ccall("llvm.rint.f64", llvmcall, Float64, (Float64,), x)
rint_llvm (generic function with 1 method)

julia> function test_roundeven_llvm(N)
           t = 1.0
           s = 0.0
           for i = 1:N
               t += eps()
               s += roundeven_llvm(t)
           end
           s
       end
test_roundeven_llvm (generic function with 1 method)

julia> function test_rint_llvm(N)
           t = 1.0
           s = 0.0
           for i = 1:N
               t += eps()
               s += rint_llvm(t)
           end
           s
       end
test_rint_llvm (generic function with 1 method)

julia> @time test_roundeven_llvm(100_000_000);
  0.274178 seconds

julia> @time test_roundeven_llvm(100_000_000);
  0.274118 seconds

julia> @time test_rint_llvm(100_000_000);
  0.087601 seconds

julia> @time test_rint_llvm(100_000_000);
  0.087860 seconds

On x86:

julia> @code_native roundeven_llvm(2.5)
	.text
	movabsq	$roundevenf64, %rax
	jmpq	*%rax
	nopl	(%rax)

e.g it's implemented with a function call to roundevenf64, which is implemented by libc.

@vchuravy vchuravy requested a review from simonbyrne April 17, 2021 17:27
@mkitti
Copy link
Contributor

mkitti commented Apr 17, 2021

A custom x86 with sse4.1 lowering for llvm.roundeven was added with LLVM 12
https://reviews.llvm.org/D84592
https://reviews.llvm.org/rGc4823b24a41b9e3552af7781e05ed1784fb84f46

@ViralBShah ViralBShah added the maths Mathematical functions label Feb 26, 2022
@ViralBShah
Copy link
Member

@simonbyrne your thoughts here?

The `llvm.rint` intrinsic is sensitive to the floating-point
environment, so determined enough users can change the definition
of `round(x, RoundNearest)` to not be rount to even.

```
julia> round(2.5, RoundNearest)
2.0
julia> Base.Rounding.setrounding_raw(Float64, Base.Rounding.to_fenv(RoundUp))
julia> round(2.5, RoundNearest)
3.0
julia> round_even(x::Float64) = ccall("llvm.roundeven.f64", llvmcall, Float64, (Float64,), x)
round_even (generic function with 1 method)
julia> round_even(2.5)
2.0
```
@simonbyrne
Copy link
Member

Since we're now using a newer LLVM, this should be fine, and we should probably make the change.
I tried rebasing, but not sure how to deal with runtime intrinsics: @vchuravy?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
maths Mathematical functions
4 participants