Some optimizations of things I've seen looking at generated code.
(x+y)-x == y
x-0 == x
The ptr portion of the constant string "" can be nil.
Also update TODO with recent changes.
Change-Id: I02c41ca2f9e9e178bf889058d3e083b446672dbe
Reviewed-on: https://go-review.googlesource.com/16771
Run-TryBot: Keith Randall <khr@golang.org>
Reviewed-by: David Chase <drchase@google.com>
Correctness
-----------
-- Write barriers
-- Debugging info
-- Can/should we move control values out of their basic block?
-- Anything to do for the race detector?
-- Slicing details (avoid ptr to next object) [done for string]
+- Debugging info (check & fix as much as we can)
Optimizations (better compiled code)
------------------------------------
- Strength reduction: constant divides -> multiply
- Expand current optimizations to all bit widths
- Add a value range propagation pass (for bounds elim & bitwidth reduction)
-- Combining nil checks with subsequent load
-- Implement memory zeroing with REPSTOSQ and DuffZero
-- Implement memory copying with REPMOVSQ and DuffCopy
-- Stackalloc: organize values to allow good packing
-- Regalloc: use arg slots as the home for arguments (don't copy args to locals)
-- Reuse stack slots for noninterfering & compatible values (but see issue 8740)
+- Make dead store pass inter-block
- (x86) Combine loads into other ops
- (x86) More combining address arithmetic into loads/stores
+- (x86) use ADDQ instead of LEAQ when we can
+- redundant CMP in sequences like this:
+ SUBQ $8, AX
+ CMP AX, $0
+ JEQ ...
+- Use better write barrier calls
Optimizations (better compiler)
-------------------------------
Regalloc
--------
- Make less arch-dependent
-- Allow args and return values to be ssa-able
+- Allow return values to be ssa-able
- Handle 2-address instructions
- Make liveness analysis non-quadratic
-- Materialization of constants
Future/other
------------
(MOVSDstore [off1] {sym1} (LEAQ8 [off2] {sym2} ptr idx) val mem) && canMergeSym(sym1, sym2) ->
(MOVSDstoreidx8 [addOff(off1, off2)] {mergeSym(sym1,sym2)} ptr idx val mem)
-(ADDQconst [0] x) -> x
-
// lower Zero instructions with word sizes
(Zero [0] _ mem) -> mem
(Zero [1] destptr mem) -> (MOVBstoreconst [0] destptr mem)
(SBBLcarrymask (CMPWconst [c] (MOVWconst [d]))) && !inBounds16(d, c) -> (MOVLconst [0])
(SBBLcarrymask (CMPBconst [c] (MOVBconst [d]))) && inBounds8(d, c) -> (MOVLconst [-1])
(SBBLcarrymask (CMPBconst [c] (MOVBconst [d]))) && !inBounds8(d, c) -> (MOVLconst [0])
+
+// Remove redundant *const ops
+(ADDQconst [0] x) -> x
+(ADDLconst [c] x) && int32(c)==0 -> x
+(ADDWconst [c] x) && int16(c)==0 -> x
+(ADDBconst [c] x) && int8(c)==0 -> x
+(SUBQconst [0] x) -> x
+(SUBLconst [c] x) && int32(c) == 0 -> x
+(SUBWconst [c] x) && int16(c) == 0 -> x
+(SUBBconst [c] x) && int8(c) == 0 -> x
(ANDQconst [0] _) -> (MOVQconst [0])
(ANDLconst [c] _) && int32(c)==0 -> (MOVLconst [0])
(ANDWconst [c] _) && int16(c)==0 -> (MOVWconst [0])
(ORLconst [c] _) && int32(c)==-1 -> (MOVLconst [-1])
(ORWconst [c] _) && int16(c)==-1 -> (MOVWconst [-1])
(ORBconst [c] _) && int8(c)==-1 -> (MOVBconst [-1])
+(XORQconst [0] x) -> x
+(XORLconst [c] x) && int32(c)==0 -> x
+(XORWconst [c] x) && int16(c)==0 -> x
+(XORBconst [c] x) && int8(c)==0 -> x
// generic constant folding
// TODO: more of this
(XORL x x) -> (MOVLconst [0])
(XORW x x) -> (MOVWconst [0])
(XORB x x) -> (MOVBconst [0])
+
(Com32 (Com32 x)) -> x
(Com64 (Com64 x)) -> x
+// simplifications often used for lengths. e.g. len(s[i:i+5])==5
+(Sub64 (Add64 x y) x) -> y
+(Sub64 (Add64 x y) y) -> x
+(Sub32 (Add32 x y) x) -> y
+(Sub32 (Add32 x y) y) -> x
+(Sub16 (Add16 x y) x) -> y
+(Sub16 (Add16 x y) y) -> x
+(Sub8 (Add8 x y) x) -> y
+(Sub8 (Add8 x y) y) -> x
+
// user nil checks
(NeqPtr p (ConstNil)) -> (IsNonNil p)
(NeqPtr (ConstNil) p) -> (IsNonNil p)
// string ops
(StringPtr (StringMake ptr _)) -> ptr
(StringLen (StringMake _ len)) -> len
-(ConstString {s}) && config.PtrSize == 4 ->
+(ConstString {s}) && config.PtrSize == 4 && s.(string) == "" ->
+ (StringMake (ConstNil) (Const32 <config.fe.TypeInt()> [0]))
+(ConstString {s}) && config.PtrSize == 8 && s.(string) == "" ->
+ (StringMake (ConstNil) (Const64 <config.fe.TypeInt()> [0]))
+(ConstString {s}) && config.PtrSize == 4 && s.(string) != "" ->
(StringMake
(Addr <config.fe.TypeBytePtr()> {config.fe.StringData(s.(string))}
(SB))
(Const32 <config.fe.TypeInt()> [int64(len(s.(string)))]))
-(ConstString {s}) && config.PtrSize == 8 ->
+(ConstString {s}) && config.PtrSize == 8 && s.(string) != "" ->
(StringMake
(Addr <config.fe.TypeBytePtr()> {config.fe.StringData(s.(string))}
(SB))
// bits of the AuxInt field matter.
{name: "ConstBool"},
{name: "ConstString"},
- {name: "ConstNil"},
+ {name: "ConstNil", typ: "BytePtr"},
{name: "Const8"},
{name: "Const16"},
{name: "Const32"},
func rewriteValueAMD64_OpAMD64ADDBconst(v *Value, config *Config) bool {
b := v.Block
_ = b
+ // match: (ADDBconst [c] x)
+ // cond: int8(c)==0
+ // result: x
+ {
+ c := v.AuxInt
+ x := v.Args[0]
+ if !(int8(c) == 0) {
+ goto end3fbe38dfc1de8f48c755862c4c8b6bac
+ }
+ v.Op = OpCopy
+ v.AuxInt = 0
+ v.Aux = nil
+ v.resetArgs()
+ v.Type = x.Type
+ v.AddArg(x)
+ return true
+ }
+ goto end3fbe38dfc1de8f48c755862c4c8b6bac
+end3fbe38dfc1de8f48c755862c4c8b6bac:
+ ;
// match: (ADDBconst [c] (MOVBconst [d]))
// cond:
// result: (MOVBconst [c+d])
func rewriteValueAMD64_OpAMD64ADDLconst(v *Value, config *Config) bool {
b := v.Block
_ = b
+ // match: (ADDLconst [c] x)
+ // cond: int32(c)==0
+ // result: x
+ {
+ c := v.AuxInt
+ x := v.Args[0]
+ if !(int32(c) == 0) {
+ goto endf04fb6232fbd3b460bb0d1bdcdc57d65
+ }
+ v.Op = OpCopy
+ v.AuxInt = 0
+ v.Aux = nil
+ v.resetArgs()
+ v.Type = x.Type
+ v.AddArg(x)
+ return true
+ }
+ goto endf04fb6232fbd3b460bb0d1bdcdc57d65
+endf04fb6232fbd3b460bb0d1bdcdc57d65:
+ ;
// match: (ADDLconst [c] (MOVLconst [d]))
// cond:
// result: (MOVLconst [c+d])
func rewriteValueAMD64_OpAMD64ADDWconst(v *Value, config *Config) bool {
b := v.Block
_ = b
+ // match: (ADDWconst [c] x)
+ // cond: int16(c)==0
+ // result: x
+ {
+ c := v.AuxInt
+ x := v.Args[0]
+ if !(int16(c) == 0) {
+ goto end8564670ff18b2a91eb92d5e5775464cd
+ }
+ v.Op = OpCopy
+ v.AuxInt = 0
+ v.Aux = nil
+ v.resetArgs()
+ v.Type = x.Type
+ v.AddArg(x)
+ return true
+ }
+ goto end8564670ff18b2a91eb92d5e5775464cd
+end8564670ff18b2a91eb92d5e5775464cd:
+ ;
// match: (ADDWconst [c] (MOVWconst [d]))
// cond:
// result: (MOVWconst [c+d])
func rewriteValueAMD64_OpAMD64SUBBconst(v *Value, config *Config) bool {
b := v.Block
_ = b
+ // match: (SUBBconst [c] x)
+ // cond: int8(c) == 0
+ // result: x
+ {
+ c := v.AuxInt
+ x := v.Args[0]
+ if !(int8(c) == 0) {
+ goto end974a26e947badc62fc104581f49138e6
+ }
+ v.Op = OpCopy
+ v.AuxInt = 0
+ v.Aux = nil
+ v.resetArgs()
+ v.Type = x.Type
+ v.AddArg(x)
+ return true
+ }
+ goto end974a26e947badc62fc104581f49138e6
+end974a26e947badc62fc104581f49138e6:
+ ;
// match: (SUBBconst [c] (MOVBconst [d]))
// cond:
// result: (MOVBconst [d-c])
func rewriteValueAMD64_OpAMD64SUBLconst(v *Value, config *Config) bool {
b := v.Block
_ = b
+ // match: (SUBLconst [c] x)
+ // cond: int32(c) == 0
+ // result: x
+ {
+ c := v.AuxInt
+ x := v.Args[0]
+ if !(int32(c) == 0) {
+ goto end3fa10eaa42f9e283cf1757e1b2d3cac2
+ }
+ v.Op = OpCopy
+ v.AuxInt = 0
+ v.Aux = nil
+ v.resetArgs()
+ v.Type = x.Type
+ v.AddArg(x)
+ return true
+ }
+ goto end3fa10eaa42f9e283cf1757e1b2d3cac2
+end3fa10eaa42f9e283cf1757e1b2d3cac2:
+ ;
// match: (SUBLconst [c] (MOVLconst [d]))
// cond:
// result: (MOVLconst [d-c])
func rewriteValueAMD64_OpAMD64SUBQconst(v *Value, config *Config) bool {
b := v.Block
_ = b
+ // match: (SUBQconst [0] x)
+ // cond:
+ // result: x
+ {
+ if v.AuxInt != 0 {
+ goto endfce1d3cec7c543c9dd80a27d944eb09e
+ }
+ x := v.Args[0]
+ v.Op = OpCopy
+ v.AuxInt = 0
+ v.Aux = nil
+ v.resetArgs()
+ v.Type = x.Type
+ v.AddArg(x)
+ return true
+ }
+ goto endfce1d3cec7c543c9dd80a27d944eb09e
+endfce1d3cec7c543c9dd80a27d944eb09e:
+ ;
// match: (SUBQconst [c] (MOVQconst [d]))
// cond:
// result: (MOVQconst [d-c])
func rewriteValueAMD64_OpAMD64SUBWconst(v *Value, config *Config) bool {
b := v.Block
_ = b
+ // match: (SUBWconst [c] x)
+ // cond: int16(c) == 0
+ // result: x
+ {
+ c := v.AuxInt
+ x := v.Args[0]
+ if !(int16(c) == 0) {
+ goto end1e7a493992465c9cc8314e3256ed6394
+ }
+ v.Op = OpCopy
+ v.AuxInt = 0
+ v.Aux = nil
+ v.resetArgs()
+ v.Type = x.Type
+ v.AddArg(x)
+ return true
+ }
+ goto end1e7a493992465c9cc8314e3256ed6394
+end1e7a493992465c9cc8314e3256ed6394:
+ ;
// match: (SUBWconst [c] (MOVWconst [d]))
// cond:
// result: (MOVWconst [d-c])
func rewriteValueAMD64_OpAMD64XORBconst(v *Value, config *Config) bool {
b := v.Block
_ = b
+ // match: (XORBconst [c] x)
+ // cond: int8(c)==0
+ // result: x
+ {
+ c := v.AuxInt
+ x := v.Args[0]
+ if !(int8(c) == 0) {
+ goto end14b03b70e5579dfe3f9b243e02a887c3
+ }
+ v.Op = OpCopy
+ v.AuxInt = 0
+ v.Aux = nil
+ v.resetArgs()
+ v.Type = x.Type
+ v.AddArg(x)
+ return true
+ }
+ goto end14b03b70e5579dfe3f9b243e02a887c3
+end14b03b70e5579dfe3f9b243e02a887c3:
+ ;
// match: (XORBconst [c] (MOVBconst [d]))
// cond:
// result: (MOVBconst [c^d])
func rewriteValueAMD64_OpAMD64XORLconst(v *Value, config *Config) bool {
b := v.Block
_ = b
+ // match: (XORLconst [c] x)
+ // cond: int32(c)==0
+ // result: x
+ {
+ c := v.AuxInt
+ x := v.Args[0]
+ if !(int32(c) == 0) {
+ goto end99808ca9fb8e3220e42f5678e1042a08
+ }
+ v.Op = OpCopy
+ v.AuxInt = 0
+ v.Aux = nil
+ v.resetArgs()
+ v.Type = x.Type
+ v.AddArg(x)
+ return true
+ }
+ goto end99808ca9fb8e3220e42f5678e1042a08
+end99808ca9fb8e3220e42f5678e1042a08:
+ ;
// match: (XORLconst [c] (MOVLconst [d]))
// cond:
// result: (MOVLconst [c^d])
func rewriteValueAMD64_OpAMD64XORQconst(v *Value, config *Config) bool {
b := v.Block
_ = b
+ // match: (XORQconst [0] x)
+ // cond:
+ // result: x
+ {
+ if v.AuxInt != 0 {
+ goto end0ee8d195a97eff476cf1f69a4dc0ec75
+ }
+ x := v.Args[0]
+ v.Op = OpCopy
+ v.AuxInt = 0
+ v.Aux = nil
+ v.resetArgs()
+ v.Type = x.Type
+ v.AddArg(x)
+ return true
+ }
+ goto end0ee8d195a97eff476cf1f69a4dc0ec75
+end0ee8d195a97eff476cf1f69a4dc0ec75:
+ ;
// match: (XORQconst [c] (MOVQconst [d]))
// cond:
// result: (MOVQconst [c^d])
func rewriteValueAMD64_OpAMD64XORWconst(v *Value, config *Config) bool {
b := v.Block
_ = b
+ // match: (XORWconst [c] x)
+ // cond: int16(c)==0
+ // result: x
+ {
+ c := v.AuxInt
+ x := v.Args[0]
+ if !(int16(c) == 0) {
+ goto enda371132353dee83828836da851240f0a
+ }
+ v.Op = OpCopy
+ v.AuxInt = 0
+ v.Aux = nil
+ v.resetArgs()
+ v.Type = x.Type
+ v.AddArg(x)
+ return true
+ }
+ goto enda371132353dee83828836da851240f0a
+enda371132353dee83828836da851240f0a:
+ ;
// match: (XORWconst [c] (MOVWconst [d]))
// cond:
// result: (MOVWconst [c^d])
b := v.Block
_ = b
// match: (ConstString {s})
- // cond: config.PtrSize == 4
+ // cond: config.PtrSize == 4 && s.(string) == ""
+ // result: (StringMake (ConstNil) (Const32 <config.fe.TypeInt()> [0]))
+ {
+ s := v.Aux
+ if !(config.PtrSize == 4 && s.(string) == "") {
+ goto end85d5f388ba947643af63cdc68c1155a5
+ }
+ v.Op = OpStringMake
+ 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, OpConst32, TypeInvalid)
+ v1.Type = config.fe.TypeInt()
+ v1.AuxInt = 0
+ v.AddArg(v1)
+ return true
+ }
+ goto end85d5f388ba947643af63cdc68c1155a5
+end85d5f388ba947643af63cdc68c1155a5:
+ ;
+ // match: (ConstString {s})
+ // cond: config.PtrSize == 8 && s.(string) == ""
+ // result: (StringMake (ConstNil) (Const64 <config.fe.TypeInt()> [0]))
+ {
+ s := v.Aux
+ if !(config.PtrSize == 8 && s.(string) == "") {
+ goto endc807259a5ed2760fbbd3dc7386641343
+ }
+ v.Op = OpStringMake
+ 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, OpConst64, TypeInvalid)
+ v1.Type = config.fe.TypeInt()
+ v1.AuxInt = 0
+ v.AddArg(v1)
+ return true
+ }
+ goto endc807259a5ed2760fbbd3dc7386641343
+endc807259a5ed2760fbbd3dc7386641343:
+ ;
+ // match: (ConstString {s})
+ // cond: config.PtrSize == 4 && s.(string) != ""
// result: (StringMake (Addr <config.fe.TypeBytePtr()> {config.fe.StringData(s.(string))} (SB)) (Const32 <config.fe.TypeInt()> [int64(len(s.(string)))]))
{
s := v.Aux
- if !(config.PtrSize == 4) {
- goto endaa2b20a40588873f370c5a12f084505a
+ if !(config.PtrSize == 4 && s.(string) != "") {
+ goto end107a700a4519d18f418602421444ddb6
}
v.Op = OpStringMake
v.AuxInt = 0
v.AddArg(v2)
return true
}
- goto endaa2b20a40588873f370c5a12f084505a
-endaa2b20a40588873f370c5a12f084505a:
+ goto end107a700a4519d18f418602421444ddb6
+end107a700a4519d18f418602421444ddb6:
;
// match: (ConstString {s})
- // cond: config.PtrSize == 8
+ // cond: config.PtrSize == 8 && s.(string) != ""
// result: (StringMake (Addr <config.fe.TypeBytePtr()> {config.fe.StringData(s.(string))} (SB)) (Const64 <config.fe.TypeInt()> [int64(len(s.(string)))]))
{
s := v.Aux
- if !(config.PtrSize == 8) {
- goto endab37d89f3959d3cf1e71b57a3c61b8eb
+ if !(config.PtrSize == 8 && s.(string) != "") {
+ goto end7ce9db29d17866f26d21e6e12f442e54
}
v.Op = OpStringMake
v.AuxInt = 0
v.AddArg(v2)
return true
}
- goto endab37d89f3959d3cf1e71b57a3c61b8eb
-endab37d89f3959d3cf1e71b57a3c61b8eb:
+ goto end7ce9db29d17866f26d21e6e12f442e54
+end7ce9db29d17866f26d21e6e12f442e54:
;
return false
}
}
goto end83da541391be564f2a08464e674a49e7
end83da541391be564f2a08464e674a49e7:
+ ;
+ // match: (Sub16 (Add16 x y) x)
+ // cond:
+ // result: y
+ {
+ if v.Args[0].Op != OpAdd16 {
+ goto end0dd8f250c457b9c005ecbed59fc2e758
+ }
+ x := v.Args[0].Args[0]
+ y := v.Args[0].Args[1]
+ if v.Args[1] != x {
+ goto end0dd8f250c457b9c005ecbed59fc2e758
+ }
+ v.Op = OpCopy
+ v.AuxInt = 0
+ v.Aux = nil
+ v.resetArgs()
+ v.Type = y.Type
+ v.AddArg(y)
+ return true
+ }
+ goto end0dd8f250c457b9c005ecbed59fc2e758
+end0dd8f250c457b9c005ecbed59fc2e758:
+ ;
+ // match: (Sub16 (Add16 x y) y)
+ // cond:
+ // result: x
+ {
+ if v.Args[0].Op != OpAdd16 {
+ goto end01c8db2e0bce69e048cf79f3bdc82b9b
+ }
+ x := v.Args[0].Args[0]
+ y := v.Args[0].Args[1]
+ if v.Args[1] != y {
+ goto end01c8db2e0bce69e048cf79f3bdc82b9b
+ }
+ v.Op = OpCopy
+ v.AuxInt = 0
+ v.Aux = nil
+ v.resetArgs()
+ v.Type = x.Type
+ v.AddArg(x)
+ return true
+ }
+ goto end01c8db2e0bce69e048cf79f3bdc82b9b
+end01c8db2e0bce69e048cf79f3bdc82b9b:
;
return false
}
}
goto enda747581e798f199e07f4ad69747cd069
enda747581e798f199e07f4ad69747cd069:
+ ;
+ // match: (Sub32 (Add32 x y) x)
+ // cond:
+ // result: y
+ {
+ if v.Args[0].Op != OpAdd32 {
+ goto end70c1e60e58a6c106d060f10cd3f179ea
+ }
+ x := v.Args[0].Args[0]
+ y := v.Args[0].Args[1]
+ if v.Args[1] != x {
+ goto end70c1e60e58a6c106d060f10cd3f179ea
+ }
+ v.Op = OpCopy
+ v.AuxInt = 0
+ v.Aux = nil
+ v.resetArgs()
+ v.Type = y.Type
+ v.AddArg(y)
+ return true
+ }
+ goto end70c1e60e58a6c106d060f10cd3f179ea
+end70c1e60e58a6c106d060f10cd3f179ea:
+ ;
+ // match: (Sub32 (Add32 x y) y)
+ // cond:
+ // result: x
+ {
+ if v.Args[0].Op != OpAdd32 {
+ goto end20e42db178ec4f423cc56a991863a4a2
+ }
+ x := v.Args[0].Args[0]
+ y := v.Args[0].Args[1]
+ if v.Args[1] != y {
+ goto end20e42db178ec4f423cc56a991863a4a2
+ }
+ v.Op = OpCopy
+ v.AuxInt = 0
+ v.Aux = nil
+ v.resetArgs()
+ v.Type = x.Type
+ v.AddArg(x)
+ return true
+ }
+ goto end20e42db178ec4f423cc56a991863a4a2
+end20e42db178ec4f423cc56a991863a4a2:
;
return false
}
}
goto end0387dc2b7bbe57d4aa54eab5d959da4b
end0387dc2b7bbe57d4aa54eab5d959da4b:
+ ;
+ // match: (Sub64 (Add64 x y) x)
+ // cond:
+ // result: y
+ {
+ if v.Args[0].Op != OpAdd64 {
+ goto end7d177451cf8959cb781f52d5ded46fff
+ }
+ x := v.Args[0].Args[0]
+ y := v.Args[0].Args[1]
+ if v.Args[1] != x {
+ goto end7d177451cf8959cb781f52d5ded46fff
+ }
+ v.Op = OpCopy
+ v.AuxInt = 0
+ v.Aux = nil
+ v.resetArgs()
+ v.Type = y.Type
+ v.AddArg(y)
+ return true
+ }
+ goto end7d177451cf8959cb781f52d5ded46fff
+end7d177451cf8959cb781f52d5ded46fff:
+ ;
+ // match: (Sub64 (Add64 x y) y)
+ // cond:
+ // result: x
+ {
+ if v.Args[0].Op != OpAdd64 {
+ goto end6ea8172b21100cfe3dc86b7a850fbe97
+ }
+ x := v.Args[0].Args[0]
+ y := v.Args[0].Args[1]
+ if v.Args[1] != y {
+ goto end6ea8172b21100cfe3dc86b7a850fbe97
+ }
+ v.Op = OpCopy
+ v.AuxInt = 0
+ v.Aux = nil
+ v.resetArgs()
+ v.Type = x.Type
+ v.AddArg(x)
+ return true
+ }
+ goto end6ea8172b21100cfe3dc86b7a850fbe97
+end6ea8172b21100cfe3dc86b7a850fbe97:
;
return false
}
}
goto end4e2ee15ef17611919a1a6b5f80bbfe18
end4e2ee15ef17611919a1a6b5f80bbfe18:
+ ;
+ // match: (Sub8 (Add8 x y) x)
+ // cond:
+ // result: y
+ {
+ if v.Args[0].Op != OpAdd8 {
+ goto endd79d561e14dc3d11da4c3bb20270b541
+ }
+ x := v.Args[0].Args[0]
+ y := v.Args[0].Args[1]
+ if v.Args[1] != x {
+ goto endd79d561e14dc3d11da4c3bb20270b541
+ }
+ v.Op = OpCopy
+ v.AuxInt = 0
+ v.Aux = nil
+ v.resetArgs()
+ v.Type = y.Type
+ v.AddArg(y)
+ return true
+ }
+ goto endd79d561e14dc3d11da4c3bb20270b541
+endd79d561e14dc3d11da4c3bb20270b541:
+ ;
+ // match: (Sub8 (Add8 x y) y)
+ // cond:
+ // result: x
+ {
+ if v.Args[0].Op != OpAdd8 {
+ goto endcb7111b11d6d068c97026a97ecff8248
+ }
+ x := v.Args[0].Args[0]
+ y := v.Args[0].Args[1]
+ if v.Args[1] != y {
+ goto endcb7111b11d6d068c97026a97ecff8248
+ }
+ v.Op = OpCopy
+ v.AuxInt = 0
+ v.Aux = nil
+ v.resetArgs()
+ v.Type = x.Type
+ v.AddArg(x)
+ return true
+ }
+ goto endcb7111b11d6d068c97026a97ecff8248
+endcb7111b11d6d068c97026a97ecff8248:
;
return false
}