cmd/gc: recognize u<<1 op u>>31 as a rotate when op is ^, not just |.

R=rsc
CC=golang-dev
https://golang.org/cl/6249071
This commit is contained in:
Nigel Tao 2012-06-04 20:53:32 +10:00
parent 5612fd770d
commit 947a3ddf87
2 changed files with 64 additions and 43 deletions

View File

@ -468,7 +468,6 @@ walkexpr(Node **np, NodeList **init)
goto ret; goto ret;
case OAND: case OAND:
case OXOR:
case OSUB: case OSUB:
case OMUL: case OMUL:
case OLT: case OLT:
@ -483,6 +482,7 @@ walkexpr(Node **np, NodeList **init)
goto ret; goto ret;
case OOR: case OOR:
case OXOR:
walkexpr(&n->left, init); walkexpr(&n->left, init);
walkexpr(&n->right, init); walkexpr(&n->right, init);
walkrotate(&n); walkrotate(&n);
@ -2708,10 +2708,10 @@ walkrotate(Node **np)
n = *np; n = *np;
// Want << | >> or >> | << on unsigned value. // Want << | >> or >> | << or << ^ >> or >> ^ << on unsigned value.
l = n->left; l = n->left;
r = n->right; r = n->right;
if(n->op != OOR || if((n->op != OOR && n->op != OXOR) ||
(l->op != OLSH && l->op != ORSH) || (l->op != OLSH && l->op != ORSH) ||
(r->op != OLSH && r->op != ORSH) || (r->op != OLSH && r->op != ORSH) ||
n->type == T || issigned[n->type->etype] || n->type == T || issigned[n->type->etype] ||

View File

@ -9,7 +9,7 @@
// Generate test of shift and rotate by constants. // Generate test of shift and rotate by constants.
// The output is compiled and run. // The output is compiled and run.
// //
// The output takes around a minute to compile, link, and run // The output takes around a minute or two to compile, link, and run
// but it is only done during ./run, not in normal builds using run.go. // but it is only done during ./run, not in normal builds using run.go.
package main package main
@ -86,6 +86,26 @@ func main() {
` `
var (
uop = [2]func(x, y uint64) uint64{
func(x, y uint64) uint64 {
return x | y
},
func(x, y uint64) uint64 {
return x ^ y
},
}
iop = [2]func(x, y int64) int64{
func(x, y int64) int64 {
return x | y
},
func(x, y int64) int64 {
return x ^ y
},
}
cop = [2]byte{'|', '^'}
)
func gentest(b *bufio.Writer, bits uint, unsigned, inverted bool) { func gentest(b *bufio.Writer, bits uint, unsigned, inverted bool) {
fmt.Fprintf(b, "func init() {\n") fmt.Fprintf(b, "func init() {\n")
defer fmt.Fprintf(b, "}\n") defer fmt.Fprintf(b, "}\n")
@ -94,48 +114,49 @@ func gentest(b *bufio.Writer, bits uint, unsigned, inverted bool) {
// Generate tests for left/right and right/left. // Generate tests for left/right and right/left.
for l := uint(0); l <= bits; l++ { for l := uint(0); l <= bits; l++ {
for r := uint(0); r <= bits; r++ { for r := uint(0); r <= bits; r++ {
typ := fmt.Sprintf("int%d", bits) for o, op := range cop {
v := fmt.Sprintf("i%d", bits) typ := fmt.Sprintf("int%d", bits)
if unsigned { v := fmt.Sprintf("i%d", bits)
typ = "u" + typ if unsigned {
v = "u" + v typ = "u" + typ
} v = "u" + v
v0 := int64(0x123456789abcdef0) }
if inverted { v0 := int64(0x123456789abcdef0)
v = "n" + v if inverted {
v0 = ^v0 v = "n" + v
} v0 = ^v0
expr1 := fmt.Sprintf("%s<<%d | %s>>%d", v, l, v, r) }
expr2 := fmt.Sprintf("%s>>%d | %s<<%d", v, r, v, l) expr1 := fmt.Sprintf("%s<<%d %c %s>>%d", v, l, op, v, r)
expr2 := fmt.Sprintf("%s>>%d %c %s<<%d", v, r, op, v, l)
var result string
if unsigned {
v := uint64(v0) >> (64 - bits)
v = v<<l | v>>r
v <<= 64 - bits
v >>= 64 - bits
result = fmt.Sprintf("%#x", v)
} else {
v := int64(v0) >> (64 - bits)
v = v<<l | v>>r
v <<= 64 - bits
v >>= 64 - bits
result = fmt.Sprintf("%#x", v)
}
fmt.Fprintf(b, "\tcheck(%q, %s, %s(%s))\n", expr1, expr1, typ, result) var result string
fmt.Fprintf(b, "\tcheck(%q, %s, %s(%s))\n", expr2, expr2, typ, result) if unsigned {
v := uint64(v0) >> (64 - bits)
v = uop[o](v<<l, v>>r)
v <<= 64 - bits
v >>= 64 - bits
result = fmt.Sprintf("%#x", v)
} else {
v := int64(v0) >> (64 - bits)
v = iop[o](v<<l, v>>r)
v <<= 64 - bits
v >>= 64 - bits
result = fmt.Sprintf("%#x", v)
}
// Chop test into multiple functions so that there's not one fmt.Fprintf(b, "\tcheck(%q, %s, %s(%s))\n", expr1, expr1, typ, result)
// enormous function to compile/link. fmt.Fprintf(b, "\tcheck(%q, %s, %s(%s))\n", expr2, expr2, typ, result)
// All the functions are named init so we don't have to do
// anything special to call them. ☺ // Chop test into multiple functions so that there's not one
if n++; n >= 100 { // enormous function to compile/link.
fmt.Fprintf(b, "}\n") // All the functions are named init so we don't have to do
fmt.Fprintf(b, "func init() {\n") // anything special to call them. ☺
n = 0 if n++; n >= 50 {
fmt.Fprintf(b, "}\n")
fmt.Fprintf(b, "func init() {\n")
n = 0
}
} }
} }
} }
} }