]> Cypherpunks repositories - gostls13.git/commitdiff
[release-branch.go1.8] cmd/compile: fix subword store/load elision for amd64, x86...
authorDavid Chase <drchase@google.com>
Tue, 30 May 2017 20:06:59 +0000 (16:06 -0400)
committerRuss Cox <rsc@golang.org>
Wed, 25 Oct 2017 18:56:46 +0000 (18:56 +0000)
Replacing byteload-of-bytestore-of-x with x is incorrect
when x contains a larger-than-byte value (and so on for
16 and 32-bit load/store pairs).  Replace "x" with the
appropriate zero/sign extension of x, which if unnecessary
will be repaired by other rules.

Made logic for arm match x86 and amd64; yields minor extra
optimization, plus I am (much) more confident it's correct,
despite inability to reproduce bug on arm.

Ppc64 lacks this optimization, hence lacks this problem.

See related https://golang.org/cl/37154/
Fixes #20530.

[Merge conflicts in generated rewrite files resolved by
regenerating from scratch, using the programs in ssa/gen.]

Change-Id: I6af9cac2ad43bee99cafdcb04725ce7e55a43323
Reviewed-on: https://go-review.googlesource.com/44355
Run-TryBot: David Chase <drchase@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Keith Randall <khr@golang.org>
Reviewed-on: https://go-review.googlesource.com/70841
Run-TryBot: Russ Cox <rsc@golang.org>
Reviewed-by: Cherry Zhang <cherryyz@google.com>
src/cmd/compile/internal/ssa/gen/386.rules
src/cmd/compile/internal/ssa/gen/AMD64.rules
src/cmd/compile/internal/ssa/gen/ARM.rules
src/cmd/compile/internal/ssa/rewrite386.go
src/cmd/compile/internal/ssa/rewriteAMD64.go
src/cmd/compile/internal/ssa/rewriteARM.go
test/fixedbugs/issue20530.go [new file with mode: 0644]

index a3f2ecb8c384dc6403a429bed71b949b22a14a5e..d77bbb2a4bc6a8d190dc2f77a21073b8c093a8b9 100644 (file)
 (MOVWLZX x:(MOVWloadidx1 [off] {sym} ptr idx mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVWloadidx1 <v.Type> [off] {sym} ptr idx mem)
 (MOVWLZX x:(MOVWloadidx2 [off] {sym} ptr idx mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVWloadidx2 <v.Type> [off] {sym} ptr idx mem)
 
-// replace load from same location as preceding store with copy
-(MOVBload [off] {sym} ptr (MOVBstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> x
-(MOVWload [off] {sym} ptr (MOVWstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> x
+// replace load from same location as preceding store with zero/sign extension (or copy in case of full width)
+(MOVBload [off] {sym} ptr (MOVBstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVBLZX x)
+(MOVWload [off] {sym} ptr (MOVWstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVWLZX x)
 (MOVLload [off] {sym} ptr (MOVLstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> x
+(MOVBLSXload [off] {sym} ptr (MOVBstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVBLSX x)
+(MOVWLSXload [off] {sym} ptr (MOVWstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVWLSX x)
 
 // Fold extensions and ANDs together.
 (MOVBLZX (ANDLconst [c] x)) -> (ANDLconst [c & 0xff] x)
index 5b4649cb143cd9d0fc72e46e65924727f1953eca..1ac74a6a7b6e6b0945ec3987d8a9f3d8d82affc5 100644 (file)
 (MOVLQZX x:(MOVLloadidx1 [off] {sym} ptr idx mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVLloadidx1 <v.Type> [off] {sym} ptr idx mem)
 (MOVLQZX x:(MOVLloadidx4 [off] {sym} ptr idx mem)) && x.Uses == 1 && clobber(x) -> @x.Block (MOVLloadidx4 <v.Type> [off] {sym} ptr idx mem)
 
-// replace load from same location as preceding store with copy
-(MOVBload [off] {sym} ptr (MOVBstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> x
-(MOVWload [off] {sym} ptr (MOVWstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> x
-(MOVLload [off] {sym} ptr (MOVLstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> x
+// replace load from same location as preceding store with zero/sign extension (or copy in case of full width)
+(MOVBload [off] {sym} ptr (MOVBstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVBQZX x)
+(MOVWload [off] {sym} ptr (MOVWstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVWQZX x)
+(MOVLload [off] {sym} ptr (MOVLstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVLQZX x)
 (MOVQload [off] {sym} ptr (MOVQstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> x
+(MOVBQSXload [off] {sym} ptr (MOVBstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVBQSX x)
+(MOVWQSXload [off] {sym} ptr (MOVWstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVWQSX x)
+(MOVLQSXload [off] {sym} ptr (MOVLstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVLQSX x)
 
 // Fold extensions and ANDs together.
 (MOVBQZX (ANDLconst [c] x)) -> (ANDLconst [c & 0xff] x)
index aad25871afaf1fba23e77106d402205b62206182..f0d3cd8d1583bf63faff3c976c011939126a59d7 100644 (file)
 (MOVDstore [off1] {sym1} (MOVWaddr [off2] {sym2} ptr) val mem) && canMergeSym(sym1,sym2) ->
        (MOVDstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem)
 
-// replace load from same location as preceding store with copy
-(MOVBload [off] {sym} ptr (MOVBstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) && isSigned(x.Type) -> x
-(MOVBUload [off] {sym} ptr (MOVBstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) && !isSigned(x.Type) -> x
-(MOVHload [off] {sym} ptr (MOVHstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) && isSigned(x.Type) -> x
-(MOVHUload [off] {sym} ptr (MOVHstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) && !isSigned(x.Type) -> x
+// replace load from same location as preceding store with zero/sign extension (or copy in case of full width)
+(MOVBload [off] {sym} ptr (MOVBstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVBreg x)
+(MOVBUload [off] {sym} ptr (MOVBstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVBUreg x)
+(MOVHload [off] {sym} ptr (MOVHstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVHreg x)
+(MOVHUload [off] {sym} ptr (MOVHstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> (MOVHUreg x)
 (MOVWload [off] {sym} ptr (MOVWstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> x
+
 (MOVFload [off] {sym} ptr (MOVFstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> x
 (MOVDload [off] {sym} ptr (MOVDstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> x
 
index 741886da90597cbeb8c775fc8700ffeb6f7bc15b..7b5252134cb7269ba5169d2c8fbf4b42c32c0b7b 100644 (file)
@@ -2503,6 +2503,28 @@ func rewriteValue386_Op386MOVBLSX(v *Value, config *Config) bool {
 func rewriteValue386_Op386MOVBLSXload(v *Value, config *Config) bool {
        b := v.Block
        _ = b
+       // match: (MOVBLSXload [off] {sym} ptr (MOVBstore [off2] {sym2} ptr2 x _))
+       // cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)
+       // result: (MOVBLSX x)
+       for {
+               off := v.AuxInt
+               sym := v.Aux
+               ptr := v.Args[0]
+               v_1 := v.Args[1]
+               if v_1.Op != Op386MOVBstore {
+                       break
+               }
+               off2 := v_1.AuxInt
+               sym2 := v_1.Aux
+               ptr2 := v_1.Args[0]
+               x := v_1.Args[1]
+               if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)) {
+                       break
+               }
+               v.reset(Op386MOVBLSX)
+               v.AddArg(x)
+               return true
+       }
        // match: (MOVBLSXload [off1] {sym1} (LEAL [off2] {sym2} base) mem)
        // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)   && (base.Op != OpSB || !config.ctxt.Flag_shared)
        // result: (MOVBLSXload [off1+off2] {mergeSym(sym1,sym2)} base mem)
@@ -2606,7 +2628,7 @@ func rewriteValue386_Op386MOVBload(v *Value, config *Config) bool {
        _ = b
        // match: (MOVBload [off] {sym} ptr (MOVBstore [off2] {sym2} ptr2 x _))
        // cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)
-       // result: x
+       // result: (MOVBLZX x)
        for {
                off := v.AuxInt
                sym := v.Aux
@@ -2622,8 +2644,7 @@ func rewriteValue386_Op386MOVBload(v *Value, config *Config) bool {
                if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)) {
                        break
                }
-               v.reset(OpCopy)
-               v.Type = x.Type
+               v.reset(Op386MOVBLZX)
                v.AddArg(x)
                return true
        }
@@ -5248,6 +5269,28 @@ func rewriteValue386_Op386MOVWLSX(v *Value, config *Config) bool {
 func rewriteValue386_Op386MOVWLSXload(v *Value, config *Config) bool {
        b := v.Block
        _ = b
+       // match: (MOVWLSXload [off] {sym} ptr (MOVWstore [off2] {sym2} ptr2 x _))
+       // cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)
+       // result: (MOVWLSX x)
+       for {
+               off := v.AuxInt
+               sym := v.Aux
+               ptr := v.Args[0]
+               v_1 := v.Args[1]
+               if v_1.Op != Op386MOVWstore {
+                       break
+               }
+               off2 := v_1.AuxInt
+               sym2 := v_1.Aux
+               ptr2 := v_1.Args[0]
+               x := v_1.Args[1]
+               if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)) {
+                       break
+               }
+               v.reset(Op386MOVWLSX)
+               v.AddArg(x)
+               return true
+       }
        // match: (MOVWLSXload [off1] {sym1} (LEAL [off2] {sym2} base) mem)
        // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)   && (base.Op != OpSB || !config.ctxt.Flag_shared)
        // result: (MOVWLSXload [off1+off2] {mergeSym(sym1,sym2)} base mem)
@@ -5378,7 +5421,7 @@ func rewriteValue386_Op386MOVWload(v *Value, config *Config) bool {
        _ = b
        // match: (MOVWload [off] {sym} ptr (MOVWstore [off2] {sym2} ptr2 x _))
        // cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)
-       // result: x
+       // result: (MOVWLZX x)
        for {
                off := v.AuxInt
                sym := v.Aux
@@ -5394,8 +5437,7 @@ func rewriteValue386_Op386MOVWload(v *Value, config *Config) bool {
                if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)) {
                        break
                }
-               v.reset(OpCopy)
-               v.Type = x.Type
+               v.reset(Op386MOVWLZX)
                v.AddArg(x)
                return true
        }
index 1257ec6e7c37c81256bb091ddd692acf775319d4..001003cf130db625540406c169f36b446603e526 100644 (file)
@@ -3361,6 +3361,28 @@ func rewriteValueAMD64_OpAMD64MOVBQSX(v *Value, config *Config) bool {
 func rewriteValueAMD64_OpAMD64MOVBQSXload(v *Value, config *Config) bool {
        b := v.Block
        _ = b
+       // match: (MOVBQSXload [off] {sym} ptr (MOVBstore [off2] {sym2} ptr2 x _))
+       // cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)
+       // result: (MOVBQSX x)
+       for {
+               off := v.AuxInt
+               sym := v.Aux
+               ptr := v.Args[0]
+               v_1 := v.Args[1]
+               if v_1.Op != OpAMD64MOVBstore {
+                       break
+               }
+               off2 := v_1.AuxInt
+               sym2 := v_1.Aux
+               ptr2 := v_1.Args[0]
+               x := v_1.Args[1]
+               if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)) {
+                       break
+               }
+               v.reset(OpAMD64MOVBQSX)
+               v.AddArg(x)
+               return true
+       }
        // match: (MOVBQSXload [off1] {sym1} (LEAQ [off2] {sym2} base) mem)
        // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
        // result: (MOVBQSXload [off1+off2] {mergeSym(sym1,sym2)} base mem)
@@ -3539,7 +3561,7 @@ func rewriteValueAMD64_OpAMD64MOVBload(v *Value, config *Config) bool {
        _ = b
        // match: (MOVBload [off] {sym} ptr (MOVBstore [off2] {sym2} ptr2 x _))
        // cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)
-       // result: x
+       // result: (MOVBQZX x)
        for {
                off := v.AuxInt
                sym := v.Aux
@@ -3555,8 +3577,7 @@ func rewriteValueAMD64_OpAMD64MOVBload(v *Value, config *Config) bool {
                if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)) {
                        break
                }
-               v.reset(OpCopy)
-               v.Type = x.Type
+               v.reset(OpAMD64MOVBQZX)
                v.AddArg(x)
                return true
        }
@@ -4834,6 +4855,28 @@ func rewriteValueAMD64_OpAMD64MOVLQSX(v *Value, config *Config) bool {
 func rewriteValueAMD64_OpAMD64MOVLQSXload(v *Value, config *Config) bool {
        b := v.Block
        _ = b
+       // match: (MOVLQSXload [off] {sym} ptr (MOVLstore [off2] {sym2} ptr2 x _))
+       // cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)
+       // result: (MOVLQSX x)
+       for {
+               off := v.AuxInt
+               sym := v.Aux
+               ptr := v.Args[0]
+               v_1 := v.Args[1]
+               if v_1.Op != OpAMD64MOVLstore {
+                       break
+               }
+               off2 := v_1.AuxInt
+               sym2 := v_1.Aux
+               ptr2 := v_1.Args[0]
+               x := v_1.Args[1]
+               if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)) {
+                       break
+               }
+               v.reset(OpAMD64MOVLQSX)
+               v.AddArg(x)
+               return true
+       }
        // match: (MOVLQSXload [off1] {sym1} (LEAQ [off2] {sym2} base) mem)
        // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
        // result: (MOVLQSXload [off1+off2] {mergeSym(sym1,sym2)} base mem)
@@ -5041,7 +5084,7 @@ func rewriteValueAMD64_OpAMD64MOVLload(v *Value, config *Config) bool {
        _ = b
        // match: (MOVLload [off] {sym} ptr (MOVLstore [off2] {sym2} ptr2 x _))
        // cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)
-       // result: x
+       // result: (MOVLQZX x)
        for {
                off := v.AuxInt
                sym := v.Aux
@@ -5057,8 +5100,7 @@ func rewriteValueAMD64_OpAMD64MOVLload(v *Value, config *Config) bool {
                if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)) {
                        break
                }
-               v.reset(OpCopy)
-               v.Type = x.Type
+               v.reset(OpAMD64MOVLQZX)
                v.AddArg(x)
                return true
        }
@@ -8703,6 +8745,28 @@ func rewriteValueAMD64_OpAMD64MOVWQSX(v *Value, config *Config) bool {
 func rewriteValueAMD64_OpAMD64MOVWQSXload(v *Value, config *Config) bool {
        b := v.Block
        _ = b
+       // match: (MOVWQSXload [off] {sym} ptr (MOVWstore [off2] {sym2} ptr2 x _))
+       // cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)
+       // result: (MOVWQSX x)
+       for {
+               off := v.AuxInt
+               sym := v.Aux
+               ptr := v.Args[0]
+               v_1 := v.Args[1]
+               if v_1.Op != OpAMD64MOVWstore {
+                       break
+               }
+               off2 := v_1.AuxInt
+               sym2 := v_1.Aux
+               ptr2 := v_1.Args[0]
+               x := v_1.Args[1]
+               if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)) {
+                       break
+               }
+               v.reset(OpAMD64MOVWQSX)
+               v.AddArg(x)
+               return true
+       }
        // match: (MOVWQSXload [off1] {sym1} (LEAQ [off2] {sym2} base) mem)
        // cond: is32Bit(off1+off2) && canMergeSym(sym1, sym2)
        // result: (MOVWQSXload [off1+off2] {mergeSym(sym1,sym2)} base mem)
@@ -8883,7 +8947,7 @@ func rewriteValueAMD64_OpAMD64MOVWload(v *Value, config *Config) bool {
        _ = b
        // match: (MOVWload [off] {sym} ptr (MOVWstore [off2] {sym2} ptr2 x _))
        // cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)
-       // result: x
+       // result: (MOVWQZX x)
        for {
                off := v.AuxInt
                sym := v.Aux
@@ -8899,8 +8963,7 @@ func rewriteValueAMD64_OpAMD64MOVWload(v *Value, config *Config) bool {
                if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)) {
                        break
                }
-               v.reset(OpCopy)
-               v.Type = x.Type
+               v.reset(OpAMD64MOVWQZX)
                v.AddArg(x)
                return true
        }
index 234783b409690b7c9b0c122e4af226e0ee20c3e8..569081be10093a4aee83f9098351b29d1f5e1edf 100644 (file)
@@ -5188,8 +5188,8 @@ func rewriteValueARM_OpARMMOVBUload(v *Value, config *Config) bool {
                return true
        }
        // match: (MOVBUload [off] {sym} ptr (MOVBstore [off2] {sym2} ptr2 x _))
-       // cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) && !isSigned(x.Type)
-       // result: x
+       // cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)
+       // result: (MOVBUreg x)
        for {
                off := v.AuxInt
                sym := v.Aux
@@ -5202,11 +5202,10 @@ func rewriteValueARM_OpARMMOVBUload(v *Value, config *Config) bool {
                sym2 := v_1.Aux
                ptr2 := v_1.Args[0]
                x := v_1.Args[1]
-               if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) && !isSigned(x.Type)) {
+               if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)) {
                        break
                }
-               v.reset(OpCopy)
-               v.Type = x.Type
+               v.reset(OpARMMOVBUreg)
                v.AddArg(x)
                return true
        }
@@ -5317,8 +5316,8 @@ func rewriteValueARM_OpARMMOVBload(v *Value, config *Config) bool {
                return true
        }
        // match: (MOVBload [off] {sym} ptr (MOVBstore [off2] {sym2} ptr2 x _))
-       // cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) && isSigned(x.Type)
-       // result: x
+       // cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)
+       // result: (MOVBreg x)
        for {
                off := v.AuxInt
                sym := v.Aux
@@ -5331,11 +5330,10 @@ func rewriteValueARM_OpARMMOVBload(v *Value, config *Config) bool {
                sym2 := v_1.Aux
                ptr2 := v_1.Args[0]
                x := v_1.Args[1]
-               if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) && isSigned(x.Type)) {
+               if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)) {
                        break
                }
-               v.reset(OpCopy)
-               v.Type = x.Type
+               v.reset(OpARMMOVBreg)
                v.AddArg(x)
                return true
        }
@@ -5836,8 +5834,8 @@ func rewriteValueARM_OpARMMOVHUload(v *Value, config *Config) bool {
                return true
        }
        // match: (MOVHUload [off] {sym} ptr (MOVHstore [off2] {sym2} ptr2 x _))
-       // cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) && !isSigned(x.Type)
-       // result: x
+       // cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)
+       // result: (MOVHUreg x)
        for {
                off := v.AuxInt
                sym := v.Aux
@@ -5850,11 +5848,10 @@ func rewriteValueARM_OpARMMOVHUload(v *Value, config *Config) bool {
                sym2 := v_1.Aux
                ptr2 := v_1.Args[0]
                x := v_1.Args[1]
-               if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) && !isSigned(x.Type)) {
+               if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)) {
                        break
                }
-               v.reset(OpCopy)
-               v.Type = x.Type
+               v.reset(OpARMMOVHUreg)
                v.AddArg(x)
                return true
        }
@@ -5989,8 +5986,8 @@ func rewriteValueARM_OpARMMOVHload(v *Value, config *Config) bool {
                return true
        }
        // match: (MOVHload [off] {sym} ptr (MOVHstore [off2] {sym2} ptr2 x _))
-       // cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) && isSigned(x.Type)
-       // result: x
+       // cond: sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)
+       // result: (MOVHreg x)
        for {
                off := v.AuxInt
                sym := v.Aux
@@ -6003,11 +6000,10 @@ func rewriteValueARM_OpARMMOVHload(v *Value, config *Config) bool {
                sym2 := v_1.Aux
                ptr2 := v_1.Args[0]
                x := v_1.Args[1]
-               if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) && isSigned(x.Type)) {
+               if !(sym == sym2 && off == off2 && isSamePtr(ptr, ptr2)) {
                        break
                }
-               v.reset(OpCopy)
-               v.Type = x.Type
+               v.reset(OpARMMOVHreg)
                v.AddArg(x)
                return true
        }
diff --git a/test/fixedbugs/issue20530.go b/test/fixedbugs/issue20530.go
new file mode 100644 (file)
index 0000000..7027b10
--- /dev/null
@@ -0,0 +1,18 @@
+// run
+
+// Copyright 2017 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 main
+
+var a uint8
+
+func main() {
+       b := int8(func() int32 { return -1 }())
+       a = uint8(b)
+       if int32(a) != 255 {
+               // Failing case prints 'got 255 expected 255'
+               println("got", a, "expected 255")
+       }
+}