Repository navigation
internal/loopir: keep a named constant bound's name in emitted code - #13
Merged
Merged
Conversation
In #2, bound started spelling every constant start or limit as its value, so that the checks that parse Trip.Start and Trip.Limit as text would see named constants too. The emitted file is compiled for every build, though, and a named constant can have another value in another one. With const width = 32 in a file for amd64 and 64 in one for arm64, loopvec -split on amd64 wrote 32 into the vector loop of a for i := 0; i < width; i++ loop, while the fallback kept width, so the arm64 build vectorized only half of the elements. plusOne and a loop counting down to i > low had always done the same for <= limits and loops that count down. Trip now carries the values of a constant start and limit, and the checks read those instead of parsing the text: the negative-index check from #2, the short-loop rule, and the copy check. A constant is spelled as its value only when it is written with literals alone, and one that names a constant keeps the name. x - k + 1 is written as x - (k-1) for a constant x as well, so i <= width-1 gives width rather than width-1+1. negativeSource could no longer return true after #2 and is removed. The negative-index check now runs in the same walk as the stored-offset checks and negates the offset rather than adding it to the bound, so a constant limit near the largest int no longer overflows into a wrong rejection. A positive offset that pushes a constant start or limit past the largest int is rejected as that bound: the emitted code adds them, and for i := 0; i < math.MaxInt64; i++ { dst[i] = a[i+1] } produced an overlap window of math.MaxInt64 + 1, which does not compile. offset_negative_constant.txt now checks the rewritten source and runs the loops under both builds, and the rejected loops, including loops that count down and range over a slice, move to offset_negative_constant_no_rewrite.txt. bound_arch_constant.txt pins the GOARCH case for <, <=, and loops that count down. The vectorized sets of std and gonum do not change.
mauri870
enabled auto-merge (squash)
November 3, 2026 21:15
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Follow-up to #2.
#2 started replacing every constant start or limit with its value, so that the checks parsing
Trip.Start/Trip.Limitas text would also see named constants. The emitted file is compiled for every build, though, and a named constant can have a different value in another one. Withconst width = 32for amd64 and64for arm64,loopvec -spliton amd64 hard-coded32into the vector loop offor i := 0; i < width; i++, while the scalar fallback keptwidth. The arm64 build would then vectorize only half the elements.plusOneandi > lowloops had always done the same for<=limits and loops that count down.What changes:
Tripcarries the values of a constant start and limit. The checks read those values instead of parsing text: the negative-index check, the short-loop rule and the copy check. A constant is written as its value only when it's built from literals alone (16,1 - 1). A constant that uses a name keeps the name.i <= width-1comes out aswidth.negativeSourcecould no longer return true after internal/loopir: reject a constant offset that puts an index below zero #2.for i := 0; i < math.MaxInt64; i++ { dst[i] = a[i+1] }used to produce an overlap window ofmath.MaxInt64 + 1, which doesn't compile.offset_negative_constant.txtnow checks the rewritten source and runs the loops under both builds.offset_negative_constant_no_rewrite.txt, which adds a loop counting down to 0, a range over a slice, and the two loops pushed past the largest int.bound_arch_constant.txtcovers the GOARCH case for<,<=, counting down and>.Tested locally:
bound_arch_constant.txtfails against internal/loopir: reject a constant offset that puts an index below zero #2'sinternal/loopir, which writes_ = dst[32-1]where the test expects_ = dst[width-1].make testandmake test-qemu-arm64pass.make test-updateandmake fixleave no diff, andmake lintreports 0 issues.loopvec -jsongives identical output before and after over std (1663 loops) and gonum (3252 loops).