From 31072e41f4e2ed0a135c46816cb2a65daba12540 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Thu, 14 Feb 2013 14:54:00 -0500 Subject: [PATCH] cmd/gc: replace x*8 by x<<3 etc Fixes #4199. R=ken2 CC=golang-dev https://golang.org/cl/7322081 --- src/cmd/gc/walk.c | 72 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 71 insertions(+), 1 deletion(-) diff --git a/src/cmd/gc/walk.c b/src/cmd/gc/walk.c index a781ed20c4..4e751cbce7 100644 --- a/src/cmd/gc/walk.c +++ b/src/cmd/gc/walk.c @@ -24,6 +24,7 @@ static Node* append(Node*, NodeList**); static Node* sliceany(Node*, NodeList**); static void walkcompare(Node**, NodeList**); static void walkrotate(Node**); +static void walkmul(Node**, NodeList**); static void walkdiv(Node**, NodeList**); static int bounded(Node*, int64); static Mpint mpzero; @@ -481,7 +482,6 @@ walkexpr(Node **np, NodeList **init) case OAND: case OSUB: - case OMUL: case OHMUL: case OLT: case OLE: @@ -932,6 +932,12 @@ walkexpr(Node **np, NodeList **init) walkexpr(&n->right, init); goto ret; + case OMUL: + walkexpr(&n->left, init); + walkexpr(&n->right, init); + walkmul(&n, init); + goto ret; + case ODIV: case OMOD: walkexpr(&n->left, init); @@ -2897,6 +2903,70 @@ yes: return; } +/* + * walkmul rewrites integer multiplication by powers of two as shifts. + */ +static void +walkmul(Node **np, NodeList **init) +{ + Node *n, *nl, *nr; + int pow, neg, w; + + n = *np; + if(!isint[n->type->etype]) + return; + + if(n->right->op == OLITERAL) { + nl = n->left; + nr = n->right; + } else if(n->left->op == OLITERAL) { + nl = n->right; + nr = n->left; + } else + return; + + neg = 0; + + // x*0 is 0 (and side effects of x). + if(mpgetfix(nr->val.u.xval) == 0) { + cheapexpr(nl, init); + nodconst(n, n->type, 0); + goto ret; + } + + // nr is a constant. + pow = powtwo(nr); + if(pow < 0) + return; + if(pow >= 1000) { + // negative power of 2, like -16 + neg = 1; + pow -= 1000; + } + + w = nl->type->width*8; + if(pow+1 >= w)// too big, shouldn't happen + return; + + nl = cheapexpr(nl, init); + + if(pow == 0) { + // x*1 is x + n = nl; + goto ret; + } + + n = nod(OLSH, nl, nodintconst(pow)); + +ret: + if(neg) + n = nod(OMINUS, n, N); + + typecheck(&n, Erv); + walkexpr(&n, init); + *np = n; +} + /* * walkdiv rewrites division by a constant as less expensive * operations. -- 2.48.1