]> Cypherpunks.ru repositories - gostls13.git/commitdiff
cmd/compile: handle string concatenation in static init inliner
authorCuong Manh Le <cuong.manhle.vn@gmail.com>
Wed, 8 Feb 2023 08:45:09 +0000 (15:45 +0700)
committerCuong Manh Le <cuong.manhle.vn@gmail.com>
Fri, 14 Apr 2023 17:57:14 +0000 (17:57 +0000)
Static init inliner is using typecheck.EvalConst to handle string
concatenation expressions. But static init inliner may reveal constant
expressions after substitution, and the compiler needs to evaluate those
expressions in non-constant semantic. Using typecheck.EvalConst, which
always evaluates expressions in constant semantic, is not the right
choice.

For safety, this CL fold the logic to handle string concatenation to
static init inliner, so there won't be regression in handling constant
expressions in non-constant semantic. And also, future CL can simplify
typecheck.EvalConst logic.

Updates #58293
Updates #58339
Fixes #58439

Change-Id: I74068d99c245938e576afe9460cbd2b39677bbff
Reviewed-on: https://go-review.googlesource.com/c/go/+/466277
Reviewed-by: Keith Randall <khr@google.com>
Run-TryBot: Cuong Manh Le <cuong.manhle.vn@gmail.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: David Chase <drchase@google.com>
Reviewed-by: Keith Randall <khr@golang.org>
src/cmd/compile/internal/staticinit/sched.go
test/fixedbugs/issue58439.go [new file with mode: 0644]

index c9b023946536992d5c1ed79e740626d4c4590f9f..e5f7be4c5f4cac6f2f64402d639f0b28e3e646ef 100644 (file)
@@ -9,6 +9,7 @@ import (
        "go/constant"
        "go/token"
        "os"
+       "strings"
 
        "cmd/compile/internal/base"
        "cmd/compile/internal/ir"
@@ -866,14 +867,22 @@ func subst(n ir.Node, m map[*ir.Name]ir.Node) (ir.Node, bool) {
                }
                x = ir.Copy(x)
                ir.EditChildrenWithHidden(x, edit)
-               if x, ok := x.(*ir.ConvExpr); ok && x.X.Op() == ir.OLITERAL {
-                       if x, ok := truncate(x.X, x.Type()); ok {
+
+               // TODO: handle more operations, see details discussion in go.dev/cl/466277.
+               switch x.Op() {
+               case ir.OCONV:
+                       x := x.(*ir.ConvExpr)
+                       if x.X.Op() == ir.OLITERAL {
+                               if x, ok := truncate(x.X, x.Type()); ok {
+                                       return x
+                               }
+                               valid = false
                                return x
                        }
-                       valid = false
-                       return x
+               case ir.OADDSTR:
+                       return addStr(x.(*ir.AddStringExpr))
                }
-               return typecheck.EvalConst(x)
+               return x
        }
        n = edit(n)
        return n, valid
@@ -909,6 +918,51 @@ func truncate(c ir.Node, t *types.Type) (ir.Node, bool) {
        return c, true
 }
 
+func addStr(n *ir.AddStringExpr) ir.Node {
+       // Merge adjacent constants in the argument list.
+       s := n.List
+       need := 0
+       for i := 0; i < len(s); i++ {
+               if i == 0 || !ir.IsConst(s[i-1], constant.String) || !ir.IsConst(s[i], constant.String) {
+                       // Can't merge s[i] into s[i-1]; need a slot in the list.
+                       need++
+               }
+       }
+       if need == len(s) {
+               return n
+       }
+       if need == 1 {
+               var strs []string
+               for _, c := range s {
+                       strs = append(strs, ir.StringVal(c))
+               }
+               return typecheck.OrigConst(n, constant.MakeString(strings.Join(strs, "")))
+       }
+       newList := make([]ir.Node, 0, need)
+       for i := 0; i < len(s); i++ {
+               if ir.IsConst(s[i], constant.String) && i+1 < len(s) && ir.IsConst(s[i+1], constant.String) {
+                       // merge from i up to but not including i2
+                       var strs []string
+                       i2 := i
+                       for i2 < len(s) && ir.IsConst(s[i2], constant.String) {
+                               strs = append(strs, ir.StringVal(s[i2]))
+                               i2++
+                       }
+
+                       nl := ir.Copy(n).(*ir.AddStringExpr)
+                       nl.List = s[i:i2]
+                       newList = append(newList, typecheck.OrigConst(nl, constant.MakeString(strings.Join(strs, ""))))
+                       i = i2 - 1
+               } else {
+                       newList = append(newList, s[i])
+               }
+       }
+
+       nn := ir.Copy(n).(*ir.AddStringExpr)
+       nn.List = newList
+       return nn
+}
+
 const wrapGlobalMapInitSizeThreshold = 20
 
 // tryWrapGlobalMapInit examines the node 'n' to see if it is a map
diff --git a/test/fixedbugs/issue58439.go b/test/fixedbugs/issue58439.go
new file mode 100644 (file)
index 0000000..daf188f
--- /dev/null
@@ -0,0 +1,14 @@
+// compile -d=inlstaticinit
+
+// Copyright 2023 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package p
+
+var x = f(-1)
+var y = f(64)
+
+func f(x int) int {
+       return 1 << x
+}