mirror of https://github.com/golang/go.git
cmd/compile: remove walkinrange optimization
The walkinrange optimization has been superseded by CL 165998.
Has a small positive impact on binary sizes:
compilecmp master -> HEAD
master (e37cc29863): cmd/compile: optimize integer-in-range checks
HEAD (1a70680a34): cmd/compile: remove walkinrange optimization
platform: linux/amd64
file before after Δ %
addr2line 4329144 4325048 -4096 -0.095%
api 6060970 6056874 -4096 -0.068%
asm 5196905 5192809 -4096 -0.079%
cgo 4898769 4890577 -8192 -0.167%
compile 20222193 20209713 -12480 -0.062%
cover 5331580 5323388 -8192 -0.154%
dist 3732778 3728682 -4096 -0.110%
doc 4748488 4740296 -8192 -0.173%
link 6707380 6695092 -12288 -0.183%
nm 4278685 4274589 -4096 -0.096%
pack 2305038 2300942 -4096 -0.178%
pprof 14874834 14870738 -4096 -0.028%
test2json 2849221 2845125 -4096 -0.144%
vet 8393173 8384981 -8192 -0.098%
go 15205572 15193284 -12288 -0.081%
total 131812292 131709700 -102592 -0.078%
Updates #30645.
Change-Id: I42d74481652c90fef1a9bc58c70836e42c9b1c4b
Reviewed-on: https://go-review.googlesource.com/c/go/+/221802
Run-TryBot: Michael Munday <mike.munday@ibm.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Josh Bleecher Snyder <josharian@gmail.com>
This commit is contained in:
parent
7b0b6c2f7e
commit
24343cb886
|
|
@ -565,7 +565,6 @@ opswitch:
|
|||
|
||||
n.Right = walkexpr(n.Right, &ll)
|
||||
n.Right = addinit(n.Right, ll.Slice())
|
||||
n = walkinrange(n, init)
|
||||
|
||||
case OPRINT, OPRINTN:
|
||||
n = walkprint(n, init)
|
||||
|
|
@ -3523,133 +3522,6 @@ func (n *Node) isIntOrdering() bool {
|
|||
return n.Left.Type.IsInteger() && n.Right.Type.IsInteger()
|
||||
}
|
||||
|
||||
// walkinrange optimizes integer-in-range checks, such as 4 <= x && x < 10.
|
||||
// n must be an OANDAND or OOROR node.
|
||||
// The result of walkinrange MUST be assigned back to n, e.g.
|
||||
// n.Left = walkinrange(n.Left)
|
||||
func walkinrange(n *Node, init *Nodes) *Node {
|
||||
// We are looking for something equivalent to a opl b OP b opr c, where:
|
||||
// * a, b, and c have integer type
|
||||
// * b is side-effect-free
|
||||
// * opl and opr are each < or ≤
|
||||
// * OP is &&
|
||||
l := n.Left
|
||||
r := n.Right
|
||||
if !l.isIntOrdering() || !r.isIntOrdering() {
|
||||
return n
|
||||
}
|
||||
|
||||
// Find b, if it exists, and rename appropriately.
|
||||
// Input is: l.Left l.Op l.Right ANDAND/OROR r.Left r.Op r.Right
|
||||
// Output is: a opl b(==x) ANDAND/OROR b(==x) opr c
|
||||
a, opl, b := l.Left, l.Op, l.Right
|
||||
x, opr, c := r.Left, r.Op, r.Right
|
||||
for i := 0; ; i++ {
|
||||
if samesafeexpr(b, x) {
|
||||
break
|
||||
}
|
||||
if i == 3 {
|
||||
// Tried all permutations and couldn't find an appropriate b == x.
|
||||
return n
|
||||
}
|
||||
if i&1 == 0 {
|
||||
a, opl, b = b, brrev(opl), a
|
||||
} else {
|
||||
x, opr, c = c, brrev(opr), x
|
||||
}
|
||||
}
|
||||
|
||||
// If n.Op is ||, apply de Morgan.
|
||||
// Negate the internal ops now; we'll negate the top level op at the end.
|
||||
// Henceforth assume &&.
|
||||
negateResult := n.Op == OOROR
|
||||
if negateResult {
|
||||
opl = brcom(opl)
|
||||
opr = brcom(opr)
|
||||
}
|
||||
|
||||
cmpdir := func(o Op) int {
|
||||
switch o {
|
||||
case OLE, OLT:
|
||||
return -1
|
||||
case OGE, OGT:
|
||||
return +1
|
||||
}
|
||||
Fatalf("walkinrange cmpdir %v", o)
|
||||
return 0
|
||||
}
|
||||
if cmpdir(opl) != cmpdir(opr) {
|
||||
// Not a range check; something like b < a && b < c.
|
||||
return n
|
||||
}
|
||||
|
||||
switch opl {
|
||||
case OGE, OGT:
|
||||
// We have something like a > b && b ≥ c.
|
||||
// Switch and reverse ops and rename constants,
|
||||
// to make it look like a ≤ b && b < c.
|
||||
a, c = c, a
|
||||
opl, opr = brrev(opr), brrev(opl)
|
||||
}
|
||||
|
||||
// We must ensure that c-a is non-negative.
|
||||
// For now, require a and c to be constants.
|
||||
// In the future, we could also support a == 0 and c == len/cap(...).
|
||||
// Unfortunately, by this point, most len/cap expressions have been
|
||||
// stored into temporary variables.
|
||||
if !Isconst(a, CTINT) || !Isconst(c, CTINT) {
|
||||
return n
|
||||
}
|
||||
|
||||
// Ensure that Int64() does not overflow on a and c (it'll happen
|
||||
// for any const above 2**63; see issue #27143).
|
||||
if !a.CanInt64() || !c.CanInt64() {
|
||||
return n
|
||||
}
|
||||
|
||||
if opl == OLT {
|
||||
// We have a < b && ...
|
||||
// We need a ≤ b && ... to safely use unsigned comparison tricks.
|
||||
// If a is not the maximum constant for b's type,
|
||||
// we can increment a and switch to ≤.
|
||||
if a.Int64() >= maxintval[b.Type.Etype].Int64() {
|
||||
return n
|
||||
}
|
||||
a = nodintconst(a.Int64() + 1)
|
||||
opl = OLE
|
||||
}
|
||||
|
||||
bound := c.Int64() - a.Int64()
|
||||
if bound < 0 {
|
||||
// Bad news. Something like 5 <= x && x < 3.
|
||||
// Rare in practice, and we still need to generate side-effects,
|
||||
// so just leave it alone.
|
||||
return n
|
||||
}
|
||||
|
||||
// We have a ≤ b && b < c (or a ≤ b && b ≤ c).
|
||||
// This is equivalent to (a-a) ≤ (b-a) && (b-a) < (c-a),
|
||||
// which is equivalent to 0 ≤ (b-a) && (b-a) < (c-a),
|
||||
// which is equivalent to uint(b-a) < uint(c-a).
|
||||
ut := b.Type.ToUnsigned()
|
||||
lhs := conv(nod(OSUB, b, a), ut)
|
||||
rhs := nodintconst(bound)
|
||||
if negateResult {
|
||||
// Negate top level.
|
||||
opr = brcom(opr)
|
||||
}
|
||||
cmp := nod(opr, lhs, rhs)
|
||||
cmp.Pos = n.Pos
|
||||
cmp = addinit(cmp, l.Ninit.Slice())
|
||||
cmp = addinit(cmp, r.Ninit.Slice())
|
||||
// Typecheck the AST rooted at cmp...
|
||||
cmp = typecheck(cmp, ctxExpr)
|
||||
// ...but then reset cmp's type to match n's type.
|
||||
cmp.Type = n.Type
|
||||
cmp = walkexpr(cmp, init)
|
||||
return cmp
|
||||
}
|
||||
|
||||
// return 1 if integer n must be in range [0, max), 0 otherwise
|
||||
func bounded(n *Node, max int64) bool {
|
||||
if n.Type == nil || !n.Type.IsInteger() {
|
||||
|
|
|
|||
Loading…
Reference in New Issue