Skip to content

Commit 75ea2c7

Browse files
authored
Help compiler know integer bounds in vector resizing ops (#59540)
This produces much better code than _deleteend!, because it skips a needless error check for negative length. It's also easier on the compiler because it does not produce _unsetindex! code which is optimised away. `empty!` is already pretty fast, but this produces smaller code more likely to inline.
1 parent 260b414 commit 75ea2c7

File tree

1 file changed

+14
-3
lines changed

1 file changed

+14
-3
lines changed

base/array.jl

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1257,7 +1257,10 @@ end
12571257
function _deletebeg!(a::Vector, delta::Integer)
12581258
delta = Int(delta)
12591259
len = length(a)
1260-
0 <= delta <= len || throw(ArgumentError("_deletebeg! requires delta in 0:length(a)"))
1260+
# See comment in _deleteend!
1261+
if unsigned(delta) > unsigned(len)
1262+
throw(ArgumentError("_deletebeg! requires delta in 0:length(a)"))
1263+
end
12611264
for i in 1:delta
12621265
@inbounds _unsetindex!(a, i)
12631266
end
@@ -1272,7 +1275,12 @@ end
12721275
function _deleteend!(a::Vector, delta::Integer)
12731276
delta = Int(delta)
12741277
len = length(a)
1275-
0 <= delta <= len || throw(ArgumentError("_deleteend! requires delta in 0:length(a)"))
1278+
# Do the comparison unsigned, to so the compiler knows `len` cannot be negative.
1279+
# This works because if delta is negative, it will overflow and still trigger.
1280+
# This enables the compiler to skip the check sometimes.
1281+
if unsigned(delta) > unsigned(len)
1282+
throw(ArgumentError("_deleteend! requires delta in 0:length(a)"))
1283+
end
12761284
newlen = len - delta
12771285
for i in newlen+1:len
12781286
@inbounds _unsetindex!(a, i)
@@ -1525,7 +1533,10 @@ function resize!(a::Vector, nl_::Integer)
15251533
nl = Int(nl_)::Int
15261534
l = length(a)
15271535
if nl > l
1528-
_growend!(a, nl-l)
1536+
# Since l is positive, if nl > l, both are positive, and so nl-l is also
1537+
# positive. But the compiler does not know that, so we mask out top bit.
1538+
# This allows the compiler to skip the check
1539+
_growend!(a, (nl-l) & typemax(Int))
15291540
elseif nl != l
15301541
if nl < 0
15311542
_throw_argerror("new length must be ≥ 0")

0 commit comments

Comments
 (0)