From: Keith Randall Date: Tue, 12 Aug 2025 00:32:05 +0000 (-0700) Subject: Revert "cmd/compile: allow multi-field structs to be stored directly in interfaces" X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=74421a305b4d76259d9860529fe59e8fc9bad81e;p=gostls13.git Revert "cmd/compile: allow multi-field structs to be stored directly in interfaces" This reverts commit cd55f86b8dcfc139ee5c17d32530ac9e758c8bc0 (CL 681937) Reason for revert: still causing compiler failures on Google test code Change-Id: I5cd482fd607fd060a523257082d48821b5f965d6 Reviewed-on: https://go-review.googlesource.com/c/go/+/695016 Reviewed-by: Keith Randall Auto-Submit: Keith Randall LUCI-TryBot-Result: Go LUCI Reviewed-by: Dmitri Shuralyov --- diff --git a/src/cmd/compile/internal/ssa/_gen/generic.rules b/src/cmd/compile/internal/ssa/_gen/generic.rules index 8f354e977f..7ac36c3b3c 100644 --- a/src/cmd/compile/internal/ssa/_gen/generic.rules +++ b/src/cmd/compile/internal/ssa/_gen/generic.rules @@ -921,8 +921,8 @@ @x.Block (Load (OffPtr [t.FieldOff(int(i))] ptr) mem) // Putting struct{*byte} and similar into direct interfaces. -(IMake _typ (StructMake val)) => imakeOfStructMake(v) -(StructSelect [_] (IData x)) => (IData x) +(IMake _typ (StructMake val)) => (IMake _typ val) +(StructSelect [0] (IData x)) => (IData x) // un-SSAable values use mem->mem copies (Store {t} dst (Load src mem) mem) && !CanSSA(t) => diff --git a/src/cmd/compile/internal/ssa/expand_calls.go b/src/cmd/compile/internal/ssa/expand_calls.go index 1730dbf53d..f6bb863c00 100644 --- a/src/cmd/compile/internal/ssa/expand_calls.go +++ b/src/cmd/compile/internal/ssa/expand_calls.go @@ -423,14 +423,7 @@ func (x *expandState) decomposeAsNecessary(pos src.XPos, b *Block, a, m0 *Value, if a.Op == OpIMake { data := a.Args[1] for data.Op == OpStructMake || data.Op == OpArrayMake1 { - // A struct make might have a few zero-sized fields. - // Use the pointer-y one we know is there. - for _, a := range data.Args { - if a.Type.Size() > 0 { - data = a - break - } - } + data = data.Args[0] } return x.decomposeAsNecessary(pos, b, data, mem, rc.next(data.Type)) } diff --git a/src/cmd/compile/internal/ssa/rewrite.go b/src/cmd/compile/internal/ssa/rewrite.go index 03b1e39b74..2239927521 100644 --- a/src/cmd/compile/internal/ssa/rewrite.go +++ b/src/cmd/compile/internal/ssa/rewrite.go @@ -2621,17 +2621,3 @@ func panicBoundsCToAux(p PanicBoundsC) Aux { func panicBoundsCCToAux(p PanicBoundsCC) Aux { return p } - -// When v is (IMake typ (StructMake ...)), convert to -// (IMake typ arg) where arg is the pointer-y argument to -// the StructMake (there must be exactly one). -func imakeOfStructMake(v *Value) *Value { - var arg *Value - for _, a := range v.Args[1].Args { - if a.Type.Size() > 0 { - arg = a - break - } - } - return v.Block.NewValue2(v.Pos, OpIMake, v.Type, v.Args[0], arg) -} diff --git a/src/cmd/compile/internal/ssa/rewritegeneric.go b/src/cmd/compile/internal/ssa/rewritegeneric.go index 83be129a7b..3af7f40e68 100644 --- a/src/cmd/compile/internal/ssa/rewritegeneric.go +++ b/src/cmd/compile/internal/ssa/rewritegeneric.go @@ -11201,12 +11201,15 @@ func rewriteValuegeneric_OpIMake(v *Value) bool { v_1 := v.Args[1] v_0 := v.Args[0] // match: (IMake _typ (StructMake val)) - // result: imakeOfStructMake(v) + // result: (IMake _typ val) for { + _typ := v_0 if v_1.Op != OpStructMake || len(v_1.Args) != 1 { break } - v.copyOf(imakeOfStructMake(v)) + val := v_1.Args[0] + v.reset(OpIMake) + v.AddArg2(_typ, val) return true } // match: (IMake _typ (ArrayMake1 val)) @@ -32042,10 +32045,10 @@ func rewriteValuegeneric_OpStructSelect(v *Value) bool { v0.AddArg2(v1, mem) return true } - // match: (StructSelect [_] (IData x)) + // match: (StructSelect [0] (IData x)) // result: (IData x) for { - if v_0.Op != OpIData { + if auxIntToInt64(v.AuxInt) != 0 || v_0.Op != OpIData { break } x := v_0.Args[0] diff --git a/src/cmd/compile/internal/types/type.go b/src/cmd/compile/internal/types/type.go index f28490fc44..6a3e9b512e 100644 --- a/src/cmd/compile/internal/types/type.go +++ b/src/cmd/compile/internal/types/type.go @@ -1822,7 +1822,26 @@ func IsReflexive(t *Type) bool { // Can this type be stored directly in an interface word? // Yes, if the representation is a single pointer. func IsDirectIface(t *Type) bool { - return t.Size() == int64(PtrSize) && PtrDataSize(t) == int64(PtrSize) + switch t.Kind() { + case TPTR: + // Pointers to notinheap types must be stored indirectly. See issue 42076. + return !t.Elem().NotInHeap() + case TCHAN, + TMAP, + TFUNC, + TUNSAFEPTR: + return true + + case TARRAY: + // Array of 1 direct iface type can be direct. + return t.NumElem() == 1 && IsDirectIface(t.Elem()) + + case TSTRUCT: + // Struct with 1 field of direct iface type can be direct. + return t.NumFields() == 1 && IsDirectIface(t.Field(0).Type) + } + + return false } // IsInterfaceMethod reports whether (field) m is diff --git a/src/internal/abi/type.go b/src/internal/abi/type.go index 9f783a34c1..1920a8a37f 100644 --- a/src/internal/abi/type.go +++ b/src/internal/abi/type.go @@ -121,8 +121,8 @@ const ( TFlagGCMaskOnDemand TFlag = 1 << 4 // TFlagDirectIface means that a value of this type is stored directly - // in the data field of an interface, instead of indirectly. - // This flag is just a cached computation of Size_ == PtrBytes == goarch.PtrSize. + // in the data field of an interface, instead of indirectly. Normally + // this means the type is pointer-ish. TFlagDirectIface TFlag = 1 << 5 // Leaving this breadcrumb behind for dlv. It should not be used, and no diff --git a/src/reflect/type.go b/src/reflect/type.go index 19a28abfcf..cec8662c01 100644 --- a/src/reflect/type.go +++ b/src/reflect/type.go @@ -2524,7 +2524,8 @@ func StructOf(fields []StructField) Type { } switch { - case typ.Size_ == goarch.PtrSize && typ.PtrBytes == goarch.PtrSize: + case len(fs) == 1 && fs[0].Typ.IsDirectIface(): + // structs of 1 direct iface type can be direct typ.TFlag |= abi.TFlagDirectIface default: typ.TFlag &^= abi.TFlagDirectIface @@ -2693,7 +2694,8 @@ func ArrayOf(length int, elem Type) Type { } switch { - case array.Size_ == goarch.PtrSize && array.PtrBytes == goarch.PtrSize: + case length == 1 && typ.IsDirectIface(): + // array of 1 direct iface type can be direct array.TFlag |= abi.TFlagDirectIface default: array.TFlag &^= abi.TFlagDirectIface