From: Youlin Feng Date: Mon, 1 Sep 2025 10:31:29 +0000 (+0800) Subject: cmd/compile/internal/ssa: load constant values from abi.PtrType.Elem X-Git-Tag: go1.26rc1~969 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=df29038486;p=gostls13.git 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 Reviewed-by: Keith Randall Reviewed-by: Keith Randall Reviewed-by: Michael Pratt Auto-Submit: Keith Randall --- diff --git a/src/cmd/compile/internal/ssa/_gen/generic.rules b/src/cmd/compile/internal/ssa/_gen/generic.rules index da112abbf5..c5e2507a14 100644 --- a/src/cmd/compile/internal/ssa/_gen/generic.rules +++ b/src/cmd/compile/internal/ssa/_gen/generic.rules @@ -2767,6 +2767,22 @@ (Load (OffPtr [off] (ITab (IMake (Addr {s} sb) _))) _) && isFixedSym(s, off) => (Addr {fixedSym(b.Func, s, off)} sb) (Load (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 (Addr {s} sb) _) && isFixedSym(s, 0) => (Addr {fixedSym(b.Func, s, 0)} sb) +(Load (Convert (Addr {s} sb) _) _) && isFixedSym(s, 0) => (Addr {fixedSym(b.Func, s, 0)} sb) +(Load (ITab (IMake (Addr {s} sb) _)) _) && isFixedSym(s, 0) => (Addr {fixedSym(b.Func, s, 0)} sb) +(Load (ITab (IMake (Convert (Addr {s} sb) _) _)) _) && isFixedSym(s, 0) => (Addr {fixedSym(b.Func, s, 0)} sb) +(Load (Addr {s} sb) _) && isFixedSym(s, 0) => (Addr {fixedSym(b.Func, s, 0)} sb) +(Load (Convert (Addr {s} sb) _) _) && isFixedSym(s, 0) => (Addr {fixedSym(b.Func, s, 0)} sb) +(Load (ITab (IMake (Addr {s} sb) _)) _) && isFixedSym(s, 0) => (Addr {fixedSym(b.Func, s, 0)} sb) +(Load (ITab (IMake (Convert (Addr {s} sb) _) _)) _) && isFixedSym(s, 0) => (Addr {fixedSym(b.Func, s, 0)} sb) + +// Loading constant values from abi.PtrType.Elem. +(Load (OffPtr [off] (Addr {s} sb) ) _) && t.IsPtr() && isPtrElem(s, off) => (Addr {ptrElem(s, off)} sb) +(Load (OffPtr [off] (Convert (Addr {s} sb) _) ) _) && t.IsPtr() && isPtrElem(s, off) => (Addr {ptrElem(s, off)} sb) +(Load (OffPtr [off] (ITab (IMake (Addr {s} sb) _))) _) && t.IsPtr() && isPtrElem(s, off) => (Addr {ptrElem(s, off)} sb) +(Load (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 (OffPtr [off] (Addr {sym} _) ) _) && t.IsInteger() && t.Size() == 4 && isFixed32(config, sym, off) => (Const32 [fixed32(config, sym, off)]) (Load (OffPtr [off] (Convert (Addr {sym} _) _) ) _) && t.IsInteger() && t.Size() == 4 && isFixed32(config, sym, off) => (Const32 [fixed32(config, sym, off)]) diff --git a/src/cmd/compile/internal/ssa/rewrite.go b/src/cmd/compile/internal/ssa/rewrite.go index 6704c7d6e0..8f331c283a 100644 --- a/src/cmd/compile/internal/ssa/rewrite.go +++ b/src/cmd/compile/internal/ssa/rewrite.go @@ -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 { diff --git a/src/cmd/compile/internal/ssa/rewritegeneric.go b/src/cmd/compile/internal/ssa/rewritegeneric.go index 5394747ba5..a0a4960397 100644 --- a/src/cmd/compile/internal/ssa/rewritegeneric.go +++ b/src/cmd/compile/internal/ssa/rewritegeneric.go @@ -14897,6 +14897,306 @@ func rewriteValuegeneric_OpLoad(v *Value) bool { v.AddArg(sb) return true } + // match: (Load (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (OffPtr [off] (Addr {sym} _) ) _) // cond: t.IsInteger() && t.Size() == 4 && isFixed32(config, sym, off) // result: (Const32 [fixed32(config, sym, off)]) diff --git a/test/codegen/issue75203.go b/test/codegen/issue75203.go new file mode 100644 index 0000000000..68e1794120 --- /dev/null +++ b/test/codegen/issue75203.go @@ -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]() +} +