]> Cypherpunks repositories - gostls13.git/commitdiff
[dev.ssa] cmd/compile: add decompose pass
authorKeith Randall <khr@golang.org>
Tue, 18 Aug 2015 17:26:28 +0000 (10:26 -0700)
committerKeith Randall <khr@golang.org>
Thu, 20 Aug 2015 21:09:24 +0000 (21:09 +0000)
Decompose breaks compound objects up into pieces that can be
operated on by the target architecture.  The decompose pass only
does phi ops, the rest is done by the rewrite rules in generic.rules.

Compound objects include strings,slices,interfaces,structs,arrays.

Arrays aren't decomposed because of indexing (we could support
constant indexes, but dynamic indexes can't be handled using SSA).
Structs will come in a subsequent CL.

TODO: after this pass we have lost the association between, e.g.,
a string's pointer and its size.  It would be nice if we could keep
that information around for debugging info somehow.

Change-Id: I6379ab962a7beef62297d0f68c421f22aa0a0901
Reviewed-on: https://go-review.googlesource.com/13683
Reviewed-by: Josh Bleecher Snyder <josharian@gmail.com>
src/cmd/compile/internal/gc/ssa.go
src/cmd/compile/internal/gc/testdata/compound_ssa.go [new file with mode: 0644]
src/cmd/compile/internal/gc/type.go
src/cmd/compile/internal/ssa/compile.go
src/cmd/compile/internal/ssa/decompose.go [new file with mode: 0644]
src/cmd/compile/internal/ssa/gen/generic.rules
src/cmd/compile/internal/ssa/gen/genericOps.go
src/cmd/compile/internal/ssa/opGen.go
src/cmd/compile/internal/ssa/rewritegeneric.go
src/cmd/compile/internal/ssa/type.go
src/cmd/compile/internal/ssa/type_test.go

index 1fb5485183cddac4908c3fbbce9b188e6eda5781..a324ed2a42ffb38fca50052475a8e45bd2655a61 100644 (file)
@@ -1072,7 +1072,15 @@ func (s *state) expr(n *Node) *ssa.Value {
                case CTBOOL:
                        return s.entryNewValue0A(ssa.OpConstBool, n.Type, n.Val().U)
                case CTNIL:
-                       return s.entryNewValue0(ssa.OpConstNil, n.Type)
+                       t := n.Type
+                       switch {
+                       case t.IsSlice():
+                               return s.entryNewValue0(ssa.OpConstSlice, t)
+                       case t.IsInterface():
+                               return s.entryNewValue0(ssa.OpConstInterface, t)
+                       default:
+                               return s.entryNewValue0(ssa.OpConstNil, t)
+                       }
                case CTFLT:
                        f := n.Val().U.(*Mpflt)
                        switch n.Type.Size() {
@@ -1470,6 +1478,10 @@ func (s *state) zeroVal(t *Type) *ssa.Value {
                return s.entryNewValue0(ssa.OpConstNil, t)
        case t.IsBoolean():
                return s.entryNewValue0A(ssa.OpConstBool, t, false) // TODO: store bools as 0/1 in AuxInt?
+       case t.IsInterface():
+               return s.entryNewValue0(ssa.OpConstInterface, t)
+       case t.IsSlice():
+               return s.entryNewValue0(ssa.OpConstSlice, t)
        }
        s.Unimplementedf("zero for type %v not implemented", t)
        return nil
@@ -1582,11 +1594,47 @@ func canSSA(n *Node) bool {
        if n.Class == PPARAMOUT {
                return false
        }
-       if Isfat(n.Type) {
+       return canSSAType(n.Type)
+       // TODO: try to make more variables SSAable?
+}
+
+// canSSA reports whether variables of type t are SSA-able.
+func canSSAType(t *Type) bool {
+       dowidth(t)
+       if t.Width > int64(4*Widthptr) {
+               // 4*Widthptr is an arbitrary constant.  We want it
+               // to be at least 3*Widthptr so slices can be registerized.
+               // Too big and we'll introduce too much register pressure.
                return false
        }
-       return true
-       // TODO: try to make more variables SSAable.
+       switch t.Etype {
+       case TARRAY:
+               if Isslice(t) {
+                       return true
+               }
+               // We can't do arrays because dynamic indexing is
+               // not supported on SSA variables.
+               // TODO: maybe allow if length is <=1?  All indexes
+               // are constant?  Might be good for the arrays
+               // introduced by the compiler for variadic functions.
+               return false
+       case TSTRUCT:
+               if countfield(t) > 4 {
+                       // 4 is an arbitrary constant.  Same reasoning
+                       // as above, lots of small fields would waste
+                       // register space needed by other values.
+                       return false
+               }
+               for t1 := t.Type; t1 != nil; t1 = t1.Down {
+                       if !canSSAType(t1.Type) {
+                               return false
+                       }
+               }
+               return false // until it is implemented
+               //return true
+       default:
+               return true
+       }
 }
 
 // nilCheck generates nil pointer checking code.
diff --git a/src/cmd/compile/internal/gc/testdata/compound_ssa.go b/src/cmd/compile/internal/gc/testdata/compound_ssa.go
new file mode 100644 (file)
index 0000000..9b84ce4
--- /dev/null
@@ -0,0 +1,91 @@
+// run
+
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Test compound objects
+
+package main
+
+import "fmt"
+
+func string_ssa(a, b string, x bool) string {
+       s := ""
+       if x {
+               s = a
+       } else {
+               s = b
+       }
+       return s
+}
+
+func testString() {
+       a := "foo"
+       b := "barz"
+       if want, got := a, string_ssa(a, b, true); got != want {
+               fmt.Printf("string_ssa(%v, %v, true) = %v, want %v\n", a, b, got, want)
+               failed = true
+       }
+       if want, got := b, string_ssa(a, b, false); got != want {
+               fmt.Printf("string_ssa(%v, %v, false) = %v, want %v\n", a, b, got, want)
+               failed = true
+       }
+}
+
+func slice_ssa(a, b []byte, x bool) []byte {
+       var s []byte
+       if x {
+               s = a
+       } else {
+               s = b
+       }
+       return s
+}
+
+func testSlice() {
+       a := []byte{3, 4, 5}
+       b := []byte{7, 8, 9}
+       if want, got := byte(3), slice_ssa(a, b, true)[0]; got != want {
+               fmt.Printf("slice_ssa(%v, %v, true) = %v, want %v\n", a, b, got, want)
+               failed = true
+       }
+       if want, got := byte(7), slice_ssa(a, b, false)[0]; got != want {
+               fmt.Printf("slice_ssa(%v, %v, false) = %v, want %v\n", a, b, got, want)
+               failed = true
+       }
+}
+
+func interface_ssa(a, b interface{}, x bool) interface{} {
+       var s interface{}
+       if x {
+               s = a
+       } else {
+               s = b
+       }
+       return s
+}
+
+func testInterface() {
+       a := interface{}(3)
+       b := interface{}(4)
+       if want, got := 3, interface_ssa(a, b, true).(int); got != want {
+               fmt.Printf("interface_ssa(%v, %v, true) = %v, want %v\n", a, b, got, want)
+               failed = true
+       }
+       if want, got := 4, interface_ssa(a, b, false).(int); got != want {
+               fmt.Printf("interface_ssa(%v, %v, false) = %v, want %v\n", a, b, got, want)
+               failed = true
+       }
+}
+
+var failed = false
+
+func main() {
+       testString()
+       testSlice()
+       testInterface()
+       if failed {
+               panic("failed")
+       }
+}
index f60d01b3bb497ec3b501526910962bfad63a6e31..bcad025ba646d40a3097884105e1a222e5bae02e 100644 (file)
@@ -68,6 +68,10 @@ func (t *Type) IsSlice() bool {
        return t.Etype == TARRAY && t.Bound < 0
 }
 
+func (t *Type) IsInterface() bool {
+       return t.Etype == TINTER
+}
+
 func (t *Type) Elem() ssa.Type {
        return t.Type
 }
index e85fb10e0058790832323df837ff6cb3c01c7c4e..7413e721fe505c8d8cf5e81fb68be19a39fb935d 100644 (file)
@@ -60,6 +60,7 @@ type pass struct {
 var passes = [...]pass{
        {"phielim", phielim},
        {"copyelim", copyelim},
+       {"decompose", decompose},
        {"early deadcode", deadcode}, // remove generated dead code to avoid doing pointless work during opt
        {"opt", opt},
        {"opt deadcode", deadcode}, // remove any blocks orphaned during opt
@@ -103,6 +104,8 @@ var passOrder = [...]constraint{
        // tighten will be most effective when as many values have been removed as possible
        {"generic deadcode", "tighten"},
        {"generic cse", "tighten"},
+       // don't run optimization pass until we've decomposed compound objects
+       {"decompose", "opt"},
        // don't layout blocks until critical edges have been removed
        {"critical", "layout"},
        // regalloc requires the removal of all critical edges
diff --git a/src/cmd/compile/internal/ssa/decompose.go b/src/cmd/compile/internal/ssa/decompose.go
new file mode 100644 (file)
index 0000000..534ffc2
--- /dev/null
@@ -0,0 +1,93 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ssa
+
+// decompose converts phi ops on compound types into phi
+// ops on simple types.
+// (The remaining compound ops are decomposed with rewrite rules.)
+func decompose(f *Func) {
+       for _, b := range f.Blocks {
+               for _, v := range b.Values {
+                       if v.Op != OpPhi {
+                               continue
+                       }
+                       switch {
+                       case v.Type.IsString():
+                               decomposeStringPhi(v)
+                       case v.Type.IsSlice():
+                               decomposeSlicePhi(v)
+                       case v.Type.IsInterface():
+                               decomposeInterfacePhi(v)
+                               //case v.Type.IsStruct():
+                               //      decomposeStructPhi(v)
+                       case v.Type.Size() > f.Config.IntSize:
+                               f.Unimplementedf("undecomposed type %s", v.Type)
+                       }
+               }
+       }
+       // TODO: decompose complex?
+       // TODO: decompose 64-bit ops on 32-bit archs?
+}
+
+func decomposeStringPhi(v *Value) {
+       fe := v.Block.Func.Config.fe
+       ptrType := fe.TypeBytePtr()
+       lenType := fe.TypeUintptr()
+
+       ptr := v.Block.NewValue0(v.Line, OpPhi, ptrType)
+       len := v.Block.NewValue0(v.Line, OpPhi, lenType)
+       for _, a := range v.Args {
+               ptr.AddArg(a.Block.NewValue1(v.Line, OpStringPtr, ptrType, a))
+               len.AddArg(a.Block.NewValue1(v.Line, OpStringLen, lenType, a))
+       }
+       v.Op = OpStringMake
+       v.AuxInt = 0
+       v.Aux = nil
+       v.resetArgs()
+       v.AddArg(ptr)
+       v.AddArg(len)
+}
+
+func decomposeSlicePhi(v *Value) {
+       fe := v.Block.Func.Config.fe
+       ptrType := fe.TypeBytePtr()
+       lenType := fe.TypeUintptr()
+
+       ptr := v.Block.NewValue0(v.Line, OpPhi, ptrType)
+       len := v.Block.NewValue0(v.Line, OpPhi, lenType)
+       cap := v.Block.NewValue0(v.Line, OpPhi, lenType)
+       for _, a := range v.Args {
+               ptr.AddArg(a.Block.NewValue1(v.Line, OpSlicePtr, ptrType, a))
+               len.AddArg(a.Block.NewValue1(v.Line, OpSliceLen, lenType, a))
+               cap.AddArg(a.Block.NewValue1(v.Line, OpSliceCap, lenType, a))
+       }
+       v.Op = OpSliceMake
+       v.AuxInt = 0
+       v.Aux = nil
+       v.resetArgs()
+       v.AddArg(ptr)
+       v.AddArg(len)
+       v.AddArg(cap)
+}
+
+func decomposeInterfacePhi(v *Value) {
+       ptrType := v.Block.Func.Config.fe.TypeBytePtr()
+
+       itab := v.Block.NewValue0(v.Line, OpPhi, ptrType)
+       data := v.Block.NewValue0(v.Line, OpPhi, ptrType)
+       for _, a := range v.Args {
+               itab.AddArg(a.Block.NewValue1(v.Line, OpITab, ptrType, a))
+               data.AddArg(a.Block.NewValue1(v.Line, OpIData, ptrType, a))
+       }
+       v.Op = OpIMake
+       v.AuxInt = 0
+       v.Aux = nil
+       v.resetArgs()
+       v.AddArg(itab)
+       v.AddArg(data)
+}
+func decomposeStructPhi(v *Value) {
+       // TODO
+}
index db66a457c33b643ce12eb37f218a0e41dc13912f..7be00569ea5ba731e80d83b8fd0ae3a604d37018 100644 (file)
 (Com32 (Com32 x)) -> x
 (Com64 (Com64 x)) -> x
 
-// tear apart slices
-// TODO: anything that generates a slice needs to go in here.
-(SlicePtr (Load ptr mem)) -> (Load ptr mem)
-(SliceLen (Load ptr mem)) -> (Load (AddPtr <ptr.Type> ptr (ConstPtr <config.Frontend().TypeUintptr()> [config.PtrSize])) mem)
-(SliceCap (Load ptr mem)) -> (Load (AddPtr <ptr.Type> ptr (ConstPtr <config.Frontend().TypeUintptr()> [config.PtrSize*2])) mem)
-
 // slice and interface comparisons
 // the frontend ensures that we can only compare against nil
 // start by putting nil on the right to simplify the other rules
 (EqFat x y) && x.Op == OpConstNil && y.Op != OpConstNil -> (EqFat y x)
 (NeqFat x y) && x.Op == OpConstNil && y.Op != OpConstNil -> (NeqFat y x)
 // it suffices to check the first word (backing array for slices, dynamic type for interfaces)
-(EqFat (Load ptr mem) (ConstNil)) -> (EqPtr (Load <config.Frontend().TypeUintptr()> ptr mem) (ConstPtr <config.Frontend().TypeUintptr()> [0]))
-(NeqFat (Load ptr mem) (ConstNil)) -> (NeqPtr (Load <config.Frontend().TypeUintptr()> ptr mem) (ConstPtr <config.Frontend().TypeUintptr()> [0]))
+(EqFat (Load ptr mem) (ConstNil)) -> (EqPtr (Load <config.fe.TypeUintptr()> ptr mem) (ConstPtr <config.fe.TypeUintptr()> [0]))
+(NeqFat (Load ptr mem) (ConstNil)) -> (NeqPtr (Load <config.fe.TypeUintptr()> ptr mem) (ConstPtr <config.fe.TypeUintptr()> [0]))
 
 // indexing operations
 // Note: bounds check has already been done
 (ArrayIndex (Load ptr mem) idx) -> (Load (PtrIndex <v.Type.PtrTo()> ptr idx) mem)
-(PtrIndex <t> ptr idx) -> (AddPtr ptr (MulPtr <config.Frontend().TypeUintptr()> idx (ConstPtr <config.Frontend().TypeUintptr()> [t.Elem().Size()])))
+(PtrIndex <t> ptr idx) -> (AddPtr ptr (MulPtr <config.fe.TypeUintptr()> idx (ConstPtr <config.fe.TypeUintptr()> [t.Elem().Size()])))
 (StructSelect [idx] (Load ptr mem)) -> (Load (OffPtr <v.Type.PtrTo()> [idx] ptr) mem)
 
-// big-object moves
-(Store [size] dst (Load src mem) mem) && size > config.IntSize -> (Move [size] dst src mem)
-
 // string ops
-(ConstString {s}) -> (StringMake (Addr <config.Frontend().TypeBytePtr()> {config.fe.StringData(s.(string))} (SB <config.Frontend().TypeUintptr()>)) (ConstPtr <config.Frontend().TypeUintptr()> [int64(len(s.(string)))]))
-(Load <t> ptr mem) && t.IsString() -> (StringMake (Load <config.Frontend().TypeBytePtr()> ptr mem) (Load <config.Frontend().TypeUintptr()> (OffPtr <config.Frontend().TypeBytePtr()> [config.PtrSize] ptr) mem))
 (StringPtr (StringMake ptr _)) -> ptr
 (StringLen (StringMake _ len)) -> len
-(Store [2*config.PtrSize] dst str mem) && str.Type.IsString() -> (Store [config.PtrSize] (OffPtr <config.Frontend().TypeBytePtr()> [config.PtrSize] dst) (StringLen <config.Frontend().TypeUintptr()> str) (Store [config.PtrSize] <TypeMem> dst (StringPtr <config.Frontend().TypeBytePtr()> str) mem))
+(ConstString {s}) ->
+  (StringMake
+    (Addr <config.fe.TypeBytePtr()> {config.fe.StringData(s.(string))}
+      (SB <config.fe.TypeUintptr()>))
+    (ConstPtr <config.fe.TypeUintptr()> [int64(len(s.(string)))]))
+(Load <t> ptr mem) && t.IsString() ->
+  (StringMake
+    (Load <config.fe.TypeBytePtr()> ptr mem)
+    (Load <config.fe.TypeUintptr()>
+      (OffPtr <config.fe.TypeUintptr().PtrTo()> [config.PtrSize] ptr)
+      mem))
+(Store [2*config.PtrSize] dst (StringMake ptr len) mem) ->
+  (Store [config.PtrSize]
+    (OffPtr <config.fe.TypeUintptr().PtrTo()> [config.PtrSize] dst)
+    len
+    (Store <TypeMem> [config.PtrSize] dst ptr mem))
+
+// slice ops
+(SlicePtr (SliceMake ptr _ _ )) -> ptr
+(SliceLen (SliceMake _ len _)) -> len
+(SliceCap (SliceMake _ _ cap)) -> cap
+(ConstSlice) ->
+  (SliceMake
+    (ConstNil <config.fe.TypeBytePtr()>)
+    (ConstPtr <config.fe.TypeUintptr()>)
+    (ConstPtr <config.fe.TypeUintptr()>))
+
+(Load <t> ptr mem) && t.IsSlice() ->
+  (SliceMake
+    (Load <config.fe.TypeBytePtr()> ptr mem)
+    (Load <config.fe.TypeUintptr()>
+      (OffPtr <config.fe.TypeUintptr().PtrTo()> [config.PtrSize] ptr)
+      mem)
+    (Load <config.fe.TypeUintptr()>
+      (OffPtr <config.fe.TypeUintptr().PtrTo()> [2*config.PtrSize] ptr)
+      mem))
+(Store [3*config.PtrSize] dst (SliceMake ptr len cap) mem) ->
+  (Store [config.PtrSize]
+    (OffPtr <config.fe.TypeUintptr().PtrTo()> [2*config.PtrSize] dst)
+    cap
+    (Store <TypeMem> [config.PtrSize]
+      (OffPtr <config.fe.TypeUintptr().PtrTo()> [config.PtrSize] dst)
+      len
+      (Store <TypeMem> [config.PtrSize] dst ptr mem)))
+
+// interface ops
+(ITab (IMake itab _)) -> itab
+(IData (IMake _ data)) -> data
+(ConstInterface) ->
+  (IMake
+    (ConstNil <config.fe.TypeBytePtr()>)
+    (ConstNil <config.fe.TypeBytePtr()>))
+(Load <t> ptr mem) && t.IsInterface() ->
+  (IMake
+    (Load <config.fe.TypeBytePtr()> ptr mem)
+    (Load <config.fe.TypeBytePtr()>
+      (OffPtr <config.fe.TypeBytePtr().PtrTo()> [config.PtrSize] ptr)
+      mem))
+(Store [2*config.PtrSize] dst (IMake itab data) mem) ->
+  (Store [config.PtrSize]
+    (OffPtr <config.fe.TypeBytePtr().PtrTo()> [config.PtrSize] dst)
+    data
+    (Store <TypeMem> [config.PtrSize] dst itab mem))
+
+// big-object moves (TODO: remove?)
+(Store [size] dst (Load src mem) mem) && size > config.IntSize -> (Move [size] dst src mem)
 
 (If (IsNonNil (GetG)) yes no) -> (Plain nil yes)
 
index 2024788c5d52fd4c60b4112dc3b90c8bb5240c62..5b8b064bb50214db569cc8251aef246752946109 100644 (file)
@@ -229,7 +229,9 @@ var genericOps = []opData{
        {name: "Const64"},
        {name: "Const32F"},
        {name: "Const64F"},
-       {name: "ConstPtr"}, // pointer-sized integer constant
+       {name: "ConstPtr"},       // pointer-sized integer constant
+       {name: "ConstInterface"}, // nil interface
+       {name: "ConstSlice"},     // nil slice
        // TODO: Const32F, ...
 
        // Constant-like things
@@ -305,7 +307,9 @@ var genericOps = []opData{
        {name: "StringLen"},  // len(arg0)
 
        // Interfaces
-       {name: "ITab"}, // arg0=interface, returns itable field
+       {name: "IMake"}, // arg0=itab, arg1=data
+       {name: "ITab"},  // arg0=interface, returns itable field
+       {name: "IData"}, // arg0=interface, returns data field
 
        // Spill&restore ops for the register allocator.  These are
        // semantically identical to OpCopy; they do not take/return
index 003aacffbb661a4678228ef65a5780c00687f287..17d4edb221bf5746272ab93b6275c86f38c40ce6 100644 (file)
@@ -396,6 +396,8 @@ const (
        OpConst32F
        OpConst64F
        OpConstPtr
+       OpConstInterface
+       OpConstSlice
        OpArg
        OpAddr
        OpSP
@@ -442,7 +444,9 @@ const (
        OpStringMake
        OpStringPtr
        OpStringLen
+       OpIMake
        OpITab
+       OpIData
        OpStoreReg
        OpLoadReg
        OpFwdRef
@@ -3374,6 +3378,14 @@ var opcodeTable = [...]opInfo{
                name:    "ConstPtr",
                generic: true,
        },
+       {
+               name:    "ConstInterface",
+               generic: true,
+       },
+       {
+               name:    "ConstSlice",
+               generic: true,
+       },
        {
                name:    "Arg",
                generic: true,
@@ -3558,10 +3570,18 @@ var opcodeTable = [...]opInfo{
                name:    "StringLen",
                generic: true,
        },
+       {
+               name:    "IMake",
+               generic: true,
+       },
        {
                name:    "ITab",
                generic: true,
        },
+       {
+               name:    "IData",
+               generic: true,
+       },
        {
                name:    "StoreReg",
                generic: true,
index 4c278cb1682d7e2f2bdfb4829b9adffd57fed786..bd53e05230ad046d1057f96bc99e46bc8e436e61 100644 (file)
@@ -237,10 +237,53 @@ func rewriteValuegeneric(v *Value, config *Config) bool {
                goto end4d92ff3ba567d9afd38fc9ca113602ad
        end4d92ff3ba567d9afd38fc9ca113602ad:
                ;
+       case OpConstInterface:
+               // match: (ConstInterface)
+               // cond:
+               // result: (IMake     (ConstNil <config.fe.TypeBytePtr()>)     (ConstNil <config.fe.TypeBytePtr()>))
+               {
+                       v.Op = OpIMake
+                       v.AuxInt = 0
+                       v.Aux = nil
+                       v.resetArgs()
+                       v0 := b.NewValue0(v.Line, OpConstNil, TypeInvalid)
+                       v0.Type = config.fe.TypeBytePtr()
+                       v.AddArg(v0)
+                       v1 := b.NewValue0(v.Line, OpConstNil, TypeInvalid)
+                       v1.Type = config.fe.TypeBytePtr()
+                       v.AddArg(v1)
+                       return true
+               }
+               goto end0367bd8f20a320cc41568f2b28657f6b
+       end0367bd8f20a320cc41568f2b28657f6b:
+               ;
+       case OpConstSlice:
+               // match: (ConstSlice)
+               // cond:
+               // result: (SliceMake     (ConstNil <config.fe.TypeBytePtr()>)     (ConstPtr <config.fe.TypeUintptr()>)     (ConstPtr <config.fe.TypeUintptr()>))
+               {
+                       v.Op = OpSliceMake
+                       v.AuxInt = 0
+                       v.Aux = nil
+                       v.resetArgs()
+                       v0 := b.NewValue0(v.Line, OpConstNil, TypeInvalid)
+                       v0.Type = config.fe.TypeBytePtr()
+                       v.AddArg(v0)
+                       v1 := b.NewValue0(v.Line, OpConstPtr, TypeInvalid)
+                       v1.Type = config.fe.TypeUintptr()
+                       v.AddArg(v1)
+                       v2 := b.NewValue0(v.Line, OpConstPtr, TypeInvalid)
+                       v2.Type = config.fe.TypeUintptr()
+                       v.AddArg(v2)
+                       return true
+               }
+               goto endfd2d8ffcd55eaf8a5092a20c3ae61ba3
+       endfd2d8ffcd55eaf8a5092a20c3ae61ba3:
+               ;
        case OpConstString:
                // match: (ConstString {s})
                // cond:
-               // result: (StringMake (Addr <config.Frontend().TypeBytePtr()> {config.fe.StringData(s.(string))} (SB <config.Frontend().TypeUintptr()>)) (ConstPtr <config.Frontend().TypeUintptr()> [int64(len(s.(string)))]))
+               // result: (StringMake     (Addr <config.fe.TypeBytePtr()> {config.fe.StringData(s.(string))}       (SB <config.fe.TypeUintptr()>))     (ConstPtr <config.fe.TypeUintptr()> [int64(len(s.(string)))]))
                {
                        s := v.Aux
                        v.Op = OpStringMake
@@ -248,20 +291,20 @@ func rewriteValuegeneric(v *Value, config *Config) bool {
                        v.Aux = nil
                        v.resetArgs()
                        v0 := b.NewValue0(v.Line, OpAddr, TypeInvalid)
-                       v0.Type = config.Frontend().TypeBytePtr()
+                       v0.Type = config.fe.TypeBytePtr()
                        v0.Aux = config.fe.StringData(s.(string))
                        v1 := b.NewValue0(v.Line, OpSB, TypeInvalid)
-                       v1.Type = config.Frontend().TypeUintptr()
+                       v1.Type = config.fe.TypeUintptr()
                        v0.AddArg(v1)
                        v.AddArg(v0)
                        v2 := b.NewValue0(v.Line, OpConstPtr, TypeInvalid)
-                       v2.Type = config.Frontend().TypeUintptr()
+                       v2.Type = config.fe.TypeUintptr()
                        v2.AuxInt = int64(len(s.(string)))
                        v.AddArg(v2)
                        return true
                }
-               goto end68cc91679848c7c30bd8b0a8ed533843
-       end68cc91679848c7c30bd8b0a8ed533843:
+               goto end51a3d96f2d304db9a52f36ee6b29c14e
+       end51a3d96f2d304db9a52f36ee6b29c14e:
                ;
        case OpEq16:
                // match: (Eq16 x x)
@@ -362,33 +405,73 @@ func rewriteValuegeneric(v *Value, config *Config) bool {
                ;
                // match: (EqFat (Load ptr mem) (ConstNil))
                // cond:
-               // result: (EqPtr (Load <config.Frontend().TypeUintptr()> ptr mem) (ConstPtr <config.Frontend().TypeUintptr()> [0]))
+               // result: (EqPtr (Load <config.fe.TypeUintptr()> ptr mem) (ConstPtr <config.fe.TypeUintptr()> [0]))
                {
                        if v.Args[0].Op != OpLoad {
-                               goto end540dc8dfbc66adcd3db2d7e819c534f6
+                               goto ende10070e5ddd3dc059674d25ccc6a63b5
                        }
                        ptr := v.Args[0].Args[0]
                        mem := v.Args[0].Args[1]
                        if v.Args[1].Op != OpConstNil {
-                               goto end540dc8dfbc66adcd3db2d7e819c534f6
+                               goto ende10070e5ddd3dc059674d25ccc6a63b5
                        }
                        v.Op = OpEqPtr
                        v.AuxInt = 0
                        v.Aux = nil
                        v.resetArgs()
                        v0 := b.NewValue0(v.Line, OpLoad, TypeInvalid)
-                       v0.Type = config.Frontend().TypeUintptr()
+                       v0.Type = config.fe.TypeUintptr()
                        v0.AddArg(ptr)
                        v0.AddArg(mem)
                        v.AddArg(v0)
                        v1 := b.NewValue0(v.Line, OpConstPtr, TypeInvalid)
-                       v1.Type = config.Frontend().TypeUintptr()
+                       v1.Type = config.fe.TypeUintptr()
                        v1.AuxInt = 0
                        v.AddArg(v1)
                        return true
                }
-               goto end540dc8dfbc66adcd3db2d7e819c534f6
-       end540dc8dfbc66adcd3db2d7e819c534f6:
+               goto ende10070e5ddd3dc059674d25ccc6a63b5
+       ende10070e5ddd3dc059674d25ccc6a63b5:
+               ;
+       case OpIData:
+               // match: (IData (IMake _ data))
+               // cond:
+               // result: data
+               {
+                       if v.Args[0].Op != OpIMake {
+                               goto endbfa1bb944cdc07933effb16a35152e12
+                       }
+                       data := v.Args[0].Args[1]
+                       v.Op = OpCopy
+                       v.AuxInt = 0
+                       v.Aux = nil
+                       v.resetArgs()
+                       v.Type = data.Type
+                       v.AddArg(data)
+                       return true
+               }
+               goto endbfa1bb944cdc07933effb16a35152e12
+       endbfa1bb944cdc07933effb16a35152e12:
+               ;
+       case OpITab:
+               // match: (ITab (IMake itab _))
+               // cond:
+               // result: itab
+               {
+                       if v.Args[0].Op != OpIMake {
+                               goto endfcbb9414a776ff9c8512da3e0f4d8fbd
+                       }
+                       itab := v.Args[0].Args[0]
+                       v.Op = OpCopy
+                       v.AuxInt = 0
+                       v.Aux = nil
+                       v.resetArgs()
+                       v.Type = itab.Type
+                       v.AddArg(itab)
+                       return true
+               }
+               goto endfcbb9414a776ff9c8512da3e0f4d8fbd
+       endfcbb9414a776ff9c8512da3e0f4d8fbd:
                ;
        case OpIsInBounds:
                // match: (IsInBounds (Const32 [c]) (Const32 [d]))
@@ -488,36 +571,111 @@ func rewriteValuegeneric(v *Value, config *Config) bool {
        case OpLoad:
                // match: (Load <t> ptr mem)
                // cond: t.IsString()
-               // result: (StringMake (Load <config.Frontend().TypeBytePtr()> ptr mem) (Load <config.Frontend().TypeUintptr()> (OffPtr <config.Frontend().TypeBytePtr()> [config.PtrSize] ptr) mem))
+               // result: (StringMake     (Load <config.fe.TypeBytePtr()> ptr mem)     (Load <config.fe.TypeUintptr()>       (OffPtr <config.fe.TypeUintptr().PtrTo()> [config.PtrSize] ptr)       mem))
                {
                        t := v.Type
                        ptr := v.Args[0]
                        mem := v.Args[1]
                        if !(t.IsString()) {
-                               goto end18afa4a6fdd6d0b92ed292840898c8f6
+                               goto end7c75255555bf9dd796298d9f6eaf9cf2
                        }
                        v.Op = OpStringMake
                        v.AuxInt = 0
                        v.Aux = nil
                        v.resetArgs()
                        v0 := b.NewValue0(v.Line, OpLoad, TypeInvalid)
-                       v0.Type = config.Frontend().TypeBytePtr()
+                       v0.Type = config.fe.TypeBytePtr()
+                       v0.AddArg(ptr)
+                       v0.AddArg(mem)
+                       v.AddArg(v0)
+                       v1 := b.NewValue0(v.Line, OpLoad, TypeInvalid)
+                       v1.Type = config.fe.TypeUintptr()
+                       v2 := b.NewValue0(v.Line, OpOffPtr, TypeInvalid)
+                       v2.Type = config.fe.TypeUintptr().PtrTo()
+                       v2.AuxInt = config.PtrSize
+                       v2.AddArg(ptr)
+                       v1.AddArg(v2)
+                       v1.AddArg(mem)
+                       v.AddArg(v1)
+                       return true
+               }
+               goto end7c75255555bf9dd796298d9f6eaf9cf2
+       end7c75255555bf9dd796298d9f6eaf9cf2:
+               ;
+               // match: (Load <t> ptr mem)
+               // cond: t.IsSlice()
+               // result: (SliceMake     (Load <config.fe.TypeBytePtr()> ptr mem)     (Load <config.fe.TypeUintptr()>       (OffPtr <config.fe.TypeUintptr().PtrTo()> [config.PtrSize] ptr)       mem)     (Load <config.fe.TypeUintptr()>       (OffPtr <config.fe.TypeUintptr().PtrTo()> [2*config.PtrSize] ptr)       mem))
+               {
+                       t := v.Type
+                       ptr := v.Args[0]
+                       mem := v.Args[1]
+                       if !(t.IsSlice()) {
+                               goto end12c46556d962198680eb3238859e3016
+                       }
+                       v.Op = OpSliceMake
+                       v.AuxInt = 0
+                       v.Aux = nil
+                       v.resetArgs()
+                       v0 := b.NewValue0(v.Line, OpLoad, TypeInvalid)
+                       v0.Type = config.fe.TypeBytePtr()
                        v0.AddArg(ptr)
                        v0.AddArg(mem)
                        v.AddArg(v0)
                        v1 := b.NewValue0(v.Line, OpLoad, TypeInvalid)
-                       v1.Type = config.Frontend().TypeUintptr()
+                       v1.Type = config.fe.TypeUintptr()
                        v2 := b.NewValue0(v.Line, OpOffPtr, TypeInvalid)
-                       v2.Type = config.Frontend().TypeBytePtr()
+                       v2.Type = config.fe.TypeUintptr().PtrTo()
                        v2.AuxInt = config.PtrSize
                        v2.AddArg(ptr)
                        v1.AddArg(v2)
                        v1.AddArg(mem)
                        v.AddArg(v1)
+                       v3 := b.NewValue0(v.Line, OpLoad, TypeInvalid)
+                       v3.Type = config.fe.TypeUintptr()
+                       v4 := b.NewValue0(v.Line, OpOffPtr, TypeInvalid)
+                       v4.Type = config.fe.TypeUintptr().PtrTo()
+                       v4.AuxInt = 2 * config.PtrSize
+                       v4.AddArg(ptr)
+                       v3.AddArg(v4)
+                       v3.AddArg(mem)
+                       v.AddArg(v3)
                        return true
                }
-               goto end18afa4a6fdd6d0b92ed292840898c8f6
-       end18afa4a6fdd6d0b92ed292840898c8f6:
+               goto end12c46556d962198680eb3238859e3016
+       end12c46556d962198680eb3238859e3016:
+               ;
+               // match: (Load <t> ptr mem)
+               // cond: t.IsInterface()
+               // result: (IMake     (Load <config.fe.TypeBytePtr()> ptr mem)     (Load <config.fe.TypeBytePtr()>       (OffPtr <config.fe.TypeBytePtr().PtrTo()> [config.PtrSize] ptr)       mem))
+               {
+                       t := v.Type
+                       ptr := v.Args[0]
+                       mem := v.Args[1]
+                       if !(t.IsInterface()) {
+                               goto end12671c83ebe3ccbc8e53383765ee7675
+                       }
+                       v.Op = OpIMake
+                       v.AuxInt = 0
+                       v.Aux = nil
+                       v.resetArgs()
+                       v0 := b.NewValue0(v.Line, OpLoad, TypeInvalid)
+                       v0.Type = config.fe.TypeBytePtr()
+                       v0.AddArg(ptr)
+                       v0.AddArg(mem)
+                       v.AddArg(v0)
+                       v1 := b.NewValue0(v.Line, OpLoad, TypeInvalid)
+                       v1.Type = config.fe.TypeBytePtr()
+                       v2 := b.NewValue0(v.Line, OpOffPtr, TypeInvalid)
+                       v2.Type = config.fe.TypeBytePtr().PtrTo()
+                       v2.AuxInt = config.PtrSize
+                       v2.AddArg(ptr)
+                       v1.AddArg(v2)
+                       v1.AddArg(mem)
+                       v.AddArg(v1)
+                       return true
+               }
+               goto end12671c83ebe3ccbc8e53383765ee7675
+       end12671c83ebe3ccbc8e53383765ee7675:
                ;
        case OpMul64:
                // match: (Mul64 (Const64 [c]) (Const64 [d]))
@@ -664,33 +822,33 @@ func rewriteValuegeneric(v *Value, config *Config) bool {
                ;
                // match: (NeqFat (Load ptr mem) (ConstNil))
                // cond:
-               // result: (NeqPtr (Load <config.Frontend().TypeUintptr()> ptr mem) (ConstPtr <config.Frontend().TypeUintptr()> [0]))
+               // result: (NeqPtr (Load <config.fe.TypeUintptr()> ptr mem) (ConstPtr <config.fe.TypeUintptr()> [0]))
                {
                        if v.Args[0].Op != OpLoad {
-                               goto end67d723bb0f39a5c897816abcf411e5cf
+                               goto end423eea941d60473e73140e25f5818bfb
                        }
                        ptr := v.Args[0].Args[0]
                        mem := v.Args[0].Args[1]
                        if v.Args[1].Op != OpConstNil {
-                               goto end67d723bb0f39a5c897816abcf411e5cf
+                               goto end423eea941d60473e73140e25f5818bfb
                        }
                        v.Op = OpNeqPtr
                        v.AuxInt = 0
                        v.Aux = nil
                        v.resetArgs()
                        v0 := b.NewValue0(v.Line, OpLoad, TypeInvalid)
-                       v0.Type = config.Frontend().TypeUintptr()
+                       v0.Type = config.fe.TypeUintptr()
                        v0.AddArg(ptr)
                        v0.AddArg(mem)
                        v.AddArg(v0)
                        v1 := b.NewValue0(v.Line, OpConstPtr, TypeInvalid)
-                       v1.Type = config.Frontend().TypeUintptr()
+                       v1.Type = config.fe.TypeUintptr()
                        v1.AuxInt = 0
                        v.AddArg(v1)
                        return true
                }
-               goto end67d723bb0f39a5c897816abcf411e5cf
-       end67d723bb0f39a5c897816abcf411e5cf:
+               goto end423eea941d60473e73140e25f5818bfb
+       end423eea941d60473e73140e25f5818bfb:
                ;
        case OpOr16:
                // match: (Or16 x x)
@@ -775,7 +933,7 @@ func rewriteValuegeneric(v *Value, config *Config) bool {
        case OpPtrIndex:
                // match: (PtrIndex <t> ptr idx)
                // cond:
-               // result: (AddPtr ptr (MulPtr <config.Frontend().TypeUintptr()> idx (ConstPtr <config.Frontend().TypeUintptr()> [t.Elem().Size()])))
+               // result: (AddPtr ptr (MulPtr <config.fe.TypeUintptr()> idx (ConstPtr <config.fe.TypeUintptr()> [t.Elem().Size()])))
                {
                        t := v.Type
                        ptr := v.Args[0]
@@ -786,96 +944,201 @@ func rewriteValuegeneric(v *Value, config *Config) bool {
                        v.resetArgs()
                        v.AddArg(ptr)
                        v0 := b.NewValue0(v.Line, OpMulPtr, TypeInvalid)
-                       v0.Type = config.Frontend().TypeUintptr()
+                       v0.Type = config.fe.TypeUintptr()
                        v0.AddArg(idx)
                        v1 := b.NewValue0(v.Line, OpConstPtr, TypeInvalid)
-                       v1.Type = config.Frontend().TypeUintptr()
+                       v1.Type = config.fe.TypeUintptr()
                        v1.AuxInt = t.Elem().Size()
                        v0.AddArg(v1)
                        v.AddArg(v0)
                        return true
                }
-               goto endf7546737f42c76a99699f241d41f491a
-       endf7546737f42c76a99699f241d41f491a:
+               goto end1e1c5ef80c11231f89a5439cdda98359
+       end1e1c5ef80c11231f89a5439cdda98359:
                ;
        case OpSliceCap:
-               // match: (SliceCap (Load ptr mem))
+               // match: (SliceCap (SliceMake _ _ cap))
                // cond:
-               // result: (Load (AddPtr <ptr.Type> ptr (ConstPtr <config.Frontend().TypeUintptr()> [config.PtrSize*2])) mem)
+               // result: cap
                {
-                       if v.Args[0].Op != OpLoad {
-                               goto end6696811bf6bd45e505d24c1a15c68e70
+                       if v.Args[0].Op != OpSliceMake {
+                               goto end1bd11616743632b33b410964667fb3c6
                        }
-                       ptr := v.Args[0].Args[0]
-                       mem := v.Args[0].Args[1]
-                       v.Op = OpLoad
+                       cap := v.Args[0].Args[2]
+                       v.Op = OpCopy
                        v.AuxInt = 0
                        v.Aux = nil
                        v.resetArgs()
-                       v0 := b.NewValue0(v.Line, OpAddPtr, TypeInvalid)
-                       v0.Type = ptr.Type
-                       v0.AddArg(ptr)
-                       v1 := b.NewValue0(v.Line, OpConstPtr, TypeInvalid)
-                       v1.Type = config.Frontend().TypeUintptr()
-                       v1.AuxInt = config.PtrSize * 2
-                       v0.AddArg(v1)
-                       v.AddArg(v0)
-                       v.AddArg(mem)
+                       v.Type = cap.Type
+                       v.AddArg(cap)
                        return true
                }
-               goto end6696811bf6bd45e505d24c1a15c68e70
-       end6696811bf6bd45e505d24c1a15c68e70:
+               goto end1bd11616743632b33b410964667fb3c6
+       end1bd11616743632b33b410964667fb3c6:
                ;
        case OpSliceLen:
-               // match: (SliceLen (Load ptr mem))
+               // match: (SliceLen (SliceMake _ len _))
                // cond:
-               // result: (Load (AddPtr <ptr.Type> ptr (ConstPtr <config.Frontend().TypeUintptr()> [config.PtrSize])) mem)
+               // result: len
                {
-                       if v.Args[0].Op != OpLoad {
-                               goto end9844ce3e290e81355493141e653e37d5
+                       if v.Args[0].Op != OpSliceMake {
+                               goto endebb2090199d13e4c2ae52fb3e778f7fd
                        }
-                       ptr := v.Args[0].Args[0]
-                       mem := v.Args[0].Args[1]
-                       v.Op = OpLoad
+                       len := v.Args[0].Args[1]
+                       v.Op = OpCopy
                        v.AuxInt = 0
                        v.Aux = nil
                        v.resetArgs()
-                       v0 := b.NewValue0(v.Line, OpAddPtr, TypeInvalid)
-                       v0.Type = ptr.Type
-                       v0.AddArg(ptr)
-                       v1 := b.NewValue0(v.Line, OpConstPtr, TypeInvalid)
-                       v1.Type = config.Frontend().TypeUintptr()
-                       v1.AuxInt = config.PtrSize
-                       v0.AddArg(v1)
-                       v.AddArg(v0)
-                       v.AddArg(mem)
+                       v.Type = len.Type
+                       v.AddArg(len)
                        return true
                }
-               goto end9844ce3e290e81355493141e653e37d5
-       end9844ce3e290e81355493141e653e37d5:
+               goto endebb2090199d13e4c2ae52fb3e778f7fd
+       endebb2090199d13e4c2ae52fb3e778f7fd:
                ;
        case OpSlicePtr:
-               // match: (SlicePtr (Load ptr mem))
+               // match: (SlicePtr (SliceMake ptr _ _ ))
                // cond:
-               // result: (Load ptr mem)
+               // result: ptr
                {
-                       if v.Args[0].Op != OpLoad {
-                               goto end459613b83f95b65729d45c2ed663a153
+                       if v.Args[0].Op != OpSliceMake {
+                               goto end526acc0a705137a5d25577499206720b
                        }
                        ptr := v.Args[0].Args[0]
-                       mem := v.Args[0].Args[1]
-                       v.Op = OpLoad
+                       v.Op = OpCopy
                        v.AuxInt = 0
                        v.Aux = nil
                        v.resetArgs()
+                       v.Type = ptr.Type
                        v.AddArg(ptr)
-                       v.AddArg(mem)
                        return true
                }
-               goto end459613b83f95b65729d45c2ed663a153
-       end459613b83f95b65729d45c2ed663a153:
+               goto end526acc0a705137a5d25577499206720b
+       end526acc0a705137a5d25577499206720b:
                ;
        case OpStore:
+               // match: (Store [2*config.PtrSize] dst (StringMake ptr len) mem)
+               // cond:
+               // result: (Store [config.PtrSize]     (OffPtr <config.fe.TypeUintptr().PtrTo()> [config.PtrSize] dst)     len     (Store <TypeMem> [config.PtrSize] dst ptr mem))
+               {
+                       if v.AuxInt != 2*config.PtrSize {
+                               goto end25ae4fc3dc01583a4adc45067d49940a
+                       }
+                       dst := v.Args[0]
+                       if v.Args[1].Op != OpStringMake {
+                               goto end25ae4fc3dc01583a4adc45067d49940a
+                       }
+                       ptr := v.Args[1].Args[0]
+                       len := v.Args[1].Args[1]
+                       mem := v.Args[2]
+                       v.Op = OpStore
+                       v.AuxInt = 0
+                       v.Aux = nil
+                       v.resetArgs()
+                       v.AuxInt = config.PtrSize
+                       v0 := b.NewValue0(v.Line, OpOffPtr, TypeInvalid)
+                       v0.Type = config.fe.TypeUintptr().PtrTo()
+                       v0.AuxInt = config.PtrSize
+                       v0.AddArg(dst)
+                       v.AddArg(v0)
+                       v.AddArg(len)
+                       v1 := b.NewValue0(v.Line, OpStore, TypeInvalid)
+                       v1.Type = TypeMem
+                       v1.AuxInt = config.PtrSize
+                       v1.AddArg(dst)
+                       v1.AddArg(ptr)
+                       v1.AddArg(mem)
+                       v.AddArg(v1)
+                       return true
+               }
+               goto end25ae4fc3dc01583a4adc45067d49940a
+       end25ae4fc3dc01583a4adc45067d49940a:
+               ;
+               // match: (Store [3*config.PtrSize] dst (SliceMake ptr len cap) mem)
+               // cond:
+               // result: (Store [config.PtrSize]     (OffPtr <config.fe.TypeUintptr().PtrTo()> [2*config.PtrSize] dst)     cap     (Store <TypeMem> [config.PtrSize]       (OffPtr <config.fe.TypeUintptr().PtrTo()> [config.PtrSize] dst)       len       (Store <TypeMem> [config.PtrSize] dst ptr mem)))
+               {
+                       if v.AuxInt != 3*config.PtrSize {
+                               goto end39ab85d51c8cd7f5d54e3eea4fb79a96
+                       }
+                       dst := v.Args[0]
+                       if v.Args[1].Op != OpSliceMake {
+                               goto end39ab85d51c8cd7f5d54e3eea4fb79a96
+                       }
+                       ptr := v.Args[1].Args[0]
+                       len := v.Args[1].Args[1]
+                       cap := v.Args[1].Args[2]
+                       mem := v.Args[2]
+                       v.Op = OpStore
+                       v.AuxInt = 0
+                       v.Aux = nil
+                       v.resetArgs()
+                       v.AuxInt = config.PtrSize
+                       v0 := b.NewValue0(v.Line, OpOffPtr, TypeInvalid)
+                       v0.Type = config.fe.TypeUintptr().PtrTo()
+                       v0.AuxInt = 2 * config.PtrSize
+                       v0.AddArg(dst)
+                       v.AddArg(v0)
+                       v.AddArg(cap)
+                       v1 := b.NewValue0(v.Line, OpStore, TypeInvalid)
+                       v1.Type = TypeMem
+                       v1.AuxInt = config.PtrSize
+                       v2 := b.NewValue0(v.Line, OpOffPtr, TypeInvalid)
+                       v2.Type = config.fe.TypeUintptr().PtrTo()
+                       v2.AuxInt = config.PtrSize
+                       v2.AddArg(dst)
+                       v1.AddArg(v2)
+                       v1.AddArg(len)
+                       v3 := b.NewValue0(v.Line, OpStore, TypeInvalid)
+                       v3.Type = TypeMem
+                       v3.AuxInt = config.PtrSize
+                       v3.AddArg(dst)
+                       v3.AddArg(ptr)
+                       v3.AddArg(mem)
+                       v1.AddArg(v3)
+                       v.AddArg(v1)
+                       return true
+               }
+               goto end39ab85d51c8cd7f5d54e3eea4fb79a96
+       end39ab85d51c8cd7f5d54e3eea4fb79a96:
+               ;
+               // match: (Store [2*config.PtrSize] dst (IMake itab data) mem)
+               // cond:
+               // result: (Store [config.PtrSize]     (OffPtr <config.fe.TypeBytePtr().PtrTo()> [config.PtrSize] dst)     data     (Store <TypeMem> [config.PtrSize] dst itab mem))
+               {
+                       if v.AuxInt != 2*config.PtrSize {
+                               goto end63b77ae78d92c05d496202e8b6b96ff3
+                       }
+                       dst := v.Args[0]
+                       if v.Args[1].Op != OpIMake {
+                               goto end63b77ae78d92c05d496202e8b6b96ff3
+                       }
+                       itab := v.Args[1].Args[0]
+                       data := v.Args[1].Args[1]
+                       mem := v.Args[2]
+                       v.Op = OpStore
+                       v.AuxInt = 0
+                       v.Aux = nil
+                       v.resetArgs()
+                       v.AuxInt = config.PtrSize
+                       v0 := b.NewValue0(v.Line, OpOffPtr, TypeInvalid)
+                       v0.Type = config.fe.TypeBytePtr().PtrTo()
+                       v0.AuxInt = config.PtrSize
+                       v0.AddArg(dst)
+                       v.AddArg(v0)
+                       v.AddArg(data)
+                       v1 := b.NewValue0(v.Line, OpStore, TypeInvalid)
+                       v1.Type = TypeMem
+                       v1.AuxInt = config.PtrSize
+                       v1.AddArg(dst)
+                       v1.AddArg(itab)
+                       v1.AddArg(mem)
+                       v.AddArg(v1)
+                       return true
+               }
+               goto end63b77ae78d92c05d496202e8b6b96ff3
+       end63b77ae78d92c05d496202e8b6b96ff3:
+               ;
                // match: (Store [size] dst (Load src mem) mem)
                // cond: size > config.IntSize
                // result: (Move [size] dst src mem)
@@ -906,48 +1169,6 @@ func rewriteValuegeneric(v *Value, config *Config) bool {
                goto enda18a7163888e2f4fca9f38bae56cef42
        enda18a7163888e2f4fca9f38bae56cef42:
                ;
-               // match: (Store [2*config.PtrSize] dst str mem)
-               // cond: str.Type.IsString()
-               // result: (Store [config.PtrSize] (OffPtr <config.Frontend().TypeBytePtr()> [config.PtrSize] dst) (StringLen <config.Frontend().TypeUintptr()> str) (Store [config.PtrSize] <TypeMem> dst (StringPtr <config.Frontend().TypeBytePtr()> str) mem))
-               {
-                       if v.AuxInt != 2*config.PtrSize {
-                               goto end6942df62f9cb570a99ab97a5aeebfd2d
-                       }
-                       dst := v.Args[0]
-                       str := v.Args[1]
-                       mem := v.Args[2]
-                       if !(str.Type.IsString()) {
-                               goto end6942df62f9cb570a99ab97a5aeebfd2d
-                       }
-                       v.Op = OpStore
-                       v.AuxInt = 0
-                       v.Aux = nil
-                       v.resetArgs()
-                       v.AuxInt = config.PtrSize
-                       v0 := b.NewValue0(v.Line, OpOffPtr, TypeInvalid)
-                       v0.Type = config.Frontend().TypeBytePtr()
-                       v0.AuxInt = config.PtrSize
-                       v0.AddArg(dst)
-                       v.AddArg(v0)
-                       v1 := b.NewValue0(v.Line, OpStringLen, TypeInvalid)
-                       v1.Type = config.Frontend().TypeUintptr()
-                       v1.AddArg(str)
-                       v.AddArg(v1)
-                       v2 := b.NewValue0(v.Line, OpStore, TypeInvalid)
-                       v2.AuxInt = config.PtrSize
-                       v2.Type = TypeMem
-                       v2.AddArg(dst)
-                       v3 := b.NewValue0(v.Line, OpStringPtr, TypeInvalid)
-                       v3.Type = config.Frontend().TypeBytePtr()
-                       v3.AddArg(str)
-                       v2.AddArg(v3)
-                       v2.AddArg(mem)
-                       v.AddArg(v2)
-                       return true
-               }
-               goto end6942df62f9cb570a99ab97a5aeebfd2d
-       end6942df62f9cb570a99ab97a5aeebfd2d:
-               ;
        case OpStringLen:
                // match: (StringLen (StringMake _ len))
                // cond:
index d6e8384cf09ae91cf7b5891a506ef7005d7ebc31..c6cc889420c7bf7ff9fc302d230a5e87024902ab 100644 (file)
@@ -18,6 +18,8 @@ type Type interface {
        IsFloat() bool
        IsPtr() bool
        IsString() bool
+       IsSlice() bool
+       IsInterface() bool
 
        IsMemory() bool // special ssa-package-only types
        IsFlags() bool
@@ -36,19 +38,21 @@ type CompilerType struct {
        Flags  bool
 }
 
-func (t *CompilerType) Size() int64      { return 0 }
-func (t *CompilerType) Alignment() int64 { return 0 }
-func (t *CompilerType) IsBoolean() bool  { return false }
-func (t *CompilerType) IsInteger() bool  { return false }
-func (t *CompilerType) IsSigned() bool   { return false }
-func (t *CompilerType) IsFloat() bool    { return false }
-func (t *CompilerType) IsPtr() bool      { return false }
-func (t *CompilerType) IsString() bool   { return false }
-func (t *CompilerType) IsMemory() bool   { return t.Memory }
-func (t *CompilerType) IsFlags() bool    { return t.Flags }
-func (t *CompilerType) String() string   { return t.Name }
-func (t *CompilerType) Elem() Type       { panic("not implemented") }
-func (t *CompilerType) PtrTo() Type      { panic("not implemented") }
+func (t *CompilerType) Size() int64       { return 0 }
+func (t *CompilerType) Alignment() int64  { return 0 }
+func (t *CompilerType) IsBoolean() bool   { return false }
+func (t *CompilerType) IsInteger() bool   { return false }
+func (t *CompilerType) IsSigned() bool    { return false }
+func (t *CompilerType) IsFloat() bool     { return false }
+func (t *CompilerType) IsPtr() bool       { return false }
+func (t *CompilerType) IsString() bool    { return false }
+func (t *CompilerType) IsSlice() bool     { return false }
+func (t *CompilerType) IsInterface() bool { return false }
+func (t *CompilerType) IsMemory() bool    { return t.Memory }
+func (t *CompilerType) IsFlags() bool     { return t.Flags }
+func (t *CompilerType) String() string    { return t.Name }
+func (t *CompilerType) Elem() Type        { panic("not implemented") }
+func (t *CompilerType) PtrTo() Type       { panic("not implemented") }
 
 func (t *CompilerType) Equal(u Type) bool {
        x, ok := u.(*CompilerType)
index 29bd5cd131fb7c3a1e11bff45373b75114415e9d..3dfa5f7c0b02fca52cf4606500edea77123c451f 100644 (file)
@@ -14,24 +14,28 @@ type TypeImpl struct {
        Float   bool
        Ptr     bool
        string  bool
+       slice   bool
+       inter   bool
        Elem_   Type
 
        Name string
 }
 
-func (t *TypeImpl) Size() int64      { return t.Size_ }
-func (t *TypeImpl) Alignment() int64 { return t.Align }
-func (t *TypeImpl) IsBoolean() bool  { return t.Boolean }
-func (t *TypeImpl) IsInteger() bool  { return t.Integer }
-func (t *TypeImpl) IsSigned() bool   { return t.Signed }
-func (t *TypeImpl) IsFloat() bool    { return t.Float }
-func (t *TypeImpl) IsPtr() bool      { return t.Ptr }
-func (t *TypeImpl) IsString() bool   { return t.string }
-func (t *TypeImpl) IsMemory() bool   { return false }
-func (t *TypeImpl) IsFlags() bool    { return false }
-func (t *TypeImpl) String() string   { return t.Name }
-func (t *TypeImpl) Elem() Type       { return t.Elem_ }
-func (t *TypeImpl) PtrTo() Type      { panic("not implemented") }
+func (t *TypeImpl) Size() int64       { return t.Size_ }
+func (t *TypeImpl) Alignment() int64  { return t.Align }
+func (t *TypeImpl) IsBoolean() bool   { return t.Boolean }
+func (t *TypeImpl) IsInteger() bool   { return t.Integer }
+func (t *TypeImpl) IsSigned() bool    { return t.Signed }
+func (t *TypeImpl) IsFloat() bool     { return t.Float }
+func (t *TypeImpl) IsPtr() bool       { return t.Ptr }
+func (t *TypeImpl) IsString() bool    { return t.string }
+func (t *TypeImpl) IsSlice() bool     { return t.slice }
+func (t *TypeImpl) IsInterface() bool { return t.inter }
+func (t *TypeImpl) IsMemory() bool    { return false }
+func (t *TypeImpl) IsFlags() bool     { return false }
+func (t *TypeImpl) String() string    { return t.Name }
+func (t *TypeImpl) Elem() Type        { return t.Elem_ }
+func (t *TypeImpl) PtrTo() Type       { panic("not implemented") }
 
 func (t *TypeImpl) Equal(u Type) bool {
        x, ok := u.(*TypeImpl)