Skip to content

compiler: avoid byte slice copies in mixed string comparisons - #5784

Merged
deadprogram merged 1 commit into
tinygo-org:devfrom
davecheney:davecheney-mixed-string-comparisons
Oct 19, 2026
Merged

deadprogram merged 1 commit into
tinygo-org:devfrom
davecheney:davecheney-mixed-string-comparisons

Conversation

@davecheney

@davecheney davecheney commented Sep 29, 2026 •

Copy link
Copy Markdown
Contributor

Compare string(a) with any string operand without copying the []byte operand when nothing between the conversion and the comparison can change it.

#5765 and #5773 needed both operands to be []byte conversions, but Go's gc compiler marks each operand on its own, and this change does the same.

The safety check from #5765 does not change, so a call, store, load, or slice between the conversion and the comparison keeps the copy.

On cortex-m-qemu with -opt=z, the size corpus code drops from 9923 to 9907 bytes.

@dgryski

dgryski commented Sep 29, 2026

Copy link
Copy Markdown
Member

From a corrrectness standpoint the test corpus is happy with this change, but we should figure out what's happening with the AVR build (and also the binary size test failed CI).

@davecheney
davecheney force-pushed the davecheney-mixed-string-comparisons branch from c535c5d to 26cbd22 Compare September 30, 2026 09:25
@davecheney

Copy link
Copy Markdown
Contributor Author

From a corrrectness standpoint the test corpus is happy with this change, but we should figure out what's happening with the AVR build (and also the binary size test failed CI).

The AVR build needs an exception, like math.go, because after inlining main.main is large enough it needs more stack than simavr provides.

@davecheney
davecheney force-pushed the davecheney-mixed-string-comparisons branch from 26cbd22 to ce70b56 Compare October 13, 2026 13:00
@davecheney
davecheney marked this pull request as ready for review October 14, 2026 10:15
@davecheney
davecheney force-pushed the davecheney-mixed-string-comparisons branch from 18a32c9 to 2019822 Compare October 14, 2026 10:17
@davecheney
davecheney requested a review from jakebailey October 14, 2026 10:23
@davecheney
davecheney force-pushed the davecheney-mixed-string-comparisons branch 3 times, most recently from 4fee9cf to 42c617d Compare October 17, 2026 22:57
Compare string(a) with any string operand without copying the []byte operand when nothing between the conversion and the comparison can change it.

tinygo-org#5765 and tinygo-org#5773 needed both operands to be []byte conversions, but Go's gc compiler [marks each operand on its own](https://github.com/golang/go/blob/go1.27.2/src/cmd/compile/internal/walk/order.go#L1447-L1456), and this change does the same.

The safety check from tinygo-org#5765 does not change, so a call, store, load, or slice between the conversion and the comparison keeps the copy.

On cortex-m-qemu with -opt=z, the size corpus code drops from 9923 to 9907 bytes.
@davecheney
davecheney force-pushed the davecheney-mixed-string-comparisons branch from 42c617d to 72a6963 Compare October 17, 2026 22:58
@davecheney

Copy link
Copy Markdown
Contributor Author

@dgryski @deadprogram after a bunch of side quests this is now ready for review.

@deadprogram

Copy link
Copy Markdown
Member

Thanks @davecheney. I ran the tests locally. The following is edited from an automated review:

  1. A string load (*s) or a string slice (s[:n]) between the conversion and the comparison can't write to the byte slice, and if either panics the comparison never runs. So adjacentComparison could perhaps let those through as well, as a follow up. Keeping it conservative for this PR seems fine too.

  2. checkAllocs in tests/stringcompare/allocs_test.go checks for an exact TotalAlloc byte count. That relies on the conservative GC counting the requested size, not the rounded size. Should it check Mallocs only, so a GC change does not break this test?

WDYT?

@deadprogram deadprogram left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My comments being just comments, this PR is looking good to me. Now merging, thank you @davecheney

@deadprogram
deadprogram merged commit 04ca26f into tinygo-org:dev Oct 19, 2026
34 checks passed
@davecheney

Copy link
Copy Markdown
Contributor Author

@deadprogram thanks for your comments

Thanks @davecheney. I ran the tests locally. The following is edited from an automated review:

  1. A string load (*s) or a string slice (s[:n]) between the conversion and the comparison can't write to the byte slice, and if either panics the comparison never runs. So adjacentComparison could perhaps let those through as well, as a follow up. Keeping it conservative for this PR seems fine too.

fortunately I have #5937 waiting in the wings

  1. checkAllocs in tests/stringcompare/allocs_test.go checks for an exact TotalAlloc byte count. That relies on the conservative GC counting the requested size, not the rounded size. Should it check Mallocs only, so a GC change does not break this test?

I'll take this under advisement. I'll send a PR to switch the memory size arithmetic.

@davecheney
davecheney deleted the davecheney-mixed-string-comparisons branch October 19, 2026 21:27
deadprogram pushed a commit that referenced this pull request Oct 21, 2026
The test read exact byte counts from runtime.MemStats, so it needed the conservative collector, and a change in how that collector counts bytes could break it, as deadprogram said in #5784 (comment).

testing.AllocsPerRun gives the same count with every collector, so the test can also run with the default collector of each target, which is boehm on hosts.
mklocdev pushed a commit to mklocdev/tinygo that referenced this pull request Oct 21, 2026
The test read exact byte counts from runtime.MemStats, so it needed the conservative collector, and a change in how that collector counts bytes could break it, as deadprogram said in tinygo-org#5784 (comment).

testing.AllocsPerRun gives the same count with every collector, so the test can also run with the default collector of each target, which is boehm on hosts.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants