]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile: make loopbce handle 8, 16 and 32 bit induction variables
authorJakub Ciolek <jakub@ciolek.dev>
Mon, 3 Oct 2022 16:08:29 +0000 (18:08 +0200)
committerKeith Randall <khr@golang.org>
Mon, 23 Jan 2023 18:10:40 +0000 (18:10 +0000)
Compute limits and increment values for all integer widths.
Resolves 2 TODO's in loopbce.go

compilecmp linux/amd64:

compress/flate
compress/flate.(*huffmanEncoder).bitCounts 1235 -> 1207  (-2.27%)

cmd/internal/obj/wasm
cmd/internal/obj/wasm.assemble 7443 -> 7303  (-1.88%)
cmd/internal/obj/wasm.assemble.func1 165 -> 138  (-16.36%)

cmd/link/internal/ld
cmd/link/internal/ld.(*Link).findfunctab.func1 1646 -> 1627  (-1.15%)

Change-Id: I2d79b7376eb67d6bcc8fdaf0c197c11e631562d0
Reviewed-on: https://go-review.googlesource.com/c/go/+/435258
Reviewed-by: Benny Siegert <bsiegert@gmail.com>
Run-TryBot: Keith Randall <khr@golang.org>
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Keith Randall <khr@golang.org>
Reviewed-by: Keith Randall <khr@google.com>
src/cmd/compile/internal/ssa/loopbce.go
test/loopbce.go

index d92566f2d3eb456b690f5a70e79b1d45878ec4e9..273ead4942c3c29e9dc1417bebba9731c90cf36d 100644 (file)
@@ -6,8 +6,8 @@ package ssa
 
 import (
        "cmd/compile/internal/base"
+       "cmd/compile/internal/types"
        "fmt"
-       "math"
 )
 
 type indVarFlags uint8
@@ -44,9 +44,9 @@ func parseIndVar(ind *Value) (min, inc, nxt *Value) {
                return
        }
 
-       if n := ind.Args[0]; n.Op == OpAdd64 && (n.Args[0] == ind || n.Args[1] == ind) {
+       if n := ind.Args[0]; (n.Op == OpAdd64 || n.Op == OpAdd32 || n.Op == OpAdd16 || n.Op == OpAdd8) && (n.Args[0] == ind || n.Args[1] == ind) {
                min, nxt = ind.Args[1], n
-       } else if n := ind.Args[1]; n.Op == OpAdd64 && (n.Args[0] == ind || n.Args[1] == ind) {
+       } else if n := ind.Args[1]; (n.Op == OpAdd64 || n.Op == OpAdd32 || n.Op == OpAdd16 || n.Op == OpAdd8) && (n.Args[0] == ind || n.Args[1] == ind) {
                min, nxt = ind.Args[0], n
        } else {
                // Not a recognized induction variable.
@@ -80,8 +80,6 @@ func parseIndVar(ind *Value) (min, inc, nxt *Value) {
 //             goto loop
 //
 //      exit_loop:
-//
-// TODO: handle 32 bit operations
 func findIndVar(f *Func) []indVar {
        var iv []indVar
        sdom := f.Sdom()
@@ -96,15 +94,14 @@ func findIndVar(f *Func) []indVar {
                var limit *Value // ending value
 
                // Check thet the control if it either ind </<= limit or limit </<= ind.
-               // TODO: Handle 32-bit comparisons.
                // TODO: Handle unsigned comparisons?
                c := b.Controls[0]
                inclusive := false
                switch c.Op {
-               case OpLeq64:
+               case OpLeq64, OpLeq32, OpLeq16, OpLeq8:
                        inclusive = true
                        fallthrough
-               case OpLess64:
+               case OpLess64, OpLess32, OpLess16, OpLess8:
                        ind, limit = c.Args[0], c.Args[1]
                default:
                        continue
@@ -131,7 +128,7 @@ func findIndVar(f *Func) []indVar {
                }
 
                // Expect the increment to be a nonzero constant.
-               if inc.Op != OpConst64 {
+               if !inc.isGenericIntConst() {
                        continue
                }
                step := inc.AuxInt
@@ -184,16 +181,16 @@ func findIndVar(f *Func) []indVar {
                // This function returns true if the increment will never overflow/underflow.
                ok := func() bool {
                        if step > 0 {
-                               if limit.Op == OpConst64 {
+                               if limit.isGenericIntConst() {
                                        // Figure out the actual largest value.
                                        v := limit.AuxInt
                                        if !inclusive {
-                                               if v == math.MinInt64 {
+                                               if v == minSignedValue(limit.Type) {
                                                        return false // < minint is never satisfiable.
                                                }
                                                v--
                                        }
-                                       if init.Op == OpConst64 {
+                                       if init.isGenericIntConst() {
                                                // Use stride to compute a better lower limit.
                                                if init.AuxInt > v {
                                                        return false
@@ -205,7 +202,7 @@ func findIndVar(f *Func) []indVar {
                                        }
                                        if inclusive && v != limit.AuxInt || !inclusive && v+1 != limit.AuxInt {
                                                // We know a better limit than the programmer did. Use our limit instead.
-                                               limit = f.ConstInt64(f.Config.Types.Int64, v)
+                                               limit = f.constVal(limit.Op, limit.Type, v, true)
                                                inclusive = true
                                        }
                                        return true
@@ -227,18 +224,18 @@ func findIndVar(f *Func) []indVar {
                                        return step <= k
                                }
                                // ind < knn - k cannot overflow if step is at most k+1
-                               return step <= k+1 && k != math.MaxInt64
+                               return step <= k+1 && k != maxSignedValue(limit.Type)
                        } else { // step < 0
                                if limit.Op == OpConst64 {
                                        // Figure out the actual smallest value.
                                        v := limit.AuxInt
                                        if !inclusive {
-                                               if v == math.MaxInt64 {
+                                               if v == maxSignedValue(limit.Type) {
                                                        return false // > maxint is never satisfiable.
                                                }
                                                v++
                                        }
-                                       if init.Op == OpConst64 {
+                                       if init.isGenericIntConst() {
                                                // Use stride to compute a better lower limit.
                                                if init.AuxInt < v {
                                                        return false
@@ -250,7 +247,7 @@ func findIndVar(f *Func) []indVar {
                                        }
                                        if inclusive && v != limit.AuxInt || !inclusive && v-1 != limit.AuxInt {
                                                // We know a better limit than the programmer did. Use our limit instead.
-                                               limit = f.ConstInt64(f.Config.Types.Int64, v)
+                                               limit = f.constVal(limit.Op, limit.Type, v, true)
                                                inclusive = true
                                        }
                                        return true
@@ -361,14 +358,14 @@ func findKNN(v *Value) (*Value, int64) {
        var x, y *Value
        x = v
        switch v.Op {
-       case OpSub64:
+       case OpSub64, OpSub32, OpSub16, OpSub8:
                x = v.Args[0]
                y = v.Args[1]
 
-       case OpAdd64:
+       case OpAdd64, OpAdd32, OpAdd16, OpAdd8:
                x = v.Args[0]
                y = v.Args[1]
-               if x.Op == OpConst64 {
+               if x.isGenericIntConst() {
                        x, y = y, x
                }
        }
@@ -380,10 +377,10 @@ func findKNN(v *Value) (*Value, int64) {
        if y == nil {
                return x, 0
        }
-       if y.Op != OpConst64 {
+       if !y.isGenericIntConst() {
                return nil, 0
        }
-       if v.Op == OpAdd64 {
+       if v.Op == OpAdd64 || v.Op == OpAdd32 || v.Op == OpAdd16 || v.Op == OpAdd8 {
                return x, -y.AuxInt
        }
        return x, y.AuxInt
@@ -419,3 +416,11 @@ func printIndVar(b *Block, i, min, max *Value, inc int64, flags indVarFlags) {
        }
        b.Func.Warnl(b.Pos, "Induction variable: limits %v%v,%v%v, increment %d%s", mb1, mlim1, mlim2, mb2, inc, extra)
 }
+
+func minSignedValue(t *types.Type) int64 {
+       return -1 << (t.Size()*8 - 1)
+}
+
+func maxSignedValue(t *types.Type) int64 {
+       return 1<<((t.Size()*8)-1) - 1
+}
index db830daf5cc191cdacd3a5452d0d3c8783f082fd..fcf0d8d90dbdc15c1b21d960864b8fd6dcf34065 100644 (file)
@@ -63,6 +63,30 @@ func f5(a [10]int) int {
        return x
 }
 
+func f5_int32(a [10]int) int {
+       x := 0
+       for i := int32(-10); i < int32(len(a)); i += 2 { // ERROR "Induction variable: limits \[-10,8\], increment 2$"
+               x += a[i]
+       }
+       return x
+}
+
+func f5_int16(a [10]int) int {
+       x := 0
+       for i := int16(-10); i < int16(len(a)); i += 2 { // ERROR "Induction variable: limits \[-10,8\], increment 2$"
+               x += a[i]
+       }
+       return x
+}
+
+func f5_int8(a [10]int) int {
+       x := 0
+       for i := int8(-10); i < int8(len(a)); i += 2 { // ERROR "Induction variable: limits \[-10,8\], increment 2$"
+               x += a[i]
+       }
+       return x
+}
+
 func f6(a []int) {
        for i := range a { // ERROR "Induction variable: limits \[0,\?\), increment 1$"
                b := a[0:i] // ERROR "(\([0-9]+\) )?Proved IsSliceInBounds$"