Skip to content

Commit 635839a

Browse files
randall77gopherbot
authored andcommitted
cmd/compile: constant-fold loads from constant dictionaries and types
Update #59591 Change-Id: Id250a7779c5b53776fff73f3e678fec54d92a8e3 Reviewed-on: https://go-review.googlesource.com/c/go/+/486895 Reviewed-by: Cuong Manh Le <[email protected]> Reviewed-by: Dmitri Shuralyov <[email protected]> Run-TryBot: Keith Randall <[email protected]> Reviewed-by: Matthew Dempsky <[email protected]> Auto-Submit: Keith Randall <[email protected]> TryBot-Result: Gopher Robot <[email protected]>
1 parent 3a7806d commit 635839a

File tree

6 files changed

+453
-55
lines changed

6 files changed

+453
-55
lines changed

src/cmd/compile/internal/noder/reader.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3988,7 +3988,7 @@ func setBasePos(pos src.XPos) {
39883988
//
39893989
// N.B., this variable name is known to Delve:
39903990
// https://github.com/go-delve/delve/blob/cb91509630529e6055be845688fd21eb89ae8714/pkg/proc/eval.go#L28
3991-
const dictParamName = ".dict"
3991+
const dictParamName = typecheck.LocalDictName
39923992

39933993
// shapeSig returns a copy of fn's signature, except adding a
39943994
// dictionary parameter and promoting the receiver parameter (if any)

src/cmd/compile/internal/reflectdata/reflect.go

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -844,7 +844,14 @@ func TypeLinksymLookup(name string) *obj.LSym {
844844
}
845845

846846
func TypeLinksym(t *types.Type) *obj.LSym {
847-
return TypeSym(t).Linksym()
847+
lsym := TypeSym(t).Linksym()
848+
signatmu.Lock()
849+
if lsym.Extra == nil {
850+
ti := lsym.NewTypeInfo()
851+
ti.Type = t
852+
}
853+
signatmu.Unlock()
854+
return lsym
848855
}
849856

850857
// Deprecated: Use TypePtrAt instead.
@@ -1878,7 +1885,9 @@ func MarkTypeUsedInInterface(t *types.Type, from *obj.LSym) {
18781885
// Shape types shouldn't be put in interfaces, so we shouldn't ever get here.
18791886
base.Fatalf("shape types have no methods %+v", t)
18801887
}
1881-
tsym := TypeLinksym(t)
1888+
MarkTypeSymUsedInInterface(TypeLinksym(t), from)
1889+
}
1890+
func MarkTypeSymUsedInInterface(tsym *obj.LSym, from *obj.LSym) {
18821891
// Emit a marker relocation. The linker will know the type is converted
18831892
// to an interface if "from" is reachable.
18841893
r := obj.Addrel(from)

src/cmd/compile/internal/ssa/_gen/generic.rules

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2061,6 +2061,10 @@
20612061
&& warnRule(fe.Debug_checknil(), v, "removed nil check")
20622062
=> (Invalid)
20632063

2064+
// Addresses of globals are always non-nil.
2065+
(NilCheck (Addr {_} (SB)) _) => (Invalid)
2066+
(NilCheck (Convert (Addr {_} (SB)) _) _) => (Invalid)
2067+
20642068
// for late-expanded calls, recognize memequal applied to a single constant byte
20652069
// Support is limited by 1, 2, 4, 8 byte sizes
20662070
(StaticLECall {callAux} sptr (Addr {scon} (SB)) (Const64 [1]) mem)
@@ -2148,6 +2152,8 @@
21482152
(NeqPtr (OffPtr [o1] p1) (OffPtr [o2] p2)) && isSamePtr(p1, p2) => (ConstBool [o1 != o2])
21492153
(EqPtr (Const(32|64) [c]) (Const(32|64) [d])) => (ConstBool [c == d])
21502154
(NeqPtr (Const(32|64) [c]) (Const(32|64) [d])) => (ConstBool [c != d])
2155+
(EqPtr (Convert (Addr {x} _) _) (Addr {y} _)) => (ConstBool [x==y])
2156+
(NeqPtr (Convert (Addr {x} _) _) (Addr {y} _)) => (ConstBool [x!=y])
21512157

21522158
(EqPtr (LocalAddr _ _) (Addr _)) => (ConstBool [false])
21532159
(EqPtr (OffPtr (LocalAddr _ _)) (Addr _)) => (ConstBool [false])
@@ -2169,7 +2175,8 @@
21692175
// Evaluate constant user nil checks.
21702176
(IsNonNil (ConstNil)) => (ConstBool [false])
21712177
(IsNonNil (Const(32|64) [c])) => (ConstBool [c != 0])
2172-
(IsNonNil (Addr _)) => (ConstBool [true])
2178+
(IsNonNil (Addr _) ) => (ConstBool [true])
2179+
(IsNonNil (Convert (Addr _) _)) => (ConstBool [true])
21732180
(IsNonNil (LocalAddr _ _)) => (ConstBool [true])
21742181

21752182
// Inline small or disjoint runtime.memmove calls with constant length.
@@ -2212,11 +2219,7 @@
22122219
=> (Move {types.Types[types.TUINT8]} [int64(sz)] dst src mem)
22132220

22142221
// De-virtualize late-expanded interface calls into late-expanded static calls.
2215-
// Note that (ITab (IMake)) doesn't get rewritten until after the first opt pass,
2216-
// so this rule should trigger reliably.
2217-
// devirtLECall removes the first argument, adds the devirtualized symbol to the AuxCall, and changes the opcode
2218-
(InterLECall [argsize] {auxCall} (Load (OffPtr [off] (ITab (IMake (Addr {itab} (SB)) _))) _) ___) && devirtLESym(v, auxCall, itab, off) !=
2219-
nil => devirtLECall(v, devirtLESym(v, auxCall, itab, off))
2222+
(InterLECall [argsize] {auxCall} (Addr {fn} (SB)) ___) => devirtLECall(v, fn.(*obj.LSym))
22202223

22212224
// Move and Zero optimizations.
22222225
// Move source and destination may overlap.
@@ -2730,3 +2733,15 @@
27302733
(RotateLeft(64|32|16|8) (RotateLeft(64|32|16|8) x c) d) && c.Type.Size() == 4 && d.Type.Size() == 4 => (RotateLeft(64|32|16|8) x (Add32 <c.Type> c d))
27312734
(RotateLeft(64|32|16|8) (RotateLeft(64|32|16|8) x c) d) && c.Type.Size() == 2 && d.Type.Size() == 2 => (RotateLeft(64|32|16|8) x (Add16 <c.Type> c d))
27322735
(RotateLeft(64|32|16|8) (RotateLeft(64|32|16|8) x c) d) && c.Type.Size() == 1 && d.Type.Size() == 1 => (RotateLeft(64|32|16|8) x (Add8 <c.Type> c d))
2736+
2737+
// Loading constant values from dictionaries and itabs.
2738+
(Load <t> (OffPtr [off] (Addr {s} sb) ) _) && t.IsUintptr() && isFixedSym(s, off) => (Addr {fixedSym(b.Func, s, off)} sb)
2739+
(Load <t> (OffPtr [off] (Convert (Addr {s} sb) _) ) _) && t.IsUintptr() && isFixedSym(s, off) => (Addr {fixedSym(b.Func, s, off)} sb)
2740+
(Load <t> (OffPtr [off] (ITab (IMake (Addr {s} sb) _))) _) && t.IsUintptr() && isFixedSym(s, off) => (Addr {fixedSym(b.Func, s, off)} sb)
2741+
(Load <t> (OffPtr [off] (ITab (IMake (Convert (Addr {s} sb) _) _))) _) && t.IsUintptr() && isFixedSym(s, off) => (Addr {fixedSym(b.Func, s, off)} sb)
2742+
2743+
// Loading constant values from runtime._type.hash.
2744+
(Load <t> (OffPtr [off] (Addr {sym} _) ) _) && t.IsInteger() && t.Size() == 4 && isFixed32(config, sym, off) => (Const32 [fixed32(config, sym, off)])
2745+
(Load <t> (OffPtr [off] (Convert (Addr {sym} _) _) ) _) && t.IsInteger() && t.Size() == 4 && isFixed32(config, sym, off) => (Const32 [fixed32(config, sym, off)])
2746+
(Load <t> (OffPtr [off] (ITab (IMake (Addr {sym} _) _))) _) && t.IsInteger() && t.Size() == 4 && isFixed32(config, sym, off) => (Const32 [fixed32(config, sym, off)])
2747+
(Load <t> (OffPtr [off] (ITab (IMake (Convert (Addr {sym} _) _) _))) _) && t.IsInteger() && t.Size() == 4 && isFixed32(config, sym, off) => (Const32 [fixed32(config, sym, off)])

src/cmd/compile/internal/ssa/rewrite.go

Lines changed: 72 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ package ssa
77
import (
88
"cmd/compile/internal/base"
99
"cmd/compile/internal/logopt"
10+
"cmd/compile/internal/reflectdata"
1011
"cmd/compile/internal/types"
1112
"cmd/internal/obj"
1213
"cmd/internal/obj/s390x"
@@ -19,6 +20,7 @@ import (
1920
"math/bits"
2021
"os"
2122
"path/filepath"
23+
"strings"
2224
)
2325

2426
type deadValueChoice bool
@@ -799,25 +801,6 @@ func loadLSymOffset(lsym *obj.LSym, offset int64) *obj.LSym {
799801
return nil
800802
}
801803

802-
// de-virtualize an InterLECall
803-
// 'sym' is the symbol for the itab.
804-
func devirtLESym(v *Value, aux Aux, sym Sym, offset int64) *obj.LSym {
805-
n, ok := sym.(*obj.LSym)
806-
if !ok {
807-
return nil
808-
}
809-
810-
lsym := loadLSymOffset(n, offset)
811-
if f := v.Block.Func; f.pass.debug > 0 {
812-
if lsym != nil {
813-
f.Warnl(v.Pos, "de-virtualizing call")
814-
} else {
815-
f.Warnl(v.Pos, "couldn't de-virtualize call")
816-
}
817-
}
818-
return lsym
819-
}
820-
821804
func devirtLECall(v *Value, sym *obj.LSym) *Value {
822805
v.Op = OpStaticLECall
823806
auxcall := v.Aux.(*AuxCall)
@@ -827,6 +810,9 @@ func devirtLECall(v *Value, sym *obj.LSym) *Value {
827810
copy(v.Args[0:], v.Args[1:])
828811
v.Args[len(v.Args)-1] = nil // aid GC
829812
v.Args = v.Args[:len(v.Args)-1]
813+
if f := v.Block.Func; f.pass.debug > 0 {
814+
f.Warnl(v.Pos, "de-virtualizing call")
815+
}
830816
return v
831817
}
832818

@@ -1743,6 +1729,73 @@ func symIsROZero(sym Sym) bool {
17431729
return true
17441730
}
17451731

1732+
// isFixed32 returns true if the int32 at offset off in symbol sym
1733+
// is known and constant.
1734+
func isFixed32(c *Config, sym Sym, off int64) bool {
1735+
return isFixed(c, sym, off, 4)
1736+
}
1737+
1738+
// isFixed returns true if the range [off,off+size] of the symbol sym
1739+
// is known and constant.
1740+
func isFixed(c *Config, sym Sym, off, size int64) bool {
1741+
lsym := sym.(*obj.LSym)
1742+
if lsym.Extra == nil {
1743+
return false
1744+
}
1745+
if _, ok := (*lsym.Extra).(*obj.TypeInfo); ok {
1746+
if off == 2*c.PtrSize && size == 4 {
1747+
return true // type hash field
1748+
}
1749+
}
1750+
return false
1751+
}
1752+
func fixed32(c *Config, sym Sym, off int64) int32 {
1753+
lsym := sym.(*obj.LSym)
1754+
if ti, ok := (*lsym.Extra).(*obj.TypeInfo); ok {
1755+
if off == 2*c.PtrSize {
1756+
return int32(types.TypeHash(ti.Type.(*types.Type)))
1757+
}
1758+
}
1759+
base.Fatalf("fixed32 data not known for %s:%d", sym, off)
1760+
return 0
1761+
}
1762+
1763+
// isFixedSym returns true if the contents of sym at the given offset
1764+
// is known and is the constant address of another symbol.
1765+
func isFixedSym(sym Sym, off int64) bool {
1766+
lsym := sym.(*obj.LSym)
1767+
switch {
1768+
case lsym.Type == objabi.SRODATA:
1769+
// itabs, dictionaries
1770+
default:
1771+
return false
1772+
}
1773+
for _, r := range lsym.R {
1774+
if (r.Type == objabi.R_ADDR || r.Type == objabi.R_WEAKADDR) && int64(r.Off) == off && r.Add == 0 {
1775+
return true
1776+
}
1777+
}
1778+
return false
1779+
}
1780+
func fixedSym(f *Func, sym Sym, off int64) Sym {
1781+
lsym := sym.(*obj.LSym)
1782+
for _, r := range lsym.R {
1783+
if (r.Type == objabi.R_ADDR || r.Type == objabi.R_WEAKADDR) && int64(r.Off) == off {
1784+
if strings.HasPrefix(r.Sym.Name, "type:") {
1785+
// In case we're loading a type out of a dictionary, we need to record
1786+
// that the containing function might put that type in an interface.
1787+
// That information is currently recorded in relocations in the dictionary,
1788+
// but if we perform this load at compile time then the dictionary
1789+
// might be dead.
1790+
reflectdata.MarkTypeSymUsedInInterface(r.Sym, f.fe.Func().Linksym())
1791+
}
1792+
return r.Sym
1793+
}
1794+
}
1795+
base.Fatalf("fixedSym data not known for %s:%d", sym, off)
1796+
return nil
1797+
}
1798+
17461799
// read8 reads one byte from the read-only global sym at offset off.
17471800
func read8(sym interface{}, off int64) uint8 {
17481801
lsym := sym.(*obj.LSym)

0 commit comments

Comments
 (0)