diff options
| author | Robert Griesemer <gri@google.com> | 2026-03-11 19:02:07 -0700 |
|---|---|---|
| committer | Robert Griesemer <gri@google.com> | 2026-03-19 14:32:34 -0700 |
| commit | d9a600a73bed7b907f7321200650fe5103f47fc9 (patch) | |
| tree | 47e838eb42993fec92442cc20a1cc0d83a52f948 /src/cmd/compile | |
| parent | 9f7e98d263f1e496991110f057763a2b4319e1c1 (diff) | |
| download | go-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.go | 99 | ||||
| -rw-r--r-- | src/cmd/compile/internal/noder/writer.go | 89 |
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) |
