mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
cmd/compile/internal/noder: pointer shaping for unified IR
This CL implements pointer shaping in unified IR, corresponding to the existing pointer shaping implemented in the non-unified frontend. For example, if `func F[T any]` is instantiated as both `F[*int]` and `F[*string]`, we'll now generate a single `F[go.shape.*uint8]` shaped function that can be used by both. Fixes #54513. Change-Id: I2cef5ae411919e6dc5bcb3cac912abecb4cd5218 Reviewed-on: https://go-review.googlesource.com/c/go/+/424734 Run-TryBot: Matthew Dempsky <mdempsky@google.com> Reviewed-by: Keith Randall <khr@golang.org> TryBot-Result: Gopher Robot <gobot@golang.org> Reviewed-by: Keith Randall <khr@google.com> Reviewed-by: Cuong Manh Le <cuong.manhle.vn@gmail.com>
This commit is contained in:
parent
330cffb869
commit
b23d469e85
3 changed files with 59 additions and 28 deletions
|
|
@ -795,18 +795,31 @@ func (dict *readerDict) mangle(sym *types.Sym) *types.Sym {
|
|||
}
|
||||
|
||||
// shapify returns the shape type for targ.
|
||||
func shapify(targ *types.Type) *types.Type {
|
||||
if targ.IsShape() {
|
||||
return targ
|
||||
}
|
||||
|
||||
//
|
||||
// If basic is true, then the type argument is used to instantiate a
|
||||
// type parameter whose constraint is a basic interface.
|
||||
func shapify(targ *types.Type, basic bool) *types.Type {
|
||||
base.Assertf(targ.Kind() != types.TFORW, "%v is missing its underlying type", targ)
|
||||
|
||||
// TODO(go.dev/issue/54513): Better shaping than merely converting
|
||||
// to underlying type. E.g., shape pointer types to unsafe.Pointer
|
||||
// when we know the element type doesn't matter, and then enable
|
||||
// cmd/compile/internal/test.TestInst.
|
||||
// When a pointer type is used to instantiate a type parameter
|
||||
// constrained by a basic interface, we know the pointer's element
|
||||
// type can't matter to the generated code. In this case, we can use
|
||||
// an arbitrary pointer type as the shape type. (To match the
|
||||
// non-unified frontend, we use `*byte`.)
|
||||
//
|
||||
// Otherwise, we simply use the type's underlying type as its shape.
|
||||
//
|
||||
// TODO(mdempsky): It should be possible to do much more aggressive
|
||||
// shaping still; e.g., collapsing all pointer-shaped types into a
|
||||
// common type, collapsing scalars of the same size/alignment into a
|
||||
// common type, recursively shaping the element types of composite
|
||||
// types, and discarding struct field names and tags. However, we'll
|
||||
// need to start tracking how type parameters are actually used to
|
||||
// implement some of these optimizations.
|
||||
under := targ.Underlying()
|
||||
if basic && targ.IsPtr() && !targ.Elem().NotInHeap() {
|
||||
under = types.NewPtr(types.Types[types.TUINT8])
|
||||
}
|
||||
|
||||
sym := types.ShapePkg.Lookup(under.LinkString())
|
||||
if sym.Def == nil {
|
||||
|
|
@ -839,6 +852,20 @@ func (pr *pkgReader) objDictIdx(sym *types.Sym, idx pkgbits.Index, implicits, ex
|
|||
dict.targs = append(implicits[:nimplicits:nimplicits], explicits...)
|
||||
dict.implicits = nimplicits
|
||||
|
||||
// Within the compiler, we can just skip over the type parameters.
|
||||
for range dict.targs[dict.implicits:] {
|
||||
// Skip past bounds without actually evaluating them.
|
||||
r.typInfo()
|
||||
}
|
||||
|
||||
dict.derived = make([]derivedInfo, r.Len())
|
||||
dict.derivedTypes = make([]*types.Type, len(dict.derived))
|
||||
for i := range dict.derived {
|
||||
dict.derived[i] = derivedInfo{r.Reloc(pkgbits.RelocType), r.Bool()}
|
||||
}
|
||||
|
||||
// Runtime dictionary information; private to the compiler.
|
||||
|
||||
// If any type argument is already shaped, then we're constructing a
|
||||
// shaped object, even if not explicitly requested (i.e., calling
|
||||
// objIdx with shaped==true). This can happen with instantiating
|
||||
|
|
@ -852,26 +879,15 @@ func (pr *pkgReader) objDictIdx(sym *types.Sym, idx pkgbits.Index, implicits, ex
|
|||
|
||||
// And if we're constructing a shaped object, then shapify all type
|
||||
// arguments.
|
||||
if dict.shaped {
|
||||
for i, targ := range dict.targs {
|
||||
dict.targs[i] = shapify(targ)
|
||||
for i, targ := range dict.targs {
|
||||
basic := r.Bool()
|
||||
if dict.shaped {
|
||||
dict.targs[i] = shapify(targ, basic)
|
||||
}
|
||||
}
|
||||
|
||||
dict.baseSym = dict.mangle(sym)
|
||||
|
||||
// For stenciling, we can just skip over the type parameters.
|
||||
for range dict.targs[dict.implicits:] {
|
||||
// Skip past bounds without actually evaluating them.
|
||||
r.typInfo()
|
||||
}
|
||||
|
||||
dict.derived = make([]derivedInfo, r.Len())
|
||||
dict.derivedTypes = make([]*types.Type, len(dict.derived))
|
||||
for i := range dict.derived {
|
||||
dict.derived[i] = derivedInfo{r.Reloc(pkgbits.RelocType), r.Bool()}
|
||||
}
|
||||
|
||||
dict.typeParamMethodExprs = make([]readerMethodExprInfo, r.Len())
|
||||
for i := range dict.typeParamMethodExprs {
|
||||
typeParamIdx := r.Len()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue