JuliaLang / julia

The Julia Programming Language
https://julialang.org/
MIT License
45.73k stars 5.49k forks source link

checked_add not optimized to a checked_mul #51037

Open simonbyrne opened 1 year ago

simonbyrne commented 1 year ago

If I have a loop which adds a constant integer, we're able to optimize it to a (constant time) multiply:

julia> using BenchmarkTools

julia> function mul_by_add(a, b)
         x = zero(a)
         for i = 1:b
           x += a
         end
         return x
       end
mul_by_add (generic function with 1 method)

julia> @btime mul_by_add($3, $10)
  1.375 ns (0 allocations: 0 bytes)
30

julia> @btime mul_by_add($3, $100)
  1.333 ns (0 allocations: 0 bytes)
300

julia> @btime mul_by_add($3, $1000)
  1.333 ns (0 allocations: 0 bytes)
3000

However if I use checked arithmetic, it is not:

julia> function mul_by_add_checked(a, b)
         x = zero(a)
         for i = 1:b
           x = Base.Checked.checked_add(x, a)
         end
         return x
       end
mul_by_add_checked (generic function with 1 method)

julia> @btime mul_by_add_checked($3, $10)
  4.750 ns (0 allocations: 0 bytes)
30

julia> @btime mul_by_add_checked($3, $100)
  30.443 ns (0 allocations: 0 bytes)
300

julia> @btime mul_by_add_checked($3, $1000)
  294.797 ns (0 allocations: 0 bytes)
3000

Ideally this would get converted to a Base.Checked.checked_mul, I assume this is tricky because of the exception?

KristofferC commented 1 year ago

How does a saturating add fare?

vchuravy commented 1 year ago

I assume this is tricky because of the exception?

The conversion is done by LLVM and it likely can't fold the loop due to the exception.