From: Cuong Manh Le Date: Thu, 5 Sep 2024 07:56:43 +0000 (+0700) Subject: cmd/compile: generalize struct load/store X-Git-Tag: go1.24rc1~830 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=6d856a804c5d9cfc72104b0e7578da5b38509909;p=gostls13.git cmd/compile: generalize struct load/store The SSA backend currently only handle struct with up to 4 fields. Thus, there are different operations corresponding to number fields of the struct. This CL generalizes these with just one OpStructMake, allow struct types with arbitrary number of fields. However, the ssa.MaxStruct is still kept as-is, and future CL will increase this value to optimize large structs. Updates #24416 Change-Id: I192ffbea881186693584476b5639394e79be45c5 Reviewed-on: https://go-review.googlesource.com/c/go/+/611075 Reviewed-by: Keith Randall LUCI-TryBot-Result: Go LUCI Reviewed-by: Keith Randall Auto-Submit: Cuong Manh Le Reviewed-by: David Chase --- diff --git a/src/cmd/compile/internal/ssa/_gen/dec.rules b/src/cmd/compile/internal/ssa/_gen/dec.rules index 7944947e06..5309a7f6b4 100644 --- a/src/cmd/compile/internal/ssa/_gen/dec.rules +++ b/src/cmd/compile/internal/ssa/_gen/dec.rules @@ -97,19 +97,10 @@ // Helpers for expand calls // Some of these are copied from generic.rules -(IMake _typ (StructMake1 val)) => (IMake _typ val) +(IMake _typ (StructMake val)) => (IMake _typ val) (StructSelect [0] (IData x)) => (IData x) -(StructSelect (StructMake1 x)) => x -(StructSelect [0] (StructMake2 x _)) => x -(StructSelect [1] (StructMake2 _ x)) => x -(StructSelect [0] (StructMake3 x _ _)) => x -(StructSelect [1] (StructMake3 _ x _)) => x -(StructSelect [2] (StructMake3 _ _ x)) => x -(StructSelect [0] (StructMake4 x _ _ _)) => x -(StructSelect [1] (StructMake4 _ x _ _)) => x -(StructSelect [2] (StructMake4 _ _ x _)) => x -(StructSelect [3] (StructMake4 _ _ _ x)) => x +(StructSelect [i] x:(StructMake ___)) => x.Args[i] // Special case coming from immediate interface rewriting // Typical case: (StructSelect [0] (IData (IMake typ dat)) rewrites to (StructSelect [0] dat) @@ -123,40 +114,10 @@ // These, too. Bits is bits. (ArrayMake1 x) && x.Type.IsPtrShaped() => x -(StructMake1 x) && x.Type.IsPtrShaped() => x - -(Store dst (StructMake1 f0) mem) => - (Store {t.FieldType(0)} (OffPtr [0] dst) f0 mem) -(Store dst (StructMake2 f0 f1) mem) => - (Store {t.FieldType(1)} - (OffPtr [t.FieldOff(1)] dst) - f1 - (Store {t.FieldType(0)} - (OffPtr [0] dst) - f0 mem)) -(Store dst (StructMake3 f0 f1 f2) mem) => - (Store {t.FieldType(2)} - (OffPtr [t.FieldOff(2)] dst) - f2 - (Store {t.FieldType(1)} - (OffPtr [t.FieldOff(1)] dst) - f1 - (Store {t.FieldType(0)} - (OffPtr [0] dst) - f0 mem))) -(Store dst (StructMake4 f0 f1 f2 f3) mem) => - (Store {t.FieldType(3)} - (OffPtr [t.FieldOff(3)] dst) - f3 - (Store {t.FieldType(2)} - (OffPtr [t.FieldOff(2)] dst) - f2 - (Store {t.FieldType(1)} - (OffPtr [t.FieldOff(1)] dst) - f1 - (Store {t.FieldType(0)} - (OffPtr [0] dst) - f0 mem)))) +(StructMake x) && x.Type.IsPtrShaped() => x + + +(Store _ (StructMake ___) _) => rewriteStructStore(v) (ArraySelect (ArrayMake1 x)) => x (ArraySelect [0] (IData x)) => (IData x) diff --git a/src/cmd/compile/internal/ssa/_gen/generic.rules b/src/cmd/compile/internal/ssa/_gen/generic.rules index 243c54e5a8..7228acd14e 100644 --- a/src/cmd/compile/internal/ssa/_gen/generic.rules +++ b/src/cmd/compile/internal/ssa/_gen/generic.rules @@ -885,77 +885,15 @@ (PtrIndex ptr idx) && config.PtrSize == 8 => (AddPtr ptr (Mul64 idx (Const64 [t.Elem().Size()]))) // struct operations -(StructSelect (StructMake1 x)) => x -(StructSelect [0] (StructMake2 x _)) => x -(StructSelect [1] (StructMake2 _ x)) => x -(StructSelect [0] (StructMake3 x _ _)) => x -(StructSelect [1] (StructMake3 _ x _)) => x -(StructSelect [2] (StructMake3 _ _ x)) => x -(StructSelect [0] (StructMake4 x _ _ _)) => x -(StructSelect [1] (StructMake4 _ x _ _)) => x -(StructSelect [2] (StructMake4 _ _ x _)) => x -(StructSelect [3] (StructMake4 _ _ _ x)) => x - -(Load _ _) && t.IsStruct() && t.NumFields() == 0 && CanSSA(t) => - (StructMake0) -(Load ptr mem) && t.IsStruct() && t.NumFields() == 1 && CanSSA(t) => - (StructMake1 - (Load (OffPtr [0] ptr) mem)) -(Load ptr mem) && t.IsStruct() && t.NumFields() == 2 && CanSSA(t) => - (StructMake2 - (Load (OffPtr [0] ptr) mem) - (Load (OffPtr [t.FieldOff(1)] ptr) mem)) -(Load ptr mem) && t.IsStruct() && t.NumFields() == 3 && CanSSA(t) => - (StructMake3 - (Load (OffPtr [0] ptr) mem) - (Load (OffPtr [t.FieldOff(1)] ptr) mem) - (Load (OffPtr [t.FieldOff(2)] ptr) mem)) -(Load ptr mem) && t.IsStruct() && t.NumFields() == 4 && CanSSA(t) => - (StructMake4 - (Load (OffPtr [0] ptr) mem) - (Load (OffPtr [t.FieldOff(1)] ptr) mem) - (Load (OffPtr [t.FieldOff(2)] ptr) mem) - (Load (OffPtr [t.FieldOff(3)] ptr) mem)) +(StructSelect [i] x:(StructMake ___)) => x.Args[i] +(Load _ _) && t.IsStruct() && CanSSA(t) => rewriteStructLoad(v) +(Store _ (StructMake ___) _) => rewriteStructStore(v) (StructSelect [i] x:(Load ptr mem)) && !CanSSA(t) => @x.Block (Load (OffPtr [t.FieldOff(int(i))] ptr) mem) -(Store _ (StructMake0) mem) => mem -(Store dst (StructMake1 f0) mem) => - (Store {t.FieldType(0)} (OffPtr [0] dst) f0 mem) -(Store dst (StructMake2 f0 f1) mem) => - (Store {t.FieldType(1)} - (OffPtr [t.FieldOff(1)] dst) - f1 - (Store {t.FieldType(0)} - (OffPtr [0] dst) - f0 mem)) -(Store dst (StructMake3 f0 f1 f2) mem) => - (Store {t.FieldType(2)} - (OffPtr [t.FieldOff(2)] dst) - f2 - (Store {t.FieldType(1)} - (OffPtr [t.FieldOff(1)] dst) - f1 - (Store {t.FieldType(0)} - (OffPtr [0] dst) - f0 mem))) -(Store dst (StructMake4 f0 f1 f2 f3) mem) => - (Store {t.FieldType(3)} - (OffPtr [t.FieldOff(3)] dst) - f3 - (Store {t.FieldType(2)} - (OffPtr [t.FieldOff(2)] dst) - f2 - (Store {t.FieldType(1)} - (OffPtr [t.FieldOff(1)] dst) - f1 - (Store {t.FieldType(0)} - (OffPtr [0] dst) - f0 mem)))) - // Putting struct{*byte} and similar into direct interfaces. -(IMake _typ (StructMake1 val)) => (IMake _typ val) +(IMake _typ (StructMake val)) => (IMake _typ val) (StructSelect [0] (IData x)) => (IData x) // un-SSAable values use mem->mem copies diff --git a/src/cmd/compile/internal/ssa/_gen/genericOps.go b/src/cmd/compile/internal/ssa/_gen/genericOps.go index cf472dd208..9baceb1920 100644 --- a/src/cmd/compile/internal/ssa/_gen/genericOps.go +++ b/src/cmd/compile/internal/ssa/_gen/genericOps.go @@ -521,11 +521,7 @@ var genericOps = []opData{ {name: "IData", argLength: 1}, // arg0=interface, returns data field // Structs - {name: "StructMake0"}, // Returns struct with 0 fields. - {name: "StructMake1", argLength: 1}, // arg0=field0. Returns struct. - {name: "StructMake2", argLength: 2}, // arg0,arg1=field0,field1. Returns struct. - {name: "StructMake3", argLength: 3}, // arg0..2=field0..2. Returns struct. - {name: "StructMake4", argLength: 4}, // arg0..3=field0..3. Returns struct. + {name: "StructMake", argLength: -1}, // args...=field0..n-1. Returns struct with n fields. {name: "StructSelect", argLength: 1, aux: "Int64"}, // arg0=struct, auxint=field index. Returns the auxint'th field. // Arrays diff --git a/src/cmd/compile/internal/ssa/copyelim.go b/src/cmd/compile/internal/ssa/copyelim.go index ea888f46f9..09df63565b 100644 --- a/src/cmd/compile/internal/ssa/copyelim.go +++ b/src/cmd/compile/internal/ssa/copyelim.go @@ -106,7 +106,7 @@ func phielim(f *Func) { // Rewrite all 0-sized Go values to remove accessors, dereferences, loads, etc. if t := v.Type; (t.IsStruct() || t.IsArray()) && t.Size() == 0 { if t.IsStruct() { - v.reset(OpStructMake0) + v.reset(OpStructMake) } else { v.reset(OpArrayMake0) } diff --git a/src/cmd/compile/internal/ssa/decompose.go b/src/cmd/compile/internal/ssa/decompose.go index 250b2321af..cf9285741e 100644 --- a/src/cmd/compile/internal/ssa/decompose.go +++ b/src/cmd/compile/internal/ssa/decompose.go @@ -318,11 +318,10 @@ func decomposeUserStructInto(f *Func, name *LocalSlot, slots []*LocalSlot) []*Lo } } - makeOp := StructMakeOp(n) var keep []*Value // create named values for each struct field for _, v := range f.NamedValues[*name] { - if v.Op != makeOp { + if v.Op != OpStructMake || len(v.Args) != n { keep = append(keep, v) continue } @@ -373,7 +372,7 @@ func decomposeStructPhi(v *Value) { fields[i].AddArg(a.Block.NewValue1I(v.Pos, OpStructSelect, t.FieldType(i), int64(i), a)) } } - v.reset(StructMakeOp(n)) + v.reset(OpStructMake) v.AddArgs(fields[:n]...) // Recursively decompose phis for each field. @@ -408,24 +407,6 @@ func decomposeArrayPhi(v *Value) { // can have and still be SSAable. const MaxStruct = 4 -// StructMakeOp returns the opcode to construct a struct with the -// given number of fields. -func StructMakeOp(nf int) Op { - switch nf { - case 0: - return OpStructMake0 - case 1: - return OpStructMake1 - case 2: - return OpStructMake2 - case 3: - return OpStructMake3 - case 4: - return OpStructMake4 - } - panic("too many fields in an SSAable struct") -} - type namedVal struct { locIndex, valIndex int // f.NamedValues[f.Names[locIndex]][valIndex] = key } diff --git a/src/cmd/compile/internal/ssa/expand_calls.go b/src/cmd/compile/internal/ssa/expand_calls.go index b0788f1db4..f589db4199 100644 --- a/src/cmd/compile/internal/ssa/expand_calls.go +++ b/src/cmd/compile/internal/ssa/expand_calls.go @@ -425,7 +425,7 @@ func (x *expandState) decomposeAsNecessary(pos src.XPos, b *Block, a, m0 *Value, // Immediate interfaces cause so many headaches. if a.Op == OpIMake { data := a.Args[1] - for data.Op == OpStructMake1 || data.Op == OpArrayMake1 { + for data.Op == OpStructMake || data.Op == OpArrayMake1 { data = data.Args[0] } return x.decomposeAsNecessary(pos, b, data, mem, rc.next(data.Type)) @@ -505,7 +505,7 @@ func (x *expandState) rewriteSelectOrArg(pos src.XPos, b *Block, container, a, m return makeOf(a, OpArrayMake0, nil) } if at.IsStruct() { - return makeOf(a, OpStructMake0, nil) + return makeOf(a, OpStructMake, nil) } return a } @@ -559,7 +559,7 @@ func (x *expandState) rewriteSelectOrArg(pos src.XPos, b *Block, container, a, m if at.NumFields() > 4 { panic(fmt.Errorf("Too many fields (%d, %d bytes), container=%s", at.NumFields(), at.Size(), container.LongString())) } - a = makeOf(a, StructMakeOp(at.NumFields()), args) + a = makeOf(a, OpStructMake, args) x.commonSelectors[sk] = a return a diff --git a/src/cmd/compile/internal/ssa/numberlines.go b/src/cmd/compile/internal/ssa/numberlines.go index b4eca324d5..bd7794042a 100644 --- a/src/cmd/compile/internal/ssa/numberlines.go +++ b/src/cmd/compile/internal/ssa/numberlines.go @@ -15,7 +15,7 @@ func isPoorStatementOp(op Op) bool { // Note that Nilcheck often vanishes, but when it doesn't, you'd love to start the statement there // so that a debugger-user sees the stop before the panic, and can examine the value. case OpAddr, OpLocalAddr, OpOffPtr, OpStructSelect, OpPhi, OpITab, OpIData, - OpIMake, OpStringMake, OpSliceMake, OpStructMake0, OpStructMake1, OpStructMake2, OpStructMake3, OpStructMake4, + OpIMake, OpStringMake, OpSliceMake, OpStructMake, OpConstBool, OpConst8, OpConst16, OpConst32, OpConst64, OpConst32F, OpConst64F, OpSB, OpSP, OpArgIntReg, OpArgFloatReg: return true diff --git a/src/cmd/compile/internal/ssa/opGen.go b/src/cmd/compile/internal/ssa/opGen.go index 9e6f8b9a97..574bbbdc61 100644 --- a/src/cmd/compile/internal/ssa/opGen.go +++ b/src/cmd/compile/internal/ssa/opGen.go @@ -3197,11 +3197,7 @@ const ( OpIMake OpITab OpIData - OpStructMake0 - OpStructMake1 - OpStructMake2 - OpStructMake3 - OpStructMake4 + OpStructMake OpStructSelect OpArrayMake0 OpArrayMake1 @@ -40862,28 +40858,8 @@ var opcodeTable = [...]opInfo{ generic: true, }, { - name: "StructMake0", - argLen: 0, - generic: true, - }, - { - name: "StructMake1", - argLen: 1, - generic: true, - }, - { - name: "StructMake2", - argLen: 2, - generic: true, - }, - { - name: "StructMake3", - argLen: 3, - generic: true, - }, - { - name: "StructMake4", - argLen: 4, + name: "StructMake", + argLen: -1, generic: true, }, { diff --git a/src/cmd/compile/internal/ssa/rewrite.go b/src/cmd/compile/internal/ssa/rewrite.go index 045e571652..71b8f09daf 100644 --- a/src/cmd/compile/internal/ssa/rewrite.go +++ b/src/cmd/compile/internal/ssa/rewrite.go @@ -2356,3 +2356,41 @@ func isNonNegative(v *Value) bool { } return false } + +func rewriteStructLoad(v *Value) *Value { + b := v.Block + ptr := v.Args[0] + mem := v.Args[1] + + t := v.Type + args := make([]*Value, t.NumFields()) + for i := range args { + ft := t.FieldType(i) + addr := b.NewValue1I(v.Pos, OpOffPtr, ft.PtrTo(), t.FieldOff(i), ptr) + args[i] = b.NewValue2(v.Pos, OpLoad, ft, addr, mem) + } + + v.reset(OpStructMake) + v.AddArgs(args...) + return v +} + +func rewriteStructStore(v *Value) *Value { + b := v.Block + dst := v.Args[0] + x := v.Args[1] + if x.Op != OpStructMake { + base.Fatalf("invalid struct store: %v", x) + } + mem := v.Args[2] + + t := x.Type + for i, arg := range x.Args { + ft := t.FieldType(i) + + addr := b.NewValue1I(v.Pos, OpOffPtr, ft.PtrTo(), t.FieldOff(i), dst) + mem = b.NewValue3A(v.Pos, OpStore, types.TypeMem, typeToAux(ft), addr, arg, mem) + } + + return mem +} diff --git a/src/cmd/compile/internal/ssa/rewritedec.go b/src/cmd/compile/internal/ssa/rewritedec.go index 3c481adc15..16d0269210 100644 --- a/src/cmd/compile/internal/ssa/rewritedec.go +++ b/src/cmd/compile/internal/ssa/rewritedec.go @@ -36,8 +36,8 @@ func rewriteValuedec(v *Value) bool { return rewriteValuedec_OpStringLen(v) case OpStringPtr: return rewriteValuedec_OpStringPtr(v) - case OpStructMake1: - return rewriteValuedec_OpStructMake1(v) + case OpStructMake: + return rewriteValuedec_OpStructMake(v) case OpStructSelect: return rewriteValuedec_OpStructSelect(v) } @@ -279,11 +279,11 @@ func rewriteValuedec_OpIData(v *Value) bool { func rewriteValuedec_OpIMake(v *Value) bool { v_1 := v.Args[1] v_0 := v.Args[0] - // match: (IMake _typ (StructMake1 val)) + // match: (IMake _typ (StructMake val)) // result: (IMake _typ val) for { _typ := v_0 - if v_1.Op != OpStructMake1 { + if v_1.Op != OpStructMake || len(v_1.Args) != 1 { break } val := v_1.Args[0] @@ -718,118 +718,13 @@ func rewriteValuedec_OpStore(v *Value) bool { v.AddArg3(v0, data, v1) return true } - // match: (Store dst (StructMake1 f0) mem) - // result: (Store {t.FieldType(0)} (OffPtr [0] dst) f0 mem) + // match: (Store _ (StructMake ___) _) + // result: rewriteStructStore(v) for { - dst := v_0 - if v_1.Op != OpStructMake1 { + if v_1.Op != OpStructMake { break } - t := v_1.Type - f0 := v_1.Args[0] - mem := v_2 - v.reset(OpStore) - v.Aux = typeToAux(t.FieldType(0)) - v0 := b.NewValue0(v.Pos, OpOffPtr, t.FieldType(0).PtrTo()) - v0.AuxInt = int64ToAuxInt(0) - v0.AddArg(dst) - v.AddArg3(v0, f0, mem) - return true - } - // match: (Store dst (StructMake2 f0 f1) mem) - // result: (Store {t.FieldType(1)} (OffPtr [t.FieldOff(1)] dst) f1 (Store {t.FieldType(0)} (OffPtr [0] dst) f0 mem)) - for { - dst := v_0 - if v_1.Op != OpStructMake2 { - break - } - t := v_1.Type - f1 := v_1.Args[1] - f0 := v_1.Args[0] - mem := v_2 - v.reset(OpStore) - v.Aux = typeToAux(t.FieldType(1)) - v0 := b.NewValue0(v.Pos, OpOffPtr, t.FieldType(1).PtrTo()) - v0.AuxInt = int64ToAuxInt(t.FieldOff(1)) - v0.AddArg(dst) - v1 := b.NewValue0(v.Pos, OpStore, types.TypeMem) - v1.Aux = typeToAux(t.FieldType(0)) - v2 := b.NewValue0(v.Pos, OpOffPtr, t.FieldType(0).PtrTo()) - v2.AuxInt = int64ToAuxInt(0) - v2.AddArg(dst) - v1.AddArg3(v2, f0, mem) - v.AddArg3(v0, f1, v1) - return true - } - // match: (Store dst (StructMake3 f0 f1 f2) mem) - // result: (Store {t.FieldType(2)} (OffPtr [t.FieldOff(2)] dst) f2 (Store {t.FieldType(1)} (OffPtr [t.FieldOff(1)] dst) f1 (Store {t.FieldType(0)} (OffPtr [0] dst) f0 mem))) - for { - dst := v_0 - if v_1.Op != OpStructMake3 { - break - } - t := v_1.Type - f2 := v_1.Args[2] - f0 := v_1.Args[0] - f1 := v_1.Args[1] - mem := v_2 - v.reset(OpStore) - v.Aux = typeToAux(t.FieldType(2)) - v0 := b.NewValue0(v.Pos, OpOffPtr, t.FieldType(2).PtrTo()) - v0.AuxInt = int64ToAuxInt(t.FieldOff(2)) - v0.AddArg(dst) - v1 := b.NewValue0(v.Pos, OpStore, types.TypeMem) - v1.Aux = typeToAux(t.FieldType(1)) - v2 := b.NewValue0(v.Pos, OpOffPtr, t.FieldType(1).PtrTo()) - v2.AuxInt = int64ToAuxInt(t.FieldOff(1)) - v2.AddArg(dst) - v3 := b.NewValue0(v.Pos, OpStore, types.TypeMem) - v3.Aux = typeToAux(t.FieldType(0)) - v4 := b.NewValue0(v.Pos, OpOffPtr, t.FieldType(0).PtrTo()) - v4.AuxInt = int64ToAuxInt(0) - v4.AddArg(dst) - v3.AddArg3(v4, f0, mem) - v1.AddArg3(v2, f1, v3) - v.AddArg3(v0, f2, v1) - return true - } - // match: (Store dst (StructMake4 f0 f1 f2 f3) mem) - // result: (Store {t.FieldType(3)} (OffPtr [t.FieldOff(3)] dst) f3 (Store {t.FieldType(2)} (OffPtr [t.FieldOff(2)] dst) f2 (Store {t.FieldType(1)} (OffPtr [t.FieldOff(1)] dst) f1 (Store {t.FieldType(0)} (OffPtr [0] dst) f0 mem)))) - for { - dst := v_0 - if v_1.Op != OpStructMake4 { - break - } - t := v_1.Type - f3 := v_1.Args[3] - f0 := v_1.Args[0] - f1 := v_1.Args[1] - f2 := v_1.Args[2] - mem := v_2 - v.reset(OpStore) - v.Aux = typeToAux(t.FieldType(3)) - v0 := b.NewValue0(v.Pos, OpOffPtr, t.FieldType(3).PtrTo()) - v0.AuxInt = int64ToAuxInt(t.FieldOff(3)) - v0.AddArg(dst) - v1 := b.NewValue0(v.Pos, OpStore, types.TypeMem) - v1.Aux = typeToAux(t.FieldType(2)) - v2 := b.NewValue0(v.Pos, OpOffPtr, t.FieldType(2).PtrTo()) - v2.AuxInt = int64ToAuxInt(t.FieldOff(2)) - v2.AddArg(dst) - v3 := b.NewValue0(v.Pos, OpStore, types.TypeMem) - v3.Aux = typeToAux(t.FieldType(1)) - v4 := b.NewValue0(v.Pos, OpOffPtr, t.FieldType(1).PtrTo()) - v4.AuxInt = int64ToAuxInt(t.FieldOff(1)) - v4.AddArg(dst) - v5 := b.NewValue0(v.Pos, OpStore, types.TypeMem) - v5.Aux = typeToAux(t.FieldType(0)) - v6 := b.NewValue0(v.Pos, OpOffPtr, t.FieldType(0).PtrTo()) - v6.AuxInt = int64ToAuxInt(0) - v6.AddArg(dst) - v5.AddArg3(v6, f0, mem) - v3.AddArg3(v4, f1, v5) - v1.AddArg3(v2, f2, v3) - v.AddArg3(v0, f3, v1) + v.copyOf(rewriteStructStore(v)) return true } // match: (Store dst (ArrayMake1 e) mem) @@ -924,13 +819,15 @@ func rewriteValuedec_OpStringPtr(v *Value) bool { } return false } -func rewriteValuedec_OpStructMake1(v *Value) bool { - v_0 := v.Args[0] - // match: (StructMake1 x) +func rewriteValuedec_OpStructMake(v *Value) bool { + // match: (StructMake x) // cond: x.Type.IsPtrShaped() // result: x for { - x := v_0 + if len(v.Args) != 1 { + break + } + x := v.Args[0] if !(x.Type.IsPtrShaped()) { break } @@ -953,104 +850,15 @@ func rewriteValuedec_OpStructSelect(v *Value) bool { v.AddArg(x) return true } - // match: (StructSelect (StructMake1 x)) - // result: x - for { - if v_0.Op != OpStructMake1 { - break - } - x := v_0.Args[0] - v.copyOf(x) - return true - } - // match: (StructSelect [0] (StructMake2 x _)) - // result: x - for { - if auxIntToInt64(v.AuxInt) != 0 || v_0.Op != OpStructMake2 { - break - } - x := v_0.Args[0] - v.copyOf(x) - return true - } - // match: (StructSelect [1] (StructMake2 _ x)) - // result: x + // match: (StructSelect [i] x:(StructMake ___)) + // result: x.Args[i] for { - if auxIntToInt64(v.AuxInt) != 1 || v_0.Op != OpStructMake2 { - break - } - x := v_0.Args[1] - v.copyOf(x) - return true - } - // match: (StructSelect [0] (StructMake3 x _ _)) - // result: x - for { - if auxIntToInt64(v.AuxInt) != 0 || v_0.Op != OpStructMake3 { - break - } - x := v_0.Args[0] - v.copyOf(x) - return true - } - // match: (StructSelect [1] (StructMake3 _ x _)) - // result: x - for { - if auxIntToInt64(v.AuxInt) != 1 || v_0.Op != OpStructMake3 { - break - } - x := v_0.Args[1] - v.copyOf(x) - return true - } - // match: (StructSelect [2] (StructMake3 _ _ x)) - // result: x - for { - if auxIntToInt64(v.AuxInt) != 2 || v_0.Op != OpStructMake3 { - break - } - x := v_0.Args[2] - v.copyOf(x) - return true - } - // match: (StructSelect [0] (StructMake4 x _ _ _)) - // result: x - for { - if auxIntToInt64(v.AuxInt) != 0 || v_0.Op != OpStructMake4 { - break - } - x := v_0.Args[0] - v.copyOf(x) - return true - } - // match: (StructSelect [1] (StructMake4 _ x _ _)) - // result: x - for { - if auxIntToInt64(v.AuxInt) != 1 || v_0.Op != OpStructMake4 { - break - } - x := v_0.Args[1] - v.copyOf(x) - return true - } - // match: (StructSelect [2] (StructMake4 _ _ x _)) - // result: x - for { - if auxIntToInt64(v.AuxInt) != 2 || v_0.Op != OpStructMake4 { - break - } - x := v_0.Args[2] - v.copyOf(x) - return true - } - // match: (StructSelect [3] (StructMake4 _ _ _ x)) - // result: x - for { - if auxIntToInt64(v.AuxInt) != 3 || v_0.Op != OpStructMake4 { + i := auxIntToInt64(v.AuxInt) + x := v_0 + if x.Op != OpStructMake { break } - x := v_0.Args[3] - v.copyOf(x) + v.copyOf(x.Args[i]) return true } // match: (StructSelect [0] x) diff --git a/src/cmd/compile/internal/ssa/rewritegeneric.go b/src/cmd/compile/internal/ssa/rewritegeneric.go index 760c55fca8..f0685c205e 100644 --- a/src/cmd/compile/internal/ssa/rewritegeneric.go +++ b/src/cmd/compile/internal/ssa/rewritegeneric.go @@ -10556,11 +10556,11 @@ func rewriteValuegeneric_OpFloor(v *Value) bool { func rewriteValuegeneric_OpIMake(v *Value) bool { v_1 := v.Args[1] v_0 := v.Args[0] - // match: (IMake _typ (StructMake1 val)) + // match: (IMake _typ (StructMake val)) // result: (IMake _typ val) for { _typ := v_0 - if v_1.Op != OpStructMake1 { + if v_1.Op != OpStructMake || len(v_1.Args) != 1 { break } val := v_1.Args[0] @@ -13991,120 +13991,14 @@ func rewriteValuegeneric_OpLoad(v *Value) bool { return true } // match: (Load _ _) - // cond: t.IsStruct() && t.NumFields() == 0 && CanSSA(t) - // result: (StructMake0) + // cond: t.IsStruct() && CanSSA(t) + // result: rewriteStructLoad(v) for { t := v.Type - if !(t.IsStruct() && t.NumFields() == 0 && CanSSA(t)) { + if !(t.IsStruct() && CanSSA(t)) { break } - v.reset(OpStructMake0) - return true - } - // match: (Load ptr mem) - // cond: t.IsStruct() && t.NumFields() == 1 && CanSSA(t) - // result: (StructMake1 (Load (OffPtr [0] ptr) mem)) - for { - t := v.Type - ptr := v_0 - mem := v_1 - if !(t.IsStruct() && t.NumFields() == 1 && CanSSA(t)) { - break - } - v.reset(OpStructMake1) - v0 := b.NewValue0(v.Pos, OpLoad, t.FieldType(0)) - v1 := b.NewValue0(v.Pos, OpOffPtr, t.FieldType(0).PtrTo()) - v1.AuxInt = int64ToAuxInt(0) - v1.AddArg(ptr) - v0.AddArg2(v1, mem) - v.AddArg(v0) - return true - } - // match: (Load ptr mem) - // cond: t.IsStruct() && t.NumFields() == 2 && CanSSA(t) - // result: (StructMake2 (Load (OffPtr [0] ptr) mem) (Load (OffPtr [t.FieldOff(1)] ptr) mem)) - for { - t := v.Type - ptr := v_0 - mem := v_1 - if !(t.IsStruct() && t.NumFields() == 2 && CanSSA(t)) { - break - } - v.reset(OpStructMake2) - v0 := b.NewValue0(v.Pos, OpLoad, t.FieldType(0)) - v1 := b.NewValue0(v.Pos, OpOffPtr, t.FieldType(0).PtrTo()) - v1.AuxInt = int64ToAuxInt(0) - v1.AddArg(ptr) - v0.AddArg2(v1, mem) - v2 := b.NewValue0(v.Pos, OpLoad, t.FieldType(1)) - v3 := b.NewValue0(v.Pos, OpOffPtr, t.FieldType(1).PtrTo()) - v3.AuxInt = int64ToAuxInt(t.FieldOff(1)) - v3.AddArg(ptr) - v2.AddArg2(v3, mem) - v.AddArg2(v0, v2) - return true - } - // match: (Load ptr mem) - // cond: t.IsStruct() && t.NumFields() == 3 && CanSSA(t) - // result: (StructMake3 (Load (OffPtr [0] ptr) mem) (Load (OffPtr [t.FieldOff(1)] ptr) mem) (Load (OffPtr [t.FieldOff(2)] ptr) mem)) - for { - t := v.Type - ptr := v_0 - mem := v_1 - if !(t.IsStruct() && t.NumFields() == 3 && CanSSA(t)) { - break - } - v.reset(OpStructMake3) - v0 := b.NewValue0(v.Pos, OpLoad, t.FieldType(0)) - v1 := b.NewValue0(v.Pos, OpOffPtr, t.FieldType(0).PtrTo()) - v1.AuxInt = int64ToAuxInt(0) - v1.AddArg(ptr) - v0.AddArg2(v1, mem) - v2 := b.NewValue0(v.Pos, OpLoad, t.FieldType(1)) - v3 := b.NewValue0(v.Pos, OpOffPtr, t.FieldType(1).PtrTo()) - v3.AuxInt = int64ToAuxInt(t.FieldOff(1)) - v3.AddArg(ptr) - v2.AddArg2(v3, mem) - v4 := b.NewValue0(v.Pos, OpLoad, t.FieldType(2)) - v5 := b.NewValue0(v.Pos, OpOffPtr, t.FieldType(2).PtrTo()) - v5.AuxInt = int64ToAuxInt(t.FieldOff(2)) - v5.AddArg(ptr) - v4.AddArg2(v5, mem) - v.AddArg3(v0, v2, v4) - return true - } - // match: (Load ptr mem) - // cond: t.IsStruct() && t.NumFields() == 4 && CanSSA(t) - // result: (StructMake4 (Load (OffPtr [0] ptr) mem) (Load (OffPtr [t.FieldOff(1)] ptr) mem) (Load (OffPtr [t.FieldOff(2)] ptr) mem) (Load (OffPtr [t.FieldOff(3)] ptr) mem)) - for { - t := v.Type - ptr := v_0 - mem := v_1 - if !(t.IsStruct() && t.NumFields() == 4 && CanSSA(t)) { - break - } - v.reset(OpStructMake4) - v0 := b.NewValue0(v.Pos, OpLoad, t.FieldType(0)) - v1 := b.NewValue0(v.Pos, OpOffPtr, t.FieldType(0).PtrTo()) - v1.AuxInt = int64ToAuxInt(0) - v1.AddArg(ptr) - v0.AddArg2(v1, mem) - v2 := b.NewValue0(v.Pos, OpLoad, t.FieldType(1)) - v3 := b.NewValue0(v.Pos, OpOffPtr, t.FieldType(1).PtrTo()) - v3.AuxInt = int64ToAuxInt(t.FieldOff(1)) - v3.AddArg(ptr) - v2.AddArg2(v3, mem) - v4 := b.NewValue0(v.Pos, OpLoad, t.FieldType(2)) - v5 := b.NewValue0(v.Pos, OpOffPtr, t.FieldType(2).PtrTo()) - v5.AuxInt = int64ToAuxInt(t.FieldOff(2)) - v5.AddArg(ptr) - v4.AddArg2(v5, mem) - v6 := b.NewValue0(v.Pos, OpLoad, t.FieldType(3)) - v7 := b.NewValue0(v.Pos, OpOffPtr, t.FieldType(3).PtrTo()) - v7.AuxInt = int64ToAuxInt(t.FieldOff(3)) - v7.AddArg(ptr) - v6.AddArg2(v7, mem) - v.AddArg4(v0, v2, v4, v6) + v.copyOf(rewriteStructLoad(v)) return true } // match: (Load _ _) @@ -29772,128 +29666,13 @@ func rewriteValuegeneric_OpStore(v *Value) bool { v.copyOf(mem) return true } - // match: (Store _ (StructMake0) mem) - // result: mem - for { - if v_1.Op != OpStructMake0 { - break - } - mem := v_2 - v.copyOf(mem) - return true - } - // match: (Store dst (StructMake1 f0) mem) - // result: (Store {t.FieldType(0)} (OffPtr [0] dst) f0 mem) - for { - dst := v_0 - if v_1.Op != OpStructMake1 { - break - } - t := v_1.Type - f0 := v_1.Args[0] - mem := v_2 - v.reset(OpStore) - v.Aux = typeToAux(t.FieldType(0)) - v0 := b.NewValue0(v.Pos, OpOffPtr, t.FieldType(0).PtrTo()) - v0.AuxInt = int64ToAuxInt(0) - v0.AddArg(dst) - v.AddArg3(v0, f0, mem) - return true - } - // match: (Store dst (StructMake2 f0 f1) mem) - // result: (Store {t.FieldType(1)} (OffPtr [t.FieldOff(1)] dst) f1 (Store {t.FieldType(0)} (OffPtr [0] dst) f0 mem)) - for { - dst := v_0 - if v_1.Op != OpStructMake2 { - break - } - t := v_1.Type - f1 := v_1.Args[1] - f0 := v_1.Args[0] - mem := v_2 - v.reset(OpStore) - v.Aux = typeToAux(t.FieldType(1)) - v0 := b.NewValue0(v.Pos, OpOffPtr, t.FieldType(1).PtrTo()) - v0.AuxInt = int64ToAuxInt(t.FieldOff(1)) - v0.AddArg(dst) - v1 := b.NewValue0(v.Pos, OpStore, types.TypeMem) - v1.Aux = typeToAux(t.FieldType(0)) - v2 := b.NewValue0(v.Pos, OpOffPtr, t.FieldType(0).PtrTo()) - v2.AuxInt = int64ToAuxInt(0) - v2.AddArg(dst) - v1.AddArg3(v2, f0, mem) - v.AddArg3(v0, f1, v1) - return true - } - // match: (Store dst (StructMake3 f0 f1 f2) mem) - // result: (Store {t.FieldType(2)} (OffPtr [t.FieldOff(2)] dst) f2 (Store {t.FieldType(1)} (OffPtr [t.FieldOff(1)] dst) f1 (Store {t.FieldType(0)} (OffPtr [0] dst) f0 mem))) - for { - dst := v_0 - if v_1.Op != OpStructMake3 { - break - } - t := v_1.Type - f2 := v_1.Args[2] - f0 := v_1.Args[0] - f1 := v_1.Args[1] - mem := v_2 - v.reset(OpStore) - v.Aux = typeToAux(t.FieldType(2)) - v0 := b.NewValue0(v.Pos, OpOffPtr, t.FieldType(2).PtrTo()) - v0.AuxInt = int64ToAuxInt(t.FieldOff(2)) - v0.AddArg(dst) - v1 := b.NewValue0(v.Pos, OpStore, types.TypeMem) - v1.Aux = typeToAux(t.FieldType(1)) - v2 := b.NewValue0(v.Pos, OpOffPtr, t.FieldType(1).PtrTo()) - v2.AuxInt = int64ToAuxInt(t.FieldOff(1)) - v2.AddArg(dst) - v3 := b.NewValue0(v.Pos, OpStore, types.TypeMem) - v3.Aux = typeToAux(t.FieldType(0)) - v4 := b.NewValue0(v.Pos, OpOffPtr, t.FieldType(0).PtrTo()) - v4.AuxInt = int64ToAuxInt(0) - v4.AddArg(dst) - v3.AddArg3(v4, f0, mem) - v1.AddArg3(v2, f1, v3) - v.AddArg3(v0, f2, v1) - return true - } - // match: (Store dst (StructMake4 f0 f1 f2 f3) mem) - // result: (Store {t.FieldType(3)} (OffPtr [t.FieldOff(3)] dst) f3 (Store {t.FieldType(2)} (OffPtr [t.FieldOff(2)] dst) f2 (Store {t.FieldType(1)} (OffPtr [t.FieldOff(1)] dst) f1 (Store {t.FieldType(0)} (OffPtr [0] dst) f0 mem)))) + // match: (Store _ (StructMake ___) _) + // result: rewriteStructStore(v) for { - dst := v_0 - if v_1.Op != OpStructMake4 { + if v_1.Op != OpStructMake { break } - t := v_1.Type - f3 := v_1.Args[3] - f0 := v_1.Args[0] - f1 := v_1.Args[1] - f2 := v_1.Args[2] - mem := v_2 - v.reset(OpStore) - v.Aux = typeToAux(t.FieldType(3)) - v0 := b.NewValue0(v.Pos, OpOffPtr, t.FieldType(3).PtrTo()) - v0.AuxInt = int64ToAuxInt(t.FieldOff(3)) - v0.AddArg(dst) - v1 := b.NewValue0(v.Pos, OpStore, types.TypeMem) - v1.Aux = typeToAux(t.FieldType(2)) - v2 := b.NewValue0(v.Pos, OpOffPtr, t.FieldType(2).PtrTo()) - v2.AuxInt = int64ToAuxInt(t.FieldOff(2)) - v2.AddArg(dst) - v3 := b.NewValue0(v.Pos, OpStore, types.TypeMem) - v3.Aux = typeToAux(t.FieldType(1)) - v4 := b.NewValue0(v.Pos, OpOffPtr, t.FieldType(1).PtrTo()) - v4.AuxInt = int64ToAuxInt(t.FieldOff(1)) - v4.AddArg(dst) - v5 := b.NewValue0(v.Pos, OpStore, types.TypeMem) - v5.Aux = typeToAux(t.FieldType(0)) - v6 := b.NewValue0(v.Pos, OpOffPtr, t.FieldType(0).PtrTo()) - v6.AuxInt = int64ToAuxInt(0) - v6.AddArg(dst) - v5.AddArg3(v6, f0, mem) - v3.AddArg3(v4, f1, v5) - v1.AddArg3(v2, f2, v3) - v.AddArg3(v0, f3, v1) + v.copyOf(rewriteStructStore(v)) return true } // match: (Store {t} dst (Load src mem) mem) @@ -30407,104 +30186,15 @@ func rewriteValuegeneric_OpStringPtr(v *Value) bool { func rewriteValuegeneric_OpStructSelect(v *Value) bool { v_0 := v.Args[0] b := v.Block - // match: (StructSelect (StructMake1 x)) - // result: x - for { - if v_0.Op != OpStructMake1 { - break - } - x := v_0.Args[0] - v.copyOf(x) - return true - } - // match: (StructSelect [0] (StructMake2 x _)) - // result: x - for { - if auxIntToInt64(v.AuxInt) != 0 || v_0.Op != OpStructMake2 { - break - } - x := v_0.Args[0] - v.copyOf(x) - return true - } - // match: (StructSelect [1] (StructMake2 _ x)) - // result: x - for { - if auxIntToInt64(v.AuxInt) != 1 || v_0.Op != OpStructMake2 { - break - } - x := v_0.Args[1] - v.copyOf(x) - return true - } - // match: (StructSelect [0] (StructMake3 x _ _)) - // result: x - for { - if auxIntToInt64(v.AuxInt) != 0 || v_0.Op != OpStructMake3 { - break - } - x := v_0.Args[0] - v.copyOf(x) - return true - } - // match: (StructSelect [1] (StructMake3 _ x _)) - // result: x + // match: (StructSelect [i] x:(StructMake ___)) + // result: x.Args[i] for { - if auxIntToInt64(v.AuxInt) != 1 || v_0.Op != OpStructMake3 { - break - } - x := v_0.Args[1] - v.copyOf(x) - return true - } - // match: (StructSelect [2] (StructMake3 _ _ x)) - // result: x - for { - if auxIntToInt64(v.AuxInt) != 2 || v_0.Op != OpStructMake3 { - break - } - x := v_0.Args[2] - v.copyOf(x) - return true - } - // match: (StructSelect [0] (StructMake4 x _ _ _)) - // result: x - for { - if auxIntToInt64(v.AuxInt) != 0 || v_0.Op != OpStructMake4 { - break - } - x := v_0.Args[0] - v.copyOf(x) - return true - } - // match: (StructSelect [1] (StructMake4 _ x _ _)) - // result: x - for { - if auxIntToInt64(v.AuxInt) != 1 || v_0.Op != OpStructMake4 { - break - } - x := v_0.Args[1] - v.copyOf(x) - return true - } - // match: (StructSelect [2] (StructMake4 _ _ x _)) - // result: x - for { - if auxIntToInt64(v.AuxInt) != 2 || v_0.Op != OpStructMake4 { - break - } - x := v_0.Args[2] - v.copyOf(x) - return true - } - // match: (StructSelect [3] (StructMake4 _ _ _ x)) - // result: x - for { - if auxIntToInt64(v.AuxInt) != 3 || v_0.Op != OpStructMake4 { + i := auxIntToInt64(v.AuxInt) + x := v_0 + if x.Op != OpStructMake { break } - x := v_0.Args[3] - v.copyOf(x) + v.copyOf(x.Args[i]) return true } // match: (StructSelect [i] x:(Load ptr mem)) diff --git a/src/cmd/compile/internal/ssagen/ssa.go b/src/cmd/compile/internal/ssagen/ssa.go index 97681214e7..d086b74e82 100644 --- a/src/cmd/compile/internal/ssagen/ssa.go +++ b/src/cmd/compile/internal/ssagen/ssa.go @@ -3943,7 +3943,7 @@ func (s *state) assignWhichMayOverlap(left ir.Node, right *ssa.Value, deref bool old := s.expr(left.X) // Make new structure. - new := s.newValue0(ssa.StructMakeOp(t.NumFields()), t) + new := s.newValue0(ssa.OpStructMake, t) // Add fields as args. for i := 0; i < nf; i++ { @@ -4071,7 +4071,7 @@ func (s *state) zeroVal(t *types.Type) *ssa.Value { return s.constSlice(t) case t.IsStruct(): n := t.NumFields() - v := s.entryNewValue0(ssa.StructMakeOp(t.NumFields()), t) + v := s.entryNewValue0(ssa.OpStructMake, t) for i := 0; i < n; i++ { v.AddArg(s.zeroVal(t.FieldType(i))) }