]> Cypherpunks repositories - gostls13.git/commitdiff
[dev.ssa] cmd/compile/internal/ssa/gen: generalize strength reduction.
authorAlexandru Moșoi <mosoi@google.com>
Fri, 17 Jul 2015 10:26:35 +0000 (12:26 +0200)
committerKeith Randall <khr@golang.org>
Wed, 22 Jul 2015 22:00:31 +0000 (22:00 +0000)
Handle multiplication with -1, 0, 3, 5, 9 and all powers of two.

Change-Id: I8e87e7670dae389aebf6f446d7a56950cacb59e0
Reviewed-on: https://go-review.googlesource.com/12350
Reviewed-by: Keith Randall <khr@golang.org>
src/cmd/compile/internal/ssa/gen/AMD64.rules
src/cmd/compile/internal/ssa/rewrite.go
src/cmd/compile/internal/ssa/rewriteAMD64.go

index eb14b6a55b75fe5f98c2c5ab4d6508aab19063ac..ee5029ad5644ae202662f172c25b38ccbf59dfce 100644 (file)
 (CMPQ (MOVQconst [c]) x) -> (InvertFlags (CMPQconst <TypeFlags> x [c]))
 
 // strength reduction
-// TODO: do this a lot more generically
-(MULQconst [8] x) -> (SHLQconst [3] x)
-(MULQconst [64] x) -> (SHLQconst [6] x)
+(MULQconst [-1] x) -> (NEGQ x)
+(MULQconst [0] _) -> (MOVQconst [0])
+(MULQconst [1] x) -> (Copy x)
+(MULQconst [3] x) -> (LEAQ2 x x)
+(MULQconst [5] x) -> (LEAQ4 x x)
+(MULQconst [9] x) -> (LEAQ8 x x)
+(MULQconst [c] x) && isPowerOfTwo(c) -> (SHLQconst [log2(c)] x)
 
 // fold add/shift into leaq
 (ADDQ x (SHLQconst [3] y)) -> (LEAQ8 x y)
index 60368784e838a5afff69ff1a1582268e8c468468..90ac7d7a68b963d33b7032a585a20af3524d8302 100644 (file)
@@ -119,3 +119,18 @@ func mergeSym(x, y interface{}) interface{} {
 func inBounds(idx, len int64) bool {
        return idx >= 0 && idx < len
 }
+
+// log2 returns logarithm in base of n.
+// expects n to be a power of 2.
+func log2(n int64) (l int64) {
+       for n > 1 {
+               l++
+               n >>= 1
+       }
+       return l
+}
+
+// isPowerOfTwo returns true if n is a power of 2.
+func isPowerOfTwo(n int64) bool {
+       return n > 0 && n&(n-1) == 0
+}
index 68c7d2eb42ad6ba5d0fe364b60e87509268b3344..c118cc42794524b538a408750fb92a50f279670e 100644 (file)
@@ -1200,43 +1200,135 @@ func rewriteValueAMD64(v *Value, config *Config) bool {
        endc6e18d6968175d6e58eafa6dcf40c1b8:
                ;
        case OpAMD64MULQconst:
-               // match: (MULQconst [8] x)
+               // match: (MULQconst [-1] x)
                // cond:
-               // result: (SHLQconst [3] x)
+               // result: (NEGQ x)
                {
-                       if v.AuxInt != 8 {
-                               goto ende8d313a52a134fb2e1c0beb54ea599fd
+                       if v.AuxInt != -1 {
+                               goto end82501cca6b5fb121a7f8b197e55f2fec
                        }
                        x := v.Args[0]
-                       v.Op = OpAMD64SHLQconst
+                       v.Op = OpAMD64NEGQ
                        v.AuxInt = 0
                        v.Aux = nil
                        v.resetArgs()
-                       v.AuxInt = 3
                        v.AddArg(x)
                        return true
                }
-               goto ende8d313a52a134fb2e1c0beb54ea599fd
-       ende8d313a52a134fb2e1c0beb54ea599fd:
+               goto end82501cca6b5fb121a7f8b197e55f2fec
+       end82501cca6b5fb121a7f8b197e55f2fec:
                ;
-               // match: (MULQconst [64] x)
+               // match: (MULQconst [0] _)
                // cond:
-               // result: (SHLQconst [6] x)
+               // result: (MOVQconst [0])
                {
-                       if v.AuxInt != 64 {
-                               goto end3e36a587d1e7c193048d489a0429692c
+                       if v.AuxInt != 0 {
+                               goto endcb9faa068e3558ff44daaf1d47d091b5
+                       }
+                       v.Op = OpAMD64MOVQconst
+                       v.AuxInt = 0
+                       v.Aux = nil
+                       v.resetArgs()
+                       v.AuxInt = 0
+                       return true
+               }
+               goto endcb9faa068e3558ff44daaf1d47d091b5
+       endcb9faa068e3558ff44daaf1d47d091b5:
+               ;
+               // match: (MULQconst [1] x)
+               // cond:
+               // result: (Copy x)
+               {
+                       if v.AuxInt != 1 {
+                               goto endd7217a7c6311fc7a3e0736a1b0b5be73
                        }
                        x := v.Args[0]
+                       v.Op = OpCopy
+                       v.AuxInt = 0
+                       v.Aux = nil
+                       v.resetArgs()
+                       v.AddArg(x)
+                       return true
+               }
+               goto endd7217a7c6311fc7a3e0736a1b0b5be73
+       endd7217a7c6311fc7a3e0736a1b0b5be73:
+               ;
+               // match: (MULQconst [3] x)
+               // cond:
+               // result: (LEAQ2 x x)
+               {
+                       if v.AuxInt != 3 {
+                               goto end34a86f261671b5852bec6c57155fe0da
+                       }
+                       x := v.Args[0]
+                       v.Op = OpAMD64LEAQ2
+                       v.AuxInt = 0
+                       v.Aux = nil
+                       v.resetArgs()
+                       v.AddArg(x)
+                       v.AddArg(x)
+                       return true
+               }
+               goto end34a86f261671b5852bec6c57155fe0da
+       end34a86f261671b5852bec6c57155fe0da:
+               ;
+               // match: (MULQconst [5] x)
+               // cond:
+               // result: (LEAQ4 x x)
+               {
+                       if v.AuxInt != 5 {
+                               goto end534601906c45a9171a9fec3e4b82b189
+                       }
+                       x := v.Args[0]
+                       v.Op = OpAMD64LEAQ4
+                       v.AuxInt = 0
+                       v.Aux = nil
+                       v.resetArgs()
+                       v.AddArg(x)
+                       v.AddArg(x)
+                       return true
+               }
+               goto end534601906c45a9171a9fec3e4b82b189
+       end534601906c45a9171a9fec3e4b82b189:
+               ;
+               // match: (MULQconst [9] x)
+               // cond:
+               // result: (LEAQ8 x x)
+               {
+                       if v.AuxInt != 9 {
+                               goto end48a2280b6459821289c56073b8354997
+                       }
+                       x := v.Args[0]
+                       v.Op = OpAMD64LEAQ8
+                       v.AuxInt = 0
+                       v.Aux = nil
+                       v.resetArgs()
+                       v.AddArg(x)
+                       v.AddArg(x)
+                       return true
+               }
+               goto end48a2280b6459821289c56073b8354997
+       end48a2280b6459821289c56073b8354997:
+               ;
+               // match: (MULQconst [c] x)
+               // cond: isPowerOfTwo(c)
+               // result: (SHLQconst [log2(c)] x)
+               {
+                       c := v.AuxInt
+                       x := v.Args[0]
+                       if !(isPowerOfTwo(c)) {
+                               goto end75076953dbfe022526a153eda99b39b2
+                       }
                        v.Op = OpAMD64SHLQconst
                        v.AuxInt = 0
                        v.Aux = nil
                        v.resetArgs()
-                       v.AuxInt = 6
+                       v.AuxInt = log2(c)
                        v.AddArg(x)
                        return true
                }
-               goto end3e36a587d1e7c193048d489a0429692c
-       end3e36a587d1e7c193048d489a0429692c:
+               goto end75076953dbfe022526a153eda99b39b2
+       end75076953dbfe022526a153eda99b39b2:
                ;
        case OpMove:
                // match: (Move [size] dst src mem)