cmd/compile/internal/ssa: load constant values from abi.PtrType.Elem

This CL makes the generated code for reflect.TypeFor as simple as an
intrinsic function.

Fixes #75203

Change-Id: I7bb48787101f07e77ab5c583292e834c28a028d6
Reviewed-on: https://go-review.googlesource.com/c/go/+/700336
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Keith Randall <khr@golang.org>
Reviewed-by: Keith Randall <khr@google.com>
Reviewed-by: Michael Pratt <mpratt@google.com>
Auto-Submit: Keith Randall <khr@golang.org>
This commit is contained in:
Youlin Feng 2025-09-01 18:31:29 +08:00 committed by Gopher Robot
parent 4373754bc9
commit df29038486
4 changed files with 371 additions and 0 deletions

View file

@ -2767,6 +2767,22 @@
(Load <typ.Uintptr> (OffPtr [off] (ITab (IMake (Addr {s} sb) _))) _) && isFixedSym(s, off) => (Addr {fixedSym(b.Func, s, off)} sb)
(Load <typ.Uintptr> (OffPtr [off] (ITab (IMake (Convert (Addr {s} sb) _) _))) _) && isFixedSym(s, off) => (Addr {fixedSym(b.Func, s, off)} sb)
// Loading constant values from dictionaries and itabs. For offset 0.
(Load <typ.BytePtr> (Addr {s} sb) _) && isFixedSym(s, 0) => (Addr {fixedSym(b.Func, s, 0)} sb)
(Load <typ.BytePtr> (Convert (Addr {s} sb) _) _) && isFixedSym(s, 0) => (Addr {fixedSym(b.Func, s, 0)} sb)
(Load <typ.BytePtr> (ITab (IMake (Addr {s} sb) _)) _) && isFixedSym(s, 0) => (Addr {fixedSym(b.Func, s, 0)} sb)
(Load <typ.BytePtr> (ITab (IMake (Convert (Addr {s} sb) _) _)) _) && isFixedSym(s, 0) => (Addr {fixedSym(b.Func, s, 0)} sb)
(Load <typ.Uintptr> (Addr {s} sb) _) && isFixedSym(s, 0) => (Addr {fixedSym(b.Func, s, 0)} sb)
(Load <typ.Uintptr> (Convert (Addr {s} sb) _) _) && isFixedSym(s, 0) => (Addr {fixedSym(b.Func, s, 0)} sb)
(Load <typ.Uintptr> (ITab (IMake (Addr {s} sb) _)) _) && isFixedSym(s, 0) => (Addr {fixedSym(b.Func, s, 0)} sb)
(Load <typ.Uintptr> (ITab (IMake (Convert (Addr {s} sb) _) _)) _) && isFixedSym(s, 0) => (Addr {fixedSym(b.Func, s, 0)} sb)
// Loading constant values from abi.PtrType.Elem.
(Load <t> (OffPtr [off] (Addr {s} sb) ) _) && t.IsPtr() && isPtrElem(s, off) => (Addr {ptrElem(s, off)} sb)
(Load <t> (OffPtr [off] (Convert (Addr {s} sb) _) ) _) && t.IsPtr() && isPtrElem(s, off) => (Addr {ptrElem(s, off)} sb)
(Load <t> (OffPtr [off] (ITab (IMake (Addr {s} sb) _))) _) && t.IsPtr() && isPtrElem(s, off) => (Addr {ptrElem(s, off)} sb)
(Load <t> (OffPtr [off] (ITab (IMake (Convert (Addr {s} sb) _) _))) _) && t.IsPtr() && isPtrElem(s, off) => (Addr {ptrElem(s, off)} sb)
// Loading constant values from runtime._type.hash.
(Load <t> (OffPtr [off] (Addr {sym} _) ) _) && t.IsInteger() && t.Size() == 4 && isFixed32(config, sym, off) => (Const32 [fixed32(config, sym, off)])
(Load <t> (OffPtr [off] (Convert (Addr {sym} _) _) ) _) && t.IsInteger() && t.Size() == 4 && isFixed32(config, sym, off) => (Const32 [fixed32(config, sym, off)])

View file

@ -8,6 +8,7 @@ import (
"cmd/compile/internal/base"
"cmd/compile/internal/logopt"
"cmd/compile/internal/reflectdata"
"cmd/compile/internal/rttype"
"cmd/compile/internal/types"
"cmd/internal/obj"
"cmd/internal/obj/s390x"
@ -2012,6 +2013,38 @@ func fixed32(c *Config, sym Sym, off int64) int32 {
return 0
}
// isPtrElem returns true if sym is an instance of abi.PtrType and off
// is equal to the offset of its Elem field.
func isPtrElem(sym Sym, off int64) bool {
lsym := sym.(*obj.LSym)
if strings.HasPrefix(lsym.Name, "type:*") {
if ti, ok := (*lsym.Extra).(*obj.TypeInfo); ok {
t := ti.Type.(*types.Type)
if t.Kind() == types.TPTR {
if off == rttype.PtrType.OffsetOf("Elem") {
return true
}
}
}
}
return false
}
func ptrElem(sym Sym, off int64) Sym {
lsym := sym.(*obj.LSym)
if strings.HasPrefix(lsym.Name, "type:*") {
if ti, ok := (*lsym.Extra).(*obj.TypeInfo); ok {
t := ti.Type.(*types.Type)
if t.Kind() == types.TPTR {
if off == rttype.PtrType.OffsetOf("Elem") {
return reflectdata.TypeLinksym(t.Elem())
}
}
}
}
base.Fatalf("ptrElem data not known for %s:%d", sym, off)
return nil
}
// isFixedSym returns true if the contents of sym at the given offset
// is known and is the constant address of another symbol.
func isFixedSym(sym Sym, off int64) bool {

View file

@ -14897,6 +14897,306 @@ func rewriteValuegeneric_OpLoad(v *Value) bool {
v.AddArg(sb)
return true
}
// match: (Load <typ.BytePtr> (Addr {s} sb) _)
// cond: isFixedSym(s, 0)
// result: (Addr {fixedSym(b.Func, s, 0)} sb)
for {
if v.Type != typ.BytePtr || v_0.Op != OpAddr {
break
}
s := auxToSym(v_0.Aux)
sb := v_0.Args[0]
if !(isFixedSym(s, 0)) {
break
}
v.reset(OpAddr)
v.Aux = symToAux(fixedSym(b.Func, s, 0))
v.AddArg(sb)
return true
}
// match: (Load <typ.BytePtr> (Convert (Addr {s} sb) _) _)
// cond: isFixedSym(s, 0)
// result: (Addr {fixedSym(b.Func, s, 0)} sb)
for {
if v.Type != typ.BytePtr || v_0.Op != OpConvert {
break
}
v_0_0 := v_0.Args[0]
if v_0_0.Op != OpAddr {
break
}
s := auxToSym(v_0_0.Aux)
sb := v_0_0.Args[0]
if !(isFixedSym(s, 0)) {
break
}
v.reset(OpAddr)
v.Aux = symToAux(fixedSym(b.Func, s, 0))
v.AddArg(sb)
return true
}
// match: (Load <typ.BytePtr> (ITab (IMake (Addr {s} sb) _)) _)
// cond: isFixedSym(s, 0)
// result: (Addr {fixedSym(b.Func, s, 0)} sb)
for {
if v.Type != typ.BytePtr || v_0.Op != OpITab {
break
}
v_0_0 := v_0.Args[0]
if v_0_0.Op != OpIMake {
break
}
v_0_0_0 := v_0_0.Args[0]
if v_0_0_0.Op != OpAddr {
break
}
s := auxToSym(v_0_0_0.Aux)
sb := v_0_0_0.Args[0]
if !(isFixedSym(s, 0)) {
break
}
v.reset(OpAddr)
v.Aux = symToAux(fixedSym(b.Func, s, 0))
v.AddArg(sb)
return true
}
// match: (Load <typ.BytePtr> (ITab (IMake (Convert (Addr {s} sb) _) _)) _)
// cond: isFixedSym(s, 0)
// result: (Addr {fixedSym(b.Func, s, 0)} sb)
for {
if v.Type != typ.BytePtr || v_0.Op != OpITab {
break
}
v_0_0 := v_0.Args[0]
if v_0_0.Op != OpIMake {
break
}
v_0_0_0 := v_0_0.Args[0]
if v_0_0_0.Op != OpConvert {
break
}
v_0_0_0_0 := v_0_0_0.Args[0]
if v_0_0_0_0.Op != OpAddr {
break
}
s := auxToSym(v_0_0_0_0.Aux)
sb := v_0_0_0_0.Args[0]
if !(isFixedSym(s, 0)) {
break
}
v.reset(OpAddr)
v.Aux = symToAux(fixedSym(b.Func, s, 0))
v.AddArg(sb)
return true
}
// match: (Load <typ.Uintptr> (Addr {s} sb) _)
// cond: isFixedSym(s, 0)
// result: (Addr {fixedSym(b.Func, s, 0)} sb)
for {
if v.Type != typ.Uintptr || v_0.Op != OpAddr {
break
}
s := auxToSym(v_0.Aux)
sb := v_0.Args[0]
if !(isFixedSym(s, 0)) {
break
}
v.reset(OpAddr)
v.Aux = symToAux(fixedSym(b.Func, s, 0))
v.AddArg(sb)
return true
}
// match: (Load <typ.Uintptr> (Convert (Addr {s} sb) _) _)
// cond: isFixedSym(s, 0)
// result: (Addr {fixedSym(b.Func, s, 0)} sb)
for {
if v.Type != typ.Uintptr || v_0.Op != OpConvert {
break
}
v_0_0 := v_0.Args[0]
if v_0_0.Op != OpAddr {
break
}
s := auxToSym(v_0_0.Aux)
sb := v_0_0.Args[0]
if !(isFixedSym(s, 0)) {
break
}
v.reset(OpAddr)
v.Aux = symToAux(fixedSym(b.Func, s, 0))
v.AddArg(sb)
return true
}
// match: (Load <typ.Uintptr> (ITab (IMake (Addr {s} sb) _)) _)
// cond: isFixedSym(s, 0)
// result: (Addr {fixedSym(b.Func, s, 0)} sb)
for {
if v.Type != typ.Uintptr || v_0.Op != OpITab {
break
}
v_0_0 := v_0.Args[0]
if v_0_0.Op != OpIMake {
break
}
v_0_0_0 := v_0_0.Args[0]
if v_0_0_0.Op != OpAddr {
break
}
s := auxToSym(v_0_0_0.Aux)
sb := v_0_0_0.Args[0]
if !(isFixedSym(s, 0)) {
break
}
v.reset(OpAddr)
v.Aux = symToAux(fixedSym(b.Func, s, 0))
v.AddArg(sb)
return true
}
// match: (Load <typ.Uintptr> (ITab (IMake (Convert (Addr {s} sb) _) _)) _)
// cond: isFixedSym(s, 0)
// result: (Addr {fixedSym(b.Func, s, 0)} sb)
for {
if v.Type != typ.Uintptr || v_0.Op != OpITab {
break
}
v_0_0 := v_0.Args[0]
if v_0_0.Op != OpIMake {
break
}
v_0_0_0 := v_0_0.Args[0]
if v_0_0_0.Op != OpConvert {
break
}
v_0_0_0_0 := v_0_0_0.Args[0]
if v_0_0_0_0.Op != OpAddr {
break
}
s := auxToSym(v_0_0_0_0.Aux)
sb := v_0_0_0_0.Args[0]
if !(isFixedSym(s, 0)) {
break
}
v.reset(OpAddr)
v.Aux = symToAux(fixedSym(b.Func, s, 0))
v.AddArg(sb)
return true
}
// match: (Load <t> (OffPtr [off] (Addr {s} sb) ) _)
// cond: t.IsPtr() && isPtrElem(s, off)
// result: (Addr {ptrElem(s, off)} sb)
for {
t := v.Type
if v_0.Op != OpOffPtr {
break
}
off := auxIntToInt64(v_0.AuxInt)
v_0_0 := v_0.Args[0]
if v_0_0.Op != OpAddr {
break
}
s := auxToSym(v_0_0.Aux)
sb := v_0_0.Args[0]
if !(t.IsPtr() && isPtrElem(s, off)) {
break
}
v.reset(OpAddr)
v.Aux = symToAux(ptrElem(s, off))
v.AddArg(sb)
return true
}
// match: (Load <t> (OffPtr [off] (Convert (Addr {s} sb) _) ) _)
// cond: t.IsPtr() && isPtrElem(s, off)
// result: (Addr {ptrElem(s, off)} sb)
for {
t := v.Type
if v_0.Op != OpOffPtr {
break
}
off := auxIntToInt64(v_0.AuxInt)
v_0_0 := v_0.Args[0]
if v_0_0.Op != OpConvert {
break
}
v_0_0_0 := v_0_0.Args[0]
if v_0_0_0.Op != OpAddr {
break
}
s := auxToSym(v_0_0_0.Aux)
sb := v_0_0_0.Args[0]
if !(t.IsPtr() && isPtrElem(s, off)) {
break
}
v.reset(OpAddr)
v.Aux = symToAux(ptrElem(s, off))
v.AddArg(sb)
return true
}
// match: (Load <t> (OffPtr [off] (ITab (IMake (Addr {s} sb) _))) _)
// cond: t.IsPtr() && isPtrElem(s, off)
// result: (Addr {ptrElem(s, off)} sb)
for {
t := v.Type
if v_0.Op != OpOffPtr {
break
}
off := auxIntToInt64(v_0.AuxInt)
v_0_0 := v_0.Args[0]
if v_0_0.Op != OpITab {
break
}
v_0_0_0 := v_0_0.Args[0]
if v_0_0_0.Op != OpIMake {
break
}
v_0_0_0_0 := v_0_0_0.Args[0]
if v_0_0_0_0.Op != OpAddr {
break
}
s := auxToSym(v_0_0_0_0.Aux)
sb := v_0_0_0_0.Args[0]
if !(t.IsPtr() && isPtrElem(s, off)) {
break
}
v.reset(OpAddr)
v.Aux = symToAux(ptrElem(s, off))
v.AddArg(sb)
return true
}
// match: (Load <t> (OffPtr [off] (ITab (IMake (Convert (Addr {s} sb) _) _))) _)
// cond: t.IsPtr() && isPtrElem(s, off)
// result: (Addr {ptrElem(s, off)} sb)
for {
t := v.Type
if v_0.Op != OpOffPtr {
break
}
off := auxIntToInt64(v_0.AuxInt)
v_0_0 := v_0.Args[0]
if v_0_0.Op != OpITab {
break
}
v_0_0_0 := v_0_0.Args[0]
if v_0_0_0.Op != OpIMake {
break
}
v_0_0_0_0 := v_0_0_0.Args[0]
if v_0_0_0_0.Op != OpConvert {
break
}
v_0_0_0_0_0 := v_0_0_0_0.Args[0]
if v_0_0_0_0_0.Op != OpAddr {
break
}
s := auxToSym(v_0_0_0_0_0.Aux)
sb := v_0_0_0_0_0.Args[0]
if !(t.IsPtr() && isPtrElem(s, off)) {
break
}
v.reset(OpAddr)
v.Aux = symToAux(ptrElem(s, off))
v.AddArg(sb)
return true
}
// match: (Load <t> (OffPtr [off] (Addr {sym} _) ) _)
// cond: t.IsInteger() && t.Size() == 4 && isFixed32(config, sym, off)
// result: (Const32 [fixed32(config, sym, off)])

View file

@ -0,0 +1,22 @@
// asmcheck
// Copyright 2025 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 codegen
import "reflect"
func f() reflect.Type {
// amd64:`LEAQ\stype:\*int\(SB\)`
// arm64:`MOVD\s\$type:\*int\(SB\)`
return reflect.TypeFor[*int]()
}
func g() reflect.Type {
// amd64:`LEAQ\stype:int\(SB\)`
// arm64:`MOVD\s\$type:int\(SB\)`
return reflect.TypeFor[int]()
}