cmd/compile: checking pointers for nilness inside a loop #41666
Comments
You're right, we can't move the nil check because we don't know how many side effects happen before we check it. Keeping track of whether we did the nil check is probably going to be more expensive than just doing the check again. There are probably many situations where the nilness is checked unconditionally before any side effects. We could lift the nil check out of the loop for those cases. If the nilness is checked unconditionally, but after some side effects, we could peel the first iteration of the loop. Or we could have two loops, one with nil checks and one without, and jump from the former to the latter once the nilness is checked. There are definitely diminishing returns here, though. Your technique of adding a |
Yeah, I thought briefly about some kind of fancy duff's-device-like thing where there's a duplicate loop body in front of the actual loop, and the first instance has the nil check, but that's clearly awful. |
That's not at all "clearly awful", I've worked on compilers that did this. The question is, "which loops"? You need to ensure that the always-taken portion of the loop is most of the loop, and the fraction of loop-invariant true nil checks in that always-taken portion of the loop is large enough. Also applies to array bounds, etc. It may not align with the default policies for adding optimization to the Go compiler, that is true. |
What version of Go are you using (
go version
)?Does this issue reproduce with the latest release?
y
What operating system and processor architecture are you using (
go env
)?amd64
What did you do?
Tried to optimize a function by replacing a slice parameter with known size with a
*[N]T
parameter, in principle reducing the number of things passed to the function.https://godbolt.org/z/hz68Mn
What did you expect to see?
I'm honestly not sure, the whole exercise was perhaps doomed from the start.
What did you see instead?
There's extra tests. Well, not quite extra. But there's a
test al, cx
(spelled slightly differently in pprof output) before the first access to a given array in the function, which happens to be inside a loop, meaning that the test gets hit hundreds of times. Of course, it can't just be hoisted out of the loop in full generality -- if the loop only sometimes got hit, hitting the test before the loop would be bad, and if there are side-effects or something inside the loop, you don't want to panic before them. The corresponding slice case doesn't need this, because a slice with a nil pointer also has a 0 len and thus the loop doesn't get entered.Adding
_ = l1[0]
(for each value) to the top of the function does eliminate these.I'm not sure whether this could be trivially fixed but it feels like a lot of tests to keep testing for nilness for a pointer every time you use it...
The text was updated successfully, but these errors were encountered: