Skip to content

Commit 6d856a8

Browse files
cuonglmgopherbot
authored andcommitted
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 <[email protected]> LUCI-TryBot-Result: Go LUCI <[email protected]> Reviewed-by: Keith Randall <[email protected]> Auto-Submit: Cuong Manh Le <[email protected]> Reviewed-by: David Chase <[email protected]>
1 parent a3a05ed commit 6d856a8

File tree

12 files changed

+97
-709
lines changed

12 files changed

+97
-709
lines changed

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

Lines changed: 6 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -97,19 +97,10 @@
9797
// Helpers for expand calls
9898
// Some of these are copied from generic.rules
9999

100-
(IMake _typ (StructMake1 val)) => (IMake _typ val)
100+
(IMake _typ (StructMake val)) => (IMake _typ val)
101101
(StructSelect [0] (IData x)) => (IData x)
102102

103-
(StructSelect (StructMake1 x)) => x
104-
(StructSelect [0] (StructMake2 x _)) => x
105-
(StructSelect [1] (StructMake2 _ x)) => x
106-
(StructSelect [0] (StructMake3 x _ _)) => x
107-
(StructSelect [1] (StructMake3 _ x _)) => x
108-
(StructSelect [2] (StructMake3 _ _ x)) => x
109-
(StructSelect [0] (StructMake4 x _ _ _)) => x
110-
(StructSelect [1] (StructMake4 _ x _ _)) => x
111-
(StructSelect [2] (StructMake4 _ _ x _)) => x
112-
(StructSelect [3] (StructMake4 _ _ _ x)) => x
103+
(StructSelect [i] x:(StructMake ___)) => x.Args[i]
113104

114105
// Special case coming from immediate interface rewriting
115106
// Typical case: (StructSelect [0] (IData (IMake typ dat)) rewrites to (StructSelect [0] dat)
@@ -123,40 +114,10 @@
123114

124115
// These, too. Bits is bits.
125116
(ArrayMake1 x) && x.Type.IsPtrShaped() => x
126-
(StructMake1 x) && x.Type.IsPtrShaped() => x
127-
128-
(Store dst (StructMake1 <t> f0) mem) =>
129-
(Store {t.FieldType(0)} (OffPtr <t.FieldType(0).PtrTo()> [0] dst) f0 mem)
130-
(Store dst (StructMake2 <t> f0 f1) mem) =>
131-
(Store {t.FieldType(1)}
132-
(OffPtr <t.FieldType(1).PtrTo()> [t.FieldOff(1)] dst)
133-
f1
134-
(Store {t.FieldType(0)}
135-
(OffPtr <t.FieldType(0).PtrTo()> [0] dst)
136-
f0 mem))
137-
(Store dst (StructMake3 <t> f0 f1 f2) mem) =>
138-
(Store {t.FieldType(2)}
139-
(OffPtr <t.FieldType(2).PtrTo()> [t.FieldOff(2)] dst)
140-
f2
141-
(Store {t.FieldType(1)}
142-
(OffPtr <t.FieldType(1).PtrTo()> [t.FieldOff(1)] dst)
143-
f1
144-
(Store {t.FieldType(0)}
145-
(OffPtr <t.FieldType(0).PtrTo()> [0] dst)
146-
f0 mem)))
147-
(Store dst (StructMake4 <t> f0 f1 f2 f3) mem) =>
148-
(Store {t.FieldType(3)}
149-
(OffPtr <t.FieldType(3).PtrTo()> [t.FieldOff(3)] dst)
150-
f3
151-
(Store {t.FieldType(2)}
152-
(OffPtr <t.FieldType(2).PtrTo()> [t.FieldOff(2)] dst)
153-
f2
154-
(Store {t.FieldType(1)}
155-
(OffPtr <t.FieldType(1).PtrTo()> [t.FieldOff(1)] dst)
156-
f1
157-
(Store {t.FieldType(0)}
158-
(OffPtr <t.FieldType(0).PtrTo()> [0] dst)
159-
f0 mem))))
117+
(StructMake x) && x.Type.IsPtrShaped() => x
118+
119+
120+
(Store _ (StructMake ___) _) => rewriteStructStore(v)
160121

161122
(ArraySelect (ArrayMake1 x)) => x
162123
(ArraySelect [0] (IData x)) => (IData x)

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

Lines changed: 4 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -885,77 +885,15 @@
885885
(PtrIndex <t> ptr idx) && config.PtrSize == 8 => (AddPtr ptr (Mul64 <typ.Int> idx (Const64 <typ.Int> [t.Elem().Size()])))
886886

887887
// struct operations
888-
(StructSelect (StructMake1 x)) => x
889-
(StructSelect [0] (StructMake2 x _)) => x
890-
(StructSelect [1] (StructMake2 _ x)) => x
891-
(StructSelect [0] (StructMake3 x _ _)) => x
892-
(StructSelect [1] (StructMake3 _ x _)) => x
893-
(StructSelect [2] (StructMake3 _ _ x)) => x
894-
(StructSelect [0] (StructMake4 x _ _ _)) => x
895-
(StructSelect [1] (StructMake4 _ x _ _)) => x
896-
(StructSelect [2] (StructMake4 _ _ x _)) => x
897-
(StructSelect [3] (StructMake4 _ _ _ x)) => x
898-
899-
(Load <t> _ _) && t.IsStruct() && t.NumFields() == 0 && CanSSA(t) =>
900-
(StructMake0)
901-
(Load <t> ptr mem) && t.IsStruct() && t.NumFields() == 1 && CanSSA(t) =>
902-
(StructMake1
903-
(Load <t.FieldType(0)> (OffPtr <t.FieldType(0).PtrTo()> [0] ptr) mem))
904-
(Load <t> ptr mem) && t.IsStruct() && t.NumFields() == 2 && CanSSA(t) =>
905-
(StructMake2
906-
(Load <t.FieldType(0)> (OffPtr <t.FieldType(0).PtrTo()> [0] ptr) mem)
907-
(Load <t.FieldType(1)> (OffPtr <t.FieldType(1).PtrTo()> [t.FieldOff(1)] ptr) mem))
908-
(Load <t> ptr mem) && t.IsStruct() && t.NumFields() == 3 && CanSSA(t) =>
909-
(StructMake3
910-
(Load <t.FieldType(0)> (OffPtr <t.FieldType(0).PtrTo()> [0] ptr) mem)
911-
(Load <t.FieldType(1)> (OffPtr <t.FieldType(1).PtrTo()> [t.FieldOff(1)] ptr) mem)
912-
(Load <t.FieldType(2)> (OffPtr <t.FieldType(2).PtrTo()> [t.FieldOff(2)] ptr) mem))
913-
(Load <t> ptr mem) && t.IsStruct() && t.NumFields() == 4 && CanSSA(t) =>
914-
(StructMake4
915-
(Load <t.FieldType(0)> (OffPtr <t.FieldType(0).PtrTo()> [0] ptr) mem)
916-
(Load <t.FieldType(1)> (OffPtr <t.FieldType(1).PtrTo()> [t.FieldOff(1)] ptr) mem)
917-
(Load <t.FieldType(2)> (OffPtr <t.FieldType(2).PtrTo()> [t.FieldOff(2)] ptr) mem)
918-
(Load <t.FieldType(3)> (OffPtr <t.FieldType(3).PtrTo()> [t.FieldOff(3)] ptr) mem))
888+
(StructSelect [i] x:(StructMake ___)) => x.Args[i]
889+
(Load <t> _ _) && t.IsStruct() && CanSSA(t) => rewriteStructLoad(v)
890+
(Store _ (StructMake ___) _) => rewriteStructStore(v)
919891

920892
(StructSelect [i] x:(Load <t> ptr mem)) && !CanSSA(t) =>
921893
@x.Block (Load <v.Type> (OffPtr <v.Type.PtrTo()> [t.FieldOff(int(i))] ptr) mem)
922894

923-
(Store _ (StructMake0) mem) => mem
924-
(Store dst (StructMake1 <t> f0) mem) =>
925-
(Store {t.FieldType(0)} (OffPtr <t.FieldType(0).PtrTo()> [0] dst) f0 mem)
926-
(Store dst (StructMake2 <t> f0 f1) mem) =>
927-
(Store {t.FieldType(1)}
928-
(OffPtr <t.FieldType(1).PtrTo()> [t.FieldOff(1)] dst)
929-
f1
930-
(Store {t.FieldType(0)}
931-
(OffPtr <t.FieldType(0).PtrTo()> [0] dst)
932-
f0 mem))
933-
(Store dst (StructMake3 <t> f0 f1 f2) mem) =>
934-
(Store {t.FieldType(2)}
935-
(OffPtr <t.FieldType(2).PtrTo()> [t.FieldOff(2)] dst)
936-
f2
937-
(Store {t.FieldType(1)}
938-
(OffPtr <t.FieldType(1).PtrTo()> [t.FieldOff(1)] dst)
939-
f1
940-
(Store {t.FieldType(0)}
941-
(OffPtr <t.FieldType(0).PtrTo()> [0] dst)
942-
f0 mem)))
943-
(Store dst (StructMake4 <t> f0 f1 f2 f3) mem) =>
944-
(Store {t.FieldType(3)}
945-
(OffPtr <t.FieldType(3).PtrTo()> [t.FieldOff(3)] dst)
946-
f3
947-
(Store {t.FieldType(2)}
948-
(OffPtr <t.FieldType(2).PtrTo()> [t.FieldOff(2)] dst)
949-
f2
950-
(Store {t.FieldType(1)}
951-
(OffPtr <t.FieldType(1).PtrTo()> [t.FieldOff(1)] dst)
952-
f1
953-
(Store {t.FieldType(0)}
954-
(OffPtr <t.FieldType(0).PtrTo()> [0] dst)
955-
f0 mem))))
956-
957895
// Putting struct{*byte} and similar into direct interfaces.
958-
(IMake _typ (StructMake1 val)) => (IMake _typ val)
896+
(IMake _typ (StructMake val)) => (IMake _typ val)
959897
(StructSelect [0] (IData x)) => (IData x)
960898

961899
// un-SSAable values use mem->mem copies

src/cmd/compile/internal/ssa/_gen/genericOps.go

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -521,11 +521,7 @@ var genericOps = []opData{
521521
{name: "IData", argLength: 1}, // arg0=interface, returns data field
522522

523523
// Structs
524-
{name: "StructMake0"}, // Returns struct with 0 fields.
525-
{name: "StructMake1", argLength: 1}, // arg0=field0. Returns struct.
526-
{name: "StructMake2", argLength: 2}, // arg0,arg1=field0,field1. Returns struct.
527-
{name: "StructMake3", argLength: 3}, // arg0..2=field0..2. Returns struct.
528-
{name: "StructMake4", argLength: 4}, // arg0..3=field0..3. Returns struct.
524+
{name: "StructMake", argLength: -1}, // args...=field0..n-1. Returns struct with n fields.
529525
{name: "StructSelect", argLength: 1, aux: "Int64"}, // arg0=struct, auxint=field index. Returns the auxint'th field.
530526

531527
// Arrays

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ func phielim(f *Func) {
106106
// Rewrite all 0-sized Go values to remove accessors, dereferences, loads, etc.
107107
if t := v.Type; (t.IsStruct() || t.IsArray()) && t.Size() == 0 {
108108
if t.IsStruct() {
109-
v.reset(OpStructMake0)
109+
v.reset(OpStructMake)
110110
} else {
111111
v.reset(OpArrayMake0)
112112
}

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

Lines changed: 2 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -318,11 +318,10 @@ func decomposeUserStructInto(f *Func, name *LocalSlot, slots []*LocalSlot) []*Lo
318318
}
319319
}
320320

321-
makeOp := StructMakeOp(n)
322321
var keep []*Value
323322
// create named values for each struct field
324323
for _, v := range f.NamedValues[*name] {
325-
if v.Op != makeOp {
324+
if v.Op != OpStructMake || len(v.Args) != n {
326325
keep = append(keep, v)
327326
continue
328327
}
@@ -373,7 +372,7 @@ func decomposeStructPhi(v *Value) {
373372
fields[i].AddArg(a.Block.NewValue1I(v.Pos, OpStructSelect, t.FieldType(i), int64(i), a))
374373
}
375374
}
376-
v.reset(StructMakeOp(n))
375+
v.reset(OpStructMake)
377376
v.AddArgs(fields[:n]...)
378377

379378
// Recursively decompose phis for each field.
@@ -408,24 +407,6 @@ func decomposeArrayPhi(v *Value) {
408407
// can have and still be SSAable.
409408
const MaxStruct = 4
410409

411-
// StructMakeOp returns the opcode to construct a struct with the
412-
// given number of fields.
413-
func StructMakeOp(nf int) Op {
414-
switch nf {
415-
case 0:
416-
return OpStructMake0
417-
case 1:
418-
return OpStructMake1
419-
case 2:
420-
return OpStructMake2
421-
case 3:
422-
return OpStructMake3
423-
case 4:
424-
return OpStructMake4
425-
}
426-
panic("too many fields in an SSAable struct")
427-
}
428-
429410
type namedVal struct {
430411
locIndex, valIndex int // f.NamedValues[f.Names[locIndex]][valIndex] = key
431412
}

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -425,7 +425,7 @@ func (x *expandState) decomposeAsNecessary(pos src.XPos, b *Block, a, m0 *Value,
425425
// Immediate interfaces cause so many headaches.
426426
if a.Op == OpIMake {
427427
data := a.Args[1]
428-
for data.Op == OpStructMake1 || data.Op == OpArrayMake1 {
428+
for data.Op == OpStructMake || data.Op == OpArrayMake1 {
429429
data = data.Args[0]
430430
}
431431
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
505505
return makeOf(a, OpArrayMake0, nil)
506506
}
507507
if at.IsStruct() {
508-
return makeOf(a, OpStructMake0, nil)
508+
return makeOf(a, OpStructMake, nil)
509509
}
510510
return a
511511
}
@@ -559,7 +559,7 @@ func (x *expandState) rewriteSelectOrArg(pos src.XPos, b *Block, container, a, m
559559
if at.NumFields() > 4 {
560560
panic(fmt.Errorf("Too many fields (%d, %d bytes), container=%s", at.NumFields(), at.Size(), container.LongString()))
561561
}
562-
a = makeOf(a, StructMakeOp(at.NumFields()), args)
562+
a = makeOf(a, OpStructMake, args)
563563
x.commonSelectors[sk] = a
564564
return a
565565

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ func isPoorStatementOp(op Op) bool {
1515
// Note that Nilcheck often vanishes, but when it doesn't, you'd love to start the statement there
1616
// so that a debugger-user sees the stop before the panic, and can examine the value.
1717
case OpAddr, OpLocalAddr, OpOffPtr, OpStructSelect, OpPhi, OpITab, OpIData,
18-
OpIMake, OpStringMake, OpSliceMake, OpStructMake0, OpStructMake1, OpStructMake2, OpStructMake3, OpStructMake4,
18+
OpIMake, OpStringMake, OpSliceMake, OpStructMake,
1919
OpConstBool, OpConst8, OpConst16, OpConst32, OpConst64, OpConst32F, OpConst64F, OpSB, OpSP,
2020
OpArgIntReg, OpArgFloatReg:
2121
return true

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

Lines changed: 3 additions & 27 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

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

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2356,3 +2356,41 @@ func isNonNegative(v *Value) bool {
23562356
}
23572357
return false
23582358
}
2359+
2360+
func rewriteStructLoad(v *Value) *Value {
2361+
b := v.Block
2362+
ptr := v.Args[0]
2363+
mem := v.Args[1]
2364+
2365+
t := v.Type
2366+
args := make([]*Value, t.NumFields())
2367+
for i := range args {
2368+
ft := t.FieldType(i)
2369+
addr := b.NewValue1I(v.Pos, OpOffPtr, ft.PtrTo(), t.FieldOff(i), ptr)
2370+
args[i] = b.NewValue2(v.Pos, OpLoad, ft, addr, mem)
2371+
}
2372+
2373+
v.reset(OpStructMake)
2374+
v.AddArgs(args...)
2375+
return v
2376+
}
2377+
2378+
func rewriteStructStore(v *Value) *Value {
2379+
b := v.Block
2380+
dst := v.Args[0]
2381+
x := v.Args[1]
2382+
if x.Op != OpStructMake {
2383+
base.Fatalf("invalid struct store: %v", x)
2384+
}
2385+
mem := v.Args[2]
2386+
2387+
t := x.Type
2388+
for i, arg := range x.Args {
2389+
ft := t.FieldType(i)
2390+
2391+
addr := b.NewValue1I(v.Pos, OpOffPtr, ft.PtrTo(), t.FieldOff(i), dst)
2392+
mem = b.NewValue3A(v.Pos, OpStore, types.TypeMem, typeToAux(ft), addr, arg, mem)
2393+
}
2394+
2395+
return mem
2396+
}

0 commit comments

Comments
 (0)