aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/compile
diff options
context:
space:
mode:
authorRobert Griesemer <gri@google.com>2026-03-11 19:02:07 -0700
committerRobert Griesemer <gri@google.com>2026-03-19 14:32:34 -0700
commitd9a600a73bed7b907f7321200650fe5103f47fc9 (patch)
tree47e838eb42993fec92442cc20a1cc0d83a52f948 /src/cmd/compile
parent9f7e98d263f1e496991110f057763a2b4319e1c1 (diff)
downloadgo-d9a600a73bed7b907f7321200650fe5103f47fc9.tar.xz
cmd/compile/internal/noder: encode promoted struct fields for composite literals in UIR
This change requires an encoding format change for struct literals. Introduce a new UIR version (V3) and use the opportunity to encode all composite literals more compactly: specifically, when we know that (composite literal) keys are always present, avoid encoding a bool value for each key. Do not yet enable the new format. For #9859. Change-Id: Ic6dc9adb1aa494e923eadaf578f8cfc61efd5ea4 Reviewed-on: https://go-review.googlesource.com/c/go/+/754664 Reviewed-by: Mark Freeman <markfreeman@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Robert Griesemer <gri@google.com>
Diffstat (limited to 'src/cmd/compile')
-rw-r--r--src/cmd/compile/internal/noder/reader.go99
-rw-r--r--src/cmd/compile/internal/noder/writer.go89
2 files changed, 175 insertions, 13 deletions
diff --git a/src/cmd/compile/internal/noder/reader.go b/src/cmd/compile/internal/noder/reader.go
index a9ed77409b..b30a2a3e86 100644
--- a/src/cmd/compile/internal/noder/reader.go
+++ b/src/cmd/compile/internal/noder/reader.go
@@ -3028,21 +3028,37 @@ func (r *reader) compLit() ir.Node {
if typ.IsMap() {
rtype = r.rtype(pos)
}
- isStruct := typ.Kind() == types.TSTRUCT
- elems := make([]ir.Node, r.Len())
- for i := range elems {
- elemp := &elems[i]
-
- if isStruct {
- sk := ir.NewStructKeyExpr(r.pos(), typ.Field(r.Len()), nil)
- *elemp, elemp = sk, &sk.Value
- } else if r.Bool() {
- kv := ir.NewKeyExpr(r.pos(), r.expr(), nil)
- *elemp, elemp = kv, &kv.Value
+ var elems []ir.Node
+ if r.Version().Has(pkgbits.CompactCompLiterals) {
+ n := r.Int()
+ elems = make([]ir.Node, max(n, -n) /* abs(n) */)
+ switch typ.Kind() {
+ default:
+ base.FatalfAt(pos, "unexpected composite literal type: %v", typ)
+ case types.TARRAY:
+ r.arrayElems(n >= 0, elems)
+ case types.TMAP:
+ r.mapElems(elems)
+ case types.TSLICE:
+ r.arrayElems(n >= 0, elems)
+ case types.TSTRUCT:
+ r.structElems(typ, n >= 0, elems)
+ }
+ } else {
+ elems = make([]ir.Node, r.Len())
+ isStruct := typ.Kind() == types.TSTRUCT
+ for i := range elems {
+ elemp := &elems[i]
+ if isStruct {
+ sk := ir.NewStructKeyExpr(r.pos(), typ.Field(r.Len()), nil)
+ *elemp, elemp = sk, &sk.Value
+ } else if r.Bool() {
+ kv := ir.NewKeyExpr(r.pos(), r.expr(), nil)
+ *elemp, elemp = kv, &kv.Value
+ }
+ *elemp = r.expr()
}
-
- *elemp = r.expr()
}
lit := typecheck.Expr(ir.NewCompLitExpr(pos, ir.OCOMPLIT, typ, elems))
@@ -3057,6 +3073,63 @@ func (r *reader) compLit() ir.Node {
return lit
}
+func (r *reader) arrayElems(valuesOnly bool, elems []ir.Node) {
+ if valuesOnly {
+ for i := range elems {
+ elems[i] = r.expr()
+ }
+ return
+ }
+ // some elements may have a key
+ for i := range elems {
+ if r.Bool() {
+ kv := ir.NewKeyExpr(r.pos(), r.expr(), nil)
+ kv.Value = r.expr()
+ elems[i] = kv
+ } else {
+ elems[i] = r.expr()
+ }
+ }
+}
+
+func (r *reader) mapElems(elems []ir.Node) {
+ // all elements have a key
+ for i := range elems {
+ kv := ir.NewKeyExpr(r.pos(), r.expr(), nil)
+ kv.Value = r.expr()
+ elems[i] = kv
+ }
+}
+
+func (r *reader) structElems(typ *types.Type, valuesOnly bool, elems []ir.Node) {
+ if valuesOnly {
+ for i := range elems {
+ sk := ir.NewStructKeyExpr(r.pos(), typ.Field(i), nil)
+ sk.Value = r.expr()
+ elems[i] = sk
+ }
+ return
+ }
+
+ // all elements have a key
+ for i := range elems {
+ pos := r.pos()
+ var fld *types.Field
+ if n := r.Int(); n < 0 {
+ // embedded field
+ for range -n {
+ fld = typ.Field(r.Int())
+ typ = fld.Type
+ }
+ } else { // n >= 0
+ fld = typ.Field(n)
+ }
+ sk := ir.NewStructKeyExpr(pos, fld, nil)
+ sk.Value = r.expr()
+ elems[i] = sk
+ }
+}
+
func (r *reader) funcLit() ir.Node {
r.Sync(pkgbits.SyncFuncLit)
diff --git a/src/cmd/compile/internal/noder/writer.go b/src/cmd/compile/internal/noder/writer.go
index 8139d889df..2c648d661d 100644
--- a/src/cmd/compile/internal/noder/writer.go
+++ b/src/cmd/compile/internal/noder/writer.go
@@ -2344,6 +2344,25 @@ func (w *writer) compLit(lit *syntax.CompositeLit) {
if ptr, ok := types2.CoreType(typ).(*types2.Pointer); ok {
typ = ptr.Elem()
}
+
+ if w.Version().Has(pkgbits.CompactCompLiterals) {
+ switch typ0 := typ; typ := types2.CoreType(typ).(type) {
+ default:
+ w.p.fatalf(lit, "unexpected composite literal type: %v", typ)
+ case *types2.Array:
+ w.arrayElems(typ.Elem(), lit.ElemList)
+ case *types2.Map:
+ w.rtype(typ0)
+ w.mapElems(typ.Key(), typ.Elem(), lit.ElemList)
+ case *types2.Slice:
+ w.arrayElems(typ.Elem(), lit.ElemList)
+ case *types2.Struct:
+ w.structElems(typ, lit.NKeys == 0, lit.ElemList)
+ }
+ return
+ }
+
+ // old format
var keyType, elemType types2.Type
var structType *types2.Struct
switch typ0 := typ; typ := types2.CoreType(typ).(type) {
@@ -2386,6 +2405,76 @@ func (w *writer) compLit(lit *syntax.CompositeLit) {
}
}
+func (w *writer) arrayElems(elemType types2.Type, elems []syntax.Expr) {
+ valuesOnly := true
+ for _, elem := range elems {
+ if _, ok := elem.(*syntax.KeyValueExpr); ok {
+ valuesOnly = false
+ break
+ }
+ }
+
+ if valuesOnly {
+ w.Int(len(elems))
+ for _, elem := range elems {
+ w.implicitConvExpr(elemType, elem)
+ }
+ return
+ }
+ // some elements may have a key
+ w.Int(-len(elems))
+ for _, elem := range elems {
+ if kv, ok := elem.(*syntax.KeyValueExpr); w.Bool(ok) {
+ w.pos(kv.Key) // use position of Key rather than of elem (which has position of ':')
+ w.implicitConvExpr(nil, kv.Key)
+ elem = kv.Value
+ }
+ w.implicitConvExpr(elemType, elem)
+ }
+}
+
+func (w *writer) mapElems(keyType, valueType types2.Type, elems []syntax.Expr) {
+ // all elements have a key
+ w.Int(-len(elems))
+ for _, elem := range elems {
+ kv := elem.(*syntax.KeyValueExpr)
+ w.pos(kv.Key) // use position of Key rather than of elem (which has position of ':')
+ w.implicitConvExpr(keyType, kv.Key)
+ w.implicitConvExpr(valueType, kv.Value)
+ }
+}
+
+func (w *writer) structElems(typ *types2.Struct, valuesOnly bool, elems []syntax.Expr) {
+ n := len(elems)
+ if valuesOnly {
+ // no element has a key
+ w.Int(n)
+ for i, elem := range elems {
+ w.pos(elem)
+ w.implicitConvExpr(typ.Field(i).Type(), elem)
+ }
+ return
+ }
+ // all elements have a key
+ w.Int(-n)
+ for _, elem := range elems {
+ kv := elem.(*syntax.KeyValueExpr)
+ w.pos(kv.Key) // use position of Key rather than of elem (which has position of ':')
+ // TODO(gri): rather than doing this lookup again, perhaps the index should be recorded by types2
+ fld, index, _ := types2.LookupFieldOrMethod(typ, false, w.p.curpkg, kv.Key.(*syntax.Name).Value)
+ if n := len(index); n > 1 {
+ // embedded field
+ w.Int(-n)
+ for _, i := range index {
+ w.Int(i)
+ }
+ } else { // n == 1
+ w.Int(index[0])
+ }
+ w.implicitConvExpr(fld.Type(), kv.Value)
+ }
+}
+
func (w *writer) funcLit(expr *syntax.FuncLit) {
sig := w.p.typeOf(expr).(*types2.Signature)