Go version
go version go1.26-devel_8c41a48 Tue Nov 18 11:46:42 2025 -0800 linux/amd64
Output of go env in your module/workspace:
Workspace is `go.godbolt.org` on `x86-64 gc (tip)` as above.
What did you do?
[Code/output tested here]
Compile the following:
func constPrefixInlined(s string) bool {
const prefix = "caddyfile"
return len(s) >= len(prefix) && s[:len(prefix)] == prefix
}
func constPrefix(s string) bool {
const prefix = "caddyfile"
return innerPrefix(s, prefix)
}
// same code+result as with using strings.HasPrefix
func innerPrefix(s, prefix string) bool {
return len(s) >= len(prefix) && s[:len(prefix)] == prefix
}
What did you see happen?
constPrefix calls runtime.memequal with go:string."caddyfile", while constPrefixInlined gets the following:
CMPQ BX, $9
JLT command-line-arguments_constPrefixInlined_pc39
MOVQ $7811887700212212067, CX
CMPQ (AX), CX
JNE command-line-arguments_constPrefixInlined_pc35
CMPB 8(AX), $101
SETEQ CL
What did you expect to see?
Same assembly output for constPrefixInlined and constPrefix.
Similar results exist for when the constant string is anywhere between 9 and 16 bytes inclusive. Strings 17 bytes and over output the same for both functions.
One other notable difference is that of the optimizations for non-power-of-two constant strings of length below 8 bytes, for example when const prefix = "1234567":
CMPQ BX, $7
JLT command-line-arguments_constPrefixInlined_pc40
CMPL (AX), $875770417
JNE command-line-arguments_constPrefixInlined_pc36
CMPW 4(AX), $13877
JNE command-line-arguments_constPrefixInlined_pc36
CMPB 6(AX), $55
SETEQ CL
and for the auto-inliner:
CMPQ BX, $7
JLT command-line-arguments_constPrefix_pc42
MOVL (AX), CX
MOVL 3(AX), DX
SHLQ $32, DX
ORQ DX, CX
MOVQ $3978425819158753841, DX
CMPQ DX, CX
SETEQ CL
I'm not sure which of these two is better, but in any case I believe that they should agree on an approach.
Go version
go version go1.26-devel_8c41a48 Tue Nov 18 11:46:42 2025 -0800 linux/amd64Output of
go envin your module/workspace:What did you do?
[Code/output tested here]
Compile the following:
What did you see happen?
constPrefixcallsruntime.memequalwithgo:string."caddyfile", whileconstPrefixInlinedgets the following:What did you expect to see?
Same assembly output for
constPrefixInlinedandconstPrefix.Similar results exist for when the constant string is anywhere between 9 and 16 bytes inclusive. Strings 17 bytes and over output the same for both functions.
One other notable difference is that of the optimizations for non-power-of-two constant strings of length below 8 bytes, for example when
const prefix = "1234567":and for the auto-inliner:
I'm not sure which of these two is better, but in any case I believe that they should agree on an approach.