From 2e80c0d2645f48a4b3a8884b342339c302844ede Mon Sep 17 00:00:00 2001 From: Zentrik Date: Thu, 4 May 2023 11:26:06 +0100 Subject: [PATCH] Inline StepRange construction (#49270) This can improve performance when iterating over a range with a step as currently steprange_last is not inlined. About a 12ns improvement I don't think this should slow anything down as at worst you're making a call which is what you'd have to do without inlining. Also, it should be unlikely that branch is taken. This should allow for better automatic inlining. --- base/multidimensional.jl | 2 +- base/range.jl | 3 ++- test/ranges.jl | 25 +++++++++++++++++++++++++ 3 files changed, 28 insertions(+), 2 deletions(-) diff --git a/base/multidimensional.jl b/base/multidimensional.jl index 70b7354c18bd2..ce1b6c39adb43 100644 --- a/base/multidimensional.jl +++ b/base/multidimensional.jl @@ -526,7 +526,7 @@ module IteratorsMD dimrev = ntuple(i -> sum(==(i), dims; init = 0) == 1, Val(length(indices))) length(dims) == sum(dimrev) || throw(ArgumentError(Base.LazyString("invalid dimensions ", dims, " in reverse"))) length(dims) == length(indices) && return Base._reverse(iter, :) - indices′ = map((i, f) -> f ? reverse(i) : i, indices, dimrev) + indices′ = map((i, f) -> f ? (@noinline reverse(i)) : i, indices, dimrev) return CartesianIndices(indices′) end diff --git a/base/range.jl b/base/range.jl index ea29516f64d24..80693a8e94a0c 100644 --- a/base/range.jl +++ b/base/range.jl @@ -350,7 +350,8 @@ function steprange_last(start, step, stop)::typeof(stop) # Compute remainder as a nonnegative number: if absdiff isa Signed && absdiff < zero(absdiff) # unlikely, but handle the signed overflow case with unsigned rem - remain = convert(typeof(absdiff), unsigned(absdiff) % absstep) + overflow_case(absdiff, absstep) = (@noinline; convert(typeof(absdiff), unsigned(absdiff) % absstep)) + remain = overflow_case(absdiff, absstep) else remain = convert(typeof(absdiff), absdiff % absstep) end diff --git a/test/ranges.jl b/test/ranges.jl index bbdd303adb3c5..04c2cdcb47ac4 100644 --- a/test/ranges.jl +++ b/test/ranges.jl @@ -1,6 +1,7 @@ # This file is a part of Julia. License is MIT: https://julialang.org/license using Base.Checked: checked_length +using InteractiveUtils: code_llvm @testset "range construction" begin @test_throws ArgumentError range(start=1, step=1, stop=2, length=10) @@ -2400,3 +2401,27 @@ end @test test_firstindex(StepRange{Union{Int64,Int128},Int}(Int64(1), 1, Int128(1))) @test test_firstindex(StepRange{Union{Int64,Int128},Int}(Int64(1), 1, Int128(0))) end + +@testset "Inline StepRange Construction #49270" begin + x = rand(Float32, 80) + a = rand(round(Int, length(x) / 2):length(x), 10^6) + + function test(x, a) + c = zero(Float32) + + @inbounds for j in a + for i in 1:8:j + c += x[i] + end + end + + return c + end + + llvm_ir(f, args) = sprint((io, args...) -> code_llvm(io, args...; debuginfo=:none), f, Base.typesof(args...)) + + ir = llvm_ir(test, (x, a)) + @test !occursin("steprange_last", ir) + @test !occursin("_colon", ir) + @test !occursin("StepRange", ir) +end