From 9f954db170dff18a33fbd333082cd8758851f936 Mon Sep 17 00:00:00 2001 From: Keith Randall Date: Tue, 18 Aug 2015 10:26:28 -0700 Subject: [PATCH] [dev.ssa] cmd/compile: add decompose pass 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 --- src/cmd/compile/internal/gc/ssa.go | 56 ++- .../internal/gc/testdata/compound_ssa.go | 91 ++++ src/cmd/compile/internal/gc/type.go | 4 + src/cmd/compile/internal/ssa/compile.go | 3 + src/cmd/compile/internal/ssa/decompose.go | 93 ++++ .../compile/internal/ssa/gen/generic.rules | 84 +++- .../compile/internal/ssa/gen/genericOps.go | 8 +- src/cmd/compile/internal/ssa/opGen.go | 20 + .../compile/internal/ssa/rewritegeneric.go | 459 +++++++++++++----- src/cmd/compile/internal/ssa/type.go | 30 +- src/cmd/compile/internal/ssa/type_test.go | 30 +- 11 files changed, 712 insertions(+), 166 deletions(-) create mode 100644 src/cmd/compile/internal/gc/testdata/compound_ssa.go create mode 100644 src/cmd/compile/internal/ssa/decompose.go diff --git a/src/cmd/compile/internal/gc/ssa.go b/src/cmd/compile/internal/gc/ssa.go index 1fb5485183..a324ed2a42 100644 --- a/src/cmd/compile/internal/gc/ssa.go +++ b/src/cmd/compile/internal/gc/ssa.go @@ -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 index 0000000000..9b84ce4b11 --- /dev/null +++ b/src/cmd/compile/internal/gc/testdata/compound_ssa.go @@ -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") + } +} diff --git a/src/cmd/compile/internal/gc/type.go b/src/cmd/compile/internal/gc/type.go index f60d01b3bb..bcad025ba6 100644 --- a/src/cmd/compile/internal/gc/type.go +++ b/src/cmd/compile/internal/gc/type.go @@ -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 } diff --git a/src/cmd/compile/internal/ssa/compile.go b/src/cmd/compile/internal/ssa/compile.go index e85fb10e00..7413e721fe 100644 --- a/src/cmd/compile/internal/ssa/compile.go +++ b/src/cmd/compile/internal/ssa/compile.go @@ -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 index 0000000000..534ffc269e --- /dev/null +++ b/src/cmd/compile/internal/ssa/decompose.go @@ -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 +} diff --git a/src/cmd/compile/internal/ssa/gen/generic.rules b/src/cmd/compile/internal/ssa/gen/generic.rules index db66a457c3..7be00569ea 100644 --- a/src/cmd/compile/internal/ssa/gen/generic.rules +++ b/src/cmd/compile/internal/ssa/gen/generic.rules @@ -59,36 +59,90 @@ (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 (ConstPtr [config.PtrSize])) mem) -(SliceCap (Load ptr mem)) -> (Load (AddPtr ptr (ConstPtr [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 ptr mem) (ConstPtr [0])) -(NeqFat (Load ptr mem) (ConstNil)) -> (NeqPtr (Load ptr mem) (ConstPtr [0])) +(EqFat (Load ptr mem) (ConstNil)) -> (EqPtr (Load ptr mem) (ConstPtr [0])) +(NeqFat (Load ptr mem) (ConstNil)) -> (NeqPtr (Load ptr mem) (ConstPtr [0])) // indexing operations // Note: bounds check has already been done (ArrayIndex (Load ptr mem) idx) -> (Load (PtrIndex ptr idx) mem) -(PtrIndex ptr idx) -> (AddPtr ptr (MulPtr idx (ConstPtr [t.Elem().Size()]))) +(PtrIndex ptr idx) -> (AddPtr ptr (MulPtr idx (ConstPtr [t.Elem().Size()]))) (StructSelect [idx] (Load ptr mem)) -> (Load (OffPtr [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.fe.StringData(s.(string))} (SB )) (ConstPtr [int64(len(s.(string)))])) -(Load ptr mem) && t.IsString() -> (StringMake (Load ptr mem) (Load (OffPtr [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.PtrSize] dst) (StringLen str) (Store [config.PtrSize] dst (StringPtr str) mem)) +(ConstString {s}) -> + (StringMake + (Addr {config.fe.StringData(s.(string))} + (SB )) + (ConstPtr [int64(len(s.(string)))])) +(Load ptr mem) && t.IsString() -> + (StringMake + (Load ptr mem) + (Load + (OffPtr [config.PtrSize] ptr) + mem)) +(Store [2*config.PtrSize] dst (StringMake ptr len) mem) -> + (Store [config.PtrSize] + (OffPtr [config.PtrSize] dst) + len + (Store [config.PtrSize] dst ptr mem)) + +// slice ops +(SlicePtr (SliceMake ptr _ _ )) -> ptr +(SliceLen (SliceMake _ len _)) -> len +(SliceCap (SliceMake _ _ cap)) -> cap +(ConstSlice) -> + (SliceMake + (ConstNil ) + (ConstPtr ) + (ConstPtr )) + +(Load ptr mem) && t.IsSlice() -> + (SliceMake + (Load ptr mem) + (Load + (OffPtr [config.PtrSize] ptr) + mem) + (Load + (OffPtr [2*config.PtrSize] ptr) + mem)) +(Store [3*config.PtrSize] dst (SliceMake ptr len cap) mem) -> + (Store [config.PtrSize] + (OffPtr [2*config.PtrSize] dst) + cap + (Store [config.PtrSize] + (OffPtr [config.PtrSize] dst) + len + (Store [config.PtrSize] dst ptr mem))) + +// interface ops +(ITab (IMake itab _)) -> itab +(IData (IMake _ data)) -> data +(ConstInterface) -> + (IMake + (ConstNil ) + (ConstNil )) +(Load ptr mem) && t.IsInterface() -> + (IMake + (Load ptr mem) + (Load + (OffPtr [config.PtrSize] ptr) + mem)) +(Store [2*config.PtrSize] dst (IMake itab data) mem) -> + (Store [config.PtrSize] + (OffPtr [config.PtrSize] dst) + data + (Store [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) diff --git a/src/cmd/compile/internal/ssa/gen/genericOps.go b/src/cmd/compile/internal/ssa/gen/genericOps.go index 2024788c5d..5b8b064bb5 100644 --- a/src/cmd/compile/internal/ssa/gen/genericOps.go +++ b/src/cmd/compile/internal/ssa/gen/genericOps.go @@ -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 diff --git a/src/cmd/compile/internal/ssa/opGen.go b/src/cmd/compile/internal/ssa/opGen.go index 003aacffbb..17d4edb221 100644 --- a/src/cmd/compile/internal/ssa/opGen.go +++ b/src/cmd/compile/internal/ssa/opGen.go @@ -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, diff --git a/src/cmd/compile/internal/ssa/rewritegeneric.go b/src/cmd/compile/internal/ssa/rewritegeneric.go index 4c278cb168..bd53e05230 100644 --- a/src/cmd/compile/internal/ssa/rewritegeneric.go +++ b/src/cmd/compile/internal/ssa/rewritegeneric.go @@ -237,10 +237,53 @@ func rewriteValuegeneric(v *Value, config *Config) bool { goto end4d92ff3ba567d9afd38fc9ca113602ad end4d92ff3ba567d9afd38fc9ca113602ad: ; + case OpConstInterface: + // match: (ConstInterface) + // cond: + // result: (IMake (ConstNil ) (ConstNil )) + { + 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 ) (ConstPtr ) (ConstPtr )) + { + 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.fe.StringData(s.(string))} (SB )) (ConstPtr [int64(len(s.(string)))])) + // result: (StringMake (Addr {config.fe.StringData(s.(string))} (SB )) (ConstPtr [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 ptr mem) (ConstPtr [0])) + // result: (EqPtr (Load ptr mem) (ConstPtr [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 ptr mem) // cond: t.IsString() - // result: (StringMake (Load ptr mem) (Load (OffPtr [config.PtrSize] ptr) mem)) + // result: (StringMake (Load ptr mem) (Load (OffPtr [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 ptr mem) + // cond: t.IsSlice() + // result: (SliceMake (Load ptr mem) (Load (OffPtr [config.PtrSize] ptr) mem) (Load (OffPtr [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 ptr mem) + // cond: t.IsInterface() + // result: (IMake (Load ptr mem) (Load (OffPtr [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 ptr mem) (ConstPtr [0])) + // result: (NeqPtr (Load ptr mem) (ConstPtr [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 ptr idx) // cond: - // result: (AddPtr ptr (MulPtr idx (ConstPtr [t.Elem().Size()]))) + // result: (AddPtr ptr (MulPtr idx (ConstPtr [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 (ConstPtr [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 (ConstPtr [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.PtrSize] dst) len (Store [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 [2*config.PtrSize] dst) cap (Store [config.PtrSize] (OffPtr [config.PtrSize] dst) len (Store [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.PtrSize] dst) data (Store [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.PtrSize] dst) (StringLen str) (Store [config.PtrSize] dst (StringPtr 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: diff --git a/src/cmd/compile/internal/ssa/type.go b/src/cmd/compile/internal/ssa/type.go index d6e8384cf0..c6cc889420 100644 --- a/src/cmd/compile/internal/ssa/type.go +++ b/src/cmd/compile/internal/ssa/type.go @@ -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) diff --git a/src/cmd/compile/internal/ssa/type_test.go b/src/cmd/compile/internal/ssa/type_test.go index 29bd5cd131..3dfa5f7c0b 100644 --- a/src/cmd/compile/internal/ssa/type_test.go +++ b/src/cmd/compile/internal/ssa/type_test.go @@ -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) -- 2.48.1