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

@fastmath and literal_pow not compatible #53817

Closed
KlausC opened this issue Mar 22, 2024 · 1 comment · Fixed by #53819
Closed

@fastmath and literal_pow not compatible #53817

KlausC opened this issue Mar 22, 2024 · 1 comment · Fixed by #53819

Comments

@KlausC
Copy link
Contributor

KlausC commented Mar 22, 2024

While @fastmath claims to mimic the compiler:

julia/base/fastmath.jl

Lines 104 to 107 in 9145571

elseif expr.head === :call && expr.args[1] === :^ && expr.args[3] isa Integer
# mimic Julia's literal_pow lowering of literal integer powers
return Expr(:call, :(Base.FastMath.pow_fast), make_fastmath(expr.args[2]), Val{expr.args[3]}())
end

in reality there are some corner cases, where that fails. The condition in the first line seems incorrect. See also #53713.
Examples:

julia> @fastmath 2^-2305843009213693953
0.0

julia> 2^-2305843009213693953
ERROR: DomainError with -2305843009213693953:
Cannot raise an integer x to a negative power -2305843009213693953.

and

julia> foo(a) = a^0x2 
foo (generic function with 1 method)

julia> foofast(a) = @fastmath a^0x2
foofast (generic function with 1 method) 

julia> @code_typed debuginfo=:source foo(2)
CodeInfo(
    @ REPL[58]:1 within `foo`
   ┌ @ intfuncs.jl:349 within `^`
1 ─│ %1 = Base.power_by_squaring::typeof(Base.power_by_squaring)
│  │┌ @ intfuncs.jl:313 within `power_by_squaring`
│  ││ %2 = invoke Base.:(var"#power_by_squaring#522")(Base.:*::typeof(*), %1::typeof(Base.power_by_squaring), a::Int64, 0x02::UInt8)::Int64
└──││      return %2
   └└
) => Int64

julia> @code_typed debuginfo=:source foofast(2)
CodeInfo(
    @ REPL[61]:1 within `foofast`
   ┌ @ fastmath.jl:284 within `pow_fast`
   │┌ @ intfuncs.jl:389 within `literal_pow`
   ││┌ @ intfuncs.jl:349 within `^`
1 ─│││ %1 = Base.power_by_squaring::typeof(Base.power_by_squaring)
│  │││┌ @ intfuncs.jl:313 within `power_by_squaring`
│  ││││ %2 = invoke Base.:(var"#power_by_squaring#522")(Base.:*::typeof(*), %1::typeof(Base.power_by_squaring), a::Int64, 0x02::UInt8)::Int64
└──││││      return %2
   └└└└
) => Int64
@KlausC
Copy link
Contributor Author

KlausC commented Mar 22, 2024

Example in error case:

julia> ^(2)
ERROR: MethodError: no method matching ^(::Int64)
The function `^` exists, but no method is defined for this combination of argument types.
  ...

julia> @fastmath ^(2)
ERROR: LoadError: BoundsError: attempt to access 2-element Vector{Any} at index [3]
 ...
 [3] make_fastmath(expr::Expr)
   @ Base.FastMath ./fastmath.jl:104

mbauman pushed a commit that referenced this issue Apr 3, 2024
The expressions `a^x` and `@fastmath a^x` are now producing equivalent
results (apart from floating point accuracy) in the case of literal
integer `x`.
The logic in the `fastmath` macro, trying to mimic the behaviour of the
compiler is fixed.

Fixes #53817

---------

Co-authored-by: Oscar Smith <oscardssmith@gmail.com>
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.

1 participant