mirror of
https://github.com/golang/go
synced 2024-11-11 19:41:36 -07:00
cmd/compile: fold constants found by prove
It is hit ~70k times building go. This make the go binary, 0.04% smaller. For example, this enable rewriting things like: if x == 20 { return x + 30 + z } Into: if x == 20 { return 50 + z } It's not just fixing programer's code, the ssa generator generate code like this sometimes.
This commit is contained in:
parent
e7508598bb
commit
4c2f9b5216
@ -1222,13 +1222,13 @@ func simplifyBlock(sdom SparseTree, ft *factsTable, b *Block) {
|
|||||||
// Replace OpSlicemask operations in b with constants where possible.
|
// Replace OpSlicemask operations in b with constants where possible.
|
||||||
x, delta := isConstDelta(v.Args[0])
|
x, delta := isConstDelta(v.Args[0])
|
||||||
if x == nil {
|
if x == nil {
|
||||||
continue
|
break
|
||||||
}
|
}
|
||||||
// slicemask(x + y)
|
// slicemask(x + y)
|
||||||
// if x is larger than -y (y is negative), then slicemask is -1.
|
// if x is larger than -y (y is negative), then slicemask is -1.
|
||||||
lim, ok := ft.limits[x.ID]
|
lim, ok := ft.limits[x.ID]
|
||||||
if !ok {
|
if !ok {
|
||||||
continue
|
break
|
||||||
}
|
}
|
||||||
if lim.umin > uint64(-delta) {
|
if lim.umin > uint64(-delta) {
|
||||||
if v.Args[0].Op == OpAdd64 {
|
if v.Args[0].Op == OpAdd64 {
|
||||||
@ -1248,7 +1248,7 @@ func simplifyBlock(sdom SparseTree, ft *factsTable, b *Block) {
|
|||||||
x := v.Args[0]
|
x := v.Args[0]
|
||||||
lim, ok := ft.limits[x.ID]
|
lim, ok := ft.limits[x.ID]
|
||||||
if !ok {
|
if !ok {
|
||||||
continue
|
break
|
||||||
}
|
}
|
||||||
if lim.umin > 0 || lim.min > 0 || lim.max < 0 {
|
if lim.umin > 0 || lim.min > 0 || lim.max < 0 {
|
||||||
if b.Func.pass.debug > 0 {
|
if b.Func.pass.debug > 0 {
|
||||||
@ -1280,7 +1280,7 @@ func simplifyBlock(sdom SparseTree, ft *factsTable, b *Block) {
|
|||||||
panic("unexpected integer size")
|
panic("unexpected integer size")
|
||||||
}
|
}
|
||||||
v.AuxInt = 0
|
v.AuxInt = 0
|
||||||
continue // Be sure not to fallthrough - this is no longer OpRsh.
|
break // Be sure not to fallthrough - this is no longer OpRsh.
|
||||||
}
|
}
|
||||||
// If the Rsh hasn't been replaced with 0, still check if it is bounded.
|
// If the Rsh hasn't been replaced with 0, still check if it is bounded.
|
||||||
fallthrough
|
fallthrough
|
||||||
@ -1297,7 +1297,7 @@ func simplifyBlock(sdom SparseTree, ft *factsTable, b *Block) {
|
|||||||
by := v.Args[1]
|
by := v.Args[1]
|
||||||
lim, ok := ft.limits[by.ID]
|
lim, ok := ft.limits[by.ID]
|
||||||
if !ok {
|
if !ok {
|
||||||
continue
|
break
|
||||||
}
|
}
|
||||||
bits := 8 * v.Args[0].Type.Size()
|
bits := 8 * v.Args[0].Type.Size()
|
||||||
if lim.umax < uint64(bits) || (lim.max < bits && ft.isNonNegative(by)) {
|
if lim.umax < uint64(bits) || (lim.max < bits && ft.isNonNegative(by)) {
|
||||||
@ -1331,6 +1331,60 @@ func simplifyBlock(sdom SparseTree, ft *factsTable, b *Block) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Fold provable constant results.
|
||||||
|
// Helps in cases where we reuse a value after branching on its equality.
|
||||||
|
for i, arg := range v.Args {
|
||||||
|
switch arg.Op {
|
||||||
|
case OpConst64, OpConst32, OpConst16, OpConst8:
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
lim, ok := ft.limits[arg.ID]
|
||||||
|
if !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
var constValue int64
|
||||||
|
typ := arg.Type
|
||||||
|
bits := 8 * typ.Size()
|
||||||
|
switch {
|
||||||
|
case lim.min == lim.max:
|
||||||
|
constValue = lim.min
|
||||||
|
case lim.umin == lim.umax:
|
||||||
|
// truncate then sign extand
|
||||||
|
switch bits {
|
||||||
|
case 64:
|
||||||
|
constValue = int64(lim.umin)
|
||||||
|
case 32:
|
||||||
|
constValue = int64(int32(lim.umin))
|
||||||
|
case 16:
|
||||||
|
constValue = int64(int16(lim.umin))
|
||||||
|
case 8:
|
||||||
|
constValue = int64(int8(lim.umin))
|
||||||
|
default:
|
||||||
|
panic("unexpected integer size")
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
var c *Value
|
||||||
|
f := b.Func
|
||||||
|
switch bits {
|
||||||
|
case 64:
|
||||||
|
c = f.ConstInt64(typ, constValue)
|
||||||
|
case 32:
|
||||||
|
c = f.ConstInt32(typ, int32(constValue))
|
||||||
|
case 16:
|
||||||
|
c = f.ConstInt16(typ, int16(constValue))
|
||||||
|
case 8:
|
||||||
|
c = f.ConstInt8(typ, int8(constValue))
|
||||||
|
default:
|
||||||
|
panic("unexpected integer size")
|
||||||
|
}
|
||||||
|
v.SetArg(i, c)
|
||||||
|
if b.Func.pass.debug > 1 {
|
||||||
|
b.Func.Warnl(v.Pos, "Proved %v's arg %d (%v) is constant %d", v, i, arg, constValue)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if b.Kind != BlockIf {
|
if b.Kind != BlockIf {
|
||||||
|
@ -161,7 +161,7 @@ func CmpZero4(a int64, ptr *int) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func CmpToZero(a, b, d int32, e, f int64) int32 {
|
func CmpToZero(a, b, d int32, e, f int64, deOptC0, deOptC1 bool) int32 {
|
||||||
// arm:`TST`,-`AND`
|
// arm:`TST`,-`AND`
|
||||||
// arm64:`TSTW`,-`AND`
|
// arm64:`TSTW`,-`AND`
|
||||||
// 386:`TESTL`,-`ANDL`
|
// 386:`TESTL`,-`ANDL`
|
||||||
@ -201,13 +201,17 @@ func CmpToZero(a, b, d int32, e, f int64) int32 {
|
|||||||
} else if c4 {
|
} else if c4 {
|
||||||
return 5
|
return 5
|
||||||
} else if c5 {
|
} else if c5 {
|
||||||
return b + d
|
return 6
|
||||||
} else if c6 {
|
} else if c6 {
|
||||||
return a & d
|
|
||||||
} else if c7 {
|
|
||||||
return 7
|
return 7
|
||||||
|
} else if c7 {
|
||||||
|
return 9
|
||||||
} else if c8 {
|
} else if c8 {
|
||||||
return 8
|
return 10
|
||||||
|
} else if deOptC0 {
|
||||||
|
return b + d
|
||||||
|
} else if deOptC1 {
|
||||||
|
return a & d
|
||||||
} else {
|
} else {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
32
test/prove_constant_folding.go
Normal file
32
test/prove_constant_folding.go
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
// +build amd64
|
||||||
|
// errorcheck -0 -d=ssa/prove/debug=2
|
||||||
|
|
||||||
|
// Copyright 2022 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
|
||||||
|
|
||||||
|
func f0i(x int) int {
|
||||||
|
if x == 20 {
|
||||||
|
return x // ERROR "Proved.+is constant 20$"
|
||||||
|
}
|
||||||
|
|
||||||
|
if (x + 20) == 20 {
|
||||||
|
return x + 5 // ERROR "Proved.+is constant 0$"
|
||||||
|
}
|
||||||
|
|
||||||
|
return x / 2
|
||||||
|
}
|
||||||
|
|
||||||
|
func f0u(x uint) uint {
|
||||||
|
if x == 20 {
|
||||||
|
return x // ERROR "Proved.+is constant 20$"
|
||||||
|
}
|
||||||
|
|
||||||
|
if (x + 20) == 20 {
|
||||||
|
return x + 5 // ERROR "Proved.+is constant 0$"
|
||||||
|
}
|
||||||
|
|
||||||
|
return x / 2
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user