How string constants are propagated inside a small func

188 views
Skip to first unread message

Valentin Deleplace

unread,
Apr 30, 2021, 1:51:59 PM4/30/21
to golang-nuts
Hi, I was surprised that the funcs f and g do not generate the same assembly code:

func f() string {
        s := "a" + "b"
        return s
}

func g() string {
        s := "a"
        s += "b"
        return s
}

The compiled assembly respects the apparent instructions of the source code, with g calling runtime.concatstring2, while f does not (f benefits from an optimization that transforms "a"+"b" into the constant "ab").

I don't know exactly what SSA does in the compiler, but I thought it would be capable of optimizing f and g into the exact same generated code. Am I missing something?

Jan Mercl

unread,
Apr 30, 2021, 1:57:32 PM4/30/21
to Valentin Deleplace, golang-nuts
On Fri, Apr 30, 2021 at 7:51 PM 'Valentin Deleplace' via golang-nuts
<golan...@googlegroups.com> wrote:

> func f() string {
> s := "a" + "b"
> return s
> }

Handled by constant folding.

> func g() string {
> s := "a"
> s += "b"
> return s
> }

The second assignment to 's' here is not a constant expression but a
value computed at runtime. A different mechanism may detect this
optimization opportunity, provided it's possible without changing the
semantics of the program.

Ian Lance Taylor

unread,
Apr 30, 2021, 1:58:36 PM4/30/21
to Valentin Deleplace, golang-nuts
I agree that the compiler ought to be able to generate the same code
for both cases. But I'll note that from a language perspective, the
functions are quite different. "a" + "b" is a constant expression
(https://golang.org/ref/spec#Constant_expressions). The language
requires that "a" + "b" be evaluated at compile time. There is no
such requirement for the function g. That would require a more
complicated compiler optimization.

Ian

Jesper Louis Andersen

unread,
May 1, 2021, 7:29:15 AM5/1/21
to Valentin Deleplace, golang-nuts
On Fri, Apr 30, 2021 at 7:51 PM 'Valentin Deleplace' via golang-nuts <golan...@googlegroups.com> wrote:
I don't know exactly what SSA does in the compiler, but I thought it would be capable of optimizing f and g into the exact same generated code. Am I missing something?

Roughly, SSA would rewrite the g() function to something along the lines of

func g() string {
        s1 := "a"
        s2 = s1 + "b"
        return s
}

That is, it would make it easier to figure out where s1 is defined (since it can only have a single static assignment in the program, we don't have to worry if there is another path defining s := "x"). Yet, this is not a guarantee for optimization. You still have to carry out an analysis for when an optimization is safe to apply. The key point is that such an analysis is far easier to perform in SSA-form. Furthermore, it is often more efficient, so the compiler runs faster. My haphazard guess would be that constant/value propagation happens for number-types but not for strings.



--
J.

Valentin Deleplace

unread,
May 3, 2021, 3:07:44 AM5/3/21
to golang-nuts
Thank you all for the insights

Jesper Louis Andersen

unread,
May 4, 2021, 11:06:05 AM5/4/21
to Valentin Deleplace, golang-nuts
On Sat, May 1, 2021 at 1:28 PM Jesper Louis Andersen <jesper.lou...@gmail.com> wrote:

func g() string {
        s1 := "a"
        s2 = s1 + "b"
        return s
}


Errata: it should have been `return s2` rather than `return s`. I hope I didn't confuse people too much.


--
J.
Reply all
Reply to author
Forward
0 new messages