1
0
mirror of https://github.com/golang/go synced 2024-10-05 16:41:21 -06:00

[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 <josharian@gmail.com>
This commit is contained in:
Keith Randall 2015-08-18 10:26:28 -07:00
parent 8d23681cc8
commit 9f954db170
11 changed files with 712 additions and 166 deletions

View 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.

View File

@ -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")
}
}

View 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
}

View 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

View File

@ -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
}

View File

@ -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.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)

View 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

View 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,

View 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,27 +571,27 @@ 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.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)
@ -516,8 +599,83 @@ func rewriteValuegeneric(v *Value, config *Config) bool {
v.AddArg(v1)
return true
}
goto end18afa4a6fdd6d0b92ed292840898c8f6
end18afa4a6fdd6d0b92ed292840898c8f6:
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.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)
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 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:

View 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)

View 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)