// 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)
 
 // These, too.  Bits is bits.
 (ArrayMake1 x) && x.Type.IsPtrShaped() => x
-(StructMake1 x) && x.Type.IsPtrShaped() => x
-
-(Store dst (StructMake1 <t> f0) mem) =>
-  (Store {t.FieldType(0)} (OffPtr <t.FieldType(0).PtrTo()> [0] dst) f0 mem)
-(Store dst (StructMake2 <t> f0 f1) mem) =>
-  (Store {t.FieldType(1)}
-    (OffPtr <t.FieldType(1).PtrTo()> [t.FieldOff(1)] dst)
-    f1
-    (Store {t.FieldType(0)}
-      (OffPtr <t.FieldType(0).PtrTo()> [0] dst)
-        f0 mem))
-(Store dst (StructMake3 <t> f0 f1 f2) mem) =>
-  (Store {t.FieldType(2)}
-    (OffPtr <t.FieldType(2).PtrTo()> [t.FieldOff(2)] dst)
-    f2
-    (Store {t.FieldType(1)}
-      (OffPtr <t.FieldType(1).PtrTo()> [t.FieldOff(1)] dst)
-      f1
-      (Store {t.FieldType(0)}
-        (OffPtr <t.FieldType(0).PtrTo()> [0] dst)
-          f0 mem)))
-(Store dst (StructMake4 <t> f0 f1 f2 f3) mem) =>
-  (Store {t.FieldType(3)}
-    (OffPtr <t.FieldType(3).PtrTo()> [t.FieldOff(3)] dst)
-    f3
-    (Store {t.FieldType(2)}
-      (OffPtr <t.FieldType(2).PtrTo()> [t.FieldOff(2)] dst)
-      f2
-      (Store {t.FieldType(1)}
-        (OffPtr <t.FieldType(1).PtrTo()> [t.FieldOff(1)] dst)
-        f1
-        (Store {t.FieldType(0)}
-          (OffPtr <t.FieldType(0).PtrTo()> [0] dst)
-            f0 mem))))
+(StructMake x) && x.Type.IsPtrShaped() => x
+
+
+(Store _ (StructMake ___) _) => rewriteStructStore(v)
 
 (ArraySelect (ArrayMake1 x)) => x
 (ArraySelect [0] (IData x)) => (IData x)
 
 (PtrIndex <t> ptr idx) && config.PtrSize == 8 => (AddPtr ptr (Mul64 <typ.Int> idx (Const64 <typ.Int> [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> _ _) && t.IsStruct() && t.NumFields() == 0 && CanSSA(t) =>
-  (StructMake0)
-(Load <t> ptr mem) && t.IsStruct() && t.NumFields() == 1 && CanSSA(t) =>
-  (StructMake1
-    (Load <t.FieldType(0)> (OffPtr <t.FieldType(0).PtrTo()> [0] ptr) mem))
-(Load <t> ptr mem) && t.IsStruct() && t.NumFields() == 2 && CanSSA(t) =>
-  (StructMake2
-    (Load <t.FieldType(0)> (OffPtr <t.FieldType(0).PtrTo()> [0]             ptr) mem)
-    (Load <t.FieldType(1)> (OffPtr <t.FieldType(1).PtrTo()> [t.FieldOff(1)] ptr) mem))
-(Load <t> ptr mem) && t.IsStruct() && t.NumFields() == 3 && CanSSA(t) =>
-  (StructMake3
-    (Load <t.FieldType(0)> (OffPtr <t.FieldType(0).PtrTo()> [0]             ptr) mem)
-    (Load <t.FieldType(1)> (OffPtr <t.FieldType(1).PtrTo()> [t.FieldOff(1)] ptr) mem)
-    (Load <t.FieldType(2)> (OffPtr <t.FieldType(2).PtrTo()> [t.FieldOff(2)] ptr) mem))
-(Load <t> ptr mem) && t.IsStruct() && t.NumFields() == 4 && CanSSA(t) =>
-  (StructMake4
-    (Load <t.FieldType(0)> (OffPtr <t.FieldType(0).PtrTo()> [0]             ptr) mem)
-    (Load <t.FieldType(1)> (OffPtr <t.FieldType(1).PtrTo()> [t.FieldOff(1)] ptr) mem)
-    (Load <t.FieldType(2)> (OffPtr <t.FieldType(2).PtrTo()> [t.FieldOff(2)] ptr) mem)
-    (Load <t.FieldType(3)> (OffPtr <t.FieldType(3).PtrTo()> [t.FieldOff(3)] ptr) mem))
+(StructSelect [i] x:(StructMake ___)) => x.Args[i]
+(Load <t> _ _) && t.IsStruct() && CanSSA(t) => rewriteStructLoad(v)
+(Store _ (StructMake ___) _) => rewriteStructStore(v)
 
 (StructSelect [i] x:(Load <t> ptr mem)) && !CanSSA(t) =>
   @x.Block (Load <v.Type> (OffPtr <v.Type.PtrTo()> [t.FieldOff(int(i))] ptr) mem)
 
-(Store _ (StructMake0) mem) => mem
-(Store dst (StructMake1 <t> f0) mem) =>
-  (Store {t.FieldType(0)} (OffPtr <t.FieldType(0).PtrTo()> [0] dst) f0 mem)
-(Store dst (StructMake2 <t> f0 f1) mem) =>
-  (Store {t.FieldType(1)}
-    (OffPtr <t.FieldType(1).PtrTo()> [t.FieldOff(1)] dst)
-    f1
-    (Store {t.FieldType(0)}
-      (OffPtr <t.FieldType(0).PtrTo()> [0] dst)
-        f0 mem))
-(Store dst (StructMake3 <t> f0 f1 f2) mem) =>
-  (Store {t.FieldType(2)}
-    (OffPtr <t.FieldType(2).PtrTo()> [t.FieldOff(2)] dst)
-    f2
-    (Store {t.FieldType(1)}
-      (OffPtr <t.FieldType(1).PtrTo()> [t.FieldOff(1)] dst)
-      f1
-      (Store {t.FieldType(0)}
-        (OffPtr <t.FieldType(0).PtrTo()> [0] dst)
-          f0 mem)))
-(Store dst (StructMake4 <t> f0 f1 f2 f3) mem) =>
-  (Store {t.FieldType(3)}
-    (OffPtr <t.FieldType(3).PtrTo()> [t.FieldOff(3)] dst)
-    f3
-    (Store {t.FieldType(2)}
-      (OffPtr <t.FieldType(2).PtrTo()> [t.FieldOff(2)] dst)
-      f2
-      (Store {t.FieldType(1)}
-        (OffPtr <t.FieldType(1).PtrTo()> [t.FieldOff(1)] dst)
-        f1
-        (Store {t.FieldType(0)}
-          (OffPtr <t.FieldType(0).PtrTo()> [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
 
        {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
 
                                // 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)
                                        }
 
                }
        }
 
-       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
                }
                        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.
 // 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
 }
 
                // 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))
                        return makeOf(a, OpArrayMake0, nil)
                }
                if at.IsStruct() {
-                       return makeOf(a, OpStructMake0, nil)
+                       return makeOf(a, OpStructMake, nil)
                }
                return a
        }
                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
 
 
        // 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
 
        OpIMake
        OpITab
        OpIData
-       OpStructMake0
-       OpStructMake1
-       OpStructMake2
-       OpStructMake3
-       OpStructMake4
+       OpStructMake
        OpStructSelect
        OpArrayMake0
        OpArrayMake1
                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,
        },
        {
 
        }
        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
+}
 
                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)
        }
 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]
                v.AddArg3(v0, data, v1)
                return true
        }
-       // match: (Store dst (StructMake1 <t> f0) mem)
-       // result: (Store {t.FieldType(0)} (OffPtr <t.FieldType(0).PtrTo()> [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 <t> f0 f1) mem)
-       // result: (Store {t.FieldType(1)} (OffPtr <t.FieldType(1).PtrTo()> [t.FieldOff(1)] dst) f1 (Store {t.FieldType(0)} (OffPtr <t.FieldType(0).PtrTo()> [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 <t> f0 f1 f2) mem)
-       // result: (Store {t.FieldType(2)} (OffPtr <t.FieldType(2).PtrTo()> [t.FieldOff(2)] dst) f2 (Store {t.FieldType(1)} (OffPtr <t.FieldType(1).PtrTo()> [t.FieldOff(1)] dst) f1 (Store {t.FieldType(0)} (OffPtr <t.FieldType(0).PtrTo()> [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 <t> f0 f1 f2 f3) mem)
-       // result: (Store {t.FieldType(3)} (OffPtr <t.FieldType(3).PtrTo()> [t.FieldOff(3)] dst) f3 (Store {t.FieldType(2)} (OffPtr <t.FieldType(2).PtrTo()> [t.FieldOff(2)] dst) f2 (Store {t.FieldType(1)} (OffPtr <t.FieldType(1).PtrTo()> [t.FieldOff(1)] dst) f1 (Store {t.FieldType(0)} (OffPtr <t.FieldType(0).PtrTo()> [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)
        }
        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
                }
                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)
 
 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]
                return true
        }
        // match: (Load <t> _ _)
-       // 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 <t> ptr mem)
-       // cond: t.IsStruct() && t.NumFields() == 1 && CanSSA(t)
-       // result: (StructMake1 (Load <t.FieldType(0)> (OffPtr <t.FieldType(0).PtrTo()> [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 <t> ptr mem)
-       // cond: t.IsStruct() && t.NumFields() == 2 && CanSSA(t)
-       // result: (StructMake2 (Load <t.FieldType(0)> (OffPtr <t.FieldType(0).PtrTo()> [0] ptr) mem) (Load <t.FieldType(1)> (OffPtr <t.FieldType(1).PtrTo()> [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 <t> ptr mem)
-       // cond: t.IsStruct() && t.NumFields() == 3 && CanSSA(t)
-       // result: (StructMake3 (Load <t.FieldType(0)> (OffPtr <t.FieldType(0).PtrTo()> [0] ptr) mem) (Load <t.FieldType(1)> (OffPtr <t.FieldType(1).PtrTo()> [t.FieldOff(1)] ptr) mem) (Load <t.FieldType(2)> (OffPtr <t.FieldType(2).PtrTo()> [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 <t> ptr mem)
-       // cond: t.IsStruct() && t.NumFields() == 4 && CanSSA(t)
-       // result: (StructMake4 (Load <t.FieldType(0)> (OffPtr <t.FieldType(0).PtrTo()> [0] ptr) mem) (Load <t.FieldType(1)> (OffPtr <t.FieldType(1).PtrTo()> [t.FieldOff(1)] ptr) mem) (Load <t.FieldType(2)> (OffPtr <t.FieldType(2).PtrTo()> [t.FieldOff(2)] ptr) mem) (Load <t.FieldType(3)> (OffPtr <t.FieldType(3).PtrTo()> [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 <t> _ _)
                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 <t> f0) mem)
-       // result: (Store {t.FieldType(0)} (OffPtr <t.FieldType(0).PtrTo()> [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 <t> f0 f1) mem)
-       // result: (Store {t.FieldType(1)} (OffPtr <t.FieldType(1).PtrTo()> [t.FieldOff(1)] dst) f1 (Store {t.FieldType(0)} (OffPtr <t.FieldType(0).PtrTo()> [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 <t> f0 f1 f2) mem)
-       // result: (Store {t.FieldType(2)} (OffPtr <t.FieldType(2).PtrTo()> [t.FieldOff(2)] dst) f2 (Store {t.FieldType(1)} (OffPtr <t.FieldType(1).PtrTo()> [t.FieldOff(1)] dst) f1 (Store {t.FieldType(0)} (OffPtr <t.FieldType(0).PtrTo()> [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 <t> f0 f1 f2 f3) mem)
-       // result: (Store {t.FieldType(3)} (OffPtr <t.FieldType(3).PtrTo()> [t.FieldOff(3)] dst) f3 (Store {t.FieldType(2)} (OffPtr <t.FieldType(2).PtrTo()> [t.FieldOff(2)] dst) f2 (Store {t.FieldType(1)} (OffPtr <t.FieldType(1).PtrTo()> [t.FieldOff(1)] dst) f1 (Store {t.FieldType(0)} (OffPtr <t.FieldType(0).PtrTo()> [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)
 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 <t> ptr mem))
 
                        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++ {
                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)))
                }