diff options
| author | Cherry Zhang <cherryyz@google.com> | 2017-04-06 09:36:23 -0400 |
|---|---|---|
| committer | Cherry Zhang <cherryyz@google.com> | 2017-04-06 17:59:32 +0000 |
| commit | 257b01f8f47ace2ddd75efe37d8a0353888bce14 (patch) | |
| tree | a80252d7a164e33f7ed6e6436805fa3e1bdf7dbd /src | |
| parent | 168eb9cf3395583541224af0227c19ddb13e35be (diff) | |
| download | go-257b01f8f47ace2ddd75efe37d8a0353888bce14.tar.xz | |
cmd/compile: use ANDconst to mask out leading/trailing bits on ARM64
For an AND that masks out leading or trailing bits, generic rules
rewrite it to a pair of shifts. On ARM64, the mask actually can
fit into an AND instruction. So we rewrite it back to AND.
Fixes #19857.
Change-Id: I479d7320ae4f29bb3f0056d5979bde4478063a8f
Reviewed-on: https://go-review.googlesource.com/39651
Run-TryBot: Cherry Zhang <cherryyz@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: David Chase <drchase@google.com>
Diffstat (limited to 'src')
| -rw-r--r-- | src/cmd/compile/internal/gc/asm_test.go | 16 | ||||
| -rw-r--r-- | src/cmd/compile/internal/ssa/gen/ARM64.rules | 7 | ||||
| -rw-r--r-- | src/cmd/compile/internal/ssa/rewriteARM64.go | 42 |
3 files changed, 53 insertions, 12 deletions
diff --git a/src/cmd/compile/internal/gc/asm_test.go b/src/cmd/compile/internal/gc/asm_test.go index dd96bec282..6c56b8d8e5 100644 --- a/src/cmd/compile/internal/gc/asm_test.go +++ b/src/cmd/compile/internal/gc/asm_test.go @@ -1327,6 +1327,22 @@ var linuxARM64Tests = []*asmTest{ `, []string{"\tCLZ\t"}, }, + { + ` + func f34(a uint64) uint64 { + return a & ((1<<63)-1) + } + `, + []string{"\tAND\t"}, + }, + { + ` + func f35(a uint64) uint64 { + return a & (1<<63) + } + `, + []string{"\tAND\t"}, + }, } var linuxMIPSTests = []*asmTest{ diff --git a/src/cmd/compile/internal/ssa/gen/ARM64.rules b/src/cmd/compile/internal/ssa/gen/ARM64.rules index 8f7680a347..189e739434 100644 --- a/src/cmd/compile/internal/ssa/gen/ARM64.rules +++ b/src/cmd/compile/internal/ssa/gen/ARM64.rules @@ -1148,8 +1148,11 @@ ( ORshiftRL <t> [c] (SLLconst x [32-c]) (MOVWUreg x)) && c < 32 && t.Size() == 4 -> (RORWconst [ c] x) (XORshiftRL <t> [c] (SLLconst x [32-c]) (MOVWUreg x)) && c < 32 && t.Size() == 4 -> (RORWconst [ c] x) -// Replace SRL-of-SLL with ROR-of-SLL to avoid hardware bug. -(SRLconst [c] y:(SLLconst [c] _)) && c <= 8 -> (RORconst [c] y) +// Generic rules rewrite certain AND to a pair of shifts. +// However, on ARM64 the bitmask can fit into an instruction. +// Rewrite it back to AND. +(SRLconst [c] (SLLconst [c] x)) && 0 < c && c < 64 -> (ANDconst [1<<uint(64-c)-1] x) // mask out high bits +(SLLconst [c] (SRLconst [c] x)) && 0 < c && c < 64 -> (ANDconst [^(1<<uint(c)-1)] x) // mask out low bits // do combined loads // little endian loads diff --git a/src/cmd/compile/internal/ssa/rewriteARM64.go b/src/cmd/compile/internal/ssa/rewriteARM64.go index c32bdf7a9e..16f3d06b27 100644 --- a/src/cmd/compile/internal/ssa/rewriteARM64.go +++ b/src/cmd/compile/internal/ssa/rewriteARM64.go @@ -8583,6 +8583,27 @@ func rewriteValueARM64_OpARM64SLLconst(v *Value) bool { v.AuxInt = int64(d) << uint64(c) return true } + // match: (SLLconst [c] (SRLconst [c] x)) + // cond: 0 < c && c < 64 + // result: (ANDconst [^(1<<uint(c)-1)] x) + for { + c := v.AuxInt + v_0 := v.Args[0] + if v_0.Op != OpARM64SRLconst { + break + } + if v_0.AuxInt != c { + break + } + x := v_0.Args[0] + if !(0 < c && c < 64) { + break + } + v.reset(OpARM64ANDconst) + v.AuxInt = ^(1<<uint(c) - 1) + v.AddArg(x) + return true + } return false } func rewriteValueARM64_OpARM64SRA(v *Value) bool { @@ -8653,24 +8674,25 @@ func rewriteValueARM64_OpARM64SRLconst(v *Value) bool { v.AuxInt = int64(uint64(d) >> uint64(c)) return true } - // match: (SRLconst [c] y:(SLLconst [c] _)) - // cond: c <= 8 - // result: (RORconst [c] y) + // match: (SRLconst [c] (SLLconst [c] x)) + // cond: 0 < c && c < 64 + // result: (ANDconst [1<<uint(64-c)-1] x) for { c := v.AuxInt - y := v.Args[0] - if y.Op != OpARM64SLLconst { + v_0 := v.Args[0] + if v_0.Op != OpARM64SLLconst { break } - if y.AuxInt != c { + if v_0.AuxInt != c { break } - if !(c <= 8) { + x := v_0.Args[0] + if !(0 < c && c < 64) { break } - v.reset(OpARM64RORconst) - v.AuxInt = c - v.AddArg(y) + v.reset(OpARM64ANDconst) + v.AuxInt = 1<<uint(64-c) - 1 + v.AddArg(x) return true } return false |
